| index 1f47c06..cce4acf 100644 |
| --- a/vendor/README.md |
| +++ b/vendor/README.md |
| @@ -2,9 +2,11 @@ |
| |
| ## fastrand-2.5.0 |
| |
| +### The problem |
| + |
| `yrs` (pinned exact in `core/Cargo.toml`) depends on `fastrand` with its |
| `js` feature enabled unconditionally, and fastrand's own manifest ties that |
| -feature, on `wasm32-unknown-unknown`, to `getrandom` with the `wasm_js` |
| +feature, on `wasm32`/`wasm64`-`unknown`, to `getrandom` with the `wasm_js` |
| feature forced on. That feature makes `getrandom` default to a |
| `wasm-bindgen`-based backend which imports host JS functions |
| (`crypto.getRandomValues`, etc.) — an import the Go/wazero host cannot |
| @@ -12,34 +14,107 @@ satisfy, and the thing `core/tests/no_host_imports.rs` gates against. |
| |
| `yrs::Doc` calls into this path unconditionally on construction (even via |
| `Doc::with_client_id`, which still generates a random document GUID via |
| -`fastrand`). Merely referencing `yrs::Doc` anywhere in `docs-core`'s public |
| -API — required by `apply_update`/`text_content`, since the test suite calls |
| -them from a separate compilation unit against the `rlib` — is enough for |
| -those `wasm-bindgen` exports to end up linked into the final `.wasm` module, |
| -even though the code path is never reached at runtime. |
| +`fastrand::Rng::new()` -> `getrandom`). Worse: merely *referencing* |
| +`yrs::Doc` anywhere in `docs-core`'s public API — required for |
| +`apply_update`/`text_content`, since the test suite calls them from a |
| +separate compilation unit against the `rlib` — is enough for those |
| +`wasm-bindgen` exports to end up linked into the final `.wasm` module, even |
| +along code paths that are never reached at runtime. Reproduced in |
| +isolation (a scratch crate depending on nothing but `yrs = "=0.23.5"`, with |
| +a single `pub fn unused(_doc: &yrs::Doc) {}` and no method calls at all); |
| +see `task-3-report.md` in the plan directory for the full trace. |
| + |
| +### The fix, and why it needs vendoring |
| |
| `getrandom` supports exactly this scenario: selecting its `custom` backend |
| via `--cfg getrandom_backend="custom"` (set in `docs-wt-core/.cargo/ |
| config.toml`, scoped to the `wasm32-unknown-unknown` target only) routes |
| entropy requests to a symbol we provide ourselves |
| -(`__getrandom_v03_custom` in `core/src/lib.rs`), with no JS dependency. |
| - |
| -That override alone isn't enough, though: `getrandom-0.4.3`'s `error.rs` |
| -has a `Display` match arm for `Error::WEB_CRYPTO` gated only on |
| -`feature = "wasm_js"` (not on which backend is actually selected), while |
| -`Error::WEB_CRYPTO` itself is defined inside the `wasm_js` backend module, |
| -which a `custom`-backend override skips compiling entirely. As long as |
| -fastrand keeps requesting the `wasm_js` feature, this is a hard compile |
| -error (`E0599`) — Cargo features are additive across the whole dependency |
| -graph, so `docs-core` cannot un-request a feature another crate requires. |
| - |
| -This vendored copy of `fastrand-2.5.0` (unmodified Rust source; see the |
| -comment in its `Cargo.toml`) drops the forced `features = ["wasm_js"]` on |
| -its `wasm32`/`wasm64`-`unknown` `getrandom` dependency, so nothing in the |
| -graph requests that feature and the conflicting match arm is never |
| -compiled. `fastrand`'s actual logic (the `js` feature still exists, and |
| -`fastrand::Rng::new()` still calls into `getrandom`) is untouched — only |
| -which `getrandom` backend gets linked changes, and that is exactly what the |
| -`--cfg getrandom_backend="custom"` override is choosing on purpose. |
| - |
| -Wired in via `[patch.crates-io]` in `core/Cargo.toml`. |
| +(`__getrandom_v03_custom` in `core/src/lib.rs`, which — deliberately — |
| +fails rather than fabricating bytes; see the doc comment above it), with |
| +no JS dependency. |
| + |
| +That override alone doesn't compile, though. `getrandom-0.4.3`'s |
| +`src/error.rs:181-185` has a `Display`/`Debug` match arm: |
| + |
| +```rust |
| +#[cfg(all( |
| + feature = "wasm_js", |
| + target_arch = "wasm32", |
| + any(target_os = "unknown", target_os = "none") |
| +))] |
| +Error::WEB_CRYPTO => "Web Crypto API is unavailable", |
| +``` |
| + |
| +gated only on the `wasm_js` Cargo *feature* — not on which backend is |
| +actually *selected* via `--cfg getrandom_backend`. `Error::WEB_CRYPTO` |
| +itself is defined inside `src/backends/wasm_js.rs:71`, inside the `mod |
| +wasm_js;` declaration that a `getrandom_backend="custom"` override skips |
| +compiling entirely (`src/backends.rs`'s `cfg_if!` chain is mutually |
| +exclusive; `custom` is checked first and short-circuits the rest). Result, |
| +reproduced directly against the pinned version with nothing changed except |
| +adding the cfg override: |
| + |
| +``` |
| +error[E0599]: no associated function or constant named `WEB_CRYPTO` found for struct `error::Error` in the current scope |
| + --> .../getrandom-0.4.3/src/error.rs:185:20 |
| +``` |
| + |
| +As long as *anything* in the dependency graph requests fastrand's `js` |
| +feature on a wasm32/wasm64-unknown target — which `yrs` does, |
| +unconditionally, and which we cannot override, since Cargo features are |
| +additive across the whole graph and `docs-core` has no way to un-request a |
| +feature another crate requires — this is a hard compile error, regardless |
| +of which non-`wasm_js` backend `--cfg getrandom_backend` selects (`custom`, |
| +`unsupported`, etc. all hit the same match arm). This looks like a real |
| +gap in `getrandom` 0.4.3's own cfg-gating (the match arm's cfg should also |
| +require `not(getrandom_backend = "custom")` or equivalent, matching what |
| +the backend-selection `cfg_if!` already does) rather than anything specific |
| +to this project; `getrandom`'s own issue tracker has at least one adjacent, |
| +still-open report of the same problem area — a `custom`-backend override |
| +not fully insulating a build from a `wasm_js` feature forced on by another |
| +dependency in the graph — closed "not planned": |
| +<https://github.com/rust-random/getrandom/issues/633>. We did not find an |
| +issue number for this exact `E0599`/`WEB_CRYPTO` symptom; if one turns up, |
| +add it here. |
| + |
| +### What was changed |
| + |
| +This vendored copy of `fastrand-2.5.0` is the unmodified upstream Rust |
| +source (`src/`, `benches/`, `tests/`, licenses — byte-identical to the |
| +crates.io tarball); only `Cargo.toml` differs, by exactly one edit: the |
| +`wasm32`/`wasm64`-`unknown`-scoped `getrandom` dependency drops |
| +`features = ["wasm_js"]` (kept `optional = true`). Nothing in fastrand's |
| +actual logic changes — the `js` feature still exists, `fastrand::Rng::new()` |
| +still calls into `getrandom` the same way — only *which* `getrandom` |
| +backend ends up linked changes, and that's exactly what the |
| +`--cfg getrandom_backend="custom"` override in `.cargo/config.toml` is |
| +choosing on purpose. Wired in via `[patch.crates-io]` in `core/Cargo.toml`. |
| + |
| +### When this can be deleted |
| + |
| +Try removing the `[patch.crates-io]` block from `core/Cargo.toml` (and |
| +`vendor/fastrand-2.5.0/`) and running: |
| + |
| +``` |
| +cargo build --release --manifest-path core/Cargo.toml --target wasm32-unknown-unknown |
| +``` |
| + |
| +If that compiles cleanly (no `E0599`), delete the patch and this |
| +directory — that's the goal state. Concretely, that becomes true once any |
| +one of: |
| + |
| +1. A `getrandom` release fixes `error.rs`'s `WEB_CRYPTO` match arm to also |
| + respect `getrandom_backend` (e.g. adds `not(getrandom_backend = |
| + "custom")`), and `core/Cargo.toml`'s `getrandom = "=0.4.3"` pin is |
| + bumped to that version. |
| +2. A `fastrand` release stops forcing `wasm_js` onto its optional |
| + `getrandom` dependency (making it opt-in instead, which is what |
| + getrandom issue #633 above is effectively asking for), and `yrs`'s pin |
| + on it moves to that version. |
| +3. `yrs` stops requiring `fastrand`'s `js` feature at all for the |
| + wasm32-unknown-unknown target — unlikely while it still generates |
| + random document GUIDs internally, but would remove the whole problem. |
| + |
| +Verified as of this writing (2026-08-30) that the patch is still required: |
| +removing it and rebuilding reproduces the exact `E0599` above. |