first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,79 @@
# `runtime`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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<Pick<Rng, "nextBytes">> & 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.