+++ title = "Implement generate_id() in src/lib.rs — UUID v4 for WASM-compatible quote IDs" priority = 8 status = "done" ticket_type = "task" dependencies = [] +++ Resolved from TRIAGE ticket 6f2e18. The `nanoid` crate is not suitable for wasm32-unknown-unknown because it depends on `rand`, which relies on thread-local RNG — unavailable in WASM. The safe, WASM-compatible choice is UUID v4 via the `uuid` crate. On the wasm32 target, `uuid`'s `v4` feature depends on `getrandom`, which requires the `wasm_js` feature (renamed from `js` in getrandom 0.2; uuid 1.21+ requires getrandom ^0.4) to source entropy from the Web Crypto API (`crypto.getRandomValues()`). This must be declared as a direct dependency in the application's `Cargo.toml` at the wasm32 cfg section. UUID v4 produces 36-character hyphenated strings (e.g. `550e8400-e29b-41d4-a716-446655440000`). The design doc originally specified NanoID (~21 chars); UUID v4 is slightly longer but universally supported and zero-risk on the Workers target. The DB schema comment should be updated accordingly. Add a `generate_id()` public function to `src/lib.rs` that: - Returns a new UUID v4 as a `String` - Compiles correctly for both the native host target AND `wasm32-unknown-unknown` - Has a rustdoc comment with a doc-example (which also serves as a doctest) ## 1. Cargo.toml changes Add `uuid` to the shared (all-targets) dependencies section: ```toml [dependencies] uuid = { version = "1", features = ["v4", "serde"] } ``` Add `getrandom` with the `wasm_js` feature under the wasm32 cfg section (so native builds don't pull in wasm-bindgen). **uuid 1.21+ requires getrandom ^0.4**; getrandom 0.4 renamed the `js` feature to `wasm_js`. Also shared with the passphrase generator (ticket 03bb91 / TRIAGE 6ed325): ```toml [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.4", features = ["wasm_js"] } ``` ## 2. src/lib.rs — generate_id() ```rust /// Generates a new UUID v4 string for use as a database primary key. /// /// Returns a 36-character hyphenated UUID string. Compatible with both /// native and `wasm32-unknown-unknown` targets (uses Web Crypto API via /// `getrandom/wasm_js` on WASM). /// /// # Examples /// /// ``` /// let id = quotesdb::generate_id(); /// assert_eq!(id.len(), 36); /// assert_eq!(id.chars().filter(|&c| c == '-').count(), 4); /// ``` pub fn generate_id() -> String { uuid::Uuid::new_v4().to_string() } ``` ## 3. Callers - `PUT /api/quotes` handler (ticket 05f8ae): call `generate_id()` to produce the new quote's `id` - No other callers at this stage ## 4. DB schema comment update In `docs/plans/2026-02-27-quotesdb-design.md` and `CLAUDE.md` design reference, update the schema comment from: ```sql id TEXT PRIMARY KEY, -- NanoID (~21 chars) ``` to: ```sql id TEXT PRIMARY KEY, -- UUID v4 (36 chars), generated by generate_id() ``` - `generate_id()` must be in `src/lib.rs` (shared code, not bin-specific) - UUID v4 is the only correct choice — do NOT use `nanoid`, `rand::thread_rng`, or any crate that pulls in thread-local RNG primitives for WASM - `getrandom = { version = "0.4", features = ["wasm_js"] }` must be in the wasm32 cfg section only, not in `[dependencies]`, to avoid pulling wasm-bindgen into native builds - Do NOT use getrandom 0.2 or the old `js` feature name — uuid 1.21+ requires getrandom ^0.4 - All public items must have rustdoc comments (per project style) Use `superpowers:test-driven-development` — write a unit test verifying length (36) and hyphen count (4) before implementing. Use `superpowers:verification-before-completion` before closing. Run in order from the `quotesdb/` directory: ```sh cargo fmt cargo check cargo clippy cargo test ``` `feat(quotesdb): add generate_id() using UUID v4 — WASM-compatible ID generation`