Skip to main content

max / quasi

0.32.0: a call the host makes, and the renderer does not `a81384d4`, ruled by Max 2026-08-18 as option (a). Found starting mnw-server's audio upload, which is the first description in the tree whose destination a renderer cannot call. `f7261a5a` settled the four axes of an upload and this is none of them. The accept list, the multiplicity, the destination and the progress were all expressible; who performs the destination was not. An MNW upload is three requests, not one -- ask the server to sign a URL, PUT the file to storage with it, tell the server it landed -- and thirteen files across `static/` and `frontend/src/` run that chain against three route families. A renderer posting the field to the first of those is wrong about the response shape and about where the bytes go. `Action::by_host` says so, and it is `Action::saves`' shape rather than a new principle: a named attribute the host acts on, because there are calls a renderer cannot make and the alternative to saying so is a host reaching around the description to a control the description owns. quasi-webview emits `data-sends` with the address and no transport at all -- no verb, no trigger, no href. `data-sends` and not `data-action`: what is named is where the thing goes, which is the half the description knows. Two things that would have been silent if they were wrong, so both have a test. The payload travels as `data-vals`, since `hx-vals` is htmx's and htmx is not involved here; dropping it would be the description saying something the markup did not carry. And the wait survives while the lock does not -- `data-awaiting` is a fact about the call, `hx-disabled-elt` is htmx locking a control on a request it is making, and this is not one. That split the old block in two, so `awaiting_attrs` is now its own function. quasi-tui refuses one rather than making it wrongly. Pressing a control marked this way says "this app cannot do that here" and calls nothing: the address is a signing endpoint that answers JSON, and a terminal asking it for a screen would swap the signature it got back. Announced on the spot, because no navigation is coming to carry the message later. The cost is written onto the member rather than left to be discovered: a call marked this way is not portable, and that is permanent. A terminal meeting a described upload learns the accept list, the multiplicity and that it waits, and has nothing to perform. That is what the ruling bought for keeping the file going browser-to-storage instead of through the production box, which would otherwise proxy half-gigabyte bodies it does not proxy today.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-19 01:16 UTC
Signed with PGP, not checked
Commit: 29715efcb6228027241e418191b38304477c4ba6
Parent: a2a5aa7
17 files changed, +264 insertions, -52 deletions
M Cargo.lock +8 -8
@@ -6191,14 +6191,6 @@
6191 6191 name = "makeover-build"
6192 6192 version = "0.46.0"
6193 6193
6194 - [[patch.unused]]
6195 - name = "quasi-type"
6196 - version = "0.1.0"
6197 -
6198 - [[patch.unused]]
6199 - name = "synckit-client"
6200 - version = "0.8.0"
6201 -
6202 6194 [[patch.unused]]
6203 6195 name = "kberg"
6204 6196 version = "0.1.0"
@@ -6214,3 +6206,11 @@
6214 6206 [[patch.unused]]
6215 6207 name = "tagtree"
6216 6208 version = "0.4.0"
6209 +
6210 + [[patch.unused]]
6211 + name = "quasi-type"
6212 + version = "0.1.0"
6213 +
6214 + [[patch.unused]]
6215 + name = "synckit-client"
6216 + version = "0.8.0"
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-axum"
3 - version = "0.31.0"
3 + version = "0.32.0"
4 4 description = "The axum host adapter for quasi-router: an HTTP request in, a rendered description out"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -13,14 +13,14 @@
13 13 workspace = true
14 14
15 15 [dependencies]
16 - quasi-router = { path = "../quasi-router", version = "0.31.0" }
17 - quasi-http = { path = "../quasi-http", version = "0.31.0" }
16 + quasi-router = { path = "../quasi-router", version = "0.32.0" }
17 + quasi-http = { path = "../quasi-http", version = "0.32.0" }
18 18 axum = "0.8.8"
19 19 http = "1.3.1"
20 20 tokio = { version = "1.50.0", features = ["rt"] }
21 21
22 22 [dev-dependencies]
23 - quasi-webview = { path = "../quasi-webview", version = "0.31.0" }
23 + quasi-webview = { path = "../quasi-webview", version = "0.32.0" }
24 24 tokio = { version = "1.50.0", features = ["macros", "rt-multi-thread"] }
25 25 tower = { version = "0.5.3", features = ["util"] }
26 26 http-body-util = "0.1.3"
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-basics"
3 - version = "0.31.0"
3 + version = "0.32.0"
4 4 description = "The first-party widget set: named assemblies of primitives, shared across our apps"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -13,12 +13,12 @@
13 13 workspace = true
14 14
15 15 [dependencies]
16 - quasi-router = { path = "../quasi-router", version = "0.31.0" }
16 + quasi-router = { path = "../quasi-router", version = "0.32.0" }
17 17 makeover-layout = "0.31.0"
18 18
19 19 [dev-dependencies]
20 20 # A widget's guarantees are claims about what a renderer draws, so they are
21 21 # tested against a real one rather than by walking the tree the assembly just
22 22 # built. The webview is the renderer that recognises names today.
23 - quasi-webview = { path = "../quasi-webview", version = "0.31.0" }
24 - quasi-http = { path = "../quasi-http", version = "0.31.0" }
23 + quasi-webview = { path = "../quasi-webview", version = "0.32.0" }
24 + quasi-http = { path = "../quasi-http", version = "0.32.0" }
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-bench"
3 - version = "0.31.0"
3 + version = "0.32.0"
4 4 description = "What a described screen costs to render, in time and in allocations"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -22,13 +22,13 @@
22 22 count = ["dep:dhat"]
23 23
24 24 [dependencies]
25 - quasi-router = { path = "../quasi-router", version = "0.31.0" }
26 - quasi-webview = { path = "../quasi-webview", version = "0.31.0" }
27 - quasi-tui = { path = "../quasi-tui", version = "0.31.0" }
25 + quasi-router = { path = "../quasi-router", version = "0.32.0" }
26 + quasi-webview = { path = "../quasi-webview", version = "0.32.0" }
27 + quasi-tui = { path = "../quasi-tui", version = "0.32.0" }
28 28 # `Serves` is the trait carrying `screen` and `fragment`, which is what the
29 29 # webview is measured through. Taken directly rather than through quasi-webview
30 30 # because a bench calling a trait method should name the trait it calls.
31 - quasi-http = { path = "../quasi-http", version = "0.31.0" }
31 + quasi-http = { path = "../quasi-http", version = "0.32.0" }
32 32 makeover-layout = "0.31.0"
33 33 makeover-tui = { version = "0.30.0", features = ["theme"] }
34 34 # Only to load a bundled theme file. `makeover_tui::Theme` is `#[non_exhaustive]`,
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-http"
3 - version = "0.31.0"
3 + version = "0.32.0"
4 4 description = "The http-shaped seam quasi's webview host adapters share: decoding in, a rendered description out"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -13,6 +13,6 @@
13 13 workspace = true
14 14
15 15 [dependencies]
16 - quasi-router = { path = "../quasi-router", version = "0.31.0" }
16 + quasi-router = { path = "../quasi-router", version = "0.32.0" }
17 17 http = "1.3.1"
18 18 form_urlencoded = "1.2.2"
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-immediate"
3 - version = "0.31.0"
3 + version = "0.32.0"
4 4 edition = "2024"
5 5 description = "The immediate-mode renderer for quasi-router: a described screen in, an egui frame out. Immediate mode is the constraint that matters, not the library."
6 6 license = "MIT"
@@ -12,7 +12,7 @@
12 12 categories = ["gui"]
13 13
14 14 [dependencies]
15 - quasi-router = { path = "../quasi-router", version = "0.31.0" }
15 + quasi-router = { path = "../quasi-router", version = "0.32.0" }
16 16 # The node drawing, which is the makeover layer's and not this crate's. Every
17 17 # widget here that is not a container comes from it: a screen walk that painted
18 18 # its own meter would be the divergence the suite exists to end, one copy per
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-notifs"
3 - version = "0.31.0"
3 + version = "0.32.0"
4 4 description = "Declared notification kinds and the registry that holds them: what a notification says and what it is for, apart from how it reaches a person"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -24,5 +24,5 @@
24 24 describe = ["dep:quasi-router"]
25 25
26 26 [dependencies]
27 - quasi-router = { path = "../quasi-router", version = "0.31.0", optional = true }
27 + quasi-router = { path = "../quasi-router", version = "0.32.0", optional = true }
28 28 synckit-config = { git = "https://makenot.work/git/max/synckit.git", version = "0.2", optional = true }
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-router"
3 - version = "0.31.0"
3 + version = "0.32.0"
4 4 description = "Host-agnostic router: a request in, a renderer-agnostic description out"
5 5 edition.workspace = true
6 6 rust-version.workspace = true