Skip to main content

max / quasi

0.50.0: a route can answer with a file, and every host puts it somewhere 67881a88, ruled 2026-08-21 by Max: (a), the route answers with the file and the host puts it somewhere. Outcome::File { name, kind, bytes } mirrors Outcome::Suggestions, and the description never names a path -- the exact mirror of the upload ruling of 2026-08-18, where the destination is opaque in the other direction. kind is Accepted, the same type the upload half already uses, rather than a second way to name a file kind. name is a suggestion: safe_file_name is in the router because a name reaching a host is user input by the time it gets there, and the host that forgets is the one that writes ../../.ssh/authorized_keys beside the process. Four hosts, four answers to the same description. quasi-http writes Content-Disposition in both RFC 6266 forms and consults no renderer, because bytes are not markup -- the one outcome that cost the Serves trait nothing. quasi-tauri inherits that path. quasi-tui and quasi-immediate hand the file to their host through a new Runtime::handed, drained like refreshes: these crates own no I/O, the division that already keeps Step::Call from calling anything. The webview needed a fifth thing. A control reaches its route through htmx, htmx makes an XHR, and an XHR is not a navigation -- so the browser saves nothing and the file is swapped into the page as text. DOWNLOAD_JS cancels the swap and hands the body over as a blob, reading the same header the no-script path reads. Its one limit is stated in the file: the body arrives as a string, so a payload that is not valid UTF-8 is mangled, and every export in the tree is JSON, CSV or ICS. The alternatives all cost more than the case is worth -- responseType on every request breaks every ordinary swap, and refetching runs the route twice. The template was serving neither quasi-selection.js nor quasi-clock.js while Shell::under named both, which was two 404s and nothing in the log. build.rs writes all three from the renderer's constants now, beside the stylesheets and on the same bargain, and its quasi pins move 0.44 -> 0.50.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-22 03:03 UTC
Signed with PGP, not checked
Commit: f24f871991283cf2609f2de4d08a7c033b6536d6
Parent: cf3f2f3
31 files changed, +945 insertions, -87 deletions
M Cargo.lock +25 -35
@@ -2589,8 +2589,6 @@
2589 2589 [[package]]
2590 2590 name = "makeover"
2591 2591 version = "3.0.0"
2592 - source = "registry+https://github.com/rust-lang/crates.io-index"
2593 - checksum = "3e6da78c376074e48eb2324394004afc847e674e05ed2ea4bec1331073990b3f"
2594 2592 dependencies = [
2595 2593 "include_dir",
2596 2594 "serde",
@@ -2600,14 +2598,10 @@
2600 2598 [[package]]
2601 2599 name = "makeover-geometry"
2602 2600 version = "0.7.0"
2603 - source = "registry+https://github.com/rust-lang/crates.io-index"
2604 - checksum = "91a82b16c4f5b66dd7e87ed92fff7d22185e4d88e5355de6166dd64450cf6a16"
2605 2601
2606 2602 [[package]]
2607 2603 name = "makeover-immediate"
2608 - version = "0.32.0"
2609 - source = "registry+https://github.com/rust-lang/crates.io-index"
2610 - checksum = "437b1e68f0d1ce824f458e623fc901e81f961b97f167c58c9400453f976fc175"
2604 + version = "0.33.0"
2611 2605 dependencies = [
2612 2606 "egui",
2613 2607 "egui_extras",
@@ -2616,15 +2610,11 @@
2616 2610
2617 2611 [[package]]
2618 2612 name = "makeover-layout"
2619 - version = "0.33.0"
2620 - source = "registry+https://github.com/rust-lang/crates.io-index"
2621 - checksum = "7ba9bae28e348ef6df04ddf04222703b5ea680ac2c978f0dce8679e2acbdc5a0"
2613 + version = "0.35.0"
2622 2614
2623 2615 [[package]]
2624 2616 name = "makeover-touch"
2625 - version = "0.23.0"
2626 - source = "registry+https://github.com/rust-lang/crates.io-index"
2627 - checksum = "0f6272302ba50183af43fe35064db861d77b4786ab6f8994ed9bb6c18c57bba0"
2617 + version = "0.24.0"
2628 2618 dependencies = [
2629 2619 "makeover-geometry",
2630 2620 "makeover-layout",
@@ -2632,9 +2622,7 @@
2632 2622
2633 2623 [[package]]
2634 2624 name = "makeover-tui"
2635 - version = "0.32.0"
2636 - source = "registry+https://github.com/rust-lang/crates.io-index"
2637 - checksum = "778fc5d11417d03fa54b43176d63b26d7db397cf05595d1832cbdbdc71a93a48"
2625 + version = "0.33.0"
2638 2626 dependencies = [
2639 2627 "makeover",
2640 2628 "makeover-layout",
@@ -2643,9 +2631,7 @@
2643 2631
2644 2632 [[package]]
2645 2633 name = "makeover-webview"
2646 - version = "0.55.0"
2647 - source = "registry+https://github.com/rust-lang/crates.io-index"
2648 - checksum = "2cd308d279ece9665206044886d0da8762ce9eb81368e0f15a5afb8c0650cb41"
2634 + version = "0.56.0"
2649 2635 dependencies = [
2650 2636 "makeover-geometry",
2651 2637 "makeover-layout",
@@ -3414,11 +3400,11 @@
3414 3400
3415 3401 [[package]]
3416 3402 name = "quasi"
3417 - version = "0.48.0"
3403 + version = "0.50.0"
3418 3404
3419 3405 [[package]]
3420 3406 name = "quasi-axum"
3421 - version = "0.48.0"
3407 + version = "0.50.0"
3422 3408 dependencies = [
3423 3409 "axum",
3424 3410 "http",
@@ -3432,7 +3418,7 @@
3432 3418
3433 3419 [[package]]
3434 3420 name = "quasi-basics"
3435 - version = "0.48.0"
3421 + version = "0.50.0"
3436 3422 dependencies = [
3437 3423 "makeover-layout",
3438 3424 "quasi-http",
@@ -3442,7 +3428,7 @@
3442 3428
3443 3429 [[package]]
3444 3430 name = "quasi-bench"
3445 - version = "0.48.0"
3431 + version = "0.50.0"
3446 3432 dependencies = [
3447 3433 "dhat",
3448 3434 "makeover",
@@ -3457,7 +3443,7 @@
3457 3443
3458 3444 [[package]]
3459 3445 name = "quasi-http"
3460 - version = "0.48.0"
3446 + version = "0.50.0"
3461 3447 dependencies = [
3462 3448 "form_urlencoded",
3463 3449 "http",
@@ -3466,7 +3452,7 @@
3466 3452
3467 3453 [[package]]
3468 3454 name = "quasi-immediate"
3469 - version = "0.48.0"
3455 + version = "0.50.0"
3470 3456 dependencies = [
3471 3457 "docengine",
3472 3458 "egui",
@@ -3476,7 +3462,7 @@
3476 3462
3477 3463 [[package]]
3478 3464 name = "quasi-notifs"
3479 - version = "0.48.0"
3465 + version = "0.50.0"
3480 3466 dependencies = [
3481 3467 "quasi-router",
3482 3468 "synckit-config",
@@ -3484,7 +3470,7 @@
3484 3470
3485 3471 [[package]]
3486 3472 name = "quasi-router"
3487 - version = "0.48.0"
3473 + version = "0.50.0"
3488 3474 dependencies = [
3489 3475 "makeover-layout",
3490 3476 ]
@@ -3501,7 +3487,7 @@
3501 3487
3502 3488 [[package]]
3503 3489 name = "quasi-tauri"
3504 - version = "0.48.0"
3490 + version = "0.50.0"
3505 3491 dependencies = [
3506 3492 "http",
3507 3493 "quasi-http",
@@ -3514,7 +3500,7 @@
3514 3500
3515 3501 [[package]]
3516 3502 name = "quasi-tui"
3517 - version = "0.48.0"
3503 + version = "0.50.0"
3518 3504 dependencies = [
3519 3505 "docengine",
3520 3506 "makeover",
@@ -3526,7 +3512,7 @@
3526 3512
3527 3513 [[package]]
3528 3514 name = "quasi-webview"
3529 - version = "0.48.0"
3515 + version = "0.50.0"
3530 3516 dependencies = [
3531 3517 "docengine",
3532 3518 "makeover-layout",
@@ -6197,6 +6183,14 @@
6197 6183 "winnow 1.0.4",
6198 6184 ]
6199 6185
6186 + [[patch.unused]]
6187 + name = "quasi-type"
6188 + version = "0.1.0"
6189 +
6190 + [[patch.unused]]
6191 + name = "makeover-timing"
6192 + version = "0.1.0"
6193 +
6200 6194 [[patch.unused]]
6201 6195 name = "kberg"
6202 6196 version = "0.1.0"
@@ -6211,11 +6205,7 @@
6211 6205
6212 6206 [[patch.unused]]
6213 6207 name = "tagtree"
6214 - version = "0.4.0"
6215 -
6216 - [[patch.unused]]
6217 - name = "quasi-type"
6218 - version = "0.1.0"
6208 + version = "0.4.1"
6219 6209
6220 6210 [[patch.unused]]
6221 6211 name = "synckit-client"
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-axum"
3 - version = "0.49.0"
3 + version = "0.50.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.49.0" }
17 - quasi-http = { path = "../quasi-http", version = "0.49.0" }
16 + quasi-router = { path = "../quasi-router", version = "0.50.0" }
17 + quasi-http = { path = "../quasi-http", version = "0.50.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.49.0" }
23 + quasi-webview = { path = "../quasi-webview", version = "0.50.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.49.0"
3 + version = "0.50.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.49.0" }
17 - makeover-layout = "0.34.0"
16 + quasi-router = { path = "../quasi-router", version = "0.50.0" }
17 + makeover-layout = "0.35.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.49.0" }
24 - quasi-http = { path = "../quasi-http", version = "0.49.0" }
23 + quasi-webview = { path = "../quasi-webview", version = "0.50.0" }
24 + quasi-http = { path = "../quasi-http", version = "0.50.0" }
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-bench"
3 - version = "0.49.0"
3 + version = "0.50.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,14 +22,14 @@
22 22 count = ["dep:dhat"]
23 23
24 24 [dependencies]
25 - quasi-router = { path = "../quasi-router", version = "0.49.0" }
26 - quasi-webview = { path = "../quasi-webview", version = "0.49.0" }
27 - quasi-tui = { path = "../quasi-tui", version = "0.49.0" }
25 + quasi-router = { path = "../quasi-router", version = "0.50.0" }
26 + quasi-webview = { path = "../quasi-webview", version = "0.50.0" }
27 + quasi-tui = { path = "../quasi-tui", version = "0.50.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.49.0" }
32 - makeover-layout = "0.34.0"
31 + quasi-http = { path = "../quasi-http", version = "0.50.0" }
32 + makeover-layout = "0.35.0"
33 33 makeover-tui = { version = "0.33.0", features = ["theme"] }
34 34 # Only to load a bundled theme file. `makeover_tui::Theme` is `#[non_exhaustive]`,
35 35 # so `Theme::from_theme` is the one way to get one, the same reason quasi-tui's
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-http"
3 - version = "0.49.0"
3 + version = "0.50.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.49.0" }
16 + quasi-router = { path = "../quasi-router", version = "0.50.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.49.0"
3 + version = "0.50.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.49.0" }
15 + quasi-router = { path = "../quasi-router", version = "0.50.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