@demlik/tea 0.14.0 → 0.15.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 (77) hide show
  1. package/dist/agent/index.d.ts +14 -13
  2. package/dist/agent/index.js +6 -6
  3. package/dist/{chunk-F2US5BW6.js → chunk-22POWGFA.js} +17 -11
  4. package/dist/chunk-22POWGFA.js.map +1 -0
  5. package/dist/{chunk-HYDWG35Q.js → chunk-3B5X7SBB.js} +4 -4
  6. package/dist/{chunk-HYDWG35Q.js.map → chunk-3B5X7SBB.js.map} +1 -1
  7. package/dist/{chunk-RQULHGYH.js → chunk-66PY5WYF.js} +15 -3
  8. package/dist/{chunk-RQULHGYH.js.map → chunk-66PY5WYF.js.map} +1 -1
  9. package/dist/{chunk-AQ6ZIMEA.js → chunk-AYS5N6WY.js} +121 -37
  10. package/dist/chunk-AYS5N6WY.js.map +1 -0
  11. package/dist/{chunk-HUKZQX6U.js → chunk-L3TND7LA.js} +3 -3
  12. package/dist/{chunk-HUKZQX6U.js.map → chunk-L3TND7LA.js.map} +1 -1
  13. package/dist/{chunk-I5MQMJDW.js → chunk-Q5CQTBFA.js} +3 -3
  14. package/dist/{chunk-I5MQMJDW.js.map → chunk-Q5CQTBFA.js.map} +1 -1
  15. package/dist/{chunk-F7FMAWLA.js → chunk-QPEVCJ5Q.js} +3 -3
  16. package/dist/{chunk-F7FMAWLA.js.map → chunk-QPEVCJ5Q.js.map} +1 -1
  17. package/dist/{chunk-Z2L3LSNV.js → chunk-TCLBCERH.js} +17 -7
  18. package/dist/chunk-TCLBCERH.js.map +1 -0
  19. package/dist/{chunk-BLJ2JQSH.js → chunk-V46HSVCK.js} +3 -3
  20. package/dist/{chunk-BLJ2JQSH.js.map → chunk-V46HSVCK.js.map} +1 -1
  21. package/dist/{chunk-LYLTKJWM.js → chunk-VTQI2NHP.js} +3 -3
  22. package/dist/{chunk-LYLTKJWM.js.map → chunk-VTQI2NHP.js.map} +1 -1
  23. package/dist/{core-CTzMJ82M.d.ts → core-DnzqWy6u.d.ts} +1 -1
  24. package/dist/do/index.d.ts +13 -12
  25. package/dist/do/index.js +7 -7
  26. package/dist/{durable-effects-B0-qGQDy.d.ts → durable-effects-CWzA-o2B.d.ts} +1 -1
  27. package/dist/extension/index.d.ts +3 -3
  28. package/dist/extension/index.js +1 -1
  29. package/dist/flow/index.d.ts +15 -26
  30. package/dist/flow/index.js +8 -8
  31. package/dist/idempotency/index.d.ts +3 -3
  32. package/dist/idempotency/index.js +2 -2
  33. package/dist/{index-4vZzljCD.d.ts → index-C2DwkjlP.d.ts} +4 -4
  34. package/dist/{index-B5BZ-_cT.d.ts → index-CA_7I5g9.d.ts} +277 -87
  35. package/dist/{index-DJWIER_3.d.ts → index-CSyMYDAB.d.ts} +1 -1
  36. package/dist/{index-6A7dB8f6.d.ts → index-CuNO9m8i.d.ts} +2 -2
  37. package/dist/{index-TvRb1KVf.d.ts → index-DrIRb_Ch.d.ts} +1 -1
  38. package/dist/{index-q0hXFeZ0.d.ts → index-HSYgG2Yt.d.ts} +50 -15
  39. package/dist/{index-NjrT3fL2.d.ts → index-KXqTRJyb.d.ts} +4 -4
  40. package/dist/{index-DMCeMPMJ.d.ts → index-ZCMhnVKN.d.ts} +1 -1
  41. package/dist/index.d.ts +66 -6
  42. package/dist/index.js +1 -1
  43. package/dist/jev/index.d.ts +34 -22
  44. package/dist/jev/index.js +178 -126
  45. package/dist/jev/index.js.map +1 -1
  46. package/dist/{machine-CdIcN2Xm.d.ts → machine-DGlPWCWI.d.ts} +34 -26
  47. package/dist/machine-viz/index.d.ts +1 -1
  48. package/dist/machine-viz/index.js +1 -1
  49. package/dist/mem/index.d.ts +2 -2
  50. package/dist/mem/index.js +1 -1
  51. package/dist/node/index.d.ts +2 -2
  52. package/dist/node/index.js +1 -1
  53. package/dist/paginate/index.d.ts +6 -17
  54. package/dist/paginate/index.js +4 -4
  55. package/dist/parity/index.d.ts +3 -3
  56. package/dist/parity/index.js +2 -2
  57. package/dist/pbt/index.d.ts +1 -1
  58. package/dist/pbt/index.js +1 -1
  59. package/dist/persistence/index.d.ts +5 -5
  60. package/dist/persistence/index.js +3 -3
  61. package/dist/protocol-D8VbH-VH.d.ts +54 -0
  62. package/dist/react/index.d.ts +2 -2
  63. package/dist/react/index.js +1 -1
  64. package/dist/resilience/index.d.ts +8 -7
  65. package/dist/resilience/index.js +5 -5
  66. package/dist/{runtime-types-LWDoi943.d.ts → runtime-types-CMF13BBh.d.ts} +1 -1
  67. package/dist/testing/index.d.ts +147 -3
  68. package/dist/testing/index.js +95 -2
  69. package/dist/testing/index.js.map +1 -1
  70. package/dist/timing/index.d.ts +4 -4
  71. package/dist/timing/index.js +3 -3
  72. package/dist/{types-DP3f5NIl.d.ts → types-BseNPIhr.d.ts} +1 -1
  73. package/dist/work-queue/index.d.ts +4 -4
  74. package/package.json +1 -1
  75. package/dist/chunk-AQ6ZIMEA.js.map +0 -1
  76. package/dist/chunk-F2US5BW6.js.map +0 -1
  77. package/dist/chunk-Z2L3LSNV.js.map +0 -1
