@demlik/tea 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/index.d.ts +32 -19
- package/dist/agent/index.js +12 -10
- package/dist/{chunk-VM7PMFV5.js → chunk-2A5XTKQQ.js} +142 -19
- package/dist/chunk-2A5XTKQQ.js.map +1 -0
- package/dist/{chunk-EB5OMOXX.js → chunk-7K7SEYCH.js} +16 -15
- package/dist/chunk-7K7SEYCH.js.map +1 -0
- package/dist/{chunk-GAVLND5C.js → chunk-A3QPMX5M.js} +17 -10
- package/dist/chunk-A3QPMX5M.js.map +1 -0
- package/dist/{chunk-VHKDUBXC.js → chunk-BVFS3ICC.js} +3 -3
- package/dist/{chunk-VHKDUBXC.js.map → chunk-BVFS3ICC.js.map} +1 -1
- package/dist/{chunk-4I2LCQKB.js → chunk-CPE5ZQXQ.js} +3 -3
- package/dist/{chunk-4I2LCQKB.js.map → chunk-CPE5ZQXQ.js.map} +1 -1
- package/dist/chunk-DEAPNMKO.js +11 -0
- package/dist/chunk-DEAPNMKO.js.map +1 -0
- package/dist/{chunk-BFSZ4L6Y.js → chunk-ETRNSJCR.js} +4 -4
- package/dist/{chunk-BFSZ4L6Y.js.map → chunk-ETRNSJCR.js.map} +1 -1
- package/dist/chunk-FXWDDNGD.js +98 -0
- package/dist/chunk-FXWDDNGD.js.map +1 -0
- package/dist/chunk-GFGOQIEC.js +10 -0
- package/dist/chunk-GFGOQIEC.js.map +1 -0
- package/dist/{chunk-YDF6P74H.js → chunk-IAHEYPYJ.js} +3 -3
- package/dist/{chunk-YDF6P74H.js.map → chunk-IAHEYPYJ.js.map} +1 -1
- package/dist/{chunk-YCJPLPQQ.js → chunk-J5JNLXO7.js} +3 -3
- package/dist/{chunk-YCJPLPQQ.js.map → chunk-J5JNLXO7.js.map} +1 -1
- package/dist/{chunk-MBQR3LFW.js → chunk-NFOGYDRS.js} +5 -5
- package/dist/{chunk-MBQR3LFW.js.map → chunk-NFOGYDRS.js.map} +1 -1
- package/dist/{chunk-Z7IL735U.js → chunk-R2YNDRGL.js} +3 -3
- package/dist/{chunk-Z7IL735U.js.map → chunk-R2YNDRGL.js.map} +1 -1
- package/dist/{chunk-ZV4WGW74.js → chunk-R5NXOPL2.js} +3 -3
- package/dist/{chunk-ZV4WGW74.js.map → chunk-R5NXOPL2.js.map} +1 -1
- package/dist/chunk-RMBZ7YH7.js +52 -0
- package/dist/chunk-RMBZ7YH7.js.map +1 -0
- package/dist/{chunk-HU3Y2AZY.js → chunk-SHXUSTHM.js} +62 -15
- package/dist/chunk-SHXUSTHM.js.map +1 -0
- package/dist/{chunk-QIE4Y6BK.js → chunk-UGTC33VH.js} +4 -4
- package/dist/{chunk-QIE4Y6BK.js.map → chunk-UGTC33VH.js.map} +1 -1
- package/dist/{chunk-6NIQIUGR.js → chunk-VH5MYJ2K.js} +4 -4
- package/dist/{chunk-6NIQIUGR.js.map → chunk-VH5MYJ2K.js.map} +1 -1
- package/dist/{chunk-W6XWI6QE.js → chunk-WZEDIUWR.js} +8 -7
- package/dist/chunk-WZEDIUWR.js.map +1 -0
- package/dist/{chunk-TMYUDZLE.js → chunk-ZRRET3RP.js} +11 -11
- package/dist/chunk-ZRRET3RP.js.map +1 -0
- package/dist/{core-BKJW1Kmq.d.ts → core-DNDAEhO2.d.ts} +7 -10
- package/dist/devtools/index.d.ts +4 -4
- package/dist/do/index.d.ts +98 -35
- package/dist/do/index.js +40 -21
- package/dist/do/index.js.map +1 -1
- package/dist/{drive-loop-Dc6Z8Vbs.d.ts → drive-loop-DlOEv49c.d.ts} +2 -2
- package/dist/{durable-effects-CgrLNccA.d.ts → durable-effects-wLWEdy9H.d.ts} +1 -1
- package/dist/effect/index.d.ts +52 -26
- package/dist/effect/index.js +7 -31
- package/dist/effect/index.js.map +1 -1
- package/dist/extension/index.d.ts +3 -3
- package/dist/extension/index.js +2 -2
- package/dist/flow/index.d.ts +13 -13
- package/dist/flow/index.js +13 -11
- package/dist/flow/index.js.map +1 -1
- package/dist/idempotency/index.d.ts +3 -3
- package/dist/idempotency/index.js +3 -3
- package/dist/{index-1hit3dJ9.d.ts → index-9P1PaXIV.d.ts} +2 -2
- package/dist/{index-Cuy1_xTh.d.ts → index-BBLI2WWN.d.ts} +1 -1
- package/dist/{index-Z6Uw7C9t.d.ts → index-C1WhBZ6a.d.ts} +4 -5
- package/dist/{index-B-VC4qjx.d.ts → index-C92SgNWz.d.ts} +2 -2
- package/dist/{index-CYrUWi1c.d.ts → index-CAsUE_d1.d.ts} +4 -4
- package/dist/{index-BjwRcjBi.d.ts → index-CO34esWT.d.ts} +2 -2
- package/dist/{index-DB8Yn0-K.d.ts → index-COeX9Bmz.d.ts} +11 -9
- package/dist/{index-Diyo8WBO.d.ts → index-Cg0QXnzf.d.ts} +2 -2
- package/dist/index.d.ts +5 -5
- package/dist/index.js +2 -2
- package/dist/jev/index.d.ts +8 -8
- package/dist/jev/index.js +5 -5
- package/dist/laws-DTtCDDlU.d.ts +135 -0
- package/dist/loop-DReKGV1X.d.ts +70 -0
- package/dist/{machine-BuPTS1QH.d.ts → machine-C0WhOAyB.d.ts} +5 -5
- package/dist/machine-viz/index.d.ts +1 -1
- package/dist/machine-viz/index.js +2 -2
- package/dist/mem/index.d.ts +4 -3
- package/dist/mem/index.js +2 -2
- package/dist/mem/index.js.map +1 -1
- package/dist/node/index.d.ts +57 -9
- package/dist/node/index.js +175 -68
- package/dist/node/index.js.map +1 -1
- package/dist/otel/index.d.ts +28 -12
- package/dist/otel/index.js +25 -21
- package/dist/otel/index.js.map +1 -1
- package/dist/paginate/index.d.ts +4 -4
- package/dist/paginate/index.js +5 -5
- package/dist/parity/index.d.ts +11 -15
- package/dist/parity/index.js +4 -9
- package/dist/parity/index.js.map +1 -1
- package/dist/pbt/index.d.ts +279 -67
- package/dist/pbt/index.js +299 -58
- package/dist/pbt/index.js.map +1 -1
- package/dist/persistence/index.d.ts +10 -12
- package/dist/persistence/index.js +4 -4
- package/dist/promise/index.d.ts +95 -13
- package/dist/promise/index.js +6 -4
- package/dist/react/index.d.ts +34 -22
- package/dist/react/index.js +271 -42
- package/dist/react/index.js.map +1 -1
- package/dist/resilience/index.d.ts +6 -6
- package/dist/resilience/index.js +5 -5
- package/dist/{run-D0sxbyno.d.ts → run-Cnw4qXj2.d.ts} +86 -17
- package/dist/{runtime-types-BPKp2bGo.d.ts → runtime-types-CP-ykwgf.d.ts} +120 -31
- package/dist/testing/effect/index.d.ts +162 -9
- package/dist/testing/effect/index.js +110 -10
- package/dist/testing/effect/index.js.map +1 -1
- package/dist/testing/index.d.ts +6 -8
- package/dist/testing/index.js +4 -24
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/promise/index.d.ts +4 -4
- package/dist/testing/promise/index.js +5 -5
- package/dist/timing/index.d.ts +4 -4
- package/dist/timing/index.js +4 -4
- package/dist/{types-BiXj7k_k.d.ts → types-S53WDy_h.d.ts} +1 -1
- package/dist/work-queue/index.d.ts +4 -4
- package/dist/work-queue/index.js +2 -2
- package/package.json +18 -18
- package/dist/chunk-7Z2IDZ7R.js +0 -34
- package/dist/chunk-7Z2IDZ7R.js.map +0 -1
- package/dist/chunk-EB5OMOXX.js.map +0 -1
- package/dist/chunk-GAVLND5C.js.map +0 -1
- package/dist/chunk-HU3Y2AZY.js.map +0 -1
- package/dist/chunk-TMYUDZLE.js.map +0 -1
- package/dist/chunk-VM7PMFV5.js.map +0 -1
- package/dist/chunk-W6XWI6QE.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/effect/failures.ts","../src/effect/handle.ts","../src/effect/run.ts"],"names":["Effect","Exit"],"mappings":"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","file":"chunk-HU3Y2AZY.js","sourcesContent":["/**\n * The Effect engine's typed failures (#308, ruling R4.1 of #325), and the edge\n * that turns what the shared loop rejects with into them.\n *\n * The loop is engine-neutral: it rejects a dispatch with whatever was thrown.\n * Two throws it cannot tell apart from a bug — a hand-written cell's declared\n * failure and a store's failed save — are wrapped here on the way in, so the\n * edge can read them on the way out. The wrappers never reach the caller: a\n * handle verb fails with the typed value, and the `onError` sink is handed the\n * value it was always handed.\n */\n\nimport { Data, Exit } from \"effect\";\nimport {\n type ExtensionFactory,\n RuntimeStoppedError,\n} from \"../internal/engine/loop\";\nimport {\n DispatchDiscardedError,\n type Store,\n StoreRefusedError,\n} from \"../runtime-types\";\n\n/**\n * A dispatch the run refused because it is stopping or has stopped. The Msg\n * was never folded.\n *\n * `when` is `\"stopping\"` for a Msg that arrived while `stop()` (or a closing\n * Scope) drained the run's in-flight work, and `\"stopped\"` once it had.\n */\nexport class Stopped extends Data.TaggedError(\"Stopped\")<{\n readonly msgType: string;\n readonly when: \"stopping\" | \"stopped\";\n}> {\n override get message(): string {\n return (\n `@demlik/tea: Msg \"${this.msgType}\" was refused — the run is ` +\n `${this.when}.`\n );\n }\n}\n\n/**\n * The run's store failed. `operation` is `\"load\"` when the saved state could\n * not be restored at boot — `cause` is then the `StoreRefusedError` that says\n * why — and `\"save\"` when a transition's save threw, a fenced store's\n * `StoreConflictError` included; `cause` is then the store's own throw.\n */\nexport class StoreFailed extends Data.TaggedError(\"StoreFailed\")<{\n readonly operation: \"load\" | \"save\";\n readonly cause: unknown;\n}> {\n override get message(): string {\n return `@demlik/tea: store ${this.operation} failed.`;\n }\n}\n\n/** A hand-written cell's declared failure, on its way through the loop. */\nexport class CellFailure {\n constructor(readonly failure: unknown) {}\n}\n\n/** A store's failed save, on its way through the loop. */\nclass SaveFailure {\n constructor(readonly cause: unknown) {}\n}\n\n/** What was thrown, with the edge's wrapper taken off. */\nexport function unwrapped(error: unknown): unknown {\n if (error instanceof CellFailure) return error.failure;\n if (error instanceof SaveFailure) return error.cause;\n return error;\n}\n\n/**\n * The outermost store wrapper: every save that throws is marked as a store\n * failure. Outermost, so it wraps the fenced compare-and-swap too, and its\n * `StoreConflictError` fails as a `StoreFailed`.\n */\nexport function saveFailures<S, M, C>(): ExtensionFactory<S, M, C> {\n return () => ({\n store: (store: Store<S>): Store<S> => ({\n load: () => store.load(),\n async save(state) {\n try {\n await store.save(state);\n } catch (cause) {\n throw new SaveFailure(cause);\n }\n },\n migrate: (raw) => store.migrate(raw),\n }),\n });\n}\n\n/**\n * The Exit a handle verb ends with when the loop rejected with `error`: a\n * typed failure for a refused dispatch, a failed store and a cell's declared\n * failure, and a defect for anything else — a reducer throw, a Msg with no\n * cell, a livelock — which ADR 0011 keeps a contract breach.\n */\nexport function exitOf<Err>(\n error: unknown,\n): Exit.Exit<never, Err | Stopped | StoreFailed> {\n if (error instanceof CellFailure) return Exit.fail(error.failure as Err);\n if (error instanceof SaveFailure) {\n return Exit.fail(\n new StoreFailed({ operation: \"save\", cause: error.cause }),\n );\n }\n if (error instanceof StoreRefusedError) {\n return Exit.fail(new StoreFailed({ operation: \"load\", cause: error }));\n }\n if (error instanceof DispatchDiscardedError) {\n return Exit.fail(new Stopped({ msgType: error.msgType, when: \"stopping\" }));\n }\n if (error instanceof RuntimeStoppedError) {\n return Exit.fail(new Stopped({ msgType: error.msgType, when: \"stopped\" }));\n }\n return Exit.die(error);\n}\n","/**\n * The Effect engine's run handle (#308, ruling R4.1 of #325). Its members have\n * the Promise engine's names (the shared-handle ruling of #250); only the\n * return types differ. Each member that returns a Promise there returns an\n * Effect here, with a typed error channel a host reads with `Effect.catchTags`.\n * Members that neither wait nor fail — `getState`, `result` and the listener\n * registrations — are the same functions on both engines.\n */\n\nimport { Effect } from \"effect\";\nimport { type LiveWorkProbe, liveWork } from \"../internal/engine/loop\";\nimport type { Port } from \"../pure/core\";\nimport type { DispatchSettle, Runtime } from \"../runtime-types\";\nimport { exitOf, type Stopped, type StoreFailed } from \"./failures\";\n\n/**\n * What the Effect engine's `run` yields while boot is in flight. `Err` is the\n * union of the declared failures of the run's hand-written cells: a dispatch\n * whose Cmd's cell fails with one fails with it. Reading State and waiting for\n * quiescence need boot to have run, so they live on the {@link EffectRuntime}\n * that `ready` succeeds with.\n */\nexport interface EffectBootingRuntime<\n S,\n M extends { type: string },\n E extends { type: string } = never,\n Err = never,\n> {\n /**\n * Fold `msg` and run to quiescence, as the Promise engine's `dispatch` does.\n * Fails with `Stopped` once the run is stopping or stopped, `StoreFailed`\n * when the transition's save fails, and a hand-written cell's declared\n * failure when the transition's Cmd fails with one.\n */\n dispatch(\n msg: M,\n opts?: { readonly settle?: DispatchSettle },\n ): Effect.Effect<void, Err | Stopped | StoreFailed>;\n /** `dispatch(msg, { settle: \"once\" })`: one transition, no follow-up drain. */\n dispatchOnce(msg: M): Effect.Effect<void, Err | Stopped | StoreFailed>;\n /** A zero-arg change notifier, fired after each applied transition. */\n subscribe(listener: () => void): () => void;\n /** A `(msg, state)` hook, fired after each applied transition. */\n observe(observer: (msg: M, state: S) => void): () => void;\n /** Fires once with the initial State — at once if boot already ran. */\n onBoot(handler: (state: S) => void): () => void;\n /** Subscribe to the semantic event of `type` the run's `events` projects. */\n on<K extends E[\"type\"]>(\n type: K,\n handler: (event: Extract<E, { type: K }>) => void,\n ): () => void;\n /** Subscribe to a typed Port. */\n subscribePort<T>(port: Port<T>, listener: (value: T) => void): () => void;\n /** Emit a value on a Port from outside a Cmd handler. */\n emitPort<T>(port: Port<T>, value: T): void;\n /**\n * Succeeds with the booted handle once boot completes. Fails with\n * `StoreFailed` when the saved state could not be restored (`\"load\"`) or the\n * initial save failed (`\"save\"`), and with a hand-written cell's declared\n * failure when a boot Cmd fails with one.\n */\n readonly ready: Effect.Effect<EffectRuntime<S, M, E, Err>, Err | StoreFailed>;\n /**\n * Stop the run: drain in-flight work, up to `disposeTimeoutMs`, stop its\n * Subs, flush the final State. `stop()` interrupts every handler still in\n * flight, so the limit is reached only by a handler that cannot be\n * interrupted. Closing the run's Scope stops the run the same way, and\n * `stop()` leaves that Scope open. So for a child under `spawn` the two\n * differ: `stop()` does not take the child out of the host's table or tell\n * the parent. Stop such a child with the `stop` helper.\n */\n stop(): Effect.Effect<void>;\n}\n\n/** The Effect engine's booted handle — what `ready` succeeds with. */\nexport interface EffectRuntime<\n S,\n M extends { type: string },\n E extends { type: string } = never,\n Err = never,\n> extends EffectBootingRuntime<S, M, E, Err> {\n /** The current State. Total. */\n getState(): S;\n readonly ready: Effect.Effect<EffectRuntime<S, M, E, Err>, Err | StoreFailed>;\n /** Succeeds once every dispatched Msg and its follow-ups are processed. */\n idle(): Effect.Effect<void>;\n /** The terminal State, or `undefined` while the run is in flight. */\n result(): S | undefined;\n /** Succeeds with the terminal State the first time the run reaches one. */\n done(): Effect.Effect<S>;\n}\n\n/** Run a loop call, ending with the typed Exit its rejection maps to. */\nfunction settled<A, Err>(\n call: () => Promise<A>,\n): Effect.Effect<A, Err | Stopped | StoreFailed> {\n return Effect.flatten(\n Effect.promise(() =>\n call().then(\n (value) => Effect.succeed(value),\n (error: unknown) => exitOf<Err>(error),\n ),\n ),\n );\n}\n\n/** Build the Effect handle over the loop's Promise one. */\nexport function effectHandle<\n S,\n M extends { type: string },\n E extends { type: string },\n Err,\n>(\n loop: Runtime<S, M, E> & LiveWorkProbe,\n): EffectRuntime<S, M, E, Err> & LiveWorkProbe {\n const handle: EffectRuntime<S, M, E, Err> & LiveWorkProbe = {\n [liveWork]: loop[liveWork],\n dispatch: (msg, opts) => settled(() => loop.dispatch(msg, opts)),\n dispatchOnce: (msg) => settled(() => loop.dispatchOnce(msg)),\n subscribe: (listener) => loop.subscribe(listener),\n observe: (observer) => loop.observe(observer),\n onBoot: (handler) => loop.onBoot(handler),\n on: (type, handler) => loop.on(type, handler),\n subscribePort: (port, listener) => loop.subscribePort(port, listener),\n emitPort: (port, value) => loop.emitPort(port, value),\n getState: () => loop.getState(),\n result: () => loop.result(),\n // Boot never passes the dispatch gate, so `ready` never fails `Stopped`.\n // Suspended: `handle` is not built yet when this line runs.\n ready: Effect.suspend(() =>\n settled<unknown, Err>(() => loop.ready).pipe(Effect.as(handle)),\n ) as Effect.Effect<EffectRuntime<S, M, E, Err>, Err | StoreFailed>,\n // `idle` rejects only on a livelock, and `done` and `stop` never do: a\n // rejection here is a defect.\n idle: () => Effect.promise(() => loop.idle()),\n done: () => Effect.promise(() => loop.done()),\n stop: () => Effect.promise(() => loop.stop()),\n };\n return handle;\n}\n","/**\n * The Effect engine's `run` (#283): the same machine the Promise engine runs,\n * with Effect handlers, Effect sub runners, the caller's Layers and\n * interruption on stop.\n *\n * It runs the one core loop both engines share (`src/internal/engine/loop.ts`)\n * with the same built-ins in the same order, so a machine folds the same way on\n * either engine. What this file adds is the Effect edge:\n *\n * - an `interpret` cell returns `Effect<Ok, E, R>`, read with\n * `Effect.result`: a success settles `_ok`, a declared failure settles\n * `_err`, a defect goes to the error sink;\n * - a `subscribe` runner returns a `Stream<Msg>`, drained on its own fiber;\n * - every handler and runner fiber runs with the services the caller\n * provided, so `R` reaches them from the caller's Layers;\n * - stopping interrupts every handler fiber still in flight;\n * - the handle's verbs are Effects with a typed error channel\n * (`./handle`, `./failures`).\n */\n\nimport { Cause, Effect, Exit, Fiber, Result, Scope, Stream } from \"effect\";\nimport { builtinExtensions } from \"../internal/engine/builtins\";\nimport {\n defaultOnError,\n type LiveWorkProbe,\n type LoopHandler,\n type LoopRunner,\n startLoop,\n} from \"../internal/engine/loop\";\nimport type {\n BuiltinSub,\n BuiltinSubType,\n Cmd,\n DeclaredErrorsOf,\n ErrorsOf,\n Machine,\n OkOfCmd,\n Sub,\n TimerSub,\n} from \"../pure/core\";\nimport { applyCell, Outcome, subEntriesOf } from \"../pure/core\";\nimport type {\n CtxArg,\n OnError,\n Runtime,\n Store,\n Supervision,\n TelemetrySink,\n} from \"../runtime-types\";\nimport { CellFailure, saveFailures, unwrapped } from \"./failures\";\nimport { type EffectBootingRuntime, effectHandle } from \"./handle\";\n\n// === The handler and runner shapes ===\n\n/**\n * One Effect `interpret` cell. For a `Cmd.define`d Cmd it succeeds with the\n * Cmd's `Ok` and fails with one of its declared tags, and the engine mints\n * `<name>_ok` / `<name>_err` from that (ADR 0021). For a hand-written Cmd it\n * succeeds with a follow-up Msg, a list of them (dispatched in order), or\n * nothing, and its failure fails the dispatch with that error, typed on the\n * handle (see {@link CellErrors}). `R` is whatever services it reads.\n */\nexport type EffectInterpretCell<\n M extends { type: string },\n C extends Cmd,\n R = unknown,\n> =\n unknown extends ErrorsOf<C>\n ? // biome-ignore lint/suspicious/noConfusingVoidType: a hand-written Cmd's handler may settle with nothing\n (cmd: C) => Effect.Effect<M | readonly M[] | void, unknown, R>\n : (cmd: C) => Effect.Effect<OkOfCmd<C>, DeclaredErrorsOf<C>, R>;\n\n/**\n * The Effect engine's `interpret` map: one cell per Cmd variant, each reading\n * services within `R`.\n */\nexport type EffectInterpret<\n M extends { type: string },\n C extends Cmd,\n R = unknown,\n> = {\n readonly [K in C[\"type\"]]: EffectInterpretCell<M, Extract<C, { type: K }>, R>;\n};\n\n/**\n * One Effect sub runner: the Sub in, a `Stream` of Msgs out. The engine drains\n * it on its own fiber and interrupts that fiber when the Sub stops.\n *\n * A Sub maps the errors it expects into Msgs itself, the way an Elm `Sub msg`\n * carries no error type: `Stream.catchTag(\"Closed\", () => Stream.make({ type:\n * \"disconnected\" }))`. A stream that still fails reaches the error sink under\n * `\"sub\"` and stops the run: the run's Scope closes with that failure (#309).\n */\nexport type EffectRunner<\n M extends { type: string },\n U extends Sub,\n R = unknown,\n> = (sub: U) => Stream.Stream<M, unknown, R>;\n\n/**\n * The Effect engine's `subscribe` map: a runner for every Sub type the machine\n * declares beyond the built-ins, and optionally one for a built-in, which\n * replaces the engine's own (#270 R2.1).\n */\nexport type EffectSubscribe<\n M extends { type: string },\n U extends Sub,\n R = unknown,\n> = {\n readonly [K in Exclude<U[\"type\"], BuiltinSubType>]: EffectRunner<\n M,\n Extract<U, { type: K }>,\n R\n >;\n} & {\n readonly [K in BuiltinSubType]?: EffectRunner<\n M,\n Extract<BuiltinSub<M>, { type: K }>,\n R\n >;\n};\n\n/** The services every cell of an `interpret` map reads. */\nexport type InterpretServices<I> = {\n [K in keyof I]: ServicesOfCell<I[K]>;\n}[keyof I];\n\ntype ServicesOfCell<F> = F extends (\n cmd: never,\n) => Effect.Effect<unknown, unknown, infer R>\n ? R\n : never;\n\n/**\n * The failures a dispatch on the handle can end with from an `interpret` map:\n * the error type of every hand-written Cmd's cell. A `Cmd.define`d Cmd's\n * declared failure settles its `_err` Msg instead, so it adds nothing here.\n */\nexport type CellErrors<C extends Cmd, I> = {\n [K in keyof I & C[\"type\"]]: unknown extends ErrorsOf<Extract<C, { type: K }>>\n ? ErrorOfCell<I[K]>\n : never;\n}[keyof I & C[\"type\"]];\n\ntype ErrorOfCell<F> = F extends (\n cmd: never,\n) => Effect.Effect<unknown, infer Err, unknown>\n ? Err\n : never;\n\n/** The services every runner of a `subscribe` map reads. */\nexport type SubscribeServices<B> = {\n [K in keyof B]-?: ServicesOfRunner<NonNullable<B[K]>>;\n}[keyof B];\n\ntype ServicesOfRunner<F> = F extends (\n sub: never,\n) => Stream.Stream<unknown, unknown, infer R>\n ? R\n : never;\n\n// `interpret` is optional for a machine that emits no Cmd, and `subscribe` for\n// one that declares only built-in Subs — the same requiredness the Promise\n// engine's `RunHandlers` carries.\ntype InterpretOption<C extends Cmd, I> = [C] extends [Cmd<never>]\n ? { readonly interpret?: I }\n : { readonly interpret: I };\n\nexport type SubscribeOption<U extends Sub, B> = [\n Exclude<U[\"type\"], BuiltinSubType>,\n] extends [never]\n ? { readonly subscribe?: B }\n : { readonly subscribe: B };\n\n/**\n * The options of the Effect engine's `run`. Beside `interpret` and\n * `subscribe`, they are the Promise engine's, with the same meaning; see `run`\n * in `@demlik/tea/promise` for each one's contract.\n */\nexport type EffectRunOptions<\n S,\n M extends { type: string },\n C extends Cmd,\n U extends Sub,\n Ctx,\n E extends { type: string },\n I,\n B,\n> = CtxArg<Ctx> &\n InterpretOption<C, I> &\n SubscribeOption<U, B> & {\n readonly store?: Store<S>;\n readonly onError?: OnError;\n /** Stamps `at` on minted Msgs and telemetry. Defaults to `Date.now`. */\n readonly clock?: () => number;\n /** Projects each applied transition to the public events `on` serves. */\n readonly events?: (msg: M, state: S) => readonly E[];\n /** The policy for a reducer throw. Defaults to `\"stop\"`. */\n readonly supervision?: Supervision<S, M>;\n /** The terminal predicate `result()` and `done()` read. */\n readonly terminal?: (state: S) => boolean;\n /** A fire-and-forget sink for every applied transition. */\n readonly telemetry?: TelemetrySink;\n /**\n * How long `stop()` waits for the queue, and then for async teardown,\n * before giving up on each. Defaults to 5_000ms. `stop()` interrupts every\n * handler here, so the first wait ends early unless a handler cannot be\n * interrupted.\n *\n * A store call is not interrupted. tea starts none after `stop()` has\n * returned, but one already under way when `stop()` gave up can finish\n * after it. On a plain store that late save can overwrite what a newer\n * run saved; a fenced store refuses it. So a host that starts a new run on\n * the same store after a `stop()` that gave up needs a fenced store.\n */\n readonly disposeTimeoutMs?: number;\n };\n\n// === Built-in runners ===\n\n/** `timer`: emit `deps.msg` once, `deps.ms` after the Sub starts. */\nfunction timer<M>(sub: TimerSub<M>): Stream.Stream<M> {\n return Stream.fromEffect(Effect.as(Effect.sleep(sub.deps.ms), sub.deps.msg));\n}\n\n/** The Effect engine's built-in runners, keyed by the Sub type each runs. */\nexport const builtinRunners = { timer } as const satisfies Record<\n BuiltinSubType,\n unknown\n>;\n\n// === Settling a cell ===\n\n/**\n * The Effect a cell's Effect is run as: `Effect.result` makes a declared\n * failure a value, so only a defect or an interruption is left in the Exit's\n * cause. Read the Exit back with {@link settleCellExit}.\n */\nexport function cellResult(\n effect: Effect.Effect<unknown, unknown>,\n): Effect.Effect<Result.Result<unknown, unknown>> {\n return Effect.result(effect);\n}\n\n/**\n * What one cell's run settles to, the rule the engine and the Effect `drive`\n * share so they cannot drift:\n *\n * - interrupted — `undefined`, nothing to dispatch;\n * - a defect — thrown;\n * - a `Cmd.define`d Cmd (`defined`) — its success as `Outcome.ok`, its\n * declared failure as `Outcome.err`, for the `Cmd.define` edge to mint;\n * - a hand-written Cmd — its success (the follow-up Msgs) as is, its failure\n * thrown as a {@link CellFailure}, so a caller types it.\n */\nexport function settleCellExit(\n exit: Exit.Exit<unknown, unknown>,\n defined: boolean,\n): unknown {\n if (Exit.isFailure(exit)) {\n if (Cause.hasInterruptsOnly(exit.cause)) return undefined;\n throw Cause.squash(exit.cause);\n }\n const result = exit.value as Result.Result<unknown, unknown>;\n if (defined) {\n return Result.isSuccess(result)\n ? Outcome.ok(result.success)\n : Outcome.err(result.failure);\n }\n if (Result.isFailure(result)) throw new CellFailure(result.failure);\n return result.success;\n}\n\n// === run ===\n\n/**\n * Run `machine` on the Effect engine. The returned Effect needs a `Scope` and\n * the services its handlers and runners read, and yields the run handle. The\n * handle's members have the Promise engine's names; the ones that return a\n * Promise there return an Effect here, failing with `Stopped`, `StoreFailed`\n * or a hand-written cell's declared failure, so a host sorts them with\n * `Effect.catchTags`.\n *\n * Closing the scope stops the run and its Subs: every handler still in flight\n * is interrupted (its finalizers run), its Msg is never dispatched, and a\n * dispatch after stop fails with `Stopped`. The handle's `stop()` does the\n * same.\n *\n * A Sub whose Stream fails with an error it did not map to a Msg stops the\n * run the other way round: the engine closes that Scope with the failure.\n *\n * A fenced store is fenced here exactly as on the Promise engine: the check is\n * one of the built-ins both engines run.\n *\n * ```ts\n * const program = Effect.gen(function* () {\n * const handle = yield* run(machine, {\n * interpret: {\n * fetch: (cmd) =>\n * Effect.gen(function* () {\n * const api = yield* Api;\n * return yield* api.get(cmd.id);\n * }),\n * },\n * });\n * const runtime = yield* handle.ready;\n * yield* runtime.dispatch({ type: \"go\", id: \"7\" });\n * return runtime.getState();\n * });\n * Effect.runPromise(program.pipe(Effect.scoped, Effect.provide(ApiLive)));\n * ```\n */\nexport function run<\n S,\n M extends { type: string },\n C extends Cmd,\n U extends Sub,\n Ctx,\n // The defaults read no services, so an omitted map adds none to `R`.\n I extends EffectInterpret<M, C> = EffectInterpret<M, C, never>,\n B extends EffectSubscribe<M, U> = EffectSubscribe<M, U, never>,\n E extends { type: string } = never,\n>(\n machine: Machine<S, M, C, U, Ctx>,\n opts: EffectRunOptions<S, M, C, U, Ctx, E, I, B>,\n): Effect.Effect<\n EffectBootingRuntime<S, M, E, CellErrors<C, I>>,\n never,\n Scope.Scope | InterpretServices<I> | SubscribeServices<B>\n> {\n return Effect.gen(function* () {\n const services = yield* Effect.context<\n InterpretServices<I> | SubscribeServices<B>\n >();\n const scope = yield* Scope.Scope;\n const fork = Effect.runForkWith(services) as ForkEffect;\n return yield* Effect.acquireRelease(\n Effect.sync(() =>\n effectHandle<S, M, E, CellErrors<C, I>>(\n start<S, M, C, U, Ctx, E>(\n machine,\n opts as EffectRunOptions<S, M, C, U, Ctx, E, unknown, unknown>,\n Effect.runPromiseExitWith(services) as RunEffect,\n fork,\n // Closing the Scope runs the release below, which stops the run.\n // A Scope that closes before that release is added runs it on add.\n (exit) => fork(Scope.close(scope, exit)),\n ),\n ),\n ),\n (runtime) => runtime.stop(),\n );\n });\n}\n\n/** Run an erased Effect to its Exit, interruptible through `signal`. */\ntype RunEffect = (\n effect: Effect.Effect<unknown, unknown>,\n options: { readonly signal: AbortSignal },\n) => Promise<Exit.Exit<unknown, unknown>>;\n\n/** Fork an erased Effect onto its own fiber. */\ntype ForkEffect = (\n effect: Effect.Effect<unknown, unknown>,\n) => Fiber.Fiber<unknown, unknown>;\n\ntype AnyCell = (cmd: unknown) => Effect.Effect<unknown, unknown>;\ntype AnyRunner = (sub: Sub) => Stream.Stream<unknown, unknown>;\n\nfunction start<\n S,\n M extends { type: string },\n C extends Cmd,\n U extends Sub,\n Ctx,\n E extends { type: string },\n>(\n machine: Machine<S, M, C, U, Ctx>,\n opts: EffectRunOptions<S, M, C, U, Ctx, E, unknown, unknown>,\n runEffect: RunEffect,\n fork: ForkEffect,\n closeScope: (exit: Exit.Exit<never, unknown>) => void,\n): Runtime<S, M, E> & LiveWorkProbe {\n const interpret = ((opts as { interpret?: unknown }).interpret ??\n {}) as Readonly<Record<string, AnyCell | undefined>>;\n const subscribe = ((opts as { subscribe?: unknown }).subscribe ??\n {}) as Readonly<Record<string, AnyRunner | undefined>>;\n const builtins = builtinRunners as unknown as Readonly<\n Record<string, AnyRunner | undefined>\n >;\n const defined = new Set((machine.cmds ?? []).map((def) => def.cmdType));\n\n // Aborted on stop: every handler fiber runs under this signal, so aborting\n // it interrupts all of them at once.\n const interruption = new AbortController();\n\n // Interrupted by stop, a cell settles to nothing. A defect throws: for a\n // defined Cmd the `Cmd.define` edge routes it to the error sink, for a\n // hand-written one it rejects the dispatch. A hand-written cell's failure is\n // marked, so the handle fails the dispatch with it as a typed error.\n async function settle(cell: AnyCell, cmd: unknown): Promise<unknown> {\n const type = (cmd as { type: string }).type;\n const exit = await runEffect(cellResult(cell(cmd)), {\n signal: interruption.signal,\n });\n return settleCellExit(exit, defined.has(type));\n }\n\n function handlerFor(type: string): LoopHandler<M> | undefined {\n const cell = interpret[type];\n if (cell === undefined) return undefined;\n return (cmd) => settle(cell, cmd);\n }\n\n // The Cause the run's Scope closes with when a Sub fails: the Stream's own\n // when a Stream failed, else the runner's throw as a defect.\n let subFailure: Cause.Cause<unknown> | undefined;\n\n // A runner's Msgs reach the loop through its `dispatch`, which queues each\n // one behind the step in progress — never a transition on the stream's own\n // fiber (spike #260). A Stream that fails with anything but an interrupt\n // failed with an error the Sub did not map to a Msg, and the run stops\n // (#309).\n function runnerFor(type: string): LoopRunner<Ctx, M> | undefined {\n const make = subscribe[type] ?? builtins[type];\n if (make === undefined) return undefined;\n return (sub, _ctx, dispatch, fail) => {\n const drain = Stream.runForEach(make(sub), (msg) =>\n Effect.sync(() => dispatch(msg as M)),\n ).pipe(\n Effect.catchCause((cause) =>\n Cause.hasInterruptsOnly(cause)\n ? Effect.void\n : Effect.sync(() => {\n subFailure ??= cause;\n fail(Cause.squash(cause));\n }),\n ),\n );\n const fiber = fork(drain);\n return () => Effect.runPromise(Fiber.interrupt(fiber));\n };\n }\n\n // The sink is handed what was thrown, never the edge's marker around it.\n const sink = opts.onError ?? defaultOnError;\n\n const handle = startLoop<S, M, C, Ctx>({\n init: machine.init,\n reduce: (state, msg) => applyCell<S, M, C>(machine, state, msg),\n subs: subEntriesOf<S>(machine),\n runnerFor,\n handlerFor,\n store: opts.store,\n ctx: (opts.ctx ?? {}) as Ctx,\n onError: (error, context) => sink(unwrapped(error), context),\n disposeTimeoutMs: opts.disposeTimeoutMs ?? 5_000,\n idleCap: 100_000,\n // The save marker wraps outermost, around the fence the built-ins add.\n extensions: [\n saveFailures<S, M, C>(),\n ...builtinExtensions<S, M, C, E>(machine, opts),\n ],\n stopOnSubFailure: (error) =>\n closeScope(Exit.failCause(subFailure ?? Cause.die(error))),\n });\n\n // Stop closes the gate first, so nothing an interrupted handler leaves\n // behind is dispatched, then interrupts every handler still in flight so the\n // drain it waits on can finish.\n const stopLoop = handle.stop;\n handle.stop = () => {\n const stopped = stopLoop();\n interruption.abort();\n return stopped;\n };\n return handle as unknown as Runtime<S, M, E> & LiveWorkProbe;\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/persistence/recorder/index.ts","../src/internal/persistence/trace-replay/index.ts"],"names":[],"mappings":"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","file":"chunk-TMYUDZLE.js","sourcesContent":["// ---------------------------------------------------------------------------\n// recorder — capture a Runtime's Msg sequence for later replay.\n//\n// `historyTracker` (in ../index) is the exemplar: a BOUNDED, in-memory ring\n// buffer over `runtime.observe`. The recorder is its UNBOUNDED, SERIALIZABLE\n// cousin. Where historyTracker exists to answer \"what were the last N\n// transitions?\", the recorder exists to answer \"reproduce this entire run\n// locally against the current reducer.\"\n//\n// The killer feature this enables: record a prod Msg sequence, dump it as\n// JSONL, ship the file home, and feed it to `../trace-replay`'s `replayTrace`\n// — which folds the SAME msgs through `replay(machine, ...)` and diffs the\n// resulting state against the recorded final state. If they diverge, the\n// reducer changed behavior for that input. Regression-as-a-trace.\n//\n// What `replay` needs to reproduce a run (see `replay` in ../index):\n// - `loaded` — the value `init` was booted with. Captured at the boot\n// observe, where `msg === null` and `state` is the post-init\n// initial state. (We capture the post-init state, not the raw\n// storage value, because replay re-runs `init(loaded, ctx)`\n// itself — and for a faithful re-run we feed it that initial\n// state as `loaded` so `init` returns `[loaded, []]`. This is\n// the rehydrate path, which the substrate guarantees is a pure\n// passthrough; see Invariant 2.)\n// - `msgs` — every non-null msg, in dispatch order.\n// - `ctx` — NOT captured here. Ctx is host wiring (sibling runtimes,\n// clients), supplied fresh at replay time. The trace is the\n// INPUT (loaded + msgs); ctx is the ENVIRONMENT.\n//\n// This module OWNS the `Trace` type. `../trace-replay` imports it.\n// ---------------------------------------------------------------------------\n\nimport type { BootingRuntime } from \"../../../index\";\n\n/**\n * A recorded run, sufficient to reproduce it via `../trace-replay`.\n *\n * The recorder OWNS this type; `../trace-replay` imports it. It is the wire\n * contract between the two halves of the record/replay feature.\n *\n * @typeParam S - the machine's State type.\n * @typeParam M - the machine's Msg union.\n */\nexport interface Trace<S, M> {\n /**\n * The initial state captured at the boot observe (the transition where\n * `msg === null`). Fed back to replay as `loaded` so `init(loaded, ctx)`\n * reproduces the exact starting point. `null` only if the recorder attached\n * AFTER boot (it missed the boot observe) — replay then re-runs fresh `init`.\n */\n readonly loaded: S | null;\n /** The ordered, non-null msgs as observed. The replay input sequence. */\n readonly msgs: readonly M[];\n /**\n * The last observed state. The oracle: `replayTrace` deep-compares its\n * recomputed final state against this. Equal ⇒ the reducer still produces\n * the same result for this input.\n */\n readonly finalState: S;\n /**\n * Per-transition `(msg, post-state)` pairs, in dispatch order, for human\n * inspection (e.g. \"show me the state after step 3\"). When present, there\n * is exactly one entry per recorded msg and `state` is the POST-transition\n * state for that msg (so `steps[i].msg === msgs[i]` and `steps.at(-1).state`\n * deep-equals `finalState`). NOT required for replay — replay only needs\n * `loaded` + `msgs` + `finalState`.\n *\n * Present iff the recorder was created with `captureSteps: true`, OR the\n * Trace was re-hydrated from JSONL via {@link parseJSONL} (the JSONL format\n * carries per-step state, so the parser populates `steps` whenever a step\n * line had a non-null state). A trace dumped with `captureSteps: false` has\n * `steps === undefined`.\n */\n readonly steps?: readonly { readonly msg: M; readonly state: S }[];\n}\n\n/** Options for {@link recorder}. */\nexport interface RecorderOptions {\n /**\n * Fraction of msgs to record, in `(0, 1]`. Default `1` (record everything).\n *\n * IMPORTANT — sampling breaks replay fidelity. A sampled trace DROPS msgs,\n * so its `msgs` array is no longer the complete input sequence and\n * `replayTrace` will NOT reproduce `finalState`. Sampling exists for\n * VOLUME STATISTICS (how much traffic, msg-type distribution), not for\n * faithful replay. Use the default `1` for any trace you intend to replay.\n *\n * The boot observe (`msg === null`) is ALWAYS recorded regardless of\n * `sampleRate` — `loaded` and `finalState` are anchors, not samples.\n */\n readonly sampleRate?: number;\n /**\n * When `true`, retain a per-transition `(msg, post-state)` pair in\n * {@link Trace.steps} for EVERY recorded transition. Default `false`.\n *\n * Size vs. fidelity — the precise trade-off:\n *\n * - `captureSteps: false` (default) — the MINIMAL replay-faithful trace.\n * The recorder keeps `loaded` (boot state), the ordered `msgs`, and\n * `finalState`. That is exactly what `../trace-replay` needs to refold\n * the run and diff the result. Memory is O(msgs) — one msg ref each, no\n * per-step state snapshot. `dump().steps` is `undefined`; in JSONL,\n * interior step lines carry `state: null` (the post-states were never\n * retained) and only the LAST step line carries `finalState`. A trace\n * dumped this way REPLAYS correctly but cannot answer \"what was the\n * state after step 3?\".\n *\n * - `captureSteps: true` — the FULL-fidelity trace. The recorder also\n * snapshots the post-transition state for every msg, so `dump().steps`\n * holds `{ msg, state }` for every transition (post-state) and\n * `toJSONL()` emits a non-null `state` on every step line. Memory is\n * O(msgs × |state|) — a state ref per transition (refs, not deep\n * copies; TEA states are conventionally immutable, so the runtime's\n * post-transition state object is retained by reference). This is the\n * mode for per-step inspection and for a JSONL file that round-trips\n * `steps` exactly via {@link parseJSONL}.\n *\n * Replay fidelity is identical in both modes — `../trace-replay` reads\n * `loaded` + `msgs` + `finalState` only and never touches `steps`. The\n * choice is purely \"do I also want to inspect intermediate states?\".\n */\n readonly captureSteps?: boolean;\n}\n\n/**\n * A live recorder attached to a Runtime. Mirrors `historyTracker`'s\n * stop/snapshot semantics: `dump()` works at any time (including after\n * `stop()`), `stop()` is idempotent and detaches the observer.\n *\n * @typeParam S - the machine's State type.\n * @typeParam M - the machine's Msg union.\n */\nexport interface Recorder<S, M> {\n /**\n * Snapshot the recording so far as a {@link Trace}. Returns a fresh object\n * with copied arrays on every call (callers may slice/replay without\n * affecting the recorder's buffers). Entry values are references to the\n * originals (TEA states/msgs are conventionally immutable).\n *\n * Throws only if called before the boot observe has fired AND no msgs have\n * been recorded — i.e. there is no `finalState` yet. In practice callers\n * `await runtime.ready` before `dump()`, after which boot has fired.\n */\n dump(): Trace<S, M>;\n /**\n * Serialize the recording as JSONL (one JSON object per line) — a streamable\n * format that appends cleanly and survives truncation (a partial tail line\n * is the only loss). The first line is the boot header\n * `{ kind: \"boot\", state }`; each subsequent line is\n * `{ kind: \"step\", msg, state }` for one recorded transition.\n *\n * Re-hydrate with {@link parseJSONL}.\n *\n * Round-trip fidelity depends on `captureSteps`:\n * - `captureSteps: true` — every step line carries its non-null\n * post-state, so `parseJSONL(rec.toJSONL())` reconstructs `steps`\n * EXACTLY and deep-equals `rec.dump()` (which also has `steps`). Full\n * per-step fidelity round-trips.\n * - `captureSteps: false` (default) — interior step lines carry\n * `state: null` (those post-states were never retained); only the last\n * step line carries `finalState`. `parseJSONL` then populates `steps`\n * with just the entries that had a non-null state (the final one), so\n * the re-hydrated Trace is NOT deep-equal to `rec.dump()` (which has no\n * `steps`). It is still fully replay-faithful: `loaded`, `msgs`, and\n * `finalState` are intact. Record with `captureSteps: true` if you need\n * interior states to survive the round-trip.\n */\n toJSONL(): string;\n /**\n * Detach the underlying observer. After `stop()`:\n * - no new transitions are recorded;\n * - `dump()` / `toJSONL()` keep working against the buffered contents;\n * - the recorder holds no observer reference into the runtime.\n *\n * Idempotent — subsequent calls are no-ops.\n */\n stop(): void;\n}\n\n/**\n * Attach a recorder to a Runtime. Subscribes via `runtime.observe`, capturing\n * the boot state as `loaded` and every subsequent non-null msg in order.\n *\n * One-line creation, mirroring `historyTracker`:\n *\n * const rec = recorder(runtime);\n * // ... drive the runtime ...\n * await runtime.ready; // boot observe has fired\n * const trace = rec.dump(); // { loaded, msgs, finalState }\n *\n * @param runtime - any `BootingRuntime<S, M>` (a full `Runtime` satisfies it).\n * The recorder uses only `observe`, which is total before boot\n * — so you attach it to the synchronous `run()` handle to\n * capture the boot transition as `loaded`.\n * @param opts - see {@link RecorderOptions}. Default records everything,\n * no step retention.\n */\nexport function recorder<S, M extends { type: string }>(\n runtime: BootingRuntime<S, M>,\n opts?: RecorderOptions,\n): Recorder<S, M> {\n // Clamp sampleRate into (0, 1]. A non-positive or NaN rate would record\n // nothing (and break replay anchors); default it to 1 (record all). Rates\n // above 1 are meaningless — clamp to 1.\n const rawRate = opts?.sampleRate;\n const sampleRate =\n rawRate === undefined || Number.isNaN(rawRate) || rawRate <= 0\n ? 1\n : Math.min(rawRate, 1);\n const captureSteps = opts?.captureSteps ?? false;\n\n // `loaded` is the post-init state captured at the boot observe. `undefined`\n // sentinel = boot not yet seen; resolved to `S | null` in dump() (null when\n // the recorder attached after boot and never observed msg === null).\n let loaded: S | undefined;\n let sawBoot = false;\n // The ordered, recorded msgs. Unbounded (the recorder's whole point vs the\n // bounded historyTracker).\n const msgs: M[] = [];\n // Per-step (msg, state) pairs — only populated when captureSteps is on.\n const steps: { msg: M; state: S }[] = [];\n // The last observed state — boot state until the first step, then advances\n // with every recorded OR dropped transition (finalState must reflect the\n // true latest state even under sampling, so it stays a valid replay oracle\n // for the unsampled case and an honest \"where the run ended\" marker).\n let finalState: S | undefined;\n let stopped = false;\n\n // The boot transition — the post-init initial state the old `observe(msg ===\n // null)` arm captured as `loaded` — now arrives via `onBoot` (#47). Always\n // captured (boot is the replay anchor). It is also the first `finalState`\n // until the first applied transition advances it.\n const unboot = runtime.onBoot((state) => {\n finalState = state;\n loaded = state;\n sawBoot = true;\n });\n\n const unobserve = runtime.observe((msg, state) => {\n // finalState tracks the latest state regardless of sampling — it is the\n // run's endpoint, an anchor, not a sample.\n finalState = state;\n\n // Sampling decision. sampleRate === 1 short-circuits to always-record so\n // the common (faithful) path pays no RNG cost. Math.random() < rate keeps\n // a `rate` fraction in expectation.\n if (sampleRate < 1 && Math.random() >= sampleRate) return;\n\n msgs.push(msg);\n if (captureSteps) steps.push({ msg, state });\n });\n\n return {\n dump(): Trace<S, M> {\n if (finalState === undefined) {\n throw new Error(\n \"tea recorder: dump() called before any transition was observed. \" +\n \"Await `runtime.ready` (boot fires the first observe) before dumping.\",\n );\n }\n return {\n // sawBoot ⇒ `loaded` is the captured boot state; otherwise the\n // recorder attached post-boot and replay must re-run fresh init.\n loaded: sawBoot ? (loaded as S) : null,\n msgs: msgs.slice(),\n finalState,\n // Only attach `steps` when captureSteps was requested — keeps the\n // dumped Trace shape honest about what was retained.\n ...(captureSteps ? { steps: steps.slice() } : {}),\n };\n },\n toJSONL(): string {\n if (finalState === undefined) {\n throw new Error(\n \"tea recorder: toJSONL() called before any transition was observed. \" +\n \"Await `runtime.ready` (boot fires the first observe) before serializing.\",\n );\n }\n // Serialize the live snapshot via the shared Trace→JSONL writer so the\n // recorder and the standalone `traceAttachment` path emit byte-identical\n // wire format. `dump()` resolves the captureSteps logic (steps present\n // iff captureSteps was on); `traceToJSONL` then emits a non-null state\n // on every step line when steps exist, or `null` interior + finalState\n // on the last line when they don't. The replay path never reads step\n // states, so the captureSteps:false null-interiors never affect replay.\n return traceToJSONL(this.dump());\n },\n stop(): void {\n if (stopped) return;\n stopped = true;\n unobserve();\n unboot();\n },\n };\n}\n\n/** One line of the JSONL format produced by {@link Recorder.toJSONL}. */\ntype JsonlLine<S, M> =\n | { readonly kind: \"boot\"; readonly state: S | null }\n | { readonly kind: \"step\"; readonly msg: M; readonly state: S | null };\n\n/**\n * Re-hydrate a {@link Trace} from the JSONL produced by\n * {@link Recorder.toJSONL}. The inverse of `toJSONL`, so\n * `parseJSONL(rec.toJSONL())` deep-equals `rec.dump()`.\n *\n * Parsing rules:\n * - The first non-blank line MUST be the boot header `{ kind: \"boot\", state }`.\n * Its `state` becomes `Trace.loaded`.\n * - Each `{ kind: \"step\", msg, state }` line contributes `msg` to\n * `Trace.msgs` and `(msg, state)` to `Trace.steps`.\n * - `Trace.finalState` is the `state` of the LAST step line, or the boot\n * `state` when there are no steps (a boot-only trace).\n *\n * Blank lines are skipped (tolerant of trailing newlines / hand-edited files).\n * A malformed line, a missing/duplicate boot header, or a step with `null`\n * final state throws — the trace is unusable for replay and silent corruption\n * is worse than a loud parse error (errors are data; surface them).\n *\n * @typeParam S - the machine's State type.\n * @typeParam M - the machine's Msg union.\n */\nexport function parseJSONL<S, M>(jsonl: string): Trace<S, M> {\n const rawLines = jsonl.split(\"\\n\");\n let loaded: S | null = null;\n let sawBoot = false;\n const msgs: M[] = [];\n const steps: { msg: M; state: S }[] = [];\n let finalState: S | null = null;\n let finalKnown = false;\n\n for (const [i, rawLine] of rawLines.entries()) {\n const line = rawLine.trim();\n if (line === \"\") continue; // tolerate blank / trailing-newline lines\n\n let parsed: JsonlLine<S, M>;\n try {\n parsed = JSON.parse(line) as JsonlLine<S, M>;\n } catch (err) {\n throw new Error(\n `tea recorder: parseJSONL failed on line ${i + 1}: not valid JSON. ${String(err)}`,\n );\n }\n\n if (parsed.kind === \"boot\") {\n if (sawBoot) {\n throw new Error(\n `tea recorder: parseJSONL saw a second boot header on line ${i + 1}. ` +\n \"A trace has exactly one boot line.\",\n );\n }\n sawBoot = true;\n loaded = parsed.state;\n // The boot state is the finalState until a step supersedes it (boot-only\n // trace case).\n finalState = parsed.state;\n finalKnown = parsed.state !== null;\n } else if (parsed.kind === \"step\") {\n if (!sawBoot) {\n throw new Error(\n `tea recorder: parseJSONL saw a step line before the boot header on line ${i + 1}.`,\n );\n }\n msgs.push(parsed.msg);\n if (parsed.state !== null) {\n steps.push({ msg: parsed.msg, state: parsed.state });\n finalState = parsed.state;\n finalKnown = true;\n }\n } else {\n throw new Error(\n `tea recorder: parseJSONL saw an unknown line kind on line ${i + 1}: ` +\n JSON.stringify((parsed as { kind?: unknown }).kind),\n );\n }\n }\n\n if (!sawBoot) {\n throw new Error(\n \"tea recorder: parseJSONL found no boot header. A trace must start with \" +\n '{ kind: \"boot\", state }.',\n );\n }\n if (!finalKnown || finalState === null) {\n throw new Error(\n \"tea recorder: parseJSONL could not determine finalState — the boot state \" +\n \"was null and no step carried a non-null state. The trace is unusable for replay.\",\n );\n }\n\n return { loaded, msgs, finalState, steps };\n}\n\n// ---------------------------------------------------------------------------\n// Sentry crash→trace adapters — pure, zero-dependency, Sentry-SHAPED.\n//\n// The killer DevX flow: a machine crashes in prod → its recorded Trace rides\n// along on the Sentry event → one click later you `parseJSONL` it and replay\n// the exact run locally against the (possibly fixed) reducer. These two\n// adapters are the bridge from a `Trace` to the two Sentry surfaces that carry\n// it: an Attachment (the full replayable trace) and Breadcrumbs (a human-\n// readable timeline of the msgs that led to the crash).\n//\n// They take NO dependency on `@sentry/*`. They emit PLAIN OBJECTS whose shapes\n// match Sentry's public `Attachment` and `Breadcrumb` types, and the consumer\n// wires them at their own Sentry boundary (browser or node). This keeps the\n// recorder runnable anywhere a machine runs (a Worker, a Node script, a test)\n// and lets the consumer pin whatever Sentry SDK version they already ship.\n// ---------------------------------------------------------------------------\n\n/**\n * A Sentry-shaped attachment carrying the full {@link Trace} as JSONL. The\n * shape matches Sentry's `Attachment` type so the consumer can hand it\n * straight to `addAttachment(...)` without any adaptation.\n *\n * - `filename` — `\"tea-trace.jsonl\"`. The name Sentry shows in the UI and\n * uses for download; `.jsonl` signals the streamable format.\n * - `data` — the trace serialized via {@link Recorder.toJSONL}'s format\n * (re-hydrate downstream with {@link parseJSONL}).\n * - `contentType` — `\"application/x-ndjson\"`, the standard MIME for\n * newline-delimited JSON.\n */\nexport interface TraceAttachment {\n readonly filename: string;\n readonly data: string;\n readonly contentType: string;\n}\n\n/**\n * Serialize a {@link Trace} into a Sentry-shaped attachment so a crash event\n * carries the full, replayable run. Pure — no Sentry import, no I/O. The\n * returned object matches Sentry's `Attachment` shape exactly.\n *\n * The `data` field is JSONL in the same format {@link Recorder.toJSONL}\n * produces, so the home-side flow is `parseJSONL(attachment.data)` →\n * `replayTrace(machine, trace, ctx)`.\n *\n * Consumer wiring (no Sentry import here — the consumer owns the boundary):\n *\n * ```ts\n * import * as Sentry from \"@sentry/browser\"; // or \"@sentry/node\"\n * import { traceAttachment } from \"./internal/persistence/recorder\"; // internal module\n * Sentry.getCurrentScope().addAttachment(traceAttachment(rec.dump()));\n * ```\n *\n * @typeParam S - the machine's State type.\n * @typeParam M - the machine's Msg union.\n */\nexport function traceAttachment<S, M extends { type: string }>(\n trace: Trace<S, M>,\n): TraceAttachment {\n return {\n filename: \"tea-trace.jsonl\",\n data: traceToJSONL(trace),\n contentType: \"application/x-ndjson\",\n };\n}\n\n/** A Sentry-shaped breadcrumb. Matches the fields of Sentry's `Breadcrumb`. */\nexport interface TraceBreadcrumb {\n readonly category: string;\n readonly type: string;\n readonly level: string;\n readonly message: string;\n readonly data?: Record<string, unknown>;\n}\n\n/** Options for {@link breadcrumbsFromTrace}. */\nexport interface BreadcrumbsOptions<M> {\n /**\n * Max breadcrumbs to emit. Default `100` (Sentry's own default breadcrumb\n * cap). When the trace has more msgs than `limit`, the OLDEST are dropped —\n * the returned list is the newest-last tail, matching how a Sentry\n * breadcrumb ring buffer behaves (the crash context is the recent past).\n */\n readonly limit?: number;\n /**\n * Customize each breadcrumb's `message`. Default uses `msg.type`. Provide a\n * serializer to surface a richer one-liner (e.g. include an id). The msg is\n * ALSO always attached verbatim under `data.msg` regardless of this option,\n * so the structured payload is never lost to the string rendering.\n */\n readonly serialize?: (msg: M) => string;\n}\n\n/**\n * Project a {@link Trace}'s recorded msgs into Sentry-shaped breadcrumbs — a\n * human-readable timeline of \"what happened before the crash\". Pure — no\n * Sentry import, no I/O. Each returned object matches Sentry's `Breadcrumb`\n * shape, so the consumer can loop and call `addBreadcrumb(...)`.\n *\n * One breadcrumb per recorded msg, in dispatch order (NEWEST LAST — Sentry\n * renders breadcrumbs oldest-first and the crash is the most recent event).\n * Each breadcrumb:\n * - `category` — `\"tea\"` (groups them in the Sentry breadcrumb panel).\n * - `type` — `\"default\"` (the generic Sentry breadcrumb type).\n * - `level` — `\"info\"` (msgs are normal flow; the crash is the event).\n * - `message` — `msg.type`, or `serialize(msg)` when provided.\n * - `data.msg` — the full msg object (structured detail kept verbatim).\n *\n * Capped at `opts.limit` (default 100). When the trace has more msgs than the\n * cap, the OLDEST are dropped and the newest `limit` are kept — the recent\n * lead-up to the crash is the useful context.\n *\n * Consumer wiring (no Sentry import here — the consumer owns the boundary):\n *\n * ```ts\n * import * as Sentry from \"@sentry/browser\"; // or \"@sentry/node\"\n * import { breadcrumbsFromTrace } from \"./internal/persistence/recorder\"; // internal module\n * for (const b of breadcrumbsFromTrace(rec.dump())) Sentry.addBreadcrumb(b);\n * ```\n *\n * @typeParam S - the machine's State type.\n * @typeParam M - the machine's Msg union.\n */\nexport function breadcrumbsFromTrace<S, M extends { type: string }>(\n trace: Trace<S, M>,\n opts?: BreadcrumbsOptions<M>,\n): TraceBreadcrumb[] {\n const rawLimit = opts?.limit;\n // Clamp limit to a non-negative integer. `undefined`/NaN → 100 (Sentry's\n // default). A negative or zero limit yields an empty list (the caller asked\n // for no breadcrumbs); fractional values floor (you can't emit half a crumb).\n const limit =\n rawLimit === undefined || Number.isNaN(rawLimit)\n ? 100\n : Math.max(0, Math.floor(rawLimit));\n const serialize = opts?.serialize;\n\n // Keep the NEWEST `limit` msgs (the recent lead-up to the crash). Slicing\n // from `length - limit` (clamped to 0) preserves dispatch order within the\n // kept window. Note we do NOT use `slice(-limit)`: `slice(-0)` is `slice(0)`\n // (JS treats -0 as 0), which would return the WHOLE array for `limit: 0`.\n const start = Math.max(0, trace.msgs.length - limit);\n const kept = start === 0 ? trace.msgs : trace.msgs.slice(start);\n\n const crumbs: TraceBreadcrumb[] = [];\n for (const msg of kept) {\n crumbs.push({\n category: \"tea\",\n type: \"default\",\n level: \"info\",\n message: serialize ? serialize(msg) : msg.type,\n // Full msg kept verbatim so the structured payload survives even when\n // `message` is a terse one-liner. Cast: a Msg is a `{ type: string }`\n // record, which is a `Record<string, unknown>` for Sentry's `data`.\n data: { msg: msg as unknown as Record<string, unknown> },\n });\n }\n return crumbs;\n}\n\n// ---------------------------------------------------------------------------\n// traceToJSONL — serialize a STANDALONE Trace to JSONL (the dump→file path).\n//\n// `Recorder.toJSONL()` serializes the recorder's live buffers. `traceAttachment`\n// works over a plain `Trace` value (a `dump()` snapshot or a `parseJSONL`\n// result), which has no recorder behind it — so it needs a Trace→JSONL\n// function. This is the same wire format `Recorder.toJSONL` emits and\n// `parseJSONL` reads, so `parseJSONL(traceToJSONL(trace))` round-trips.\n//\n// When `trace.steps` is present (captureSteps was on, or the trace came from\n// parseJSONL), every step line carries its post-state. When absent, interior\n// step states are unknown — emitted as `null`, with `finalState` on the LAST\n// step line (identical to the captureSteps:false path in `Recorder.toJSONL`).\n// ---------------------------------------------------------------------------\nfunction traceToJSONL<S, M>(trace: Trace<S, M>): string {\n const lines: string[] = [];\n lines.push(JSON.stringify({ kind: \"boot\", state: trace.loaded }));\n\n const steps = trace.steps;\n for (let i = 0; i < trace.msgs.length; i++) {\n const msg = trace.msgs[i];\n const stepState = steps\n ? steps[i]?.state\n : i === trace.msgs.length - 1\n ? trace.finalState\n : null;\n lines.push(JSON.stringify({ kind: \"step\", msg, state: stepState }));\n }\n return lines.join(\"\\n\");\n}\n","// ---------------------------------------------------------------------------\n// trace-replay — replay a recorded Trace against a machine and diff the state.\n//\n// This is the back half of the record/replay feature. `../recorder` captures\n// a run (`loaded` + `msgs` + `finalState`); this module feeds that input\n// through the core `replay(machine, { msgs, ctx, loaded })` fold and asks:\n//\n// does the current reducer still produce the SAME final state for this\n// recorded input?\n//\n// Equal ⇒ the reducer is behavior-compatible with the recording. Diverged ⇒\n// the reducer changed for that input, and the divergence path\n// (`state.queue[2].status`) points at exactly the cell that drifted. This is\n// the regression / production-repro tool: record a prod incident, replay it\n// against the fixed reducer locally, confirm the fix changes the state at the\n// path you expected — or catch an unintended drift before it ships.\n//\n// Standalone by design. It imports ONLY the `Trace` type from `../recorder`\n// and the `replay` engine from `../index`. The deep-equal + first-divergence\n// path finder is self-contained (no external diff lib) — a richer pretty-diff\n// lands in `../devtools` later; trace-replay stays dependency-free so it can\n// run anywhere a machine runs (CI, a Worker, a Node script).\n// ---------------------------------------------------------------------------\n\nimport { type Cmd, type Machine, replay, type Sub } from \"../../../index\";\nimport type { Trace } from \"../recorder\";\nimport { indexPath, keyPath, typeOf, unionKeys } from \"./state-walk\";\n\n/**\n * The outcome of {@link replayTrace}.\n *\n * @typeParam S - the machine's State type.\n */\nexport interface ReplayResult<S> {\n /** `true` iff the recomputed final state deep-equals the trace's `finalState`. */\n matches: boolean;\n /** The trace's recorded `finalState` — what the run originally produced. */\n expected: S;\n /** The state the current reducer produced for the same input. */\n actual: S;\n /**\n * Present iff `matches` is `false`. The FIRST point of divergence found by\n * a deterministic pre-order walk:\n * - `path` — a dotted/indexed access path from the state root, e.g.\n * `state.queue[2].status` or `state` for a root-level\n * scalar mismatch.\n * - `expected` — the recorded value at that path.\n * - `actual` — the recomputed value at that path.\n */\n divergence?: { path: string; expected: unknown; actual: unknown };\n}\n\n/**\n * Replay a recorded {@link Trace} against `machine` and diff the recomputed\n * final state against the recorded one.\n *\n * Runs the core pure fold `replay(machine, { msgs: trace.msgs, ctx,\n * loaded: trace.loaded })` — init + update only, never `interpret`, never a\n * `Store`, never a live subscription (see `replay` in ../index). The `ctx` is\n * supplied fresh by the caller: the trace is the INPUT (loaded + msgs); ctx is\n * the ENVIRONMENT the reducer runs against now.\n *\n * @param machine - the machine to replay against. Mutating its reducer (the\n * whole point of a regression check) is what makes a recorded\n * trace diverge.\n * @param trace - a Trace from `../recorder` (live `dump()` or a re-hydrated\n * `parseJSONL(...)`).\n * @param ctx - the runtime ctx, supplied fresh at replay time.\n */\nexport function replayTrace<\n S,\n M extends { type: string },\n C extends Cmd,\n U extends Sub,\n Ctx,\n>(\n machine: Machine<S, M, C, U, Ctx>,\n trace: Trace<S, M>,\n ctx: Ctx,\n): ReplayResult<S> {\n const result = replay(machine, {\n msgs: trace.msgs,\n ctx,\n loaded: trace.loaded,\n });\n const actual = result.state;\n const expected = trace.finalState;\n\n const divergence = firstDivergence(expected, actual, \"state\");\n if (divergence === null) {\n return { matches: true, expected, actual };\n }\n return { matches: false, expected, actual, divergence };\n}\n\n/**\n * Order-insensitive structural deep-equality — the comparator the\n * record/replay lane owns, exposed so consumers (e.g. `@demlik/tea/parity`'s\n * `parityEqual`) reuse it rather than adding a third deep-compare. It is one\n * of two structural walkers in the package, divergent on purpose:\n * this `deepEqual` returns a boolean verdict (order-insensitive, for\n * replay/parity equality), and `devtools`'s `diffState` returns a change list\n * (for a human-readable diff view) — same shape, two jobs, not one to collapse.\n * `true` iff `a` and `b` are structurally equal under {@link firstDivergence}'s\n * walk (object keys compared order-insensitively, arrays index-by-index).\n */\nexport function deepEqual(a: unknown, b: unknown): boolean {\n return firstDivergence(a, b, \"state\") === null;\n}\n\n// === deep-equal + first-divergence path finder ===\n//\n// One walk does both jobs: it returns the FIRST point where `expected` and\n// `actual` differ (as a path + the two values), or `null` when they are\n// deeply equal. \"First\" is defined by a deterministic pre-order traversal:\n// the node itself, then its children in a stable key order (array index\n// order; object keys sorted so the result does not depend on insertion\n// order — two states with the same data but different key order are equal,\n// and the reported path for a real mismatch is reproducible run-to-run).\n//\n// The path grammar (`typeOf`, `indexPath`/`keyPath` segments, `unionKeys`\n// order) is shared with devtools' `diffState` via `./state-walk`, so the two\n// walkers print the SAME path for the same cell by construction. Only the leaf\n// policy differs, on purpose: first-hit here, collect-all there.\n//\n// Scope: TEA state is plain JSON-shaped data (the substrate's __DEV__ guards\n// reject closures in Cmds, and states are conventionally serializable). So\n// the walk handles: primitives, null/undefined, arrays, and plain objects.\n// It treats other object kinds (Date, Map, Set, class instances) by reference\n// identity + a structural fallback via Object.entries — sufficient for the\n// JSON-shaped states this tool targets; a richer differ lives in ../devtools.\n\n/** A divergence record, or `null` when the two values are deeply equal. */\ntype Divergence = { path: string; expected: unknown; actual: unknown } | null;\n\nfunction firstDivergence(\n expected: unknown,\n actual: unknown,\n path: string,\n): Divergence {\n // Identity / primitive fast path. Handles same-reference, and equal\n // primitives. `Object.is` so NaN === NaN and +0 ≠ -0 (matches structural\n // equality intent better than ===).\n if (Object.is(expected, actual)) return null;\n\n const te = typeOf(expected);\n const ta = typeOf(actual);\n // Different kinds at this node (e.g. object vs array, number vs string,\n // present vs null) — this node IS the divergence.\n if (te !== ta) return { path, expected, actual };\n\n if (te === \"array\") {\n const ae = expected as unknown[];\n const aa = actual as unknown[];\n if (ae.length !== aa.length) {\n // Length mismatch reported at the array node itself — the shape differs,\n // which is more informative than an arbitrary element index.\n return { path, expected, actual };\n }\n for (let i = 0; i < ae.length; i++) {\n const d = firstDivergence(ae[i], aa[i], indexPath(path, i));\n if (d !== null) return d;\n }\n return null;\n }\n\n if (te === \"object\") {\n const oe = expected as Record<string, unknown>;\n const oa = actual as Record<string, unknown>;\n // Sorted union of keys for deterministic traversal. A key present in one\n // but absent in the other diverges at that child path (its value is\n // `undefined` on the missing side).\n for (const key of unionKeys(oe, oa)) {\n const d = firstDivergence(oe[key], oa[key], keyPath(path, key));\n if (d !== null) return d;\n }\n return null;\n }\n\n // Primitives (string/number/boolean/bigint/symbol/function) that failed the\n // Object.is fast path, or null/undefined that differ — this node diverges.\n return { path, expected, actual };\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/engine/builtins.ts","../src/internal/engine/loop.ts"],"names":[],"mappings":"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","file":"chunk-VM7PMFV5.js","sourcesContent":["/**\n * tea's built-ins, each one an {@link Extension} of the core loop (`./loop`,\n * #280). None is a public plugin API (#268): each engine's `run` builds them\n * from its options through {@link builtinExtensions}, which fixes their order.\n */\n\nimport type { AnyCmdDef, Identity, Port } from \"../../pure/core\";\nimport {\n checkedStep,\n cmdContractOver,\n cmdEdge,\n lookupCell,\n NoCellError,\n Outcome,\n structuralHash,\n} from \"../../pure/core\";\nimport type {\n Store,\n Supervision,\n TelemetryEvent,\n TelemetrySink,\n} from \"../../runtime-types\";\nimport { IdentityDropNotice, isFencedStore } from \"../../runtime-types\";\nimport type { Extension, ExtensionFactory, LoopServices } from \"./loop\";\n\ntype AnyExtension<S, M, C> = ExtensionFactory<S, M, C>;\n\n// === update middleware ===\n\n/**\n * Supervision: a throw from the fold (the reducer, or any update middleware\n * inside this one) is reported under `\"reduce\"` for every strategy, then\n * `restart` commits the host's rehydrated State with no Cmds, `escalate`\n * rethrows with the runtime still live, and `stop` (the default) halts the gate\n * and rethrows, so THIS dispatch rejects too.\n *\n * A Msg the current State has no cell for is not a reducer throw — no machine\n * code ran, the caller dispatched something this State does not accept (#310).\n * Its `NoCellError` rejects only that dispatch and keeps the run alive under\n * every strategy: it is not reported under `\"reduce\"`, `restart` does not\n * rehydrate, and `stop` does not halt. The refusal stays loud; it just is not\n * the program's failure.\n */\nexport function supervision<S, M extends { type: string }, C>(\n declared: Supervision<S, M> | undefined,\n machine: CellTable,\n): AnyExtension<S, M, C> {\n const policy =\n declared === undefined\n ? ({ strategy: \"stop\" } as const)\n : typeof declared === \"string\"\n ? ({ strategy: declared } as const)\n : declared;\n return (loop) => ({\n update: (next) => (state, msg) => {\n try {\n return next(state, msg);\n } catch (reduceError) {\n if (isRefusal(machine, reduceError, state, msg)) throw reduceError;\n loop.report(reduceError, \"reduce\");\n switch (policy.strategy) {\n case \"restart\":\n // A throw inside `rehydrate` is NOT caught — it reaches the caller.\n return [policy.rehydrate(state, msg, reduceError), []];\n case \"escalate\":\n throw reduceError;\n default:\n loop.halt();\n throw reduceError;\n }\n }\n },\n });\n}\n\n/** The part of a machine that says which cell a `(state, msg)` pair selects. */\ntype CellTable = Parameters<typeof lookupCell>[0];\n\n/**\n * A `NoCellError` is a refusal only when the machine really has no cell for\n * this `(state, msg)`: then nothing ran, and the error is the lookup's own. A\n * `NoCellError` raised INSIDE a cell that does exist (a reducer stepping a\n * child machine by hand) is that reducer failing, and stays supervised.\n */\nfunction isRefusal<S, M extends { type: string }>(\n machine: CellTable,\n error: unknown,\n state: S,\n msg: M,\n): boolean {\n return (\n error instanceof NoCellError &&\n lookupCell(machine, state, msg).cell === undefined\n );\n}\n\n/**\n * The instance-identity filter: drop a Msg addressed to a DIFFERENT instance\n * than the one this State owns, before the reducer sees it. A Msg with no\n * identity, or a State that has none yet, always proceeds. The drop is no\n * transition, and it RESOLVES the dispatch — a mis-addressed Msg is not the\n * caller's error — so it is reported as an `IdentityDropNotice` (warn by\n * default) or the caller could not tell \"applied\" from \"discarded\".\n *\n * Sits INSIDE {@link supervision}, so a throwing `ofMsg` / `ofState` is reported\n * and supervised exactly like a reducer throw (spike #264 run 3).\n */\nexport function identityFilter<S, M extends { type: string }, C>(\n identity: Identity<S, M> | undefined,\n): AnyExtension<S, M, C> {\n return (loop) => {\n if (identity === undefined) return {};\n const misaddressed = (msg: M, state: S): boolean => {\n const addressed = identity.ofMsg(msg);\n if (addressed === undefined) return false;\n const own = identity.ofState(state);\n if (own === undefined) return false;\n return structuralHash(addressed) !== structuralHash(own);\n };\n return {\n update: (next) => (state, msg) => {\n if (!misaddressed(msg, state)) return next(state, msg);\n loop.report(new IdentityDropNotice(msg.type), \"identity-drop\");\n return null;\n },\n };\n };\n}\n\n/**\n * The dev pre/post pair around the reducer (`checkedStep`): freeze the input\n * State so an in-place mutation trips, and check the returned `[state, cmds]`\n * shape. Both compile out of production. Innermost, so it sees exactly what the\n * reducer saw.\n */\nexport function devChecks<S, M extends { type: string }, C>(): AnyExtension<\n S,\n M,\n C\n> {\n return () => ({\n update: (next) => (state, msg) => checkedStep(state, msg, next),\n });\n}\n\n// === interpret middleware ===\n\n/**\n * The `Cmd.define` edge (ADR 0021): a defined Cmd's handler return is minted\n * into its `_ok` / `_err` Msg, its `ok` value parsed against the def's schema\n * and stamped with `at` from `clock`. A defined Cmd's handler failing outside\n * its declared channel goes to the sink under `\"interpret\"`; a hand-written\n * Cmd's handler throw keeps rejecting the dispatch.\n *\n * A defined Cmd's handler that DISPATCHES its own `_ok` / `_err`, built by hand\n * rather than minted by this edge, breaks the same contract as one that\n * returns it: the Msg is dropped and the `OutcomeContractError` goes to the\n * sink under `\"interpret\"`. Its other Msgs are delivered as before.\n *\n * The same edge rides on ctx under `cmdEdge`, beside the `ok` / `err` builders,\n * so a handler that runs a base handler inside its own settles the base's\n * outcome through this one edge (#66).\n */\nexport function cmdDefinitions<S, M extends { type: string }, C>(\n defs: readonly AnyCmdDef[],\n clock: () => number,\n): AnyExtension<S, M, C> {\n return (loop) => {\n const { settle, checkDispatch: check } = cmdContractOver(defs, clock);\n const defined = new Set(defs.map((d) => d.cmdType));\n return {\n interpret: (next) => async (cmd, dispatch) => {\n const type = (cmd as { type: string }).type;\n const checked = defined.has(type)\n ? (msg: M) => {\n try {\n check(cmd as { type: string }, msg);\n } catch (err) {\n loop.report(err, \"interpret\");\n return;\n }\n dispatch(msg);\n }\n : dispatch;\n try {\n return settle(cmd as { type: string }, await next(cmd, checked));\n } catch (err) {\n if (!defined.has(type)) throw err;\n loop.report(err, \"interpret\");\n return undefined;\n }\n },\n ctx: { ok: Outcome.ok, err: Outcome.err, [cmdEdge]: settle },\n };\n };\n}\n\n// === store wrapper ===\n\n/**\n * Fencing is a property of the store the caller handed `run`, never a flag\n * (#143). A fenced store is read with its version at boot and every save is a\n * compare-and-swap against the last version this run saw, so a second writer\n * that took over is refused with `StoreConflictError` at this run's next save —\n * before that transition's Cmds run. A plain store passes through unchanged.\n */\nexport function fencing<S, M, C>(): AnyExtension<S, M, C> {\n return () => ({\n store: (store: Store<S>): Store<S> => {\n if (!isFencedStore(store)) return store;\n let version = 0;\n return {\n async load() {\n const read = await store.loadFenced();\n version = read.version;\n return read.raw;\n },\n async save(state) {\n version = await store.saveFenced(state, version);\n },\n migrate: (raw) => store.migrate(raw),\n };\n },\n });\n}\n\n// === ctx + handle: ports ===\n\n/**\n * Ports (`definePort`): `ctx.emit(port, value)` from a handler and\n * `emitPort` / `subscribePort` on the handle. Fanout is synchronous and\n * throw-isolated under `\"port-emit\"`; no subscribers is a no-op.\n */\nexport function ports<S, M, C>(): AnyExtension<S, M, C> {\n return (loop) => {\n const registry = new Map<Port<unknown>, Set<(value: unknown) => void>>();\n function emit<T>(port: Port<T>, value: T): void {\n const subscribers = registry.get(port as Port<unknown>);\n if (!subscribers || subscribers.size === 0) return;\n loop.fanout(subscribers, \"port-emit\", (listener) => listener(value));\n }\n return {\n ctx: { emit },\n handle: {\n subscribePort<T>(\n port: Port<T>,\n listener: (value: T) => void,\n ): () => void {\n const key = port as Port<unknown>;\n const bucket = registry.get(key) ?? new Set();\n registry.set(key, bucket);\n const erased = listener as (value: unknown) => void;\n bucket.add(erased);\n return () => {\n bucket.delete(erased);\n if (bucket.size === 0 && registry.get(key) === bucket)\n registry.delete(key);\n };\n },\n emitPort: emit,\n },\n };\n };\n}\n\n// === commit observers ===\n\n/**\n * `subscribe` (zero-arg change notifiers), then `observe` (every applied\n * transition's `(msg, state)`) or, at boot, `onBoot` (the initial State, once;\n * a handler registered after boot fires at once). Each fanout is\n * throw-isolated under its own phase.\n */\nexport function observation<S, M, C>(): AnyExtension<S, M, C> {\n return (loop) => {\n const listeners = new Set<() => void>();\n const observers = new Set<(msg: M, state: S) => void>();\n const bootHandlers = new Set<(state: S) => void>();\n let booted = false;\n return {\n commit(msg, state) {\n loop.fanout(listeners, \"listener\", (listener) => listener());\n if (msg === undefined) {\n booted = true;\n loop.fanout(bootHandlers, \"boot\", (handler) => handler(state));\n return;\n }\n loop.fanout(observers, \"observer\", (observer) => observer(msg, state));\n },\n handle: {\n subscribe: subscribeTo(listeners),\n observe: subscribeTo(observers),\n onBoot(handler: (state: S) => void): () => void {\n const state = loop.state();\n if (booted && state !== undefined) {\n loop.fanout([handler], \"boot\", (h) => h(state));\n return () => {};\n }\n return subscribeTo(bootHandlers)(handler);\n },\n },\n };\n };\n}\n\nfunction subscribeTo<T>(set: Set<T>): (item: T) => () => void {\n return (item) => {\n set.add(item);\n return () => {\n set.delete(item);\n };\n };\n}\n\n/**\n * The semantic event channel: `project` maps each APPLIED transition to zero or\n * more public events, and `on(type, handler)` receives only its own type. The\n * machine's private Msg names never reach `on`. A throw in the projector or a\n * handler is isolated under `\"event\"`. Boot projects nothing.\n */\nexport function semanticEvents<S, M, C, E extends { type: string }>(\n project: ((msg: M, state: S) => readonly E[]) | undefined,\n): AnyExtension<S, M, C> {\n return (loop) => {\n const handlers = new Map<string, Set<(event: E) => void>>();\n return {\n commit(msg, state) {\n if (msg === undefined || project === undefined || handlers.size === 0)\n return;\n let events: readonly E[];\n try {\n events = project(msg, state);\n } catch (err) {\n loop.report(err, \"event\");\n return;\n }\n for (const event of events) {\n const bucket = handlers.get(event.type);\n if (bucket === undefined) continue;\n loop.fanout(bucket, \"event\", (handler) => handler(event));\n }\n },\n handle: {\n on(type: string, handler: (event: E) => void): () => void {\n const bucket = handlers.get(type) ?? new Set();\n handlers.set(type, bucket);\n bucket.add(handler);\n return () => {\n bucket.delete(handler);\n if (bucket.size === 0 && handlers.get(type) === bucket)\n handlers.delete(type);\n };\n },\n },\n };\n };\n}\n\n/**\n * Run terminality: `result()` reads the State when `isTerminal` holds for it,\n * and `done()` resolves on the first commit (boot included — a rehydrated run\n * can land terminal) where it does. No predicate → never terminal.\n */\nexport function terminality<S, M, C>(\n isTerminal: ((state: S) => boolean) | undefined,\n): AnyExtension<S, M, C> {\n const holds = isTerminal ?? (() => false);\n return (loop) => {\n const waiters = new Set<(state: S) => void>();\n return {\n commit(_msg, state) {\n if (waiters.size === 0 || !holds(state)) return;\n const parked = [...waiters];\n waiters.clear();\n for (const resolve of parked) resolve(state);\n },\n handle: {\n result(): S | undefined {\n const current = loop.state() as S;\n return holds(current) ? current : undefined;\n },\n done(): Promise<S> {\n const current = loop.state() as S;\n if (holds(current)) return Promise.resolve(current);\n return new Promise<S>((resolve) => {\n waiters.add(resolve);\n });\n },\n },\n };\n };\n}\n\n/**\n * Telemetry (#268: `withTelemetry` moved inside tea). Every applied transition\n * hands the sink `{ seq, msgType, at }` — `seq` counts this run's applied\n * transitions from 1, `at` reads `clock`. Fire-and-forget: the loop never waits\n * on the sink, and a sink that throws or rejects reaches `onError` under\n * `\"observer\"` without touching the run.\n */\nexport function telemetry<S, M extends { type: string }, C>(\n sink: TelemetrySink | undefined,\n clock: () => number,\n): AnyExtension<S, M, C> {\n return (loop: LoopServices<S>): Extension<S, M, C> => {\n if (sink === undefined) return {};\n let seq = 0;\n return {\n commit(msg) {\n if (msg === undefined) return;\n seq += 1;\n const event: TelemetryEvent = { seq, msgType: msg.type, at: clock() };\n try {\n Promise.resolve(sink(event)).catch((err: unknown) =>\n loop.report(err, \"observer\"),\n );\n } catch (err) {\n loop.report(err, \"observer\");\n }\n },\n };\n };\n}\n\n// === assembly: the one order both engines run the built-ins in ===\n\n/** The `run` options the built-ins read. Every engine's `run` accepts them. */\nexport interface BuiltinOptions<\n S,\n M extends { type: string },\n E extends { type: string },\n> {\n readonly clock?: () => number;\n readonly events?: (msg: M, state: S) => readonly E[];\n readonly supervision?: Supervision<S, M>;\n readonly terminal?: (state: S) => boolean;\n readonly telemetry?: TelemetrySink;\n}\n\n/**\n * The built-ins, in the one order that gives them their meaning. Every engine\n * builds its loop from this list, so a machine means the same thing on each.\n *\n * Update middleware nests first-outermost: supervision wraps the identity\n * filter (a throwing `ofMsg` is supervised like a reducer throw — spike #264\n * run 3), which wraps the dev checks around the reducer itself. A Msg with no\n * cell rejects through supervision unsupervised (#310). Commit\n * callbacks run in order: change listeners, then `observe` / `onBoot`, then\n * semantic events, then `done()` waiters, then telemetry.\n */\nexport function builtinExtensions<\n S,\n M extends { type: string },\n C,\n E extends { type: string },\n>(\n machine: CellTable & {\n readonly identity?: Identity<S, M>;\n readonly cmds?: readonly AnyCmdDef[];\n },\n opts: BuiltinOptions<S, M, E>,\n): readonly ExtensionFactory<S, M, C>[] {\n const clock = opts.clock ?? Date.now;\n return [\n supervision(opts.supervision, machine),\n identityFilter(machine.identity),\n devChecks(),\n cmdDefinitions(machine.cmds ?? [], clock),\n fencing(),\n ports(),\n observation(),\n semanticEvents(opts.events),\n terminality(opts.terminal),\n telemetry(opts.telemetry, clock),\n ];\n}\n","/**\n * The core loop both engines run (#280, spike #264). It does five things and\n * nothing else: it keeps one serial tail, folds a Msg into a transition, saves\n * before any effect, reconciles the running Subs, and runs the transition's\n * Cmds, dispatching what they return. It has no special case for any built-in.\n *\n * One loop, not one per engine (#283). The loop calls a handler and a runner\n * through erased signatures and awaits a Promise either way, so an engine's\n * own types never pass through it. The Effect engine turns each handler and\n * runner into a fiber at its own edge, run with the services the caller\n * provided, so Effect services (`R`) reach every handler without the loop\n * carrying a type slot for them — the gap spike #260's generic loop left open.\n * Sharing the loop is also what makes the two engines' traces identical: the\n * fold, the save order and the built-ins are the same code.\n *\n * Everything else `run` offers is an {@link Extension} built on five points:\n *\n * 1. `update` — middleware over the fold. Returning `null` means \"no\n * transition\": no save, no effects, no commit.\n * 2. `interpret` — middleware over one Cmd's handler call; it maps what the\n * handler returned to the Msgs to dispatch, if any.\n * 3. `store` — a wrapper over the store the caller handed `run`.\n * 4. `commit` — called after a transition's effects, with the Msg and the\n * committed State, even when a Cmd handler threw. Boot\n * passes `undefined` for the Msg.\n * 5. `ctx` — keys added to the ctx every Cmd handler receives, so a\n * handler that runs another handler inside its own can reach\n * the same machinery the loop applies to it.\n *\n * An extension may also add methods to the run handle (`handle`). Array order\n * is nesting order: the first extension's middleware is the outermost, and\n * commit callbacks run first to last. `builtinExtensions` (`./builtins`) fixes\n * that order for every engine; it is not a user-facing plugin API (#268).\n *\n * `stop()` is the core's own lifecycle, because the gate it drives is what every\n * dispatch passes through: open → draining → closed, or → abandoned when\n * `stop()` gives up on the queue (ADR 0025), never backwards.\n */\n\nimport type { Dispose, Sub, SubEntry } from \"../../pure/core\";\nimport { desiredSub, detachWork, followUps } from \"../../pure/core\";\nimport type {\n DispatchSettle,\n OnError,\n RuntimeErrorContext,\n RuntimeErrorPhase,\n Store,\n} from \"../../runtime-types\";\nimport {\n DispatchDiscardedError,\n DisposeTimeoutNotice,\n DrainTimeoutNotice,\n QuiescenceTimeoutError,\n RuntimeDiscardedError,\n RuntimeDiscardNotice,\n} from \"../../runtime-types\";\nimport { restore } from \"./restore\";\n\n// === The extension points ===\n\n/** A fold's result: the next State and the Cmds it emits. */\nexport type Transition<S, C> = readonly [S, readonly C[]];\n\n/** One fold step. `null` means the Msg produced no transition. */\nexport type Step<S, M, C> = (state: S, msg: M) => Transition<S, C> | null;\n\n/**\n * One Cmd's handler call; resolves to the Msg to dispatch, a list of them in\n * order, or nothing. `dispatch` is what the handler is handed for Msgs it fires\n * itself, so an extension can check them on the way out.\n */\nexport type InterpretStep<C, M> = (\n cmd: C,\n dispatch: (msg: M) => void,\n) => Promise<unknown>;\n\n/** What the loop lends an extension. */\nexport interface LoopServices<S> {\n /** Route a failure with no caller to the `onError` sink. */\n report(error: unknown, phase: RuntimeErrorPhase): void;\n /** Call `fn` for each item, routing every throw to the sink under `phase`. */\n fanout<T>(\n items: Iterable<T>,\n phase: RuntimeErrorPhase,\n fn: (item: T) => void,\n ): void;\n /** Close the gate for good: every later dispatch is refused. */\n halt(): void;\n /** The committed State, or `undefined` before boot has produced one. */\n state(): S | undefined;\n}\n\n/** One built-in, as the loop sees it. Every member is optional. */\nexport interface Extension<S, M, C> {\n readonly update?: (next: Step<S, M, C>) => Step<S, M, C>;\n readonly interpret?: (next: InterpretStep<C, M>) => InterpretStep<C, M>;\n readonly store?: (store: Store<S>) => Store<S>;\n readonly commit?: (msg: M | undefined, state: S) => void;\n readonly ctx?: object;\n readonly handle?: object;\n}\n\n/** An extension is built once per run, from the loop's services. */\nexport type ExtensionFactory<S, M, C> = (\n loop: LoopServices<S>,\n) => Extension<S, M, C>;\n\n/** A Cmd handler as the loop calls it. */\nexport type LoopHandler<M> = (\n cmd: never,\n ctx: unknown,\n dispatch: (msg: M) => void,\n) => unknown;\n\n/**\n * A Sub runner as the loop calls it. `fail` is how an engine edge reports that\n * a Sub's source died with an error the Sub did not turn into a Msg; the loop\n * then drops the Sub and stops the run. A user runner is never handed it.\n */\nexport type LoopRunner<Ctx, M> = (\n sub: Sub,\n ctx: Ctx,\n dispatch: (msg: M) => void,\n fail: (error: unknown) => void,\n) => Dispose;\n\n/** Everything the loop needs from `run`. */\nexport interface LoopConfig<S, M extends { type: string }, C, Ctx> {\n readonly init: (loaded: S | null, ctx: Ctx) => Transition<S, C>;\n /** The innermost fold: the machine's own `update`. */\n readonly reduce: (state: S, msg: M) => Transition<S, C>;\n readonly subs: readonly SubEntry<S>[];\n readonly runnerFor: (type: string) => LoopRunner<Ctx, M> | undefined;\n readonly handlerFor: (type: string) => LoopHandler<M> | undefined;\n readonly store: Store<S> | undefined;\n readonly ctx: Ctx;\n readonly onError: OnError | undefined;\n readonly disposeTimeoutMs: number;\n readonly idleCap: number;\n readonly extensions: readonly ExtensionFactory<S, M, C>[];\n /**\n * How the engine stops the run once a Sub failed with an error it did not\n * handle (#309). The loop has already dropped the Sub, reported the error\n * under `\"sub\"` and closed the gate to new work; this does the rest —\n * `stop()` on the Promise engine, closing the run's Scope with the failure on\n * the Effect engine. Called at most once, possibly before `startLoop` has\n * returned.\n */\n readonly stopOnSubFailure: (error: unknown) => void;\n}\n\n// === liveWork: \"can anything still transition me without a dispatch?\" ===\n//\n// The one read `driveToDone` needs that the public `Runtime` does not carry:\n// after `start`'s chain quiesces, only a live Sub or an in-flight Cmd can still\n// enqueue a transition; with neither, waiting is a leak (#68). Module-private\n// and symbol-keyed so it reaches no export (the export map is the contract —\n// MAINTAINING.md), yet enumerable so it survives the spread a wrapper does over\n// the handle.\nexport const liveWork: unique symbol = Symbol(\"demlik-tea.liveWork\");\n\n/** The runtime's own sources of a caller-less transition, counted. */\nexport interface LiveWork {\n /** Live Subs — the running `machine.subs` entries. */\n readonly subs: number;\n /** Interpret handlers currently awaiting. */\n readonly cmds: number;\n}\n\nexport interface LiveWorkProbe {\n readonly [liveWork]: () => LiveWork;\n}\n\n/** The members the core itself puts on the run handle. */\nexport interface LoopHandle<S, M> extends LiveWorkProbe {\n dispatch(msg: M, opts?: { readonly settle?: DispatchSettle }): Promise<void>;\n dispatchOnce(msg: M): Promise<void>;\n getState(): S;\n ready: Promise<unknown>;\n idle(): Promise<void>;\n stop(): Promise<void>;\n}\n\n// Default `onError` sink: re-throw on a fresh macrotask so the failure reaches\n// the host's global error handler instead of vanishing — surface, not swallow\n// (invariant 6).\n//\n// A `RuntimeDiscardNotice` is NOT a failure of the runtime's own contract — a\n// host tearing a runtime down with Cmds in flight (a React ctx change, a\n// navigation) is legal, merely lossy. Rethrowing it would make every\n// unmount-during-fetch an uncaught error for consumers who never configured a\n// sink, so the default WARNS: loud enough that the silent discard #365\n// describes cannot happen again, never fatal. A configured `onError` sees\n// `\"discard\"` like any other phase and can route or ignore it.\n//\n// The branch keys on the ERROR CLASS, never on `context.phase`: `report`\n// hands a THROWING consumer sink's own error back here with the phase it was\n// handling, so a phase-keyed branch would warn away a broken sink and re-create\n// the very silent failure this exists to remove.\nexport function defaultOnError(\n error: unknown,\n _context: RuntimeErrorContext,\n): void {\n if (error instanceof RuntimeDiscardNotice) {\n console.warn(error);\n return;\n }\n setTimeout(() => {\n throw error;\n }, 0);\n}\n\n/**\n * The rejection of a dispatch into a run whose gate is closed: `stop()` has\n * returned, or a built-in halted it. Internal, so the Promise engine's\n * rejection reads as before, an `Error` with this message; the Effect engine\n * reads the class to fail the dispatch with `Stopped`.\n */\nexport class RuntimeStoppedError extends Error {\n constructor(readonly msgType: string) {\n super(\"@demlik/tea: runtime stopped\");\n }\n}\n\n/** One started Sub: its type, the cleanup its runner returned, and whether it failed. */\nclass RunningSub {\n dispose: Dispose = () => {};\n failed = false;\n constructor(readonly type: string) {}\n}\n\n/**\n * Start the loop. Returns the handle synchronously; boot runs as the FIRST entry\n * on the serial tail. Save-then-effects ordering is structural: every\n * transition installs State, awaits the save, reconciles Subs, runs the Cmds,\n * then calls the commit callbacks — even when a Cmd handler throws.\n */\nexport function startLoop<S, M extends { type: string }, C, Ctx>(\n config: LoopConfig<S, M, C, Ctx>,\n): LoopHandle<S, M> {\n const { idleCap, disposeTimeoutMs } = config;\n const onError: OnError = config.onError ?? defaultOnError;\n\n // A throwing sink routes THAT throw through `defaultOnError`, with the context\n // the sink was handling, so it cannot re-create a silent failure.\n function report(error: unknown, phase: RuntimeErrorPhase): void {\n const context: RuntimeErrorContext = { phase };\n try {\n onError(error, context);\n } catch (sinkError) {\n defaultOnError(sinkError, context);\n }\n }\n\n // Throw-isolated fanout: one bad consumer never strands its siblings\n // (invariant 6). The single home for that isolation discipline.\n function fanout<T>(\n items: Iterable<T>,\n phase: RuntimeErrorPhase,\n fn: (item: T) => void,\n ): void {\n for (const item of items) {\n try {\n fn(item);\n } catch (err) {\n report(err, phase);\n }\n }\n }\n\n // `state` is late-initialized: synchronously when there is no store to read,\n // otherwise inside the boot step (the head of the tail).\n let state: S | undefined;\n let bootError: unknown = null;\n // The dispatch gate. It only ever ADVANCES — `\"open\"` → `\"draining\"` →\n // `\"closed\"` or `\"abandoned\"` — so the discard window can never re-open under\n // a second `stop()`.\n //\n // \"open\" — normal operation; `enqueueDispatch` accepts.\n // \"draining\" — inside `stop()`, before the tail has settled. New work is\n // still refused (refusing is what makes the drain terminate),\n // but a Msg refused HERE was discarded BY the teardown: an\n // in-flight Cmd's follow-up, a detached handler's last Msg, or\n // a Sub still live because subs are torn down after the drain.\n // So the rejection is a `DispatchDiscardedError` reported\n // under `phase: \"discard\"` — lossy, legal, warn-only.\n // \"closed\" — halted by an extension, or `stop()` has drained the tail. A\n // dispatch refused here is a consumer using a retired runtime\n // — a real error, and it stays loud.\n // \"abandoned\" — `stop()` gave up on the tail at `disposeTimeoutMs` (ADR\n // 0025). Closed to a caller exactly as `\"closed\"` is, and the\n // work still on the tail is dropped as it surfaces: a stuck\n // handler's late result, the next Cmd of its step, the Msgs\n // queued behind it. Each is a teardown discard, never a save.\n // A boot whose load returns only now saves nothing either\n // (`commit`): no store call starts once `stop()` gave up.\n let gate: \"open\" | \"draining\" | \"closed\" | \"abandoned\" = \"open\";\n // The work currently awaiting: one entry per interpret handler call, named by\n // its Cmd type, and one unnamed entry per piece of detached work. Written only\n // by `trackInFlight`, read by `stop()` to make a mid-flight teardown LOUD\n // instead of silent (#365) and to name what it gave up on.\n const inFlight = new Set<{ readonly cmdType: string | undefined }>();\n\n const services: LoopServices<S> = {\n report,\n fanout,\n halt() {\n if (gate !== \"abandoned\") gate = \"closed\";\n },\n state: () => state,\n };\n const extensions = config.extensions.map((make) => make(services));\n\n // The fold, the handler call and the store, each wrapped by the extensions\n // that ask for it. `reduceRight` makes the first extension the outermost.\n const update: Step<S, M, C> = extensions.reduceRight<Step<S, M, C>>(\n (next, ext) => (ext.update ? ext.update(next) : next),\n config.reduce,\n );\n const interpret: InterpretStep<C, M> = extensions.reduceRight<\n InterpretStep<C, M>\n >((next, ext) => (ext.interpret ? ext.interpret(next) : next), callHandler);\n const store: Store<S> | undefined =\n config.store === undefined\n ? undefined\n : extensions.reduceRight<Store<S>>(\n (inner, ext) => (ext.store ? ext.store(inner) : inner),\n config.store,\n );\n const commitCallbacks = extensions.flatMap((ext) =>\n ext.commit ? [ext.commit] : [],\n );\n\n // Copied into a fresh object so handlers get the contributed keys without\n // mutating the caller's ctx (which may be shared across runtimes / tests).\n // `Object.assign`, not a spread: tsc cannot prove a generic `Ctx` is an\n // object type, and a spread refuses it.\n const handlerCtx: unknown = Object.assign(\n {},\n config.ctx,\n ...extensions.map((ext) => ext.ctx ?? {}),\n { [detachWork]: detachInFlight },\n );\n\n // Every step chains onto `tail` — the single concurrency gate.\n let tail: Promise<void> = Promise.resolve();\n\n // The running Subs, keyed by their derived id. An id present here is a runner\n // that started and has neither been disposed nor failed.\n const subRegistry = new Map<string, RunningSub>();\n\n // Tear down each named sub: run its cleanup (throws routed to the sink under\n // `\"sub-cleanup\"`), then drop it from the registry regardless.\n function stopSubs(ids: Iterable<string>): void {\n for (const id of ids) {\n const running = subRegistry.get(id);\n if (running === undefined) continue;\n try {\n trackDisposal(running.dispose());\n } catch (err) {\n report(err, \"sub-cleanup\");\n }\n subRegistry.delete(id);\n }\n }\n\n // Teardown work that returned a Promise and has not settled. Reconcile runs\n // inside the synchronous transition path (invariant 2) and cannot await a\n // cleanup, so every async disposal is remembered here the moment it starts,\n // and `stop()` drains the set before resolving: `await runtime.stop()` then\n // means \"teardown is done\", the only reading a host evicting an isolate can\n // act on. The rejection is attached HERE, once, so it can never become an\n // unhandled rejection.\n const pendingDisposals = new Set<Promise<void>>();\n\n function trackDisposal(result: void | Promise<void>): void {\n if (!(result instanceof Promise)) return;\n const settling: Promise<void> = result\n .catch((err) => {\n report(err, \"sub-cleanup\");\n })\n .finally(() => {\n pendingDisposals.delete(settling);\n });\n pendingDisposals.add(settling);\n }\n\n /**\n * Wait for `work`, for at most `disposeTimeoutMs`. The one bound both of\n * `stop()`'s waits share: `stop()` resolves regardless (contract), so neither\n * a handler nor a release that never settles may become a host that never\n * shuts down (ADR 0025).\n */\n async function withinLimit(\n work: Promise<unknown>,\n ): Promise<\"settled\" | \"timeout\"> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n work.then(() => \"settled\" as const),\n new Promise<\"timeout\">((resolve) => {\n timer = setTimeout(() => resolve(\"timeout\"), disposeTimeoutMs);\n }),\n ]);\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n }\n\n /**\n * Wait for the tail, up to the limit, and settle the gate on what happened.\n * On expiry report a `DrainTimeoutNotice` naming the handlers still awaiting\n * and leave the gate `\"abandoned\"`, which is what drops their late work.\n */\n async function drainTail(): Promise<void> {\n if ((await withinLimit(tail)) === \"settled\") {\n gate = \"closed\";\n return;\n }\n report(\n new DrainTimeoutNotice(\n [...inFlight].flatMap(({ cmdType }) => cmdType ?? []),\n inFlight.size,\n disposeTimeoutMs,\n ),\n \"discard\",\n );\n gate = \"abandoned\";\n }\n\n /**\n * Wait for the disposals started so far, up to the limit. On expiry report a\n * `DisposeTimeoutNotice` and return anyway.\n */\n async function drainDisposals(): Promise<void> {\n if (pendingDisposals.size === 0) return;\n const outstanding = [...pendingDisposals];\n if ((await withinLimit(Promise.all(outstanding))) === \"timeout\") {\n report(\n new DisposeTimeoutNotice(outstanding.length, disposeTimeoutMs),\n \"discard\",\n );\n }\n }\n\n /**\n * Reconcile the running Subs against `state`, after every save. An id already\n * running is left alone, a running id no longer wanted is stopped, and a\n * wanted id not yet running is started through its runner.\n *\n * Every failure is collected, never thrown mid-pass, so one bad entry cannot\n * strand its siblings: a throwing `deps` leaves the running Subs of that type\n * untouched, and a throwing runner is not registered. The first error is\n * thrown after the pass. A Sub type with no runner is a failure too — nothing\n * would ever start it.\n */\n function reconcileSubs(): void {\n let firstError: unknown = null;\n const remember = (err: unknown): void => {\n if (firstError === null) firstError = err;\n };\n const desired = new Map<string, Sub>();\n // Types whose entry could not be read this pass: keep what is running.\n const unreadTypes = new Set<string>();\n for (const entry of config.subs) {\n try {\n const sub = desiredSub(entry, state as S);\n if (sub !== null) desired.set(sub.id, sub);\n } catch (err) {\n remember(err);\n unreadTypes.add(entry.type);\n }\n }\n\n stopSubs(\n [...subRegistry].flatMap(([id, running]) =>\n desired.has(id) || unreadTypes.has(running.type) ? [] : [id],\n ),\n );\n\n // A run that is stopping starts nothing: stop() would only tear it down,\n // and a Sub that failed must not be re-armed by a step still queued.\n const starting = gate === \"open\" ? desired : new Map<string, Sub>();\n for (const [id, sub] of starting) {\n if (subRegistry.has(id)) continue;\n const runner = config.runnerFor(sub.type);\n if (runner === undefined) {\n remember(\n new Error(\n `@demlik/tea: no subscribe runner for Sub type \"${sub.type}\". ` +\n \"Pass one to run in `subscribe`.\",\n ),\n );\n continue;\n }\n const running = new RunningSub(sub.type);\n try {\n // A runner's dispatch is unawaited by construction, so it gets the\n // wrapped form, which also queues the transition behind this step —\n // never on the runner's own stack (spike #260).\n running.dispose = runner(sub, config.ctx, dispatchUnawaited, (error) =>\n subFailed(id, running, error),\n );\n } catch (err) {\n // A runner that throws while starting is a Sub failure too: the step\n // that started it rejects with the throw, and the run stops.\n remember(err);\n subFailed(id, running, err);\n continue;\n }\n if (!running.failed) {\n subRegistry.set(id, running);\n continue;\n }\n // The source died before its runner returned: never registered, but\n // its cleanup still runs.\n try {\n trackDisposal(running.dispose());\n } catch (err) {\n report(err, \"sub-cleanup\");\n }\n }\n if (firstError !== null) throw firstError;\n }\n\n /**\n * A Sub's source died with an error the Sub did not turn into a Msg (#309,\n * ruling R3.1 of #325). The Elm answer: a Sub maps the failures it expects to\n * Msgs itself, so one that reaches here is unhandled, and the run stops\n * rather than keep a dead Sub counted as live. The Sub leaves the registry,\n * the error reaches the sink under `\"sub\"`, the gate starts draining so no\n * new Msg is accepted, and the engine stops the run. A failure while the\n * run is already stopping is reported and nothing more.\n */\n function subFailed(id: string, running: RunningSub, error: unknown): void {\n if (running.failed) return;\n running.failed = true;\n if (subRegistry.get(id) === running) subRegistry.delete(id);\n report(error, \"sub\");\n if (gate !== \"open\") return;\n gate = \"draining\";\n config.stopOnSubFailure(error);\n }\n\n // The ONE `(msg) => void` handed to every producer that cannot await its own\n // dispatch: a Cmd handler's late tail, a Sub runner. Its rejection has no\n // caller, so it routes to the sink with the phase derived from the error\n // class (`reportUndelivered`). Handing those sites the raw `enqueueDispatch`\n // would turn a Sub firing during `stop()`'s drain into an unhandled rejection\n // the sink never sees.\n function dispatchUnawaited(msg: M): void {\n enqueueDispatch(msg, \"loop\").catch(reportUndelivered);\n }\n\n // A `DispatchDiscardedError` means the teardown refused the Msg (`\"discard\"`,\n // warn-only); anything else is a genuine failure of the follow-up itself.\n function reportUndelivered(error: unknown): void {\n report(\n error,\n error instanceof DispatchDiscardedError ? \"discard\" : \"follow-up\",\n );\n }\n\n /**\n * Count a handler's work as in flight for exactly the lifetime of its\n * promise. `finally`-balanced, so a rejecting handler can never strand the\n * count above zero. A handler that throws SYNCHRONOUSLY never reaches here,\n * which is correct — it was never in flight. `cmdType` names a handler call;\n * detached work has no Cmd of its own to name.\n */\n function trackInFlight<T>(\n work: T | Promise<T>,\n cmdType?: string,\n ): Promise<T> {\n const entry = { cmdType };\n inFlight.add(entry);\n return Promise.resolve(work).finally(() => {\n inFlight.delete(entry);\n });\n }\n\n /**\n * Enlist work a handler will NOT return — the `detachWork` key on ctx. A\n * handler that fans out inside its own Cmd (ADR 0018) returns before its\n * effect finishes; handing the promise here puts it back on both accountings\n * a returned promise had: `trackInFlight`, so `stop()` still reports it, and\n * the serial `tail`, so `idle()` drains it. The tail extension is\n * SYNCHRONOUS, so a `drainToQuiescence` that already read `tail` sees the\n * reference change and loops again.\n */\n function detachInFlight(work: Promise<unknown>): void {\n const tracked = trackInFlight(work);\n tracked.catch(reportUndelivered);\n tail = tail\n .then(async () => {\n await tracked;\n })\n .catch(() => {});\n }\n\n // The innermost interpret step: call the Cmd's handler, if one is wired. A\n // missing handler returns nothing, which is invariant 6's forward progress\n // for a miswired consumer.\n function callHandler(cmd: C, dispatch: (msg: M) => void): Promise<unknown> {\n const { type } = cmd as { type: string };\n const handler = config.handlerFor(type);\n if (handler === undefined) return Promise.resolve(undefined);\n return trackInFlight(handler(cmd as never, handlerCtx, dispatch), type);\n }\n\n /**\n * Run each emitted Cmd. A returned Msg is enqueued onto the tail, never\n * dispatched re-entrantly; a returned list enqueues each of its Msgs in\n * order, before the next Cmd's handler runs (#324). The first error stops\n * further handlers in this transition.\n *\n * THIS LOOP IS SERIAL BY RULING, NOT BY OVERSIGHT (ADR 0018). It runs a\n * transition's Cmds one at a time and never interleaves two handlers, so the\n * Msgs it enqueues fold in Cmd-EMISSION order and a replayed log reproduces\n * the same fold — invariant 2's serializability. Overlap in time belongs\n * INSIDE one Cmd's handler, never across the Cmds of one transition.\n *\n * Once `stop()` has given up on this step, no further handler starts; what\n * the stuck one returned is refused at the gate like any other late Msg.\n */\n async function runCmds(cmds: readonly C[]): Promise<void> {\n for (const cmd of cmds) {\n if (gate === \"abandoned\") return;\n const returned = await interpret(cmd, dispatchUnawaited);\n for (const follow of followUps<M>(returned)) dispatchUnawaited(follow);\n }\n }\n\n // Install State, then save → reconcile subs → run Cmds → commit callbacks.\n // Save-before-effects is the hard ordering; tests pin it. Boot and every\n // transition end here; boot passes no Msg.\n //\n // The commit callbacks run in a `finally`: a Cmd handler that throws still\n // rejects the dispatch with its own error, but the State it left installed\n // and saved still reaches every listener, observer, `on` handler, `done()`\n // waiter and the telemetry sink (#311).\n //\n // No store call starts once `stop()` has given up (ADR 0025). A step never\n // gets here abandoned, because the queued step in `enqueueDispatch` drops it\n // first; boot does, when `stop()` gave up while `store.load()` was pending and\n // the load returns afterwards. That boot installs the loaded State, so\n // `getState()` stays total, and saves nothing: the store may already belong\n // to a newer run. It starts no Sub and no handler either, as the gate rules.\n async function commit(\n next: S,\n msg: M | undefined,\n cmds: readonly C[],\n ): Promise<void> {\n state = next;\n if (store && gate !== \"abandoned\") await store.save(next);\n reconcileSubs();\n try {\n await runCmds(cmds);\n } finally {\n for (const callback of commitCallbacks) callback(msg, next);\n }\n }\n\n // One full transition. A `null` from the fold is no transition at all, and\n // it RESOLVES the dispatch. A throw from the fold rejects it.\n async function stepDispatch(msg: M): Promise<void> {\n if (state === undefined) {\n throw new Error(\"@demlik/tea: runtime not booted\");\n }\n const transition = update(state, msg);\n if (transition === null) return;\n await commit(transition[0], msg, transition[1]);\n }\n\n // With NO store there is nothing to read, so `init` runs IMMEDIATELY and\n // `getState()` is observable synchronously (what `useSyncExternalStore`\n // consumers need to render the first commit without a flicker); an `init`\n // throw leaves `run` itself. With a store, the read is the first thing boot\n // awaits; saved state it cannot restore rejects `ready` with a\n // `StoreRefusedError` before `init` runs, so nothing is saved over it.\n const storeless: Transition<S, C> | null =\n store === undefined ? config.init(null, config.ctx) : null;\n if (storeless !== null) state = storeless[0];\n\n async function boot(): Promise<void> {\n // Boundary parse (invariant 8): `store.load()` returns `unknown`;\n // `store.migrate(raw)` is the required parse — `S` on a recognized shape,\n // `null` when nothing was saved (boots fresh), a refusal otherwise.\n const [initial, cmds] =\n storeless ?? config.init(await restore(store as Store<S>), config.ctx);\n await commit(initial, undefined, cmds);\n }\n\n /**\n * Enqueue a dispatch on the tail — the single gate re-entrant handler and\n * runner calls also go through. Rejects when the gate is not open (with a\n * `DispatchDiscardedError` while `stop()` drains, a `RuntimeStoppedError`\n * once it has), boot failed, or the fold / save / sub start / handler throws.\n *\n * `origin` separates the two refusals an abandoned run makes. A Msg from the\n * loop's own producers is the late work `stop()` gave up on, so it is a\n * discard; a caller's dispatch is still a retired runtime being used. A Msg\n * accepted before `stop()` gave up is dropped when its turn comes, unfolded\n * and unsaved, as a discard whoever sent it.\n */\n function enqueueDispatch(\n msg: M,\n origin: \"caller\" | \"loop\" = \"caller\",\n ): Promise<void> {\n if (gate !== \"open\") {\n return Promise.reject(\n gate === \"draining\" || (gate === \"abandoned\" && origin === \"loop\")\n ? new DispatchDiscardedError(msg.type)\n : new RuntimeStoppedError(msg.type),\n );\n }\n const next = tail.then(() => {\n if (gate === \"abandoned\") throw new DispatchDiscardedError(msg.type);\n if (bootError !== null) throw bootError;\n return stepDispatch(msg);\n });\n // Swallow the rejection on the tail so one failing dispatch does NOT poison\n // every later one. The original `next` still rejects for the caller.\n tail = next.catch(() => {});\n return next;\n }\n\n /**\n * Drain the serial tail to quiescence. Every follow-up reassigns `tail`\n * SYNCHRONOUSLY before its parent step resolves, so awaiting the current\n * `tail` and re-reading it catches every transitively enqueued follow-up.\n * Bounded by `idleCap` — on cap REJECT with `QuiescenceTimeoutError`, keeping\n * a livelock distinguishable from quiescence (invariant 6).\n */\n async function drainToQuiescence(): Promise<void> {\n for (let i = 0; i < idleCap; i++) {\n const observed = tail;\n await observed;\n if (tail === observed) return;\n }\n throw new QuiescenceTimeoutError(idleCap);\n }\n\n /**\n * The public `dispatch`: await the Msg's OWN transition first (so its own\n * failure surfaces before any drain), then — unless `{ settle: \"once\" }` —\n * drain the transitive follow-up chain.\n */\n async function dispatchToQuiescence(\n msg: M,\n opts?: { readonly settle?: DispatchSettle },\n ): Promise<void> {\n await enqueueDispatch(msg);\n if (opts?.settle === \"once\") return;\n await drainToQuiescence();\n }\n\n // `bootPromise` is the un-swallowed promise `ready` chains off (so callers\n // see the boot error directly); `tail` gets the swallowed branch so a failed\n // boot does not poison every later dispatch's chain (each surfaces\n // `bootError` in `enqueueDispatch`).\n const bootPromise = boot();\n tail = bootPromise.catch((err) => {\n bootError = err;\n });\n\n async function teardown(): Promise<void> {\n // Open the discard window unless the gate is already past it (a halt):\n // the gate only advances.\n if (gate === \"open\") gate = \"draining\";\n // Report BEFORE the drain: a drained tail leaves nothing in flight, and\n // the fact worth surfacing is what was outstanding at the moment the\n // host let go (#365).\n if (inFlight.size > 0) {\n report(new RuntimeDiscardedError(inFlight.size), \"discard\");\n }\n // Drain in-flight work, up to `disposeTimeoutMs`. The gate refuses the\n // follow-ups those handlers return, so the tail ends once each handler\n // has returned; a handler that never returns is what the limit is for\n // (ADR 0025). Either way this resolves, and the teardown below runs.\n await drainTail();\n stopSubs([...subRegistry.keys()]);\n // …then WAIT for the teardown still settling, up to the same limit (see\n // `drainDisposals`).\n await drainDisposals();\n // Flush final State. A save throw does not reject `stop()` (contract:\n // resolves regardless) but IS loss of the last write, so it reaches the\n // sink (invariant 6).\n if (store && state !== undefined && bootError === null) {\n try {\n await store.save(state);\n } catch (error) {\n report(error, \"stop-save\");\n }\n }\n }\n\n // The teardown runs once. A second `stop()` — a host calling it again, or the\n // Effect engine's Scope closing after the handle's own `stop()` — gets the\n // first one's promise, so it reports nothing twice and, above all, runs no\n // second final save: that would be a store call after `stop()` has returned\n // (ADR 0025), over a store that may by then belong to a newer run.\n let stopped: Promise<void> | undefined;\n\n const core: LoopHandle<S, M> = {\n [liveWork]: () => ({ subs: subRegistry.size, cmds: inFlight.size }),\n dispatch: dispatchToQuiescence,\n dispatchOnce: (msg) => enqueueDispatch(msg),\n getState(): S {\n // TOTAL. A booted handle is only obtainable by awaiting `ready`, which\n // resolves AFTER boot set `state`. That holds for a run `stop()` gave up\n // on mid-load too: its late boot installs the loaded State (`commit`).\n return state as S;\n },\n // A failed boot never hands out a handle. The forward reference resolves\n // at `.then` time, after `handle` below is built.\n ready: bootPromise.then(() => handle),\n idle: drainToQuiescence,\n stop(): Promise<void> {\n stopped ??= teardown();\n return stopped;\n },\n };\n const handle: LoopHandle<S, M> = Object.assign(\n core,\n ...extensions.map((ext) => ext.handle ?? {}),\n );\n return handle;\n}\n"]}
|