@demlik/tea 0.20.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.
Files changed (130) hide show
  1. package/README.md +11 -2
  2. package/dist/agent/index.d.ts +36 -23
  3. package/dist/agent/index.js +12 -10
  4. package/dist/{chunk-UHAQ4PI6.js → chunk-2A5XTKQQ.js} +205 -59
  5. package/dist/chunk-2A5XTKQQ.js.map +1 -0
  6. package/dist/{chunk-JAKM53JF.js → chunk-7K7SEYCH.js} +16 -15
  7. package/dist/chunk-7K7SEYCH.js.map +1 -0
  8. package/dist/{chunk-RKVUVALV.js → chunk-A3QPMX5M.js} +31 -9
  9. package/dist/chunk-A3QPMX5M.js.map +1 -0
  10. package/dist/{chunk-DVNXEB7V.js → chunk-BVFS3ICC.js} +3 -3
  11. package/dist/chunk-BVFS3ICC.js.map +1 -0
  12. package/dist/{chunk-FTCYY2DO.js → chunk-CPE5ZQXQ.js} +3 -3
  13. package/dist/{chunk-FTCYY2DO.js.map → chunk-CPE5ZQXQ.js.map} +1 -1
  14. package/dist/chunk-DEAPNMKO.js +11 -0
  15. package/dist/chunk-DEAPNMKO.js.map +1 -0
  16. package/dist/{chunk-XWIE5V7R.js → chunk-ETRNSJCR.js} +4 -4
  17. package/dist/{chunk-XWIE5V7R.js.map → chunk-ETRNSJCR.js.map} +1 -1
  18. package/dist/chunk-FXWDDNGD.js +98 -0
  19. package/dist/chunk-FXWDDNGD.js.map +1 -0
  20. package/dist/chunk-GFGOQIEC.js +10 -0
  21. package/dist/chunk-GFGOQIEC.js.map +1 -0
  22. package/dist/{chunk-2R62Q5UK.js → chunk-IAHEYPYJ.js} +3 -3
  23. package/dist/{chunk-2R62Q5UK.js.map → chunk-IAHEYPYJ.js.map} +1 -1
  24. package/dist/{chunk-NGYFBD5G.js → chunk-J5JNLXO7.js} +3 -3
  25. package/dist/{chunk-NGYFBD5G.js.map → chunk-J5JNLXO7.js.map} +1 -1
  26. package/dist/{chunk-72CN3VPY.js → chunk-NFOGYDRS.js} +5 -5
  27. package/dist/{chunk-72CN3VPY.js.map → chunk-NFOGYDRS.js.map} +1 -1
  28. package/dist/{chunk-A73IJ27X.js → chunk-R2YNDRGL.js} +3 -3
  29. package/dist/{chunk-A73IJ27X.js.map → chunk-R2YNDRGL.js.map} +1 -1
  30. package/dist/{chunk-5HVKDHY6.js → chunk-R5NXOPL2.js} +3 -3
  31. package/dist/{chunk-5HVKDHY6.js.map → chunk-R5NXOPL2.js.map} +1 -1
  32. package/dist/chunk-RMBZ7YH7.js +52 -0
  33. package/dist/chunk-RMBZ7YH7.js.map +1 -0
  34. package/dist/{chunk-AIXC33SE.js → chunk-SHXUSTHM.js} +62 -15
  35. package/dist/chunk-SHXUSTHM.js.map +1 -0
  36. package/dist/{chunk-TAKPC6SD.js → chunk-UGTC33VH.js} +4 -4
  37. package/dist/{chunk-TAKPC6SD.js.map → chunk-UGTC33VH.js.map} +1 -1
  38. package/dist/{chunk-EA47MI5Q.js → chunk-VH5MYJ2K.js} +4 -4
  39. package/dist/{chunk-EA47MI5Q.js.map → chunk-VH5MYJ2K.js.map} +1 -1
  40. package/dist/{chunk-2774I242.js → chunk-WZEDIUWR.js} +21 -20
  41. package/dist/chunk-WZEDIUWR.js.map +1 -0
  42. package/dist/{chunk-TGJLXZAU.js → chunk-ZRRET3RP.js} +11 -11
  43. package/dist/chunk-ZRRET3RP.js.map +1 -0
  44. package/dist/{core-CtvAyPpH.d.ts → core-DNDAEhO2.d.ts} +9 -12
  45. package/dist/devtools/index.d.ts +4 -4
  46. package/dist/do/index.d.ts +103 -38
  47. package/dist/do/index.js +40 -21
  48. package/dist/do/index.js.map +1 -1
  49. package/dist/{drive-loop-Dw1sGSsW.d.ts → drive-loop-DlOEv49c.d.ts} +2 -2
  50. package/dist/{durable-effects-Ump5lSdO.d.ts → durable-effects-wLWEdy9H.d.ts} +1 -1
  51. package/dist/effect/index.d.ts +121 -28
  52. package/dist/effect/index.js +45 -31
  53. package/dist/effect/index.js.map +1 -1
  54. package/dist/extension/index.d.ts +3 -3
  55. package/dist/extension/index.js +2 -2
  56. package/dist/extension/index.js.map +1 -1
  57. package/dist/flow/index.d.ts +17 -13
  58. package/dist/flow/index.js +15 -12
  59. package/dist/flow/index.js.map +1 -1
  60. package/dist/idempotency/index.d.ts +3 -3
  61. package/dist/idempotency/index.js +3 -3
  62. package/dist/{index-CrcoVfd_.d.ts → index-9P1PaXIV.d.ts} +2 -2
  63. package/dist/{index-D3NY3VCN.d.ts → index-BBLI2WWN.d.ts} +1 -1
  64. package/dist/{index-Dl71V7kt.d.ts → index-C1WhBZ6a.d.ts} +4 -5
  65. package/dist/{index-CKtEKGyp.d.ts → index-C92SgNWz.d.ts} +3 -3
  66. package/dist/{index-CZZ3HI-Z.d.ts → index-CAsUE_d1.d.ts} +4 -4
  67. package/dist/{index-EIgfl83J.d.ts → index-CO34esWT.d.ts} +2 -2
  68. package/dist/{index-Bk2hBUdK.d.ts → index-COeX9Bmz.d.ts} +11 -9
  69. package/dist/{index-CVU7SK3a.d.ts → index-Cg0QXnzf.d.ts} +2 -2
  70. package/dist/index.d.ts +9 -9
  71. package/dist/index.js +2 -2
  72. package/dist/jev/index.d.ts +15 -15
  73. package/dist/jev/index.js +5 -5
  74. package/dist/jev/index.js.map +1 -1
  75. package/dist/laws-DTtCDDlU.d.ts +135 -0
  76. package/dist/loop-DReKGV1X.d.ts +70 -0
  77. package/dist/{machine-Dtre2TmN.d.ts → machine-C0WhOAyB.d.ts} +7 -7
  78. package/dist/machine-viz/index.d.ts +1 -1
  79. package/dist/machine-viz/index.js +2 -2
  80. package/dist/mem/index.d.ts +4 -3
  81. package/dist/mem/index.js +2 -2
  82. package/dist/mem/index.js.map +1 -1
  83. package/dist/node/index.d.ts +57 -9
  84. package/dist/node/index.js +175 -68
  85. package/dist/node/index.js.map +1 -1
  86. package/dist/otel/index.d.ts +28 -12
  87. package/dist/otel/index.js +25 -21
  88. package/dist/otel/index.js.map +1 -1
  89. package/dist/paginate/index.d.ts +4 -4
  90. package/dist/paginate/index.js +5 -5
  91. package/dist/parity/index.d.ts +11 -15
  92. package/dist/parity/index.js +4 -9
  93. package/dist/parity/index.js.map +1 -1
  94. package/dist/pbt/index.d.ts +279 -67
  95. package/dist/pbt/index.js +299 -58
  96. package/dist/pbt/index.js.map +1 -1
  97. package/dist/persistence/index.d.ts +10 -12
  98. package/dist/persistence/index.js +4 -4
  99. package/dist/promise/index.d.ts +118 -21
  100. package/dist/promise/index.js +6 -4
  101. package/dist/react/index.d.ts +34 -21
  102. package/dist/react/index.js +271 -42
  103. package/dist/react/index.js.map +1 -1
  104. package/dist/resilience/index.d.ts +6 -6
  105. package/dist/resilience/index.js +5 -5
  106. package/dist/{run-fiBe7pOG.d.ts → run-Cnw4qXj2.d.ts} +105 -23
  107. package/dist/{runtime-types-DEluQgGO.d.ts → runtime-types-CP-ykwgf.d.ts} +157 -29
  108. package/dist/testing/effect/index.d.ts +162 -9
  109. package/dist/testing/effect/index.js +110 -10
  110. package/dist/testing/effect/index.js.map +1 -1
  111. package/dist/testing/index.d.ts +6 -8
  112. package/dist/testing/index.js +4 -24
  113. package/dist/testing/index.js.map +1 -1
  114. package/dist/testing/promise/index.d.ts +4 -4
  115. package/dist/testing/promise/index.js +5 -5
  116. package/dist/timing/index.d.ts +4 -4
  117. package/dist/timing/index.js +4 -4
  118. package/dist/{types-CXNzlbAg.d.ts → types-S53WDy_h.d.ts} +1 -1
  119. package/dist/work-queue/index.d.ts +4 -4
  120. package/dist/work-queue/index.js +2 -2
  121. package/package.json +19 -17
  122. package/dist/chunk-2774I242.js.map +0 -1
  123. package/dist/chunk-AIXC33SE.js.map +0 -1
  124. package/dist/chunk-DVNXEB7V.js.map +0 -1
  125. package/dist/chunk-HX3C6LDK.js +0 -34
  126. package/dist/chunk-HX3C6LDK.js.map +0 -1
  127. package/dist/chunk-JAKM53JF.js.map +0 -1
  128. package/dist/chunk-RKVUVALV.js.map +0 -1
  129. package/dist/chunk-TGJLXZAU.js.map +0 -1
  130. package/dist/chunk-UHAQ4PI6.js.map +0 -1
