3.0 KiB
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.nextByteswhen 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
import { defaultRng, generateId } from "@suaveplan/broadcast-channel";
const tabId = generateId(defaultRng);
// tabId === "a3f1c0...", 16 hex chars
Usage: Advanced
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 fromrng. Usesrng.nextBytes(8)when available, otherwise twonextUint32()calls.const defaultRng: Rng— Web-Crypto-backed RNG suitable for production browser code. ExposesnextUint32,nextFloat, andnextBytes.
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.