Changelog

All versions and downloads Jump to Added | Changed | Fixed | Security

Unreleased [Not released yet]

Part 8 of 11. Previous part

Fixed (464)

  • wisp build rejects a redirects rule whose to is its own from with a / at the end ("/docs /docs/"). Before, the build accepted it and the server sent the browser round for ever.
  • The sitemap and the feed make their text once for requests that miss together. Before, each such request ran every entries() again. A crawler that read /sitemap-1.xml to /sitemap-10.xml at once made ten copies.
  • Response::file_in answers 404 for a name that the file system refuses (a file used as a directory, a name that is too long). Before, it answered 500 and fired report.
  • A #[remote(get)] function that returns a stream or a WebSocket gets no etag. Before, every stream had the etag of an empty body, so the browser showed the first stream again for ever. An ETag that the app sets in any case stays.
  • An upload of an SVG with a <!DOCTYPE svg> line or a prolog of more than 256 bytes has the type image/svg+xml. This holds for a file of 1 MB or less. A bigger file gets the check on its first 8192 bytes. Before, the type was text/plain, so types = "text/plain" took the file and types = "image/svg+xml" refused it.
  • The CSS minifier of a release build reads \' and \" in a selector as escapes. Before, an escaped quote (a class name from Tailwind) opened a string. The strings and the code then swapped places for the rest of the sheet, so a content text could lose its spaces.
  • wisp fmt keeps the : of a selector in @supports selector(..) and @scope (..). Before, selector(:has(a)) became selector(: has(a)), which is not a selector, so the @supports test failed.
  • The JavaScript tokenizer ends a line at CR, U+2028 and U+2029 as well as LF. Before, the release minifier dropped the code after a // comment that one of them ended, and read return + CR + x as return x.
  • An <Island> whose attribute value has a line break no longer moves the lines after it. Before, the lines in the value counted twice, so errors and source maps pointed one line late for each line break in the value.
  • A self-closed <iframe />, <video />, <audio /> or <object /> and the <style global> of a template add their origins to the CSP, as <video></video> does. Before, the CSP blocked the frame, the media, the font or the @import.
  • <wisp:element this={:t} /> writes its end tag. Before, the element took the siblings after it as children, and the end tag of a <wisp:element> around it had the wrong name.
  • The TypeScript type of a #[remote(batch)] that returns Vec<Option<T>> is WispQuery<T | null>. Before it was WispQuery<T>, but an item that is None answers null.
  • wisp checks the pre-release part of the version of the app against the CLI. Before, a 1.0.0-pre.4 app with a 1.0.0-pre.3 CLI gave no warning.
  • wisp deploy init installs the CLI in the workflow at the release tag that the app pins (--tag). Before, it installed the CLI of the default branch. wisp upgrade sets the --tag of the cargo install wisp-web line to the new release, and no other line. Its undo puts the workflow back, refuses when the workflow changed after the upgrade, and never deletes a workflow that the upgrade did not save.
  • The CSS minifier keeps the space after an escaped byte (.a\, .b) and the ; in --x:a\;. The scoper of a <style> reads \' in a selector or an animation value as an escape, so a @keyframes name after it still gets the scope.
  • wisp test --coverage no longer counts a line of a skipped {#if} or {#each} body as run. Before, a generated line after the end of a block took the mark of the lines inside the block. Now a generated line at or after a } line takes no mark from above it. A panic location and a build error use the same rule.
  • wisp check --types shows what node writes on stderr, and tsc failed (exit N) when tsc prints no diagnostic. Before, the error was an empty "TypeScript found errors:". A tsc line that continues a message (it starts with a space) stays as tsc wrote it. The command refuses a symbolic link at .wisp/types. Before, it deleted the link and wrote a new folder in its place. #[derive(Json)] on a tuple struct with no field gives the TypeScript type A = [];. Before, it gave type A = ;.
  • wisp test --e2e --init stops with an error when it cannot read .gitignore, and writes nothing. Before, a .gitignore that was not UTF-8 text lost all its lines. Only the two new lines stayed.
  • wisp dev keeps the variables that the [env] table of .cargo/config.toml sets, when it builds without cargo. Before, such a variable was gone after the first build (option_env! gave None, and env! failed). wisp dev no longer stops on an environment variable that is not UTF-8.
  • On Windows, wisp upgrade builds the new CLI in a folder of its own, and changes the file names only after the build. Before, it renamed the running wisp.exe first, and a Ctrl-C during the build left no wisp.exe. It moves the running file only when that file is the installed CLI.
  • The WebP and AVIF step of a release build writes a file once when two sources name it. Examples are a manifest icon that a page also shows, or two files with the same bytes. Each temporary file has its own name. Before, two encoders wrote one temporary file, and the build could show a false warning.
  • wisp new refuses an option with a value, such as --git=false, --install=false or --lib=no. Only --template takes a value. Before, Wisp dropped the value and turned the option on.
  • A form answer can redirect to the page that the browser shows. That page can redirect to another page (a guard to /login). Now the browser goes to the other page. Before, wisp.js swapped an empty page in.
  • A form answer that redirects to the page that the browser shows, and that page is a file, stays a file. Before, wisp.js swapped it in as HTML.
  • A form with an action outside the base path is no longer sent by wisp.js. The browser sends it.
  • The loading view of a slow navigation no longer leaves aria-busy="true" on main or a slot. The view also goes back when a newer navigation ends in a file, offline or in a slot page.
  • A slot page that fails no longer cancels a newer navigation. A slot page now shows its {#await} answers.
  • wisp.js follows only links under the base path. Before, a link to / or /apple under the base /app went to the other app on the same origin.
  • A refresh that began before a form post no longer swaps its older page over the answer of the post.
  • A page kept for Back that waited on {#await} swaps in the page with the answers, also after the visitor scrolled.
  • wisp.js finds queue.js and live.js by the end of the script path. Before, a host or a base that held wisp.js gave another address.
  • --spa hosts: the browser matches a path to a route as the server router does. A [[optional]] before a static segment fits. A [...rest] with segments after it fits. A [id=int] must fit a u64, and a [param] is not empty. A path outside the base path fits no route.
  • +loading.wisp on a page with a +page.js load: the busy mark goes also when the address changed during the load.
  • tweened: set() does not read the store, so an effect that sets it no longer restarts on each frame.
  • fromAction: a function that update returns is no longer called as a cleanup.
  • With the avif feature, a release build serves the AVIF widths that a <picture> names. Before, the build did not embed them, and a browser that reads AVIF got a 404 for the image.
  • The OpenAPI document and the TypeScript client show a POST, PUT, PATCH or DELETE input that is a struct but not body (fn post(note: Note)) as the fields of its request body. The server reads the struct from the body by its fields. Before, they showed one field note, and a client call failed. A field of such a struct that has the name of body, of a route parameter or of another input fails the build.
  • A GET handler with a struct input that is not body fails the build with "A GET reads no body: take the fields as inputs". Before, the server read the struct from the body and not from the query, so the fields in the URL had no effect. A handler with body: T and a struct input also fails the build: both read the request body.
  • A page action that takes a struct from the page's own Rust (fn default(post: Post)) shows the fields of the struct in the OpenAPI document. Before, it showed one field post.
  • The build fails when two routes give one TypeScript client method (/api/[id] and /api/byId are both getApiById). Before, the client kept only one of them.
  • A +loading.wisp in a (group) folder shows only for the pages below that folder. Before, it showed for the whole site, and it hid the loading view of a folder next to it.
  • A script that names a store or an import state, effect or inspect and calls the rune of the same name ($state.snapshot(state)) builds. Before, the build failed with "Wisp cannot rewrite the code here".
  • A name that starts with $ and that the script declares (const $list = ...) is that name. Before, the build read it as the store list.
  • The release CSP adds the https origins of the URLs in a <script type="importmap"> to script-src. Before, the browser blocked a module that an import map sent to a CDN.
  • The build script runs again when Cargo.lock changes, so cargo update brings a new version of a registry plugin.
  • #[validate(step = ..)] writes the step attribute of a number input only when the tag has no min and no value of its own. A browser counts steps from the min of the tag, else from its value, else from 0. Before, the browser refused values that the server takes, and it took values that the server refuses.
  • Backoff::run gives back the lockout that it found when the attempt fails with an error that is not a 401 or a 422. Before, a 500 or a 503 at the end of a lockout could double the next lockout.
  • With ORIGIN set, a form post from the onion twin of the app passes the origin check when its Origin is a .onion address that equals its Host. Before, every such post was a 403.
  • <form once>: an action that returns a Response with a status of 400 or more lets the browser send the form again. Before, Wisp counted that post as done, and a repeat got a 303 for 15 minutes.
  • A request that Wisp refuses before it reads the body (a spent RATE_LIMIT, or SIGNED_IN) is now in the JSON log, the metrics and the traces. Before, it was in none of them.
  • OpenTelemetry: the exporter tries each address of the endpoint host until one connects. Before, it tried the first only, so http://localhost:4318 failed when localhost gave ::1 first and the collector listened on 127.0.0.1. OTEL_BSP_SCHEDULE_DELAY=0 now means 1 ms. Before, it made the exporter thread use one CPU core without pause.
  • WebSocket: the clock for a message that comes in pieces starts again after each whole message. Before, a client on a slow link that sent many messages in a row could get close code 1008 although every message came in time. recv ends with close code 1001 when the server stops, also when the client keeps messages waiting. A buffer for a large frame that comes in pieces keeps its room. On the edge, a recv that waits keeps one waker for each task.
  • WISP_WS_IDLE, WISP_DRAIN, WISP_STOP_DELAY and WISP_SSE_HEARTBEAT take at most 100 years of seconds: a larger value counts as 100 years. Before, a larger number made the first recv of a WebSocket panic.
  • Saved tables: a refresh that changes rows counts as a read, so a poll that asked the store before it does not write older rows over them. A poll reads its counters while it holds the read lock of the table.
  • Auto imports: a name after | between two values (READ | WRITE), after for of an impl, or in a pattern with braces or a path (let Post { .. } = p, &mut Report::new()) is no binding. Before, the build did not import such a name, and rustc said "cannot find value".
  • Auto imports: a name at the end of a hole is still a use when {:else} or {@html …} follows ({#if SIGNUPS_OPEN}…{:else}…{/if}). The holes of a <script> start tag and a {@json …} in a data script count as Rust. <styled-card> and <script-editor> are elements. Before, the build did not import these names.
  • Browser lets: a literal let that the server reads stays in Rust in these places. They are {:else if …} or {:case …} of a server block, a {@json …} of a data script, the start tag of a <script>, and a <script-editor> element. Before, the let moved to the browser, and the generated Rust failed to build.
  • {#if let Some(u) = db::user().await} outside a block hoists only the value. Before, the build wrote let __wisp_a0 = let Some(u) = …, and rustc failed on generated code.
  • The embedded brotli copies in .wisp/br use a temporary file name of their own for each build. Before, two builds of one app (cargo, rust-analyzer, wisp dev) shared one name, and a stopped build could leave a short file that later builds embedded.
  • A #[remote] function can no longer take the name of an extra script helper (preload, announce, modal, outside, inview, shortcut, optimistic, keepscroll, swr, tweened, spring, crossfade, fromAction, MediaQuery, prefersReducedMotion). Before, a script that called it got the helper, and the call never reached the server.
  • A command refreshes all live queries when the server answers none of them, also when the first URL is 3997 characters or longer. Before, the page kept stale data until a reload.
  • $lib/x takes the file of the lowest folder, whichever of x.js and x.ts it is. Before, a layer's x.js hid the x.ts of the app.
  • A build plugin run that stops part way (an error, Ctrl-C) keeps its manifest. Before, the outputs written so far had no manifest. The next build refused them as "exists and no build plugin made it", or never deleted them. After an error, the manifest lists only the outputs that the run wrote, so a file that you make later is not overwritten.
  • First paint of {:x} and name={:x} writes nothing for an array or an object, and a number as JavaScript prints it. Before, the server wrote the JSON (["a","b"]) where the browser wrote a,b, and -0 or 1e21 in another form.
  • wisp dev works with HOST set to an address of this machine (HOST=192.168.1.5). Before, every swap failed with "Not Found". The app took only a loopback peer and a loopback Host. So each save of a template started a full rebuild. Now the app listens on loopback behind the front, and wisp dev sends each swap there with Host: localhost.
  • wisp dev: when a save changes more than one template and a later one fails to parse, browsers still show the new text of the templates that the app took before it. Before, open tabs kept the old markup until a reload.
  • wisp lsp keeps the components that parse when one component file has an error. Before, one broken file in src/components hid all components, so every use showed "no component". The error stays in the broken file. A use of the broken component says "component Bad has an error".
  • wisp lsp colors a hole as the build reads it. A } in a /* */ comment or in a raw string (r#"..."#) does not end the hole. {@json data} gets colors in a script that the browser does not run (<script type="application/ld+json">). A {:catch} or {:else} of a {:#try} block gets the client modifier.
  • wisp lsp does not rename a name to cx, because generated code uses cx in a block body.
  • wisp changelog shows only digits and - in the date of a release. Before, a release server could put control characters in the date. A long line of [ in release notes took quadratic time, and now it takes linear time.
  • wisp::sign_out_everywhere: a table that failed a read after a lock error no longer lets a session pass. Before, it counted no sign-out for each id. The log line for a later failed read now says that sessions keep their counts. Before, it said that sessions get a 503. The server logs when it cannot start the thread that reads the sign-outs again.
  • A component with --var props joins the style attribute of its root when the attribute has blanks around the = (style = "..."). Before, the root got a second style attribute, which the browser ignores.
  • The sitemap, robots.txt and the feed wait only for a make of the same file. Before, one slow entries() held every other miss.
  • wisp dev --https stops with an error when .wisp/dev-key.pem exists without .wisp/dev-cert.pem. Before, it wrote a new key over it.
  • The output of a companion command cannot mark the companion as ended by accident. Wisp accepts the exit line of the supervisor only with a nonce, and the supervisor does not pass the nonce to the command. The nonce stops accidental output only: on Linux the command can read /proc/$PPID/environ, so a hostile command can still print a valid exit line. Before, a command that printed the text wisp-companion-exit could stop the kill on Windows.
  • The dev server waits 100 ms and then 200 ms between its tries to give the app the new generation. Before, the three tries came at once, and an app that restarted missed all of them.
  • wisp dev does not hold a lock while it tells the app a new generation. Before, a restart of the app could wait for the three tries and their pauses.
  • wisp dev prints a warning when it cannot lock .wisp/run/lock-<pid>. A second wisp dev in the same app may then delete the copies of this run. Before, the run went on with no message.
  • wisp build --target does not list a file for the next build to sweep when a symbolic link in static/ leads to a path with a dot segment (static/pub to static/.git). Before, the list held static/pub/config, though no file was copied.
  • save_to of an upload copies to a name of up to 255 bytes on another disk. Before, the temporary name was longer than the target name and could pass the limit of the file system. The temporary name now holds at most 200 bytes of the target name.
  • src/hooks.rs rejects a constant with the name and the type of a page knob when the type has a lifetime (const CACHE_TAGS: &'static [&'static str]). Before, the build accepted it and the knob did nothing.
  • Build plugins: two outputs whose names differ only by the case of a letter beyond ASCII (a capital and a small e with an acute accent) are one name. Before, the check for a clash saw two names, and on Windows and macOS the second plugin could overwrite the first output.
  • The error for a +server.rs member route (/[id]) that has no page route in its folder names what the build found, not a guard that may not exist.
  • Templates: a regular expression of exactly 256 bytes in a {:js} hole ends at its closing /. A / inside a [...] class at that limit does not end it. Before, the scan took the / after the last byte it read as the end.
  • wisp lsp rename of a component reads the char literal '\'' to its end. Before, ('\'', '"') made a false string.
  • wisp dev on Windows does not wait for a slow pid query when it stops. If the job object holds, it ends what a dead companion supervisor left. Before, each such companion could hold the exit for up to 3 seconds.
  • A companion output that looks like a pid line and has no line end no longer hides the exit line of the supervisor that follows it.
  • After the app takes more than 1 second in all to fail the generation post of wisp dev, the file watcher makes no new try. Before, each failed try that took less than 1 second started a new one.
  • The Vercel and Netlify builds write a route name that holds a quote as a valid string in config.json and in the edge function. Before, a " in the Vercel src (or a ' in the Netlify path) ended the string.

Next part (9 of 11)

Source: CHANGELOG.md