@@ -1,6 +1,7 @@
1
1
  import { Effect, Stream, Scope } from 'effect';
2
- import { P as Port, C as Cmd, E as ErrorsOf, o as OkOfCmd, p as DeclaredErrorsOf, S as Sub, q as BuiltinSubType, B as BuiltinSub, M as Machine } from './core-CtvAyPpH.js';
3
- import { c as DispatchSettle, C as CtxArg, S as Store, O as OnError, a as Supervision, T as TelemetrySink } from './runtime-types-DEluQgGO.js';
2
+ import { P as Port, C as Cmd, E as ErrorsOf, p as OkOfCmd, q as DeclaredErrorsOf, c as Sub, r as BuiltinSubType, B as BuiltinSub, M as Machine } from './core-DNDAEhO2.js';
3
+ import { d as DispatchSettle, C as CtxArg, S as StoreAndOnError, c as Supervision, T as TelemetrySink } from './runtime-types-CP-ykwgf.js';
4
+ import { P as Postable } from './loop-DReKGV1X.js';
4
5
  import * as effect_Cause from 'effect/Cause';
5
6
  import * as effect_Types from 'effect/Types';
6
7
 
@@ -35,6 +36,19 @@ declare class StoreFailed extends StoreFailed_base<{
35
36
  }> {
36
37
  get message(): string;
37
38
  }
