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,99 @@
# `@suaveplan/packer/runtime` — Clock + Rng injection
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Every production code path in `@suaveplan/packer` reads wall-clock time and
randomness through an injected `PackerRuntime` bundle instead of calling
`Date.now()`, `performance.now()`, or `crypto.getRandomValues` directly.
This module hosts the platform defaults plus the `resolveRuntime(opts)`
factory that every option bundle (`PackerOptions`, `PackChunkedOptions`,
`UnpackChunkedOptions`) consumes when it constructs its resolved option
bundle. The audit line in `enterprise/packer.md` (L43) makes this a hard
requirement: "no `Math.random()` / `Date.now()` at module scope; injectable
clock and RNG".
The contracts (`Clock`, `MonotonicClock`, `Rng`) are imported from
`@suaveplan/types` — they are the shared cross-package interface every
Suaveplan library agrees on for time and randomness. Defaults wire to real
platform implementations; tests pass in `FakeClock`-backed values and a
seeded `Rng` from `@suaveplan/testing` to drive deterministic pack output.
## Features
- `defaultClock` — `() => Date.now()`; wall-clock source for `metadata.timestamp`.
- `defaultMonotonicClock` — `performance.now()` cast to nanosecond `bigint`;
used for histogram observations.
- `defaultRng` — wraps `crypto.getRandomValues` and exposes the full
`Rng` triplet (`nextUint32`, `nextFloat`, `nextBytes`).
- `resolveRuntime(opts?)` — produces a `PackerRuntime` bundle, falling back
to defaults for absent fields. Upgrades a seeded `Rng` lacking
`nextBytes` by deriving bytes from `nextUint32`.
- `elapsedMs(monotonicClock, startNanos)` — converts a monotonic-clock
delta into milliseconds for histogram observations.
## Usage: Basic Example
```ts
import { Packer } from "@suaveplan/packer";
// Default — no options needed; defaults pull from the platform.
const packer = new Packer();
const bundle = await packer.pack(new Uint8Array([1, 2, 3]));
console.log(bundle.metadata.timestamp); // current Date.now() value
```
## Usage: Advanced Example
```ts
import { Packer } from "@suaveplan/packer";
import { FakeClock, seededRng } from "@suaveplan/testing";
// Deterministic pack: byte-identical output for byte-identical input.
const fake = new FakeClock({ now: 1_700_000_000_000 });
const rng = seededRng(0xdeadbeef);
const packer = new Packer({
clock: () => fake.now,
monotonicClock: () => BigInt(fake.now) * 1_000_000n,
rng,
encryption: {
algorithm: "xchacha20-poly1305",
key: new Uint8Array(32),
},
});
const a = await packer.pack(new Uint8Array([1, 2, 3]));
const b = await packer.pack(new Uint8Array([1, 2, 3]));
// a.data === b.data byte-by-byte because the RNG is seeded and the clock is fixed.
```
## API Reference
- `defaultClock: Clock` — `() => Date.now()`.
- `defaultMonotonicClock: MonotonicClock` — `performance.now()` × 1e6 as
`bigint`.
- `defaultRng: Required<Pick<Rng, "nextBytes">> & Rng` — CSPRNG-backed
`Rng` with mandatory `nextBytes`.
- `resolveRuntime(opts?: RuntimeOptions): PackerRuntime` — produces the
resolved bundle; `opts.clock`, `opts.monotonicClock`, `opts.rng` each
default to the matching platform default.
- `elapsedMs(monotonicClock, startNanos): number` — millisecond delta from
the monotonic-clock sample at `startNanos`.
## Implementation Notes
- `defaultMonotonicClock` rounds `performance.now()` to the nearest
nanosecond integer; the float→bigint cast is lossless for any process
uptime under ~584 years.
- `ensureNextBytes` (internal) extracts four bytes per `nextUint32` call,
big-endian, when the injected `Rng` lacks `nextBytes`. This keeps the
AEAD-nonce derivation deterministic under any seeded RNG.
- The runtime carries no state between calls — the bundle is a plain
object holding the three injected functions. Re-resolving with the same
inputs is cheap and side-effect-free.
- `resolveRuntime` is the single funnel every production option bundle in
the package consumes. The grep audit pinned by PACKER-25's fourth
scenario verifies that no other production file references
`Date.now` / `Math.random` / `crypto.getRandomValues` / `performance.now`.