# `helpers` ## Purpose `helpers.ts` co-locates the small utilities the base manager and the message bus both depend on: a default wall-clock implementation, a default id generator backed by `crypto.getRandomValues`, the transfer-list validator that raises `WEB_WORKERS.INVALID_TRANSFER`, and a one-shot abort-signal wiring helper that returns a cleanup closure. Extracting them avoids duplication between `BaseWorkerManager` and `MessageBus` (both need clock, id-generator, and abort wiring) and keeps the base manager's main file under the 300-line ceiling. ## Features - `defaultClock` — wall-clock `Date.now()` Clock implementation. - `defaultIdGenerator` — cryptographically random 16-hex-character ids. - `validateTransfer(transfer)` — passes through `undefined` and arrays, throws `WebWorkersError(INVALID_TRANSFER)` for anything else (string, object, number). - `wireAbortSignal(signal, onAbort)` — registers a one-shot abort listener and returns a cleanup function that removes it. ## Usage: Basic Example ```ts import { defaultIdGenerator, validateTransfer, } from "@suaveplan/web-workers/base-manager"; const id = defaultIdGenerator(); const transfer = validateTransfer(opts?.transfer); ``` ## Usage: Advanced Example ```ts import { wireAbortSignal } from "@suaveplan/web-workers/base-manager"; function withAbort( signal: AbortSignal | undefined, onTimeout: () => void, promise: Promise ): Promise { const cleanup = wireAbortSignal(signal, onTimeout); return promise.finally(() => { cleanup?.(); }); } ``` ## API Reference - `defaultClock: Clock` — `() => Date.now()`. - `defaultIdGenerator: IdGenerator` — `() => string` returning 16 lowercase-hex chars (64 bits of entropy). - `validateTransfer(transfer: Transferable[] | undefined): Transferable[] | undefined` — pass-through on undefined / array; throws on non-array. - `wireAbortSignal(signal: AbortSignal | undefined, onAbort: () => void): (() => void) | undefined` — returns a cleanup closure or `undefined` when `signal` is undefined. ## Implementation Notes `defaultIdGenerator` uses `crypto.getRandomValues(new Uint8Array(8))` and hex-encodes the bytes. 64 bits of entropy is sufficient for per-process RPC correlation (`birthday-paradox` collision probability is < 1e-9 for fewer than 10⁵ outstanding requests). `wireAbortSignal` uses `addEventListener('abort', listener, { once: true })` so the listener removes itself after firing — the returned cleanup is therefore safe to call any number of times. `validateTransfer` is intentionally permissive on the array's contents (it doesn't try to prove every element is actually `Transferable`); structured-clone will throw at `postMessage` time if a non-transferable slips in. Surfacing that error is the transport's job, not the validator's.