39
+ declare const SubFailed_base: new <A extends Record<string, any> = {}>(args: effect_Types.VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => effect_Cause.YieldableError & {
40
+ readonly _tag: "SubFailed";
41
+ } & Readonly<A>;
42
+ /**
43
+ * A Sub failed with an error it did not map to a Msg, and that stopped the run
44
+ * before it reached a terminal State. `cause` is what the Sub failed with, the
45
+ * value `onError` heard under `"sub"`. Only `done()` fails with it.
46
+ */
47
+ declare class SubFailed extends SubFailed_base<{
48
+ readonly cause: unknown;
49
+ }> {
50
+ get message(): string;
51
+ }
38
52
 
39
53
  /**
40
54
  * The Effect engine's run handle (#308, ruling R4.1 of #325). Its members have
@@ -68,9 +82,12 @@ interface EffectBootingRuntime<S, M extends {
68
82
  }): Effect.Effect<void, Err | Stopped | StoreFailed>;
69
83
  /** `dispatch(msg, { settle: "once" })`: one transition, no follow-up drain. */
70
84
  dispatchOnce(msg: M): Effect.Effect<void, Err | Stopped | StoreFailed>;
71
- /** A zero-arg change notifier, fired after each applied transition. */
85
+ /**
86
+ * A zero-arg change notifier, fired for each applied transition after its
87
+ * save and before its first Cmd's handler starts.
88
+ */
72
89
  subscribe(listener: () => void): () => void;
73
- /** A `(msg, state)` hook, fired after each applied transition. */
90
+ /** A `(msg, state)` hook, fired after each applied transition's Cmds. */
74
91
  observe(observer: (msg: M, state: S) => void): () => void;
75
92
  /** Fires once with the initial State — at once if boot already ran. */
76
93
  onBoot(handler: (state: S) => void): () => void;
@@ -90,15 +107,20 @@ interface EffectBootingRuntime<S, M extends {
90
107
  */
91
108
  readonly ready: Effect.Effect<EffectRuntime<S, M, E, Err>, Err | StoreFailed>;
92
109
  /**
93
- * Stop the run: drain in-flight work, stop its Subs, flush the final State.
94
- * Closing the run's Scope stops the run the same way, and `stop()` leaves
95
- * that Scope open. So for a child under `spawn` the two differ: `stop()`
96
- * does not take the child out of the host's table or tell the parent. Stop
97
- * such a child with the `stop` helper.
110
+ * Stop the run: drain in-flight work, up to `disposeTimeoutMs`, stop its
111
+ * Subs, flush the final State. `stop()` interrupts every handler still in
112
+ * flight, so the limit is reached only by a handler that cannot be
113
+ * interrupted. Closing the run's Scope stops the run the same way, and
114
+ * `stop()` leaves that Scope open. So for a child under `spawn` the two
115
+ * differ: `stop()` does not take the child out of the host's table or tell
116
+ * the parent. Stop such a child with the `stop` helper.
98
117
  */
99
118
  stop(): Effect.Effect<void>;
100
119
  }
101
- /** The Effect engine's booted handle — what `ready` succeeds with. */
120
+ /**
121
+ * The Effect engine's booted handle. `ready` on a real run succeeds with an
122
+ * {@link EffectRun}, which is one of these and carries what `tell` asks for.
123
+ */
102
124
  interface EffectRuntime<S, M extends {
103
125
  type: string;
104
126
  }, E extends {
@@ -109,10 +131,53 @@ interface EffectRuntime<S, M extends {
109
131
  readonly ready: Effect.Effect<EffectRuntime<S, M, E, Err>, Err | StoreFailed>;
110
132
  /** Succeeds once every dispatched Msg and its follow-ups are processed. */
111
133
  idle(): Effect.Effect<void>;
112
- /** The terminal State, or `undefined` while the run is in flight. */
134
+ /**
135
+ * The saved terminal State, or `undefined` while its save is pending or failed.
136
+ * Without a store, answers as soon as State is set. A run a failure closed
137
+ * reads `undefined` here; `done()` says why.
138
+ */
113
139
  result(): S | undefined;
114
- /** Succeeds with the terminal State the first time the run reaches one. */
115
- done(): Effect.Effect<S>;
140
+ /**
141
+ * Succeeds with the terminal State only once it is saved. When a failure
142
+ * closes the run short of a terminal State, it fails with that failure, for
143
+ * waiting and later callers: a failed terminal save with `StoreFailed`
144
+ * (`operation: "save"`), a Sub failure with `SubFailed`, and a reducer throw
145
+ * under the `stop` strategy with a defect, the thrown value itself. The defect
146
+ * is outside the error channel, so `Effect.catchTags` does not see it and
147
+ * `Effect.catchDefect` or the fiber's `Exit` does. The Msgs already in line
148
+ * fold first, so one of them reaching a terminal State makes that State the
149
+ * answer. A terminal State already saved keeps its answer whatever fails
150
+ * after it. A `stop()` with no failure leaves this waiting. Without a store,
151
+ * answers as soon as State is set.
152
+ */
153
+ done(): Effect.Effect<S, StoreFailed | SubFailed>;
154
+ }
155
+ /**
156
+ * The handle `run` yields: an {@link EffectBootingRuntime} whose `ready` succeeds
157
+ * with an {@link EffectRun}. It does not compile as `tell`'s argument: wait for
158
+ * `ready`.
159
+ */
160
+ interface EffectBootingRun<S, M extends {
161
+ type: string;
162
+ }, E extends {
163
+ type: string;
164
+ } = never, Err = never> extends EffectBootingRuntime<S, M, E, Err> {
165
+ readonly ready: Effect.Effect<EffectRun<S, M, E, Err>, Err | StoreFailed>;
166
+ }
167
+ /**
168
+ * What an {@link EffectBootingRun}'s `ready` succeeds with: a booted
169
+ * {@link EffectRuntime} that also carries the run's line, which is what `tell`
170
+ * asks for. A spread keeps the line. An object built by hand cannot have one,
171
+ * because tea does not export its key, so an {@link EffectRuntime} that is not one
172
+ * of these does not compile as `tell`'s argument. It fits anywhere an
173
+ * `EffectRuntime` is asked for.
174
+ */
175
+ interface EffectRun<S, M extends {
176
+ type: string;
177
+ }, E extends {
178
+ type: string;
179
+ } = never, Err = never> extends EffectRuntime<S, M, E, Err>, Postable<S, M> {
180
+ readonly ready: Effect.Effect<EffectRun<S, M, E, Err>, Err | StoreFailed>;
116
181
  }
117
182
 
118
183
  /**
@@ -164,7 +229,7 @@ type EffectInterpret<M extends {
164
229
  * A Sub maps the errors it expects into Msgs itself, the way an Elm `Sub msg`
165
230
  * carries no error type: `Stream.catchTag("Closed", () => Stream.make({ type:
166
231
  * "disconnected" }))`. A stream that still fails reaches the error sink under
167
- * `"sub"` and stops the run: the run's Scope closes with that failure (#309).
232
+ * `"sub"` and stops the run (#309), and `done()` fails with `SubFailed`.
168
233
  */
169
234
  type EffectRunner<M extends {
170
235
  type: string;
@@ -227,9 +292,7 @@ type EffectRunOptions<S, M extends {
227
292
  type: string;
228
293
  }, C extends Cmd, U extends Sub, Ctx, E extends {
229
294
  type: string;
230
- }, I, B> = CtxArg<Ctx> & InterpretOption<C, I> & SubscribeOption<U, B> & {
231
- readonly store?: Store<S>;
232
- readonly onError?: OnError;
295
+ }, I, B> = CtxArg<Ctx> & InterpretOption<C, I> & SubscribeOption<U, B> & StoreAndOnError<S> & {
233
296
  /** Stamps `at` on minted Msgs and telemetry. Defaults to `Date.now`. */
234
297
  readonly clock?: () => number;
235
298
  /** Projects each applied transition to the public events `on` serves. */
@@ -240,7 +303,18 @@ type EffectRunOptions<S, M extends {
240
303
  readonly terminal?: (state: S) => boolean;
241
304
  /** A fire-and-forget sink for every applied transition. */
242
305
  readonly telemetry?: TelemetrySink;
243
- /** How long `stop()` waits for async teardown. Defaults to 5_000ms. */
306
+ /**
307
+ * How long `stop()` waits for the queue, and then for async teardown,
308
+ * before giving up on each. Defaults to 5_000ms. `stop()` interrupts every
309
+ * handler here, so the first wait ends early unless a handler cannot be
310
+ * interrupted.
311
+ *
312
+ * A store call is not interrupted. tea starts none after `stop()` has
313
+ * returned, but one already under way when `stop()` gave up can finish
314
+ * after it. On a plain store that late save can overwrite what a newer
315
+ * run saved; a fenced store refuses it. So a host that starts a new run on
316
+ * the same store after a `stop()` that gave up needs a fenced store.
317
+ */
244
318
  readonly disposeTimeoutMs?: number;
245
319
  };
246
320
  /**
@@ -256,11 +330,19 @@ type EffectRunOptions<S, M extends {
256
330
  * dispatch after stop fails with `Stopped`. The handle's `stop()` does the
257
331
  * same.
258
332
  *
259
- * A Sub whose Stream fails with an error it did not map to a Msg stops the
260
- * run the other way round: the engine closes that Scope with the failure.
333
+ * A Sub whose Stream fails with an error it did not map to a Msg stops this run
334
+ * alone. The run forks its own child of that scope and closes only the child,
335
+ * so the rest of the scope stays open, and `done()` fails with `SubFailed`. A
336
+ * handler or runner that reads `Scope.Scope` gets that child, so what it acquires
337
+ * is released with the run. With no `onError`, the default sink still rethrows
338
+ * the failure and ends the process. A reducer throw under the default `stop`
339
+ * strategy closes that same child, so the run stops and `done()` fails with
340
+ * what was thrown, as a defect (ADR 0033).
261
341
  *
262
342
  * A fenced store is fenced here exactly as on the Promise engine: the check is
263
- * one of the built-ins both engines run.
343
+ * one of the built-ins both engines run. A run on a store that is fenced at
344
+ * runtime with no `onError` dies at start, before anything is loaded, even when
345
+ * the store is typed plain `Store<S>` (ADR 0031).
264
346
  *
265
347
  * ```ts
266
348
  * const program = Effect.gen(function* () {
@@ -284,6 +366,6 @@ declare function run<S, M extends {
284
366
  type: string;
285
367
  }, C extends Cmd, U extends Sub, Ctx, I extends EffectInterpret<M, C> = EffectInterpret<M, C, never>, B extends EffectSubscribe<M, U> = EffectSubscribe<M, U, never>, E extends {
286
368
  type: string;
287
- } = never>(machine: Machine<S, M, C, U, Ctx>, opts: EffectRunOptions<S, M, C, U, Ctx, E, I, B>): Effect.Effect<EffectBootingRuntime<S, M, E, CellErrors<C, I>>, never, Scope.Scope | InterpretServices<I> | SubscribeServices<B>>;
369
+ } = never>(machine: Machine<S, M, C, U, Ctx>, opts: EffectRunOptions<S, M, C, U, Ctx, E, I, B>): Effect.Effect<EffectBootingRun<S, M, E, CellErrors<C, I>>, never, Scope.Scope | InterpretServices<I> | SubscribeServices<B>>;
288
370
 
289
- export { type CellErrors as C, type EffectRuntime as E, type InterpretServices as I, StoreFailed as S, type EffectBootingRuntime as a, type EffectInterpret as b, type EffectInterpretCell as c, type EffectRunOptions as d, type EffectRunner as e, type EffectSubscribe as f, Stopped as g, type SubscribeServices as h, type SubscribeOption as i, run as r };
371
+ export { type CellErrors as C, type EffectRun as E, type InterpretServices as I, Stopped as S, type EffectBootingRun as a, type EffectBootingRuntime as b, type EffectInterpret as c, type EffectInterpretCell as d, type EffectRunOptions as e, type EffectRunner as f, type EffectRuntime as g, type EffectSubscribe as h, StoreFailed as i, SubFailed as j, type SubscribeServices as k, type SubscribeOption as l, run as r };
@@ -1,4 +1,4 @@
1
- import { C as Cmd, S as Sub, M as Machine, R as RunHandlers, P as Port, N as NoCellError, g as Reducer, A as AnyCmdDef, h as Settled, a as CmdOf, i as Transitions, B as BuiltinSub, U as UpdateForm, O as Outcome, j as InterpretDetached, H as HandlerCtx } from './core-CtvAyPpH.js';
1
+ import { C as Cmd, c as Sub, M as Machine, R as RunHandlers, P as Port, N as NoCellError, g as Reducer, A as AnyCmdDef, h as Settled, a as CmdOf, i as Transitions, B as BuiltinSub, U as UpdateForm, O as Outcome, j as InterpretDetached, H as HandlerCtx } from './core-DNDAEhO2.js';
2
2
 
3
3
  /**
4
4
  * @demlik/tea runtime interface surface + pure helpers — the public types,
@@ -98,12 +98,15 @@ declare function __resetPortRegistry(): void;
98
98
  * run stops — on the Effect engine by closing its Scope with the failure. A
99
99
  * Sub that expects an error maps it to a Msg itself; there is no hook for it
100
100
  * here.
101
- * - `"discard"` — work lost to a teardown the host asked for. Two witnesses,
102
- * both carrying a `RuntimeDiscardNotice`: `stop()` was called while interpret
103
- * handlers were still awaiting (`RuntimeDiscardedError`), and a Msg that
104
- * arrived DURING `stop()`'s drain and so could not be delivered
105
- * (`DispatchDiscardedError`), and teardown work that did not settle inside
106
- * `disposeTimeoutMs` (`DisposeTimeoutNotice`). The one phase that is a
101
+ * - `"discard"` — work lost to a teardown the host asked for. Four witnesses,
102
+ * each carrying a `RuntimeDiscardNotice`: `stop()` was called while interpret
103
+ * handlers were still awaiting (`RuntimeDiscardedError`), a Msg that
104
+ * arrived DURING `stop()`'s drain, or from a handler `stop()` gave up on, and
105
+ * so could not be delivered (`DispatchDiscardedError`), a drain that did not
106
+ * finish inside `disposeTimeoutMs`, which also counts the Msgs that were still
107
+ * queued (`DrainTimeoutNotice`), and teardown work that did not settle inside
108
+ * `disposeTimeoutMs`
109
+ * (`DisposeTimeoutNotice`). The one phase that is a
107
110
  * LIFECYCLE report rather than a failure: legal, merely lossy.
108
111
  * - `"identity-drop"` — the `Identity` filter dropped a message addressed to a
109
112
  * different instance (`IdentityDropNotice`). Its own phase rather than
@@ -144,6 +147,14 @@ interface RuntimeErrorContext {
144
147
  * `run(machine, { onError })`. Should be total — a throw inside the sink is
145
148
  * itself surfaced via the default sink, so it can never re-introduce a silent
146
149
  * failure.
150
+ *
151
+ * Optional, except beside a fenced store (see {@link StoreAndOnError}): there it
152
+ * does not compile without one, and a run whose store is fenced at runtime is
153
+ * refused at start without one, whatever its type says. With no
154
+ * sink a `RuntimeDiscardNotice` is warned, and every other failure is rethrown on
155
+ * a fresh macrotask, which ends a Node process and every run in it. That includes
156
+ * a failing Sub (`"sub"`). A host running several machines in one process passes
157
+ * a sink that decides what one run's failure means for the rest.
147
158
  */
148
159
  type OnError = (error: unknown, context: RuntimeErrorContext) => void;
149
160
  /** The three declared reducer-throw supervision strategies. */
@@ -159,6 +170,14 @@ type SupervisionStrategy = "stop" | "escalate" | "restart";
159
170
  type Supervision<S, M extends {
160
171
  type: string;
161
172
  }> = "stop" | "escalate" | {
173
+ /**
174
+ * The default. A reducer throw stops the run by itself, the same stop a
175
+ * Sub failure starts: the Msgs already in line fold, then the Subs close,
176
+ * the final save runs and, on the Effect engine, the run's own Scope
177
+ * closes, so a run `spawn` started leaves the host's table and its
178
+ * `notify` runs. `done()` fails with the throw. A later `stop()` from the
179
+ * host does nothing more.
180
+ */
162
181
  readonly strategy: "stop";
163
182
  } | {
164
183
  readonly strategy: "escalate";
@@ -173,6 +192,17 @@ type Supervision<S, M extends {
173
192
  */
174
193
  readonly rehydrate: (state: S, msg: M, error: unknown) => S;
175
194
  };
195
+ /**
196
+ * What `done()` rejects with once a Sub's failure the Sub did not map to a Msg
197
+ * has stopped the run, which can then never reach a terminal State. `cause` is
198
+ * what the Sub failed with, the same value `onError` heard under `"sub"`.
199
+ */
200
+ declare class SubFailedError extends Error {
201
+ readonly cause: unknown;
202
+ readonly name = "SubFailedError";
203
+ readonly _tag: "SubFailedError";
204
+ constructor(cause: unknown);
205
+ }
176
206
  /**
177
207
  * Raised by `idle()` when the quiescence wait hits its iteration cap without the
178
208
  * dispatch tail stabilizing — `idle()` REJECTS rather than silently resolving,
@@ -237,7 +267,8 @@ declare abstract class RuntimeDiscardNotice extends Error {
237
267
  /**
238
268
  * Reported to the `OnError` sink under `phase: "discard"` when `stop()` is
239
269
  * called while `interpret` handlers are still awaiting. The host is dropping
240
- * its only handle on that work: `stop()` drains the tail, but the listeners,
270
+ * its only handle on that work: `stop()` drains the tail, up to
271
+ * `disposeTimeoutMs`, but the listeners,
241
272
  * observers and event handlers that would have consumed the resulting
242
273
  * transitions are gone, so the Cmds' results reach nobody.
243
274
  *
@@ -294,12 +325,57 @@ declare class DisposeTimeoutNotice extends RuntimeDiscardNotice {
294
325
  readonly _tag: "DisposeTimeoutNotice";
295
326
  constructor(pendingDisposals: number, timeoutMs: number);
296
327
  }
328
+ /**
329
+ * Reported to the `OnError` sink under `phase: "discard"` when `stop()`'s wait
330
+ * for the queue hits `disposeTimeoutMs` (ADR 0025): a Cmd handler, a save or
331
+ * detached work had not returned.
332
+ *
333
+ * `stop()` resolves by contract, so it gives up on that work instead of waiting
334
+ * for it without limit. It then stops the Subs and runs the final save as it
335
+ * always does. The work it gave up on is not recalled — a Promise cannot be
336
+ * cancelled — so a handler may still be running after `stop()` has returned.
337
+ * Whatever it returns later is dropped, and so are the Msgs queued behind it.
338
+ * The rest of its step's Cmds are skipped: no handler starts for them, and they
339
+ * get no notice of their own. None of it is saved.
340
+ *
341
+ * `droppedMsgs` is how a host learns what it lost. It counts the Msgs queued
342
+ * behind the stuck work when `stop()` gave up, per Msg type: Msgs handed to
343
+ * `dispatch` or `tell`, and those a handler or a Sub sent. It carries types and
344
+ * counts only, never a payload, so a sink can log it. It is read once and does
345
+ * not change. A Msg it counts is not reported again: if the handler returns
346
+ * late, a `dispatch` caller's promise rejects with a `DispatchDiscardedError`,
347
+ * and a Msg with no caller reaches the sink no second time. If the handler
348
+ * never returns, those promises never settle, and this count is the only word.
349
+ *
350
+ * tea starts no store call after `stop()` has returned. A store call already
351
+ * under way when `stop()` gave up is not cancelled and can finish afterwards;
352
+ * on a plain store that late save can overwrite what a newer run saved, and a
353
+ * fenced store refuses it.
354
+ *
355
+ * `cmdTypes` names the Cmd of each handler call still awaiting, one entry per
356
+ * call. `pendingCmds` counts those plus any detached work, the same count
357
+ * `RuntimeDiscardedError` carries.
358
+ */
359
+ declare class DrainTimeoutNotice extends RuntimeDiscardNotice {
360
+ readonly cmdTypes: readonly string[];
361
+ readonly pendingCmds: number;
362
+ readonly timeoutMs: number;
363
+ readonly droppedMsgs: Readonly<Record<string, number>>;
364
+ readonly name = "DrainTimeoutNotice";
365
+ readonly _tag: "DrainTimeoutNotice";
366
+ constructor(cmdTypes: readonly string[], pendingCmds: number, timeoutMs: number, droppedMsgs?: Readonly<Record<string, number>>);
367
+ }
297
368
  /**
298
369
  * The rejection of a dispatch that arrived DURING `stop()`'s drain — an in-flight
299
370
  * interpret handler's follow-up Msg, a detached handler's terminal Msg, or a Sub
300
371
  * that is still live because subs are torn down only after the drain. The stop
301
372
  * barrier is absolute (the Msg is refused, never folded), so this names the loss.
302
373
  *
374
+ * It is also the rejection of the work `stop()` gave up on (see
375
+ * `DrainTimeoutNotice`): a Msg a stuck handler produces after `stop()` has
376
+ * returned, and a Msg that was accepted before `stop()` and was still queued
377
+ * behind that handler.
378
+ *
303
379
  * It is the SECOND witness of `RuntimeDiscardedError`'s fact, and it is why the
304
380
  * drain window is a distinct runtime state rather than a plain `stopped` flag:
305
381
  * a Msg refused inside the window was discarded BY the teardown, while the same
@@ -431,6 +507,38 @@ interface DeletableStore<S> extends Store<S> {
431
507
  }
432
508
  /** Narrow a `Store<S>` to a {@link FencedStore} — what `run` uses to decide. */
433
509
  declare function isFencedStore<S>(store: Store<S>): store is FencedStore<S>;
510
+ /**
511
+ * A `Store<S>` whose type says it is not fenced. A plain `Store<S>` fits it and
512
+ * a {@link FencedStore} does not. It is what lets {@link StoreAndOnError} tell the
513
+ * two apart, because a `FencedStore` is otherwise also a `Store`.
514
+ */
515
+ type UnfencedStore<S> = Store<S> & {
516
+ readonly fenced?: never;
517
+ };
518
+ /**
519
+ * The `store` and `onError` options of a run: a fenced store needs an `onError`,
520
+ * and the mistake does not compile (ADR 0031).
521
+ *
522
+ * Losing a fence is routine for a host that moves runs between processes, and
523
+ * with no `onError` the default sink rethrows the conflict and ends the process,
524
+ * along with every other run in it. A conflict can reach the sink at any save
525
+ * with no caller to reject at: `"stop-save"` from `stop()`, `"follow-up"` from a
526
+ * Msg a Sub or a Cmd sent. So the sink is required at the type, not left to be
527
+ * remembered.
528
+ *
529
+ * It reads a store's declared type. A fenced store first assigned to a variable
530
+ * typed plain `Store<S>` has given that type up, so it compiles with no
531
+ * `onError`. Both engines then refuse it at start, before anything is loaded:
532
+ * the Promise engine's `run` throws, and the Effect engine's dies. A JavaScript
533
+ * caller is refused the same way.
534
+ */
535
+ type StoreAndOnError<S> = {
536
+ readonly store?: UnfencedStore<S>;
537
+ readonly onError?: OnError;
538
+ } | {
539
+ readonly store: Store<S>;
540
+ readonly onError: OnError;
541
+ };
434
542
  /**
435
543
  * Thrown when a fenced save finds a version other than the one it expected —
436
544
  * another live writer has this run.
@@ -518,9 +626,12 @@ interface RunHandle<S, M extends {
518
626
  } = never> {
519
627
  /** Put a Msg in the inbox; resolves once the engine has processed it. */
520
628
  dispatch(msg: M): Promise<void>;
521
- /** A zero-arg change notifier, fired after each applied transition. */
629
+ /**
630
+ * A zero-arg change notifier, fired for each applied transition after its
631
+ * save and before its first Cmd's handler starts.
632
+ */
522
633
  subscribe(listener: () => void): () => void;
523
- /** A `(msg, state)` hook, fired after each applied transition. */
634
+ /** A `(msg, state)` hook, fired after each applied transition's Cmds. */
524
635
  observe(observer: (msg: M, state: S) => void): () => void;
525
636
  /** Fires once with the initial State — at once if boot already ran. */
526
637
  onBoot(handler: (state: S) => void): () => void;
@@ -545,15 +656,15 @@ interface BootedRunHandle<S, M extends {
545
656
  }
546
657
  /**
547
658
  * The options every engine's `run` accepts: the `ctx`, the handlers the
548
- * machine runs under, an optional `store`, and the `events` projector that
549
- * feeds `on`. An engine may take more; a host adapter hands only these.
659
+ * machine runs under, an optional `store` with the `onError` a fenced one needs,
660
+ * and the `events` projector that feeds `on`. An engine may take more; a host
661
+ * adapter hands only these.
550
662
  */
551
663
  type RunOptions<S, M extends {
552
664
  type: string;
553
665
  }, C extends Cmd, U extends Sub, Ctx, E extends {
554
666
  type: string;
555
- } = never> = CtxArg<Ctx> & RunHandlers<M, C, U, Ctx> & {
556
- readonly store?: Store<S>;
667
+ } = never> = CtxArg<Ctx> & RunHandlers<M, C, U, Ctx> & StoreAndOnError<S> & {
557
668
  readonly events?: (msg: M, state: S) => readonly E[];
558
669
  };
559
670
  /**
@@ -594,12 +705,16 @@ interface BootingRuntime<S, M extends {
594
705
  }): Promise<void>;
595
706
  dispatchOnce(msg: M): Promise<void>;
596
707
  /**
597
- * Register a zero-arg change notifier, fired for every applied transition
598
- * with the fold's State already committed — `getState()` inside the listener
599
- * reads it, not the State before. A `dispatch` issued from the listener is
600
- * SCHEDULED onto the serial tail behind the fold that fired it, never folded
601
- * re-entrantly and never discarded, so it needs no `setTimeout(fn, 0)`
602
- * deferral; two listeners issuing in order fold in that order.
708
+ * Register a zero-arg change notifier, fired once for every applied
709
+ * transition, after its save and before its first Cmd's handler starts, so a
710
+ * view shows the State while that State's Cmds run. `getState()` inside the
711
+ * listener reads the new State, not the State before. A failed save fires
712
+ * nothing. The listener does not mean the Cmds are done: `observe`, `on` and
713
+ * `done()` hear after them. A `dispatch` issued from the listener is SCHEDULED
714
+ * onto the serial tail behind the fold that fired it, never folded re-entrantly
715
+ * and never discarded, so it needs no `setTimeout(fn, 0)` deferral; it folds
716
+ * ahead of what that fold's Cmds return, and two listeners issuing in order
717
+ * fold in that order.
603
718
  */
604
719
  subscribe(listener: () => void): () => void;
605
720
  /**
@@ -695,19 +810,30 @@ interface Runtime<S, M extends {
695
810
  */
696
811
  idle(): Promise<void>;
697
812
  /**
698
- * The terminal State of the run, or `undefined` while in flight — "terminal"
813
+ * The saved terminal State of the run, or `undefined` while in flight — "terminal"
699
814
  * per the `terminal` predicate passed to `run()` (no predicate → never
700
815
  * terminal → always `undefined`). The first-class result read: the run's
701
816
  * product off the State the machine already owns, NOT scraped off the `observe`
702
- * firehose by matching an internal Msg name. Total — never throws.
817
+ * firehose by matching an internal Msg name. With a store, returns `undefined`
818
+ * until the current State's save succeeds, including after a failed save.
819
+ * Without a store, answers as soon as State is set. Total — never throws, so a
820
+ * run a failure closed reads `undefined` here; `done()` says why.
703
821
  */
704
822
  result(): S | undefined;
705
823
  /**
706
- * Resolves with the terminal State the first time the run reaches one (per the
707
- * `terminal` predicate). If ALREADY terminal, resolves immediately; otherwise
708
- * on the transition that first makes `terminal` hold. The awaitable companion
709
- * to `result()`. With no predicate this never resolves. Idempotent and
710
- * multi-caller safe.
824
+ * Resolves with the terminal State only once it is saved (per the `terminal`
825
+ * predicate). If ALREADY saved and terminal, resolves immediately; otherwise
826
+ * on that terminal commit. Rejects with the save failure if a terminal State
827
+ * cannot be saved, for both waiting and later callers. When a failure closes
828
+ * the run short of a terminal State, it rejects for both waiting and later
829
+ * callers too: with `SubFailedError` for a Sub failure the Sub did not map to
830
+ * a Msg, and with what was thrown for a reducer throw under the `stop`
831
+ * strategy. It answers that only after the Msgs already in line have folded,
832
+ * because one of them can still reach a terminal State, and then the State is
833
+ * the answer. A `stop()` with no failure leaves it pending. Without a store,
834
+ * answers as soon as State is set. The awaitable companion to `result()`. With
835
+ * no predicate this resolves never, and rejects only on those failures.
836
+ * Idempotent and multi-caller safe.
711
837
  */
712
838
  done(): Promise<S>;
713
839
  }
@@ -794,7 +920,9 @@ type CtxArg<Ctx> = [Record<never, never>] extends [Ctx] ? {
794
920
  * Cmds emitted, and the Subs that would be running.
795
921
  *
796
922
  * It composes `init(loaded ?? null, ctx)` and then `update(state, msg)` for each
797
- * Msg. No Cmd handler is called, no `Store` is touched and no Sub is started.
923
+ * Msg. Restored init may change State and emit Cmds; those Cmds are collected
924
+ * alongside update Cmds. No handler, Store or Sub runner is called.
925
+ * Recorded traces instead use `replayTrace` to fold their captured post-init State.
798
926
  *
799
927
  * `subs` is each `machine.subs` entry that is on at the final state, as its
800
928
  * runner would see it: `{ id, type, deps }`, the id derived exactly as the
@@ -884,4 +1012,4 @@ declare function tryFoldMsgs<S, M extends {
884
1012
  */
885
1013
  declare function tryInterpret<C extends Cmd, Ok, M, Ctx>(work: (cmd: C, ctx: Ctx) => Promise<Ok>, onOk: (value: Ok, cmd: C) => M, onErr: (error: unknown, cmd: C) => M): (cmd: C, ctx: Ctx) => Promise<M>;
886
1014
 
887
- export { defineMachine as A, type BootingRuntime as B, type CtxArg as C, type DeletableStore as D, type EngineRun as E, type FencedStore as F, definePort as G, isFencedStore as H, IdentityDropNotice as I, noop as J, refuse as K, replay as L, type Migrated as M, schemaMigrate as N, type OnError as O, PortNameCollisionError as P, QuiescenceTimeoutError as Q, type Runtime as R, type Store as S, type TelemetrySink as T, tryApplyCell as U, tryFoldMsgs as V, tryInterpret as W, wrapDetached as X, __resetPortRegistry as _, type Supervision as a, type BootedRunHandle as b, type DispatchSettle as c, type RunHandle as d, type Branded as e, DispatchDiscardedError as f, DisposeTimeoutNotice as g, DriveFailedError as h, DriveStalledError as i, type FencedRead as j, type FoldRefusal as k, type MachineTypes as l, Refusal as m, type RunOptions as n, RuntimeDiscardNotice as o, RuntimeDiscardedError as p, type RuntimeErrorContext as q, type RuntimeErrorPhase as r, type RuntimeRef as s, type Schema as t, StoreConflictError as u, StoreRefusedError as v, type SupervisionStrategy as w, type TelemetryEvent as x, absurd as y, asReducer as z };
1015
+ export { tryInterpret as $, type TelemetryEvent as A, type BootingRuntime as B, type CtxArg as C, type DeletableStore as D, type EngineRun as E, type FencedStore as F, absurd as G, asReducer as H, IdentityDropNotice as I, defineMachine as J, definePort as K, isFencedStore as L, type Migrated as M, noop as N, type OnError as O, PortNameCollisionError as P, QuiescenceTimeoutError as Q, type Runtime as R, type StoreAndOnError as S, type TelemetrySink as T, type UnfencedStore as U, refuse as V, replay as W, schemaMigrate as X, tryApplyCell as Y, tryFoldMsgs as Z, __resetPortRegistry as _, type BootedRunHandle as a, wrapDetached as a0, type Store as b, type Supervision as c, type DispatchSettle as d, type RunHandle as e, type Branded as f, DispatchDiscardedError as g, DisposeTimeoutNotice as h, DrainTimeoutNotice as i, DriveFailedError as j, DriveStalledError as k, type FencedRead as l, type FoldRefusal as m, type MachineTypes as n, Refusal as o, type RunOptions as p, RuntimeDiscardNotice as q, RuntimeDiscardedError as r, type RuntimeErrorContext as s, type RuntimeErrorPhase as t, type RuntimeRef as u, type Schema as v, StoreConflictError as w, StoreRefusedError as x, SubFailedError as y, type SupervisionStrategy as z };