first commit
This commit is contained in:
99
docs/foundation/data/packer/src/runtime/runtime.md
Normal file
99
docs/foundation/data/packer/src/runtime/runtime.md
Normal 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`.
|
||||
Reference in New Issue
Block a user