js/sim
js/sim.ts
fino:sim — run code in a deterministic Realm against an explicit world.
A simulation is an ordinary child Realm with deterministic time and randomness, a deny-by-default import map, and parent-owned Facades for every external service. The harness observes the existing Realm transport to produce a journal; it does not introduce a second RPC or capability system.
The child owns its local values and execution state. The parent owns Facade implementations, journal copies, and Realm cleanup. Filesystem and network fakes are separate adapters and are not installed implicitly.
Example
import { simulate } from 'fino:sim';
const report = await simulate({
entry: './worker.ts',
seed: 'checkout-flow',
world: {
'app:inventory': {
available: async (sku: string) => sku === 'blue-shirt',
},
},
});
console.log(report.result, report.journal.entries);Types
type SimProvider = Facade | Record<string, unknown>
A parent-owned implementation exposed to the guest through one module specifier.
type FakeRoute =
| FakeResponse
| ((request: FakeRequest) => FakeResponse | undefined | Promise<FakeResponse | undefined>)
Static response or request-aware handler stored in a FakeNet route table.
type SimCassetteOptions = { mode: 'record' } | { mode: 'replay'; data: Cassette }
In-memory cassette behavior for one run. File storage policy is caller-owned.
Interfaces
interface SimMock {
An adapter that contributes one or more parent-owned modules to a simulation world.
Methods
world(): Record<string, SimProvider>
Return the world entries installed by this adapter, keyed by module specifier.
interface FakeRequest {
Copied HTTP request delivered to a FakeNet route handler.
Properties
url: string
Absolute request URL.
method: string
Normalized uppercase HTTP method.
headers: Record<string, string>
Normalized request headers keyed by lowercase name.
body: Uint8Array<ArrayBuffer> | null
Buffered request body, or null for requests without a body.
interface FakeResponse {
HTTP response returned by a FakeNet route.
Properties
status?: number
HTTP status code. Defaults to 200.
statusText?: string
HTTP reason phrase. Defaults to the empty string.
headers?: Record<string, string>
Response headers.
body?: string | Uint8Array
Buffered response body. Strings are UTF-8 encoded.
interface SimulateOptions {
Options for one deterministic simulation run.
Properties
entry: string
Entry module whose default export the harness calls.
args?: unknown[]
Arguments passed to the entry module's default export.
seed?: number | string
Seed for guest randomness. Defaults to 0.
startTime?: number
Initial virtual Unix time in milliseconds. Defaults to 1700000000000.
world?: Record<string, SimProvider>
Parent-owned modules available to the guest, keyed by import specifier.
overrides?: ImportRule[]
Additional rules appended after world entries. Last match wins.
cassette?: SimCassetteOptions
Record Realm RPC traffic or replay it from an in-memory cassette.
faults?: SimFaultOptions
Seeded failure and response-latency policy for Facade calls.
interface SimFaultOptions {
Deterministic behavior injected at the Realm RPC boundary.
Properties
errorRate?: number
Probability from zero through one that an eligible call fails. Defaults to 0.
only?: string[]
Restrict injected failures to these Facade specifiers.
message?: string
Error text returned for an injected failure.
latency?: [number, number]
Inclusive virtual-millisecond range charged to each Facade response.
interface SimJournal {
Read-only projection of completed Facade calls from one simulation.
Readonly Properties
readonly entries: readonly SimCall[]
Completed calls in guest invocation order.
Methods
calls(specifier?: string, method?: string): SimCall[]
Return completed calls matching an optional Facade specifier and method.
interface SimReport<Result = unknown> {
Observable outcome of one simulation run.
Properties
result: Result
Value returned by the entry module's default export.
journal: SimJournal
Completed Facade calls observed at the Realm transport boundary.
seed: number | string
Seed used for this run.
startTime: number
Initial virtual Unix time used for this run.
cassette?: Cassette
Recorded transport frames when cassette.mode is record.
interface SweepOutcome<Result = unknown> {
Result or failure produced by one seed in a simulation sweep.
Properties
seed: number | string
Seed used for this run.
report?: SimReport<Result>
Completed report when the run succeeded.
error?: unknown
Thrown value when the run failed.
Classes
class FakeNet implements SimMock {
Parent-owned HTTP route table for a simulated Realm's ambient fetch().
Method-specific keys such as POST https://api.example.com/orders take
precedence over URL-only keys. A handler that returns undefined, or a URL
with no matching route, produces a diagnostic 502 response without
touching the operating-system network.
const net = new FakeNet().route('GET https://api.example.com/health', {
body: 'ok',
});
const report = await simulate({
entry: './worker.ts',
world: net.world(),
});Static Readonly Properties
static readonly specifier
Facade specifier used by the simulation's ambient Fetch adapter.
Constructors
constructor(routes: Record<string, FakeRoute> = {})
Create a route table from optional initial entries.
Methods
route(pattern: string, handler: FakeRoute): this
Add or replace pattern, returning this route table for chaining.
world(): Record<string, SimProvider>
Return the fetch Facade entry expected by simulate().
provider(): Record<string, unknown>
Return the parent-side provider independently for custom world composition.
class FakeFs implements SimMock {
Parent-owned in-memory filesystem for a simulated Realm.
The adapter replaces fino:file through the simulation import map, so guest
code constructs DiskFileSystem normally while every operation crosses the
existing Facade transport. The parent can seed state before a run and inspect
a copied text snapshot afterwards.
import { FakeFs, simulate } from 'fino:sim';
const fs = new FakeFs({ '/etc/app.conf': 'debug=true' });
const report = await simulate({ entry: './worker.ts', world: fs.world() });
console.log(fs.snapshot(), report.journal.calls(FakeFs.specifier).length);Static Readonly Properties
static readonly specifier
Facade specifier replaced by this adapter.
Constructors
constructor(files: Record<string, string | Uint8Array> = {})
Create an independent filesystem seeded with files.
Getters
get filesystem(): MemoryFileSystem
Parent-owned filesystem used for setup and direct assertions.
Methods
snapshot(): Record<string, string>
Return a copied text snapshot of every file currently in the tree.
world(): Record<string, SimProvider>
Return the fino:file Facade entry expected by simulate().
provider(): Facade
Return the filesystem Facade independently for custom world composition.
Functions
async function simulate<Result = unknown>(
options: SimulateOptions,
): Promise<SimReport<Result>>
Run an entry module in a deterministic, deny-by-default Realm.
Plain objects in world become Facades; existing Facades retain their custom
module and streaming shapes. overrides are applied last so callers can
deliberately replace a world entry or inherit an additional pure module.
The Realm and its transport observer are disposed whether the call returns
or throws.
options defines the entry, arguments, deterministic inputs, import world,
and optional in-memory recording, replay, or fault policy.
async function sweep<Result = unknown>(
options: Omit<SimulateOptions, 'seed'>,
seeds: number | Array<number | string>,
): Promise<Array<SweepOutcome<Result>>>
Run the same simulation sequentially for each seed.
Failures are retained beside their seed instead of stopping later runs. The sequential order keeps a reported seed sufficient to reproduce an outcome, without introducing cross-run scheduling as another input.
options is reused for each run. An array in seeds is used verbatim; a
numeric seeds value runs integer seeds from zero up to that count.