# `runtime` _(no submodules)_ ## Purpose `runtime.ts` centralises the three injectable platform primitives (`Clock`, `MonotonicClock`, `Rng`) that every production path in `@suaveplan/packer-browser` reads time and randomness through. Direct `Date.now()`, `Math.random()`, and `performance.now()` calls are banned outside this file so seeded-deterministic tests can pin every observable behaviour. The shape mirrors `@suaveplan/packer/runtime`, so adopters that already inject runtime into the packer get the same contract here. ## Features - `defaultClock` / `defaultMonotonicClock` / `defaultRng` — wall-clock and CSPRNG defaults wired to the platform globals. - `resolveRuntime(opts?)` — merges caller-supplied `RuntimeOptions` against the platform defaults to produce a fully-populated `PackerBrowserRuntime` bundle. - `elapsedMs(monotonicClock, startNanos)` — convenience for the histogram observation sites that previously did `performance.now() - start` directly. - Adapter that upgrades a seeded `Rng` lacking `nextBytes` into the runtime-shape RNG by deriving bytes from `nextUint32`, so tests can inject `@suaveplan/testing`'s `seededRng()` unchanged. ## Usage: Basic ```ts import { resolveRuntime } from "@suaveplan/packer-browser"; const runtime = resolveRuntime(); const now = runtime.clock(); // ms since epoch const seed = runtime.rng.nextBytes(16); // CSPRNG bytes ``` ## Usage: Advanced ```ts import { FakeClock, seededRng } from "@suaveplan/testing"; import { resolveRuntime } from "@suaveplan/packer-browser"; const clock = new FakeClock({ now: 1_700_000_000_000 }); const runtime = resolveRuntime({ clock: () => clock.now(), rng: seededRng(42), }); // runtime.clock() returns 1_700_000_000_000 until FakeClock is advanced ``` ## API Reference - `defaultClock: Clock` — `() => Date.now()`. - `defaultMonotonicClock: MonotonicClock` — wraps `performance.now()`, returns nanoseconds as `bigint`. - `defaultRng: Required> & Rng` — CSPRNG bound to `globalThis.crypto`. - `resolveRuntime(opts?: RuntimeOptions): PackerBrowserRuntime` — fills in defaults for absent fields. - `elapsedMs(monotonicClock, startNanos: bigint): number` — returns elapsed milliseconds as a float. - `RuntimeOptions` / `PackerBrowserRuntime` — option / resolved bundles. ## Implementation Notes Monotonic time is exposed as `bigint` nanoseconds even though most consumers ultimately reduce to millisecond floats. The `bigint` discipline prevents accidental rounding when sampling the clock at nanosecond precision; the `elapsedMs` helper exists so call sites that need the float form never reach for `performance.now()` directly. `nextBytes` is part of the resolved RNG shape because the upcoming Cluster B encrypted-archive keyring needs CSPRNG bytes and the manager will forward the resolved RNG to it.