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,58 @@
# Defaults — Clock and RNG factories
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`@suaveplan/bitpacker-network` enforces the determinism rule (no module-scope `Date.now()` or `Math.random()` calls in implementation files). To do that without infecting every consumer with mandatory `clock` / `rng` parameters, this package allow-lists ONE factory per source: `defaultClock` and `defaultRng()`. Every other module reads time and randomness only through the injected primitives passed at construction time, defaulting to these factories.
This is the same pattern `@suaveplan/events` uses (`events/clock/default-clock.ts`) and is the single explicit boundary between deterministic, replayable code paths and the host environment's wall clock / CSPRNG.
## Features
- `defaultClock` — `Clock = () => Date.now()`. Produces ms-since-epoch reads from the host wall clock.
- `defaultRng()` — factory that wraps `@suaveplan/random::cryptoRng()`. Returns a fresh CSPRNG-backed `Rng` per call. Throws if the host has no `crypto.getRandomValues`.
## Usage: Basic Example
```typescript
import { NetworkSimulator } from "@suaveplan/bitpacker-network";
// Without overrides: NetworkSimulator wires defaultClock and defaultRng() internally.
const sim = new NetworkSimulator();
```
## Usage: Advanced Example
```typescript
import { NetworkSimulator } from "@suaveplan/bitpacker-network";
import { Mulberry32Rng } from "@suaveplan/pseudo-random";
// Tests: inject a seeded RNG for reproducible packet-loss patterns.
const seededRng = new Mulberry32Rng(0xDEADBEEF);
const fakeClock = (): number => 0; // every call returns t=0
const sim = new NetworkSimulator({
rng: seededRng,
clock: fakeClock,
});
// Two simulators with the same seed produce byte-identical loss sequences.
```
## API Reference
### `defaultClock: Clock`
Constant. `() => number` returning the current millisecond timestamp via `Date.now()`. Suitable for the simulator's `startTime`, `lastBandwidthCheck`, packet `timestamp`, and `uptime` calculations. NOT monotonic — consumers needing strict monotonicity should inject a different `Clock`.
### `defaultRng(): Rng`
Factory function. Returns a fresh `Rng` backed by `globalThis.crypto.getRandomValues`. Throws `RandomError` (code `RANDOM.SOURCE.UNAVAILABLE`) if the host environment lacks the API. The simulator's constructor calls this lazily — if the consumer always provides their own `rng` option, the factory is never invoked, so older / non-browser hosts that lack `crypto.getRandomValues` can still use the simulator with a seeded `Rng`.
## Implementation Notes
The package's `src/simulator/simulator.spec-conformance.test.ts` includes a grep guard that scans implementation files for `Date.now()` / `Math.random()` and fails the build if either appears outside `defaults/default-clock.ts` and `defaults/default-rng.ts`. Those two files are explicitly allow-listed in the grep — that's the integrity boundary that keeps the rest of the package deterministic given identical injected primitives.
If a future addition needs another determinism-violating API (e.g. `performance.now()`, `process.hrtime()`), the convention is: add a new file under `defaults/` and extend the spec-conformance allow-list to include it. Spreading the violations across implementation files is what the rule prevents.