From 1c845876f4ceb066780fb3f4484ee0fdeef1f925 Mon Sep 17 00:00:00 2001 From: Noah Date: Sun, 26 Apr 2026 03:53:19 -0700 Subject: [PATCH 01/13] chore(deps): upgrade leptos 0.7 -> 0.8 to resolve wasm-streams dup server_fn 0.8 uses wasm-streams 0.5, aligning with reqwest's wasm-streams 0.5 (pulled by iroh-relay). This kills the duplicate-symbol link error that has been silently breaking CI Browser tests under bash -e (no pipefail). After this lands, ui/phase-3a-composer rebases on main and its 39 browser tests will run on CI for the first time. Verified: cargo tree -i wasm-streams --target wasm32-unknown-unknown returns a single version (0.5.x). Co-Authored-By: Claude Opus 4.7 (1M context) --- Cargo.lock | 196 ++++++++++++++++++++++++++---------------- crates/web/Cargo.toml | 2 +- 2 files changed, 124 insertions(+), 74 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2885c33e..c05a1d1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -126,9 +126,9 @@ dependencies = [ [[package]] name = "any_spawner" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41058deaa38c9d9dd933d6d238d825227cffa668e2839b52879f6619c63eee3b" +checksum = "1384d3fe1eecb464229fcf6eebb72306591c56bf27b373561489458a7c73027d" dependencies = [ "futures", "thiserror 2.0.18", @@ -212,6 +212,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-once-cell" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288f83726785267c6f2ef073a3d83dc3f9b81464e9f99898240cced85fce35a" + [[package]] name = "async-trait" version = "0.1.89" @@ -379,6 +385,12 @@ dependencies = [ "tokio", ] +[[package]] +name = "base16" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d27c3610c36aee21ce8ac510e6224498de4228ad772a171ed65643a24693a5a8" + [[package]] name = "base64" version = "0.22.1" @@ -700,6 +712,12 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" +[[package]] +name = "const-str" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18f12cc9948ed9604230cdddc7c86e270f9401ccbe3c2e98a4378c5e7632212f" + [[package]] name = "const_format" version = "0.2.35" @@ -743,22 +761,31 @@ dependencies = [ [[package]] name = "convert_case" -version = "0.7.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" dependencies = [ "unicode-segmentation", ] [[package]] name = "convert_case" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +checksum = "affbf0190ed2caf063e3def54ff444b449371d55c58e513a95ab98eca50adb49" dependencies = [ "unicode-segmentation", ] +[[package]] +name = "convert_case_extras" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589c70f0faf8aa9d17787557d5eae854d7755cac50f5c3d12c81d3d57661cebb" +dependencies = [ + "convert_case 0.11.0", +] + [[package]] name = "cordyceps" version = "0.3.4" @@ -1263,9 +1290,9 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "either_of" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f7f86eef3a7e4b9c2107583dbbbe3d9535c4b800796faf1774b82ba22033da" +checksum = "5060e0a4cbf26a87550792688ade88e6b8aec9208613631a7a363bda7bc2d4cd" dependencies = [ "paste", "pin-project-lite", @@ -1300,6 +1327,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "erased" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1731451909bde27714eacba19c2566362a7f35224f52b153d3f42cf60f72472" + [[package]] name = "errno" version = "0.3.14" @@ -1970,9 +2003,9 @@ dependencies = [ [[package]] name = "hydration_context" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d35485b3dcbf7e044b8f28c73f04f13e7b509c2466fd10cb2a8a447e38f8a93a" +checksum = "e8714ae4adeaa846d838f380fbd72f049197de629948f91bf045329e0cf0a283" dependencies = [ "futures", "once_cell", @@ -2712,14 +2745,15 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "leptos" -version = "0.7.8" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b8731cb00f3f0894058155410b95c8955b17273181d2bc72600ab84edd24f1" +checksum = "efa3982e7fe36c1de68f91f3c9083124f389a975523881f3d7e3363362feda41" dependencies = [ "any_spawner", "cfg-if", "either_of", "futures", + "getrandom 0.4.2", "hydration_context", "leptos_config", "leptos_dom", @@ -2731,8 +2765,10 @@ dependencies = [ "paste", "reactive_graph", "rustc-hash", + "rustc_version", "send_wrapper", "serde", + "serde_json", "serde_qs", "server_fn", "slotmap", @@ -2742,14 +2778,16 @@ dependencies = [ "typed-builder", "typed-builder-macro", "wasm-bindgen", + "wasm-bindgen-futures", + "wasm_split_helpers", "web-sys", ] [[package]] name = "leptos_config" -version = "0.7.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bae3e0ead5a7a814c8340eef7cb8b6cba364125bd8174b15dc9fe1b3cab7e03" +checksum = "0c06f751315bccc0d193fab302ac01d25bcfcd97474d4676440e7e3250dc3fc3" dependencies = [ "config", "regex", @@ -2760,9 +2798,9 @@ dependencies = [ [[package]] name = "leptos_dom" -version = "0.7.8" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f89d4eb263bd5a9e7c49f780f17063f15aca56fd638c90b9dfd5f4739152e87d" +checksum = "35742e9ed8f8aaf9e549b454c68a7ac0992536e06856365639b111f72ab07884" dependencies = [ "js-sys", "or_poisoned", @@ -2775,14 +2813,14 @@ dependencies = [ [[package]] name = "leptos_hot_reload" -version = "0.7.8" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e80219388501d99b246f43b6e7d08a28f327cdd34ba630a35654d917f3e1788e" +checksum = "9d2a0f220c8a5ef3c51199dfb9cdd702bc0eb80d52fbe70c7890adfaaae8a4b1" dependencies = [ "anyhow", "camino", "indexmap", - "parking_lot", + "or_poisoned", "proc-macro2", "quote", "rstml", @@ -2793,13 +2831,14 @@ dependencies = [ [[package]] name = "leptos_macro" -version = "0.7.9" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e621f8f5342b9bdc93bb263b839cee7405027a74560425a2dabea9de7952b1fd" +checksum = "9360df573fb57582384a8b7640a3de94ce6501d49be3b69f637cf11a42da484b" dependencies = [ "attribute-derive", "cfg-if", - "convert_case 0.7.1", + "convert_case 0.11.0", + "convert_case_extras", "html-escape", "itertools", "leptos_hot_reload", @@ -2808,6 +2847,7 @@ dependencies = [ "proc-macro2", "quote", "rstml", + "rustc_version", "server_fn_macro", "syn 2.0.117", "uuid", @@ -2815,9 +2855,9 @@ dependencies = [ [[package]] name = "leptos_server" -version = "0.7.8" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66985242812ec95e224fb48effe651ba02728beca92c461a9464c811a71aab11" +checksum = "da974775c5ccbb6bd64be7f53f75e8321542e28f21563a416574dbe4d5447eae" dependencies = [ "any_spawner", "base64", @@ -2865,12 +2905,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "linear-map" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee" - [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -4085,18 +4119,21 @@ dependencies = [ [[package]] name = "reactive_graph" -version = "0.1.8" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a0ccddbc11a648bd09761801dac9e3f246ef7641130987d6120fced22515e6" +checksum = "00c5a025366836190c7030e883cc2bcd9e384ff555336e3c7954741ca411b177" dependencies = [ "any_spawner", "async-lock", "futures", "guardian", "hydration_context", + "indexmap", "or_poisoned", + "paste", "pin-project-lite", "rustc-hash", + "rustc_version", "send_wrapper", "serde", "slotmap", @@ -4106,26 +4143,28 @@ dependencies = [ [[package]] name = "reactive_stores" -version = "0.1.8" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aadc7c19e3a360bf19cd595d2dc8b58ce67b9240b95a103fbc1317a8ff194237" +checksum = "c30fd35b7d299c591293bb69fed47a703eb2703b1cff0493e78b16ed007e5382" dependencies = [ "guardian", + "indexmap", "itertools", "or_poisoned", "paste", "reactive_graph", "reactive_stores_macro", "rustc-hash", + "send_wrapper", ] [[package]] name = "reactive_stores_macro" -version = "0.1.8" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "221095cb028dc51fbc2833743ea8b1a585da1a2af19b440b3528027495bf1f2d" +checksum = "e5d8e790a5ae5ddf9b7fa380c728375b06858e0cca7d063a73b3408320c523e1" dependencies = [ - "convert_case 0.7.1", + "convert_case 0.11.0", "proc-macro-error2", "proc-macro2", "quote", @@ -4310,7 +4349,7 @@ dependencies = [ "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams 0.5.0", + "wasm-streams", "web-sys", ] @@ -4752,13 +4791,13 @@ dependencies = [ [[package]] name = "serde_qs" -version = "0.13.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd34f36fe4c5ba9654417139a9b3a20d2e1de6012ee678ad14d240c22c78d8d6" +checksum = "f3faaf9e727533a19351a43cc5a8de957372163c7d35cc48c90b75cdda13c352" dependencies = [ "percent-encoding", "serde", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -4784,19 +4823,22 @@ dependencies = [ [[package]] name = "server_fn" -version = "0.7.8" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d05a9e3fd8d7404985418db38c6617cc793a1a27f398d4fbc9dfe8e41b804e6" +checksum = "5d60e4c1dfccd91fe0990141f69f1d5cf5679797ad53aa1b45e5bd658eb119f0" dependencies = [ + "base64", "bytes", + "const-str", "const_format", - "dashmap", "futures", "gloo-net", "http", "js-sys", - "once_cell", + "or_poisoned", "pin-project-lite", + "rustc_version", + "rustversion", "send_wrapper", "serde", "serde_json", @@ -4807,30 +4849,31 @@ dependencies = [ "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams 0.4.2", + "wasm-streams", "web-sys", "xxhash-rust", ] [[package]] name = "server_fn_macro" -version = "0.7.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504b35e883267b3206317b46d02952ed7b8bf0e11b2e209e2eb453b609a5e052" +checksum = "1295b54815397d30d986b63f93cfd515fa86d5e528e0bb589ce9d530502f9e0f" dependencies = [ "const_format", - "convert_case 0.6.0", + "convert_case 0.11.0", "proc-macro2", "quote", + "rustc_version", "syn 2.0.117", "xxhash-rust", ] [[package]] name = "server_fn_macro_default" -version = "0.7.8" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb8b274f568c94226a8045668554aace8142a59b8bca5414ac5a79627c825568" +checksum = "63eb08f80db903d3c42f64e60ebb3875e0305be502bdc064ec0a0eab42207f00" dependencies = [ "server_fn_macro", "syn 2.0.117", @@ -5153,31 +5196,29 @@ dependencies = [ [[package]] name = "tachys" -version = "0.1.9" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f66c3b70c32844a6f1e2943c72a33ebb777ad6acbeb20d1329d62e3a7806d6ec" +checksum = "2989c94c59db8497727875aa561d4d0daa3cc79b5774d5ced48263f7091beff1" dependencies = [ "any_spawner", "async-trait", "const_str_slice_concat", "drain_filter_polyfill", - "dyn-clone", "either_of", + "erased", "futures", "html-escape", "indexmap", "itertools", "js-sys", - "linear-map", "next_tuple", "oco_ref", - "once_cell", "or_poisoned", - "parking_lot", "paste", "reactive_graph", "reactive_stores", "rustc-hash", + "rustc_version", "send_wrapper", "slotmap", "throw_error", @@ -5255,9 +5296,9 @@ dependencies = [ [[package]] name = "throw_error" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ef8bf264c6ae02a065a4a16553283f0656bd6266fc1fcb09fd2e6b5e91427b" +checksum = "dc0ed6038fcbc0795aca7c92963ddda636573b956679204e044492d2b13c8f64" dependencies = [ "pin-project-lite", ] @@ -5614,18 +5655,18 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typed-builder" -version = "0.20.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd9d30e3a08026c78f246b173243cf07b3696d274debd26680773b6773c2afc7" +checksum = "31aa81521b70f94402501d848ccc0ecaa8f93c8eb6999eb9747e72287757ffda" dependencies = [ "typed-builder-macro", ] [[package]] name = "typed-builder-macro" -version = "0.20.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c36781cc0e46a83726d9879608e4cf6c2505237e263a8eb8c24502989cfdb28" +checksum = "076a02dc54dd46795c2e9c8282ed40bcfb1e22747e955de9389a1de28190fb26" dependencies = [ "proc-macro2", "quote", @@ -5942,9 +5983,9 @@ dependencies = [ [[package]] name = "wasm-streams" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" dependencies = [ "futures-util", "js-sys", @@ -5954,16 +5995,25 @@ dependencies = [ ] [[package]] -name = "wasm-streams" -version = "0.5.0" +name = "wasm_split_helpers" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" +checksum = "d0cb6d1008be3c4c5abc31a407bfb8c8449ae14efc8561c1db821f79b9614b0a" dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", + "async-once-cell", + "wasm_split_macros", +] + +[[package]] +name = "wasm_split_macros" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a659ffe5c7f4538aa6357c07e3d73221cc61eba03bd9a081e14bc91ed09b8c" +dependencies = [ + "base16", + "quote", + "sha2 0.10.9", + "syn 2.0.117", ] [[package]] diff --git a/crates/web/Cargo.toml b/crates/web/Cargo.toml index 8de0e2f4..1e5416eb 100644 --- a/crates/web/Cargo.toml +++ b/crates/web/Cargo.toml @@ -12,7 +12,7 @@ willow-crypto = { path = "../crypto" } willow-identity = { path = "../identity" } willow-network = { path = "../network" } willow-state = { path = "../state" } -leptos = { version = "0.7", features = ["csr"] } +leptos = { version = "0.8", features = ["csr"] } tracing = { workspace = true } wasm-bindgen = "0.2" web-sys = { version = "0.3", features = [ From 9d7a91933f537539d252370971389cf89a93c4af Mon Sep 17 00:00:00 2001 From: Noah Date: Sun, 26 Apr 2026 03:18:09 -0700 Subject: [PATCH 02/13] ci: force pipefail on tee-piped steps so failures actually fail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Steps with `id:` set on this runner inherit a shell of `bash -e {0}` (no pipefail), so `cmd 2>&1 | tee /tmp/log` masks the upstream exit code — `tee` always returns 0 and the step is reported as success even when the actual command died. Discovered while auditing browser test runs: ui/phase-3a-composer shows `error: linking with rust-lld failed` followed by a green conclusion, and the same is true for recent main-branch runs. The duplicate-symbol link error from two `wasm-streams` versions has been live for some time but invisible because the step "passes." Fix is mechanical: force `bash --noprofile --norc -eo pipefail {0}` on every tee-piped step (Clippy, Test, Browser tests, Playwright E2E) so the upstream exit code surfaces. Note: this commit will likely turn Browser tests RED on this PR — that's the correct outcome. The dep skew between `wasm-streams 0.4.2` (Leptos -> server_fn) and `wasm-streams 0.5.0` (iroh -> reqwest) needs a separate fix. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci.yml | 8 ++++++++ .github/workflows/e2e.yml | 1 + 2 files changed, 9 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bc950447..b2e03528 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,6 +41,9 @@ jobs: key: clippy-${{ hashFiles('**/Cargo.lock') }} restore-keys: clippy- - id: clippy + # Steps with `id:` end up with `bash -e {0}` (no pipefail) on this runner, + # so `... | tee` would silently mask failures. Force pipefail on. + shell: bash --noprofile --norc -eo pipefail {0} run: cargo clippy --workspace --all-targets -- -D warnings 2>&1 | tee /tmp/clippy.log - name: Surface clippy failure if: failure() && steps.clippy.conclusion == 'failure' @@ -73,6 +76,7 @@ jobs: key: test-${{ hashFiles('**/Cargo.lock') }} restore-keys: test- - id: test + shell: bash --noprofile --norc -eo pipefail {0} run: cargo test --workspace 2>&1 | tee /tmp/test.log - name: Surface test failure if: failure() && steps.test.conclusion == 'failure' @@ -130,6 +134,10 @@ jobs: with: tool: wasm-pack - id: browser + # `bash -e {0}` (default) does NOT enable pipefail, so `wasm-pack ... | tee` + # would silently mask failures (tee always exits 0). Use an explicit shell + # invocation that turns pipefail on so the link/test exit code surfaces. + shell: bash --noprofile --norc -eo pipefail {0} run: wasm-pack test --headless --firefox crates/web 2>&1 | tee /tmp/browser.log - name: Surface browser-test failure if: failure() && steps.browser.conclusion == 'failure' diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 9f2beab1..7d897de8 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -42,6 +42,7 @@ jobs: - name: Run full E2E flow (setup + tests + teardown) id: e2e + shell: bash --noprofile --norc -eo pipefail {0} run: just test-e2e-full 2>&1 | tee /tmp/e2e.log - name: Surface E2E failure if: failure() && steps.e2e.conclusion == 'failure' From 3c61381939d219a5c2670eaba2b31999742274ea Mon Sep 17 00:00:00 2001 From: Noah Date: Sun, 26 Apr 2026 04:13:37 -0700 Subject: [PATCH 03/13] fix(web): unbreak foundation token tests + restore --focus-ring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two latent issues surfaced once the wasm-pack test binary actually ran to completion (CI was previously masking the link error so this whole mod was effectively unmonitored). 1. `foundation.css` ships an `@import url('https://fonts.googleapis.com/...')` for Fraunces/Plex/JetBrains. Headless Firefox under wasm-pack has no network access and the @import stalls/cancels the entire stylesheet, leaving every `:root` custom property unresolved. Strip @import lines before injecting the CSS into `