@@ -1,6 +1,6 @@
1
- import { B as BootingRuntime } from '../runtime-types-LWDoi943.js';
2
- import { C as Cmd, S as Sub, M as Machine } from '../core-CTzMJ82M.js';
3
- import { T as Trace, R as RecorderOptions } from '../index-TvRb1KVf.js';
1
+ import { B as BootingRuntime } from '../runtime-types-CMF13BBh.js';
2
+ import { C as Cmd, S as Sub, M as Machine } from '../core-DnzqWy6u.js';
3
+ import { T as Trace, R as RecorderOptions } from '../index-DrIRb_Ch.js';
4
4
  import 'better-result';
5
5
  import 'zod';
6
6
 
@@ -1,6 +1,6 @@
1
- import { recorder, deepEqual } from '../chunk-BLJ2JQSH.js';
1
+ import { recorder, deepEqual } from '../chunk-V46HSVCK.js';
2
2
  import '../chunk-HWVW4AXC.js';
3
- import { replay } from '../chunk-RQULHGYH.js';
3
+ import { replay } from '../chunk-66PY5WYF.js';
4
4
 
5
5
  // src/parity/index.ts
6
6
  function recordRun(runtime, opts) {
@@ -1,5 +1,5 @@
1
1
  import * as fc from 'fast-check';
2
- import { C as Cmd, S as Sub, M as Machine, d as Reducer, T as Transitions, U as UpdateForm } from '../core-CTzMJ82M.js';
2
+ import { C as Cmd, S as Sub, M as Machine, d as Reducer, T as Transitions, U as UpdateForm } from '../core-DnzqWy6u.js';
3
3
  import 'zod';
4
4
 
5
5
  /**
package/dist/pbt/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { replay, applyCell, msgKeysOf } from '../chunk-RQULHGYH.js';
1
+ import { replay, applyCell, msgKeysOf } from '../chunk-66PY5WYF.js';
2
2
  import * as fc from 'fast-check';
3
3
 
4
4
  // src/pbt/arbitraries/ctx.ts
@@ -1,8 +1,8 @@
1
- import { T as Trace } from '../index-TvRb1KVf.js';
2
- export { B as BreadcrumbsOptions, a as Recorder, R as RecorderOptions, b as TraceAttachment, c as TraceBreadcrumb, d as breadcrumbsFromTrace, p as parseJSONL, r as recorder, t as traceAttachment } from '../index-TvRb1KVf.js';
3
- export { h as SnapshotConfig, d as SnapshotFailedMsg, i as SnapshotKnob, g as SnapshotLoadCmd, f as SnapshotLoadFailedMsg, e as SnapshotLoadedMsg, j as SnapshotPorts, c as SnapshotSavedMsg, a as SnapshotState, b as SnapshotStore, S as SnapshotWriteCmd, k as createSnapshot, s as snapshotFailed, l as snapshotLoad, m as snapshotLoadFailed, n as snapshotLoaded, o as snapshotSaved, p as snapshotWriteDef } from '../index-DMCeMPMJ.js';
4
- import { C as Cmd, S as Sub, M as Machine } from '../core-CTzMJ82M.js';
5
- import '../runtime-types-LWDoi943.js';
1
+ import { T as Trace } from '../index-DrIRb_Ch.js';
2
+ export { B as BreadcrumbsOptions, a as Recorder, R as RecorderOptions, b as TraceAttachment, c as TraceBreadcrumb, d as breadcrumbsFromTrace, p as parseJSONL, r as recorder, t as traceAttachment } from '../index-DrIRb_Ch.js';
3
+ export { h as SnapshotConfig, d as SnapshotFailedMsg, i as SnapshotKnob, g as SnapshotLoadCmd, f as SnapshotLoadFailedMsg, e as SnapshotLoadedMsg, j as SnapshotPorts, c as SnapshotSavedMsg, a as SnapshotState, b as SnapshotStore, S as SnapshotWriteCmd, k as createSnapshot, s as snapshotFailed, l as snapshotLoad, m as snapshotLoadFailed, n as snapshotLoaded, o as snapshotSaved, p as snapshotWriteDef } from '../index-ZCMhnVKN.js';
4
+ import { C as Cmd, S as Sub, M as Machine } from '../core-DnzqWy6u.js';
5
+ import '../runtime-types-CMF13BBh.js';
6
6
  import 'better-result';
7
7
  import 'zod';
8
8
 
@@ -1,6 +1,6 @@
1
- export { breadcrumbsFromTrace, deepEqual, parseJSONL, recorder, replayTrace, traceAttachment } from '../chunk-BLJ2JQSH.js';
2
- export { createSnapshot, snapshotFailed, snapshotLoad, snapshotLoadFailed, snapshotLoaded, snapshotSaved, snapshotWriteDef } from '../chunk-HUKZQX6U.js';
1
+ export { breadcrumbsFromTrace, deepEqual, parseJSONL, recorder, replayTrace, traceAttachment } from '../chunk-V46HSVCK.js';
2
+ export { createSnapshot, snapshotFailed, snapshotLoad, snapshotLoadFailed, snapshotLoaded, snapshotSaved, snapshotWriteDef } from '../chunk-L3TND7LA.js';
3
3
  import '../chunk-HWVW4AXC.js';
4
- import '../chunk-RQULHGYH.js';
4
+ import '../chunk-66PY5WYF.js';
5
5
  //# sourceMappingURL=index.js.map
6
6
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The closed set of cross-module Msg/Cmd discriminant strings. Declared `as
3
+ * const` so each entry is usable as both a value (construction / reducer keys /
4
+ * switch labels) and, via `typeof MsgType.X`, a literal type (`readonly type:`
5
+ * fields). The single source of truth for issue #60.
6
+ */
7
+ declare const MsgType: {
8
+ /** The "run the port for `key`" effect Cmd resilient-call emits. */
9
+ readonly ResilientRun: "resilient_run";
10
+ /** PRIVATE success settle Msg (read only by `agentEvents`, #47). */
11
+ readonly ResilientOk: "resilient_ok";
12
+ /** Failure settle Msg — routed to the `fail` verb (back off via retry). */
13
+ readonly ResilientErr: "resilient_err";
14
+ /** Begin a run. */
15
+ readonly AgentStart: "agent_start";
16
+ /** PRIVATE tool-fan-out success settle Msg (read only by `agentEvents`, #47). */
17
+ readonly AgentToolOk: "agent_tool_ok";
18
+ /** Tool-fan-out failure settle Msg. */
19
+ readonly AgentToolErr: "agent_tool_err";
20
+ /**
21
+ * Re-fire the one outstanding effect on rehydrate (the do↔agent seam). Fired
22
+ * by `do/host`'s `autoBoot` via the typed `agentBootMsg` constructor, matched
23
+ * by the agent reducer — see `AgentBootPort` in `../agent`.
24
+ */
25
+ readonly AgentBoot: "agent_boot";
26
+ /**
27
+ * Stop the run from outside and settle it `cancelled` — what an `AbortSignal`
28
+ * handed to `driveToDone` / a defined agent's `run` dispatches on abort. A
29
+ * transition, never a throw: the outcome lands in the Model, so a reload reads
30
+ * a run that ended rather than one to resume.
31
+ */
32
+ readonly AgentCancel: "agent_cancel";
33
+ /**
34
+ * The "summarize the oldest N turns" effect Cmd the agent emits when its
35
+ * `CompactionPolicy` asks to compact before a brain call. A DEDICATED
36
+ * round-trip (design B1), distinct from the brain call's `resilient_run`, so
37
+ * compaction is its own honest `Awaiting` state — see `../agent`.
38
+ */
39
+ readonly CompactRun: "compact_run";
40
+ /** Compaction round-trip resolved — carries the summary text the fold-back folds. */
41
+ readonly CompactOk: "compact_ok";
42
+ /** Compaction round-trip failed (exhausted retry) — surfaced as data, not a stall. */
43
+ readonly CompactErr: "compact_err";
44
+ /** Refresh port resolved — carries the fresh `Token`. */
45
+ readonly TokenRefreshed: "token_refreshed";
46
+ /** Refresh port rejected — carries the rejection (errors are data). */
47
+ readonly TokenRefreshFailed: "token_refresh_failed";
48
+ /** The 401 the consumer dispatches when a guarded call comes back unauthorized. */
49
+ readonly Unauthorized: "unauthorized";
50
+ };
51
+ /** The union of every discriminant string in the protocol. */
52
+ type MsgTypeValue = (typeof MsgType)[keyof typeof MsgType];
53
+
54
+ export { MsgType as M, type MsgTypeValue as a };
@@ -1,5 +1,5 @@
1
- import { S as Store, R as Runtime } from '../runtime-types-LWDoi943.js';
2
- import { C as Cmd, S as Sub, M as Machine, R as RequiredCtx } from '../core-CTzMJ82M.js';
1
+ import { S as Store, R as Runtime } from '../runtime-types-CMF13BBh.js';
2
+ import { C as Cmd, S as Sub, M as Machine, R as RequiredCtx } from '../core-DnzqWy6u.js';
3
3
  import 'better-result';
4
4
  import 'zod';
5
5
 
@@ -1,4 +1,4 @@
1
- import { run } from '../chunk-RQULHGYH.js';
1
+ import { run } from '../chunk-66PY5WYF.js';
2
2
  import { useMemo, useRef, useReducer, useSyncExternalStore, useEffect } from 'react';
3
3
 
4
4
  function useMachine(machine, opts) {
@@ -1,11 +1,12 @@
1
- import { a as CmdOf, b as CmdDef, C as Cmd, I as Interpret, i as CmdValue, g as PortEmitter, S as Sub, M as Machine } from '../core-CTzMJ82M.js';
2
- import { M as MsgType, e as ResilientConfig, a as ResilientState, R as RunCmd, S as SucceedMsg, F as FailMsg, f as ResilientTimerMsg, d as ResilientPorts } from '../index-B5BZ-_cT.js';
3
- export { g as CacheConfig, h as CallBudget, i as CallPhase, C as CircuitConfig, j as CircuitPolicy, k as CircuitState, l as DeadlineExceededError, c as RateLimitConfig, D as ResilientCallDeadlineConfig, m as RunCmdDef, n as SlidingWindow, T as TokenBucket, o as canPass, p as createResilientCall, q as defaultCircuitPolicy, r as initBucket, s as initCircuit, t as initWindow, u as liftResilience, v as onFailure, w as onSuccess, x as record, y as refill, z as remaining, A as runCmdDef, B as tryConsume } from '../index-B5BZ-_cT.js';
4
- import { a as DeadlineSub } from '../index-q0hXFeZ0.js';
5
- export { A as ArmTimer, e as CacheEntry, c as CacheEvictMsg, C as CacheEvictionSub, D as DeadlineExceeded, f as DeadlineOpts, T as TtlCache, g as cacheEvictMsg, h as cacheEvictionSub, i as cacheEvictionSubscribe, d as deadlineExceeded, b as deadlineSub, j as evictExpired, k as get, l as has, m as initCache, r as remove, n as set, o as setTimeoutArmTimer, s as subscribeDeadline, p as subscribeWith } from '../index-q0hXFeZ0.js';
1
+ import { a as CmdOf, b as CmdDef, C as Cmd, I as Interpret, l as CmdValue, g as PortEmitter, i as NoCtx, S as Sub, M as Machine } from '../core-DnzqWy6u.js';
2
+ import { M as MsgType } from '../protocol-D8VbH-VH.js';
3
+ import { e as ResilientConfig, a as ResilientState, R as RunCmd, S as SucceedMsg, F as FailMsg, f as ResilientTimerMsg, c as ResilientPorts } from '../index-CA_7I5g9.js';
4
+ export { g as CacheConfig, h as CallBudget, i as CallPhase, C as CircuitConfig, j as CircuitPolicy, k as CircuitState, l as DEFAULT_RESILIENT_NAME, n as DeadlineExceededError, o as DeadlineNameOf, p as DeadlineSettled, q as DefaultResilientName, M as MountConfig, r as MountableKnob, s as MountedCell, t as MountedResilientCall, b as RateLimitConfig, D as ResilientCallDeadlineConfig, u as ResilientDeadlineType, v as ResilientErrType, d as ResilientHandlers, w as ResilientOkType, x as ResilientRunType, y as RunCmdDef, z as Settle, A as SettleFold, B as SlidingWindow, T as TokenBucket, E as canPass, G as createResilientCall, H as defaultCircuitPolicy, I as initBucket, J as initCircuit, K as initWindow, L as liftResilience, m as mountResilientCall, N as onFailure, O as onSuccess, P as record, Q as refill, U as remaining, V as runCmdDef, W as tryConsume } from '../index-CA_7I5g9.js';
5
+ import { a as DeadlineSub } from '../index-HSYgG2Yt.js';
6
+ export { A as ArmTimer, e as CacheEntry, c as CacheEvictMsg, C as CacheEvictionSub, D as DeadlineExceeded, f as DeadlineMsgType, g as DeadlineOpts, T as TtlCache, h as cacheEvictMsg, i as cacheEvictionSub, j as cacheEvictionSubscribe, d as deadlineExceeded, k as deadlineMsgType, b as deadlineSub, l as evictExpired, m as get, n as has, o as initCache, r as remove, p as set, q as setTimeoutArmTimer, s as subscribeDeadline, t as subscribeWith } from '../index-HSYgG2Yt.js';
6
7
  import { Rng, RetryPolicy } from '../retry-backoff/index.js';
7
8
  import 'zod';
8
- import '../types-DP3f5NIl.js';
9
+ import '../types-BseNPIhr.js';
9
10
 
10
11
  /**
11
12
  * A minted credential: the opaque `value` to send on the wire, and the absolute
@@ -248,7 +249,7 @@ declare function createAuthedCall<I, R>(config: AuthedConfig, rng?: () => number
248
249
  } | {
249
250
  readonly [detail: string]: unknown;
250
251
  readonly _tag: "port_rejected";
251
- }, unknown>, ctx: Readonly<Record<never, never>>) => Promise<FailMsg | SucceedMsg<R>>;
252
+ }, unknown>, ctx: NoCtx) => Promise<SucceedMsg<R, "resilient"> | FailMsg<"resilient">>;
252
253
  };
253
254
  };
254
255
  /** The shape `createAuthedCall` returns — useful for typing a held knob. */
@@ -1,9 +1,9 @@
1
- import { MsgType, createResilientCall } from '../chunk-AQ6ZIMEA.js';
2
- export { canPass, createResilientCall, defaultCircuitPolicy, initBucket, initCircuit, initWindow, liftResilience, onFailure, onSuccess, record, refill, remaining, runCmdDef, tryConsume } from '../chunk-AQ6ZIMEA.js';
1
+ import { MsgType, createResilientCall } from '../chunk-AYS5N6WY.js';
2
+ export { DEFAULT_RESILIENT_NAME, canPass, createResilientCall, defaultCircuitPolicy, initBucket, initCircuit, initWindow, liftResilience, mountResilientCall, onFailure, onSuccess, record, refill, remaining, runCmdDef, tryConsume } from '../chunk-AYS5N6WY.js';
3
3
  import { defaultRng, initRetry, recordFailure, shouldRetry, nextDelayMs } from '../chunk-VBDU4JL6.js';
4
- import { subscribeDeadline } from '../chunk-F2US5BW6.js';
5
- export { cacheEvictMsg, cacheEvictionSub, cacheEvictionSubscribe, deadlineExceeded, deadlineSub, evictExpired, get, has, initCache, remove, set, setTimeoutArmTimer, subscribeDeadline, subscribeWith } from '../chunk-F2US5BW6.js';
6
- import { Cmd, msgKeysOf, applyCell, fromTimeout, tryInterpret, cmdEdgeOf, subId, without, formOf } from '../chunk-RQULHGYH.js';
4
+ import { subscribeDeadline } from '../chunk-22POWGFA.js';
5
+ export { cacheEvictMsg, cacheEvictionSub, cacheEvictionSubscribe, deadlineExceeded, deadlineMsgType, deadlineSub, evictExpired, get, has, initCache, remove, set, setTimeoutArmTimer, subscribeDeadline, subscribeWith } from '../chunk-22POWGFA.js';
6
+ import { Cmd, msgKeysOf, applyCell, fromTimeout, tryInterpret, cmdEdgeOf, subId, without, formOf } from '../chunk-66PY5WYF.js';
7
7
  import { z } from 'zod';
8
8
 
9
9
  function initTokenRefresh() {
@@ -1,5 +1,5 @@
1
1
  import { Result } from 'better-result';
2
- import { P as Port, N as NoCellError, C as Cmd, S as Sub, d as Reducer, A as AnyCmdDef, M as Machine, e as Settled, a as CmdOf, T as Transitions, f as RequirementsOf, g as PortEmitter, O as OkOf, E as ErrOf, U as UpdateForm, h as InterpretDetached } from './core-CTzMJ82M.js';
2
+ import { P as Port, N as NoCellError, C as Cmd, S as Sub, d as Reducer, A as AnyCmdDef, M as Machine, e as Settled, a as CmdOf, T as Transitions, f as RequirementsOf, g as PortEmitter, O as OkOf, E as ErrOf, U as UpdateForm, h as InterpretDetached } from './core-DnzqWy6u.js';
3
3
 
4
4
  /**
5
5
  * @packageDocumentation
@@ -1,5 +1,5 @@
1
- import { C as Cmd, S as Sub, M as Machine } from '../core-CTzMJ82M.js';
2
- import { R as Runtime } from '../runtime-types-LWDoi943.js';
1
+ import { C as Cmd, S as Sub, M as Machine, I as Interpret } from '../core-DnzqWy6u.js';
2
+ import { C as CtxArg, R as Runtime } from '../runtime-types-CMF13BBh.js';
3
3
  import 'zod';
4
4
  import 'better-result';
5
5
 
@@ -265,6 +265,150 @@ declare function bindMachine<S, M extends {
265
265
  type: string;
266
266
  }, C extends Cmd, U extends Sub, Ctx>(machine: Machine<S, M, C, U, Ctx>, ctx: Ctx): BoundMachine<S, M, C, U, Ctx>;
267
267
 
268
+ /**
269
+ * The default round bound when `opts.maxRounds` is omitted: **100**.
270
+ *
271
+ * A round is one drain of the pending Msgs plus one drain of the Cmds those
272
+ * folds emitted, so a settling machine costs a handful; 100 is loose enough
273
+ * that a legitimate retry ladder finishes inside it and tight enough that a
274
+ * genuine cycle stops rather than hangs.
275
+ */
276
+ declare const DEFAULT_MAX_ROUNDS = 100;
277
+ /**
278
+ * One entry of a driven run's history, in dispatch order.
279
+ *
280
+ * - `msg` — a Msg folded through the machine's reducer. The seed Msg is the
281
+ * first entry of every trace; every later one is a settle Msg a handler
282
+ * returned (or fired through its injected `dispatch`).
283
+ * - `cmd` — a Cmd handed to an interpret handler. It is recorded BEFORE the
284
+ * handler is awaited, so a trace recovered from a rejected handler names the
285
+ * Cmd that rejected as its last entry.
286
+ */
287
+ type DriveTraceEntry<M, C> = {
288
+ readonly kind: "msg";
289
+ readonly msg: M;
290
+ } | {
291
+ readonly kind: "cmd";
292
+ readonly cmd: C;
293
+ };
294
+ /** What a settled {@link drive} hands back. */
295
+ interface DriveResult<S, M, C> {
296
+ /** The state after the machine went quiet — no Msg pending, no Cmd unperformed. */
297
+ readonly state: S;
298
+ /**
299
+ * Every Msg folded and every Cmd dispatched, in order. Filtering it to its
300
+ * `msg` entries and replaying those through `replay` from the same initial
301
+ * state reproduces {@link DriveResult.state}.
302
+ */
303
+ readonly trace: readonly DriveTraceEntry<M, C>[];
304
+ }
305
+ /**
306
+ * {@link drive}'s `ctx` field. `CtxArg` widened by exactly one case: a machine
307
+ * declaring `ctx: undefined` in its `types` block — the pure shape every
308
+ * how-to on this package writes — may omit it too. `CtxArg` alone keeps `ctx`
309
+ * REQUIRED there, because `{}` is not assignable to `undefined`, which would
310
+ * make the common pure call site spell `{ ctx: undefined }` to say nothing.
311
+ * A machine whose `Ctx` carries a field a handler reads still requires it.
312
+ */
313
+ type DriveCtxArg<Ctx> = [undefined] extends [Ctx] ? {
314
+ readonly ctx?: Ctx;
315
+ } : CtxArg<Ctx>;
316
+ /**
317
+ * {@link drive}'s options. `ctx` is conditionally optional (see
318
+ * {@link DriveCtxArg}).
319
+ */
320
+ type DriveOptions<Ctx> = DriveCtxArg<Ctx> & {
321
+ /**
322
+ * The round bound. Exceeding it throws {@link DriveRoundsExceededError};
323
+ * `drive` never returns a half-driven state. Defaults to
324
+ * {@link DEFAULT_MAX_ROUNDS} (100).
325
+ */
326
+ readonly maxRounds?: number;
327
+ };
328
+ /**
329
+ * Raised when a driven machine is still emitting work after `maxRounds` rounds.
330
+ * Follows the tea error dialect (`override readonly name`) and carries a `_tag`
331
+ * discriminant, so a test branches on it by `instanceof` or on the tag.
332
+ *
333
+ * It carries the round count it stopped at and the PARTIAL trace up to that
334
+ * point, which is what a test needs to see the cycle — the bound alone says
335
+ * only that one exists.
336
+ */
337
+ declare class DriveRoundsExceededError<M, C> extends Error {
338
+ /** The bound that was exceeded. */
339
+ readonly maxRounds: number;
340
+ /** The round the driver stopped at — always `maxRounds + 1`. */
341
+ readonly rounds: number;
342
+ /** Every Msg folded and Cmd dispatched before the driver gave up. */
343
+ readonly trace: readonly DriveTraceEntry<M, C>[];
344
+ readonly name = "DriveRoundsExceededError";
345
+ readonly _tag: "DriveRoundsExceededError";
346
+ constructor(
347
+ /** The bound that was exceeded. */
348
+ maxRounds: number,
349
+ /** The round the driver stopped at — always `maxRounds + 1`. */
350
+ rounds: number,
351
+ /** Every Msg folded and Cmd dispatched before the driver gave up. */
352
+ trace: readonly DriveTraceEntry<M, C>[]);
353
+ }
354
+ /**
355
+ * Raised when a Cmd reaches {@link drive} with no handler for its `type` in the
356
+ * `handlers` record. `Interpret`'s mapped type makes that a compile error at a
357
+ * well-typed call site; this is the runtime arm for a handler record assembled
358
+ * dynamically or cast.
359
+ */
360
+ declare class DriveNoHandlerError<M, C> extends Error {
361
+ /** The Cmd `type` nothing in the handler record answered. */
362
+ readonly cmdType: string;
363
+ /** Every Msg folded and Cmd dispatched before the miss. */
364
+ readonly trace: readonly DriveTraceEntry<M, C>[];
365
+ readonly name = "DriveNoHandlerError";
366
+ readonly _tag: "DriveNoHandlerError";
367
+ constructor(
368
+ /** The Cmd `type` nothing in the handler record answered. */
369
+ cmdType: string,
370
+ /** Every Msg folded and Cmd dispatched before the miss. */
371
+ trace: readonly DriveTraceEntry<M, C>[]);
372
+ }
373
+ /**
374
+ * Read back the partial trace `drive` attached to an error a handler rejected
375
+ * with. Returns `undefined` for anything `drive` did not annotate.
376
+ *
377
+ * A rejecting handler's error propagates out of `drive` UNSWALLOWED — same
378
+ * value, same `instanceof`, same `_tag` — so a test that already branches on
379
+ * the handler's own error type keeps doing so. The trace rides along on a
380
+ * non-enumerable property so it is recoverable without changing how the error
381
+ * prints or serializes.
382
+ */
383
+ declare function driveTraceOf<M, C>(err: unknown): readonly DriveTraceEntry<M, C>[] | undefined;
384
+ /**
385
+ * Drive `machine` from `initial` through `msg` against the REAL interpret
386
+ * `handlers`, feeding every settle Msg back until the machine goes quiet, and
387
+ * hand back the settled state together with the whole history.
388
+ *
389
+ * `handlers` is the same record the machine declares as its `interpret` (e.g.
390
+ * `ask.handlers()` for a jev knob), so the test drives the real interpreter and
391
+ * mocks only the port beneath it.
392
+ *
393
+ * One round is: fold every pending Msg, then await a handler for every Cmd
394
+ * those folds emitted. A Msg a handler returns — or fires through its injected
395
+ * `dispatch` — is pending for the next round. A machine that emits no Cmd for
396
+ * its seed Msg therefore settles in ONE round and never awaits a handler at
397
+ * all.
398
+ *
399
+ * The `ctx` handed to each handler is `opts.ctx` augmented with a NO-OP `emit`,
400
+ * so a handler that emits to a `Port` runs without a live runtime; nothing here
401
+ * observes ports. Supply your own `emit` on `ctx` to capture them.
402
+ *
403
+ * @throws {DriveRoundsExceededError} when the machine is still emitting work
404
+ * after `opts.maxRounds` rounds. It never returns a half-driven state.
405
+ * @throws whatever a handler rejects with, unchanged — annotated with the
406
+ * partial trace, readable via {@link driveTraceOf}.
407
+ */
408
+ declare function drive<S, M extends {
409
+ type: string;
410
+ }, C extends Cmd, U extends Sub, Ctx>(machine: Machine<S, M, C, U, Ctx>, initial: S, msg: M, handlers: Interpret<M, C, Ctx>, ...[opts]: Record<never, never> extends DriveOptions<Ctx> ? [opts?: DriveOptions<Ctx>] : [opts: DriveOptions<Ctx>]): Promise<DriveResult<S, M, C>>;
411
+
268
412
  /**
269
413
  * Construct an inert `Runtime<S, M>` value. Use at ctx sites that require
270
414
  * a Runtime reference but where the test never invokes `interpret` (so
@@ -324,4 +468,4 @@ declare function stateFactory<S extends {
324
468
  type: string;
325
469
  }>(defaults: StateFactoryDefaults<S>): StateFactoryAPI<S>;
326
470
 
327
- export { type AssertWrapperFaithfulOpts, type BoundMachine, type InterceptingOpt, type ReplayOpts, type StateFactoryAPI, type StateFactoryDefaults, type WrapperModel, assertWrapperFaithful, bindMachine, expectActiveSubs, expectCmdEmitted, expectCmdSequence, expectFinalState, noopRuntime, stateFactory, step };
471
+ export { type AssertWrapperFaithfulOpts, type BoundMachine, DEFAULT_MAX_ROUNDS, type DriveCtxArg, DriveNoHandlerError, type DriveOptions, type DriveResult, DriveRoundsExceededError, type DriveTraceEntry, type InterceptingOpt, type ReplayOpts, type StateFactoryAPI, type StateFactoryDefaults, type WrapperModel, assertWrapperFaithful, bindMachine, drive, driveTraceOf, expectActiveSubs, expectCmdEmitted, expectCmdSequence, expectFinalState, noopRuntime, stateFactory, step };
@@ -1,4 +1,4 @@
1
- import { replay } from '../chunk-RQULHGYH.js';
1
+ import { replay } from '../chunk-66PY5WYF.js';
2
2
  import { expect, vi } from 'vitest';
3
3
 
4
4
  function assertWrapperFaithful(base, makeWrapped, opts) {
@@ -223,6 +223,99 @@ function bindMachine(machine, ctx) {
223
223
  };
224
224
  }
225
225
 
226
+ // src/testing/drive.ts
227
+ var DEFAULT_MAX_ROUNDS = 100;
228
+ var DriveRoundsExceededError = class extends Error {
229
+ constructor(maxRounds, rounds, trace) {
230
+ super(
231
+ `@demlik/tea: drive did not settle within ${maxRounds} round(s) \u2014 the machine was still emitting work at round ${rounds}. The partial trace (${trace.length} entr${trace.length === 1 ? "y" : "ies"}) is on the error's \`trace\` field.`
232
+ );
233
+ this.maxRounds = maxRounds;
234
+ this.rounds = rounds;
235
+ this.trace = trace;
236
+ }
237
+ maxRounds;
238
+ rounds;
239
+ trace;
240
+ name = "DriveRoundsExceededError";
241
+ _tag = "DriveRoundsExceededError";
242
+ };
243
+ var DriveNoHandlerError = class extends Error {
244
+ constructor(cmdType, trace) {
245
+ super(
246
+ `@demlik/tea: drive found no interpret handler for Cmd type "${cmdType}" \u2014 the handlers record must answer every Cmd the machine emits.`
247
+ );
248
+ this.cmdType = cmdType;
249
+ this.trace = trace;
250
+ }
251
+ cmdType;
252
+ trace;
253
+ name = "DriveNoHandlerError";
254
+ _tag = "DriveNoHandlerError";
255
+ };
256
+ var TRACE_KEY = "driveTrace";
257
+ function driveTraceOf(err) {
258
+ if (typeof err !== "object" || err === null) return void 0;
259
+ const carried = err[TRACE_KEY];
260
+ return Array.isArray(carried) ? carried : void 0;
261
+ }
262
+ async function drive(machine, initial, msg, handlers, ...[opts]) {
263
+ const options = opts ?? {};
264
+ const maxRounds = options.maxRounds ?? DEFAULT_MAX_ROUNDS;
265
+ const bound = bindMachine(machine, options.ctx);
266
+ const noopEmit = { emit: () => {
267
+ } };
268
+ const handlerCtx = {
269
+ ...noopEmit,
270
+ ...options.ctx
271
+ };
272
+ const cells = handlers;
273
+ const trace = [];
274
+ let state = initial;
275
+ let pending = [msg];
276
+ let round = 0;
277
+ while (pending.length > 0) {
278
+ round += 1;
279
+ if (round > maxRounds) {
280
+ throw new DriveRoundsExceededError(maxRounds, round, trace);
281
+ }
282
+ const folding = pending;
283
+ pending = [];
284
+ const emitted = [];
285
+ for (const next of folding) {
286
+ trace.push({ kind: "msg", msg: next });
287
+ const [advanced, cmds] = bound.step(state, next);
288
+ state = advanced;
289
+ emitted.push(...cmds);
290
+ }
291
+ for (const cmd of emitted) {
292
+ trace.push({ kind: "cmd", cmd });
293
+ const cell = cells[cmd.type];
294
+ if (cell === void 0) {
295
+ throw new DriveNoHandlerError(cmd.type, trace);
296
+ }
297
+ let settle;
298
+ try {
299
+ settle = await cell(cmd, handlerCtx, (fired) => {
300
+ pending.push(fired);
301
+ });
302
+ } catch (err) {
303
+ if (typeof err === "object" && err !== null) {
304
+ Object.defineProperty(err, TRACE_KEY, {
305
+ value: [...trace],
306
+ enumerable: false,
307
+ configurable: true,
308
+ writable: true
309
+ });
310
+ }
311
+ throw err;
312
+ }
313
+ if (settle !== void 0) pending.push(settle);
314
+ }
315
+ }
316
+ return { state, trace };
317
+ }
318
+
226
319
  // src/testing/noop-runtime.ts
227
320
  function noopRuntime(opts) {
228
321
  const initialState = opts?.initialState;
@@ -297,6 +390,6 @@ function stateFactory(defaults) {
297
390
  return api;
298
391
  }
299
392
 
300
- export { assertWrapperFaithful, bindMachine, expectActiveSubs, expectCmdEmitted, expectCmdSequence, expectFinalState, noopRuntime, stateFactory, step };
393
+ export { DEFAULT_MAX_ROUNDS, DriveNoHandlerError, DriveRoundsExceededError, assertWrapperFaithful, bindMachine, drive, driveTraceOf, expectActiveSubs, expectCmdEmitted, expectCmdSequence, expectFinalState, noopRuntime, stateFactory, step };
301
394
  //# sourceMappingURL=index.js.map
302
395
  //# sourceMappingURL=index.js.map