diff --git a/.cargo/config.toml b/.cargo/config.toml
new file mode 100644
index 00000000..dd11e687
--- /dev/null
+++ b/.cargo/config.toml
@@ -0,0 +1,29 @@
+# getrandom 0.3 refuses to build for wasm32-unknown-unknown unless it is told
+# which backend to use. The target has no OS entropy source, so the crate will
+# not guess: it wants the `wasm_js` backend named explicitly, AND the matching
+# feature enabled on the crate itself. Its own error is unusually clear that one
+# without the other is not enough:
+#
+# error: The wasm32-unknown-unknown targets are not supported by default; you
+# may need to enable the "wasm_js" configuration flag. Note that enabling the
+# `wasm_js` feature flag alone is insufficient.
+#
+# This is the cfg half. The feature half is a wasm32-only dependency in
+# crates/sylpheed-viewer/Cargo.toml — that is the only crate reaching getrandom
+# here, transitively through `ahash`.
+#
+# Scoped to the wasm target, so native builds are untouched. Note that a
+# RUSTFLAGS environment variable, if one is ever set, replaces this rather than
+# adding to it.
+#
+# The second cfg is bevy_egui's. Its web clipboard support calls web-sys APIs
+# that are still gated behind an unstable flag, and it refuses to build without
+# it rather than silently dropping the feature:
+#
+# error: bevy_egui uses unstable APIs to support clipboard on web.
+#
+[target.wasm32-unknown-unknown]
+rustflags = [
+ '--cfg', 'getrandom_backend="wasm_js"',
+ '--cfg', 'web_sys_unstable_apis',
+]
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 19dc9943..a0d89ee6 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -111,7 +111,16 @@ jobs:
uses: Swatinem/rust-cache@v2
- name: Install Trunk
- uses: jetli/trunk-action@v0.5.0
+ # v0.5.0 selects the download by PLATFORM ONLY and never consults the
+ # architecture -- `case 'linux': arch = 'x86_64-unknown-linux-gnu'` --
+ # so on this aarch64 runner it fetches an x86_64 binary. v0.5.1 adds
+ # `process.arch` with 'x64' -> 'x86_64', 'arm64' -> 'aarch64' and
+ # core.setFailed otherwise, so a wrong arch now fails loudly instead of
+ # silently. It also moves the download host thedodd/trunk ->
+ # trunk-rs/trunk (trunk moved repositories; v0.5.0 still points at the
+ # old one), and swaps io.mv for io.cp, which is what avoids EXDEV on a
+ # self-hosted runner whose /tmp is a separate filesystem -- ours.
+ uses: jetli/trunk-action@v0.5.1
- name: Check WASM compile
run: >
@@ -123,11 +132,17 @@ jobs:
- name: Build WASM release with Trunk
run: trunk build --release
- - name: Upload WASM dist artifact
- uses: actions/upload-artifact@v4
- with:
- name: web-dist
- path: dist/
+ # No artifact upload. actions/upload-artifact@v4 hard-refuses on Gitea --
+ # Gitea presents as GHES and @actions/artifact v2+ aborts there
+ # (go-gitea/gitea#31256, #36024). Nothing consumes `web-dist`: it had
+ # exactly one reference in this repository, the line that produced it,
+ # and there is no download-artifact and no second workflow. The job's
+ # purpose -- proving the web build compiles -- is met by the step above.
+ # Add it back when something consumes the bundle, and decide then between
+ # actions/upload-artifact@v3 (the GHES guidance names v3.2.2 / the
+ # -node20 tag, so check the runner's node first) and the Gitea-specific
+ # christopherHX/gitea-upload-artifact@v4, which is a third-party
+ # dependency and therefore a decision, not a swap.
# ── Format check ─────────────────────────────────────────────────────────────
fmt:
diff --git a/Cargo.lock b/Cargo.lock
index 83cbd322..2c962ed3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2497,9 +2497,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
dependencies = [
"cfg-if",
+ "js-sys",
"libc",
"r-efi",
"wasip2",
+ "wasm-bindgen",
]
[[package]]
@@ -4675,6 +4677,7 @@ dependencies = [
"bevy",
"bevy_egui",
"futures",
+ "getrandom 0.3.4",
"image",
"rfd",
"rodio",
diff --git a/crates/sylpheed-formats/Cargo.toml b/crates/sylpheed-formats/Cargo.toml
index 1cd5d220..b08124e6 100644
--- a/crates/sylpheed-formats/Cargo.toml
+++ b/crates/sylpheed-formats/Cargo.toml
@@ -11,7 +11,12 @@ xdvdfs = { workspace = true }
binrw = { workspace = true }
flate2 = "1" # zlib/DEFLATE for IPFB "Z1" entries (miniz_oxide backend, WASM-safe)
ttf-parser = { version = "0.24", default-features = false, features = ["std", "opentype-layout"] } # font metadata (OTF/TTF/ttcf), WASM-safe
-tokio = { workspace = true }
+# tokio is a DEV dependency only (see [dev-dependencies] below). Every use in
+# this crate is inside a `mod tests`: three runtime builders in ship.rs and one
+# `#[tokio::test]` in xiso.rs. As a normal dependency it pulled `tokio/full`,
+# whose `net` feature drags in `mio`, which does not build for wasm32 —
+# error: This wasm target is unsupported by mio.
+# so the unused dependency was breaking the WASM job.
futures = { workspace = true }
thiserror = { workspace = true }
anyhow = { workspace = true }
diff --git a/crates/sylpheed-viewer/Cargo.toml b/crates/sylpheed-viewer/Cargo.toml
index 455938d6..3a3816e5 100644
--- a/crates/sylpheed-viewer/Cargo.toml
+++ b/crates/sylpheed-viewer/Cargo.toml
@@ -56,3 +56,10 @@ rodio = { workspace = true }
image = { version = "0.25", default-features = false, features = ["png"] }
# Off-thread rasterization of embedded-font samples (avoids egui's global fonts).
ab_glyph = "0.2"
+
+# Reached only through `ahash`, which needs an entropy source for its random
+# state. Declared here purely to turn on the `wasm_js` feature; nothing in this
+# crate calls getrandom directly. The paired `--cfg getrandom_backend` lives in
+# /.cargo/config.toml — both are required, neither is sufficient.
+[target.'cfg(target_arch = "wasm32")'.dependencies]
+getrandom = { version = "0.3", features = ["wasm_js"] }
diff --git a/crates/sylpheed-viewer/index.html b/crates/sylpheed-viewer/index.html
index d67d87ab..e1559e3f 100644
--- a/crates/sylpheed-viewer/index.html
+++ b/crates/sylpheed-viewer/index.html
@@ -186,7 +186,7 @@
-
+