# id/id _(no submodules)_ ## Purpose `generateId` is the shared 16-character lowercase-hex identifier generator used for tab IDs and per-message IDs throughout `@suaveplan/broadcast-channel`. The upstream library inlined two near-identical `generate*Id` helpers — pulling that into a single function with injectable `Rng` lets the channel core compute deterministic IDs in tests and resolves the enterprise-doc smell ("Two duplicate `generateTabId` / `generateMsgId` functions; should share via a local `internal/id.ts`"). The module also exports `defaultRng`, an `Rng` implementation backed by Web Crypto's `getRandomValues`. Browsers and modern Node / Bun all expose the global `crypto` object so `defaultRng` works in every supported runtime without any extra polyfill. ## Features - Single helper for every ID the package produces. - Accepts any `Rng` (`@suaveplan/types`) — seeded RNGs make tests deterministic. - Honours optional `rng.nextBytes` when present (faster, fewer calls). - Pure-function fallback that derives 8 bytes from two `nextUint32()` calls. - Stable encoding: lowercase hex, fixed 16 characters, no separators. ## Usage: Basic ```ts import { defaultRng, generateId } from "@suaveplan/broadcast-channel"; const tabId = generateId(defaultRng); // tabId === "a3f1c0...", 16 hex chars ``` ## Usage: Advanced ```ts import { generateId } from "@suaveplan/broadcast-channel"; import type { Rng } from "@suaveplan/types"; function seededRng(values: readonly number[]): Rng { let i = 0; return { nextUint32: () => { const v = values[i % values.length] ?? 0; i++; return v >>> 0; }, nextFloat() { return this.nextUint32() / 0x1_0000_0000; }, }; } const tabId = generateId(seededRng([0xdeadbeef, 0x01020304])); // tabId === "deadbeef01020304" ``` ## API Reference - `function generateId(rng: Rng): string` — returns a 16-character hex string built from 8 random bytes drawn from `rng`. Uses `rng.nextBytes(8)` when available, otherwise two `nextUint32()` calls. - `const defaultRng: Rng` — Web-Crypto-backed RNG suitable for production browser code. Exposes `nextUint32`, `nextFloat`, and `nextBytes`. ## Implementation Notes When `rng.nextBytes` is not supplied, the helper packs two unsigned 32-bit words into an 8-byte buffer in big-endian order, then encodes each byte as a two-character zero-padded hex pair. The big-endian packing is deliberate: it makes the seeded-RNG test contract human-readable (`0xdeadbeef` → first 4 hex bytes `deadbeef`) and keeps the encoding stable if downstream code ever parses the ID back into bytes. The hex emission is the simplest two-character output that survives JSON / URL / localStorage transport without escaping. We avoid `crypto.randomUUID()` because the channel needs a fixed 16-hex shape for the leader-election sort to be deterministic and because randomUUID output is not available in every test sandbox.