| 1 | # Vendored dependency patches |
| 2 | |
| 3 | ## fastrand-2.5.0 |
| 4 | |
| 5 | ### The problem |
| 6 | |
| 7 | `yrs` (pinned exact in `core/Cargo.toml`) depends on `fastrand` with its |
| 8 | `js` feature enabled unconditionally, and fastrand's own manifest ties that |
| 9 | feature, on `wasm32`/`wasm64`-`unknown`, to `getrandom` with the `wasm_js` |
| 10 | feature forced on. That feature makes `getrandom` default to a |
| 11 | `wasm-bindgen`-based backend which imports host JS functions |
| 12 | (`crypto.getRandomValues`, etc.) — an import the Go/wazero host cannot |
| 13 | satisfy, and the thing `core/tests/no_host_imports.rs` gates against. |
| 14 | |
| 15 | `yrs::Doc` calls into this path unconditionally on construction (even via |
| 16 | `Doc::with_client_id`, which still generates a random document GUID via |
| 17 | `fastrand::Rng::new()` -> `getrandom`). Worse: merely *referencing* |
| 18 | `yrs::Doc` anywhere in `docs-core`'s public API — required for |
| 19 | `apply_update`/`text_content`, since the test suite calls them from a |
| 20 | separate compilation unit against the `rlib` — is enough for those |
| 21 | `wasm-bindgen` exports to end up linked into the final `.wasm` module, even |
| 22 | along code paths that are never reached at runtime. Reproduced in |
| 23 | isolation (a scratch crate depending on nothing but `yrs = "=0.23.5"`, with |
| 24 | a single `pub fn unused(_doc: &yrs::Doc) {}` and no method calls at all); |
| 25 | see `task-3-report.md` in the plan directory for the full trace. |
| 26 | |
| 27 | ### The fix, and why it needs vendoring |
| 28 | |
| 29 | `getrandom` supports exactly this scenario: selecting its `custom` backend |
| 30 | via `--cfg getrandom_backend="custom"` (set in `docs-wt-core/.cargo/ |
| 31 | config.toml`, scoped to the `wasm32-unknown-unknown` target only) routes |
| 32 | entropy requests to a symbol we provide ourselves |
| 33 | (`__getrandom_v03_custom` in `core/src/lib.rs`, which — deliberately — |
| 34 | fails rather than fabricating bytes; see the doc comment above it), with |
| 35 | no JS dependency. |
| 36 | |
| 37 | That override alone doesn't compile, though. `getrandom-0.4.3`'s |
| 38 | `src/error.rs:181-185` has a `Display`/`Debug` match arm: |
| 39 | |
| 40 | ```rust |
| 41 | #[cfg(all( |
| 42 | feature = "wasm_js", |
| 43 | target_arch = "wasm32", |
| 44 | any(target_os = "unknown", target_os = "none") |
| 45 | ))] |
| 46 | Error::WEB_CRYPTO => "Web Crypto API is unavailable", |
| 47 | ``` |
| 48 | |
| 49 | gated only on the `wasm_js` Cargo *feature* — not on which backend is |
| 50 | actually *selected* via `--cfg getrandom_backend`. `Error::WEB_CRYPTO` |
| 51 | itself is defined inside `src/backends/wasm_js.rs:71`, inside the `mod |
| 52 | wasm_js;` declaration that a `getrandom_backend="custom"` override skips |
| 53 | compiling entirely (`src/backends.rs`'s `cfg_if!` chain is mutually |
| 54 | exclusive; `custom` is checked first and short-circuits the rest). Result, |
| 55 | reproduced directly against the pinned version with nothing changed except |
| 56 | adding the cfg override: |
| 57 | |
| 58 | ``` |
| 59 | error[E0599]: no associated function or constant named `WEB_CRYPTO` found for struct `error::Error` in the current scope |
| 60 | --> .../getrandom-0.4.3/src/error.rs:185:20 |
| 61 | ``` |
| 62 | |
| 63 | As long as *anything* in the dependency graph requests fastrand's `js` |
| 64 | feature on a wasm32/wasm64-unknown target — which `yrs` does, |
| 65 | unconditionally, and which we cannot override, since Cargo features are |
| 66 | additive across the whole graph and `docs-core` has no way to un-request a |
| 67 | feature another crate requires — this is a hard compile error, regardless |
| 68 | of which non-`wasm_js` backend `--cfg getrandom_backend` selects (`custom`, |
| 69 | `unsupported`, etc. all hit the same match arm). This looks like a real |
| 70 | gap in `getrandom` 0.4.3's own cfg-gating (the match arm's cfg should also |
| 71 | require `not(getrandom_backend = "custom")` or equivalent, matching what |
| 72 | the backend-selection `cfg_if!` already does) rather than anything specific |
| 73 | to this project; `getrandom`'s own issue tracker has at least one adjacent, |
| 74 | still-open report of the same problem area — a `custom`-backend override |
| 75 | not fully insulating a build from a `wasm_js` feature forced on by another |
| 76 | dependency in the graph — closed "not planned": |
| 77 | <https://github.com/rust-random/getrandom/issues/633>. We did not find an |
| 78 | issue number for this exact `E0599`/`WEB_CRYPTO` symptom; if one turns up, |
| 79 | add it here. |
| 80 | |
| 81 | ### What was changed |
| 82 | |
| 83 | This vendored copy of `fastrand-2.5.0` is the unmodified upstream Rust |
| 84 | source (`src/`, `benches/`, `tests/`, licenses — byte-identical to the |
| 85 | crates.io tarball); only `Cargo.toml` differs, by exactly one edit: the |
| 86 | `wasm32`/`wasm64`-`unknown`-scoped `getrandom` dependency drops |
| 87 | `features = ["wasm_js"]` (kept `optional = true`). Nothing in fastrand's |
| 88 | actual logic changes — the `js` feature still exists, `fastrand::Rng::new()` |
| 89 | still calls into `getrandom` the same way — only *which* `getrandom` |
| 90 | backend ends up linked changes, and that's exactly what the |
| 91 | `--cfg getrandom_backend="custom"` override in `.cargo/config.toml` is |
| 92 | choosing on purpose. Wired in via `[patch.crates-io]` in `core/Cargo.toml`. |
| 93 | |
| 94 | ### When this can be deleted |
| 95 | |
| 96 | Try removing the `[patch.crates-io]` block from `core/Cargo.toml` (and |
| 97 | `vendor/fastrand-2.5.0/`) and running: |
| 98 | |
| 99 | ``` |
| 100 | cargo build --release --manifest-path core/Cargo.toml --target wasm32-unknown-unknown |
| 101 | ``` |
| 102 | |
| 103 | If that compiles cleanly (no `E0599`), delete the patch and this |
| 104 | directory — that's the goal state. Concretely, that becomes true once any |
| 105 | one of: |
| 106 | |
| 107 | 1. A `getrandom` release fixes `error.rs`'s `WEB_CRYPTO` match arm to also |
| 108 | respect `getrandom_backend` (e.g. adds `not(getrandom_backend = |
| 109 | "custom")`), and `core/Cargo.toml`'s `getrandom = "=0.4.3"` pin is |
| 110 | bumped to that version. |
| 111 | 2. A `fastrand` release stops forcing `wasm_js` onto its optional |
| 112 | `getrandom` dependency (making it opt-in instead, which is what |
| 113 | getrandom issue #633 above is effectively asking for), and `yrs`'s pin |
| 114 | on it moves to that version. |
| 115 | 3. `yrs` stops requiring `fastrand`'s `js` feature at all for the |
| 116 | wasm32-unknown-unknown target — unlikely while it still generates |
| 117 | random document GUIDs internally, but would remove the whole problem. |
| 118 | |
| 119 | Verified as of this writing (2026-08-30) that the patch is still required: |
| 120 | removing it and rebuilding reproduces the exact `E0599` above. |
| 121 | |