@demlik/tea 0.15.0 → 0.16.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 (115) hide show
  1. package/README.md +30 -7
  2. package/dist/agent/index.d.ts +49 -37
  3. package/dist/agent/index.js +12 -8
  4. package/dist/chunk-4LPY67E4.js +18 -0
  5. package/dist/chunk-4LPY67E4.js.map +1 -0
  6. package/dist/chunk-5XU6ZJO2.js +533 -0
  7. package/dist/chunk-5XU6ZJO2.js.map +1 -0
  8. package/dist/{chunk-AYS5N6WY.js → chunk-6NG4V5SB.js} +62 -172
  9. package/dist/chunk-6NG4V5SB.js.map +1 -0
  10. package/dist/{chunk-3B5X7SBB.js → chunk-7MGXQZPW.js} +11 -9
  11. package/dist/chunk-7MGXQZPW.js.map +1 -0
  12. package/dist/{chunk-V46HSVCK.js → chunk-BCTEOVOU.js} +3 -3
  13. package/dist/{chunk-V46HSVCK.js.map → chunk-BCTEOVOU.js.map} +1 -1
  14. package/dist/chunk-CH5KTOEZ.js +710 -0
  15. package/dist/chunk-CH5KTOEZ.js.map +1 -0
  16. package/dist/chunk-CIHSHLQX.js +64 -0
  17. package/dist/chunk-CIHSHLQX.js.map +1 -0
  18. package/dist/{chunk-TCLBCERH.js → chunk-EHUDXAKC.js} +238 -212
  19. package/dist/chunk-EHUDXAKC.js.map +1 -0
  20. package/dist/chunk-GOX2CYIM.js +380 -0
  21. package/dist/chunk-GOX2CYIM.js.map +1 -0
  22. package/dist/{chunk-22POWGFA.js → chunk-IVJP3GKJ.js} +46 -20
  23. package/dist/chunk-IVJP3GKJ.js.map +1 -0
  24. package/dist/{chunk-QPEVCJ5Q.js → chunk-MVZS5FDM.js} +13 -6
  25. package/dist/chunk-MVZS5FDM.js.map +1 -0
  26. package/dist/{chunk-VTQI2NHP.js → chunk-MYNLY3HP.js} +9 -8
  27. package/dist/chunk-MYNLY3HP.js.map +1 -0
  28. package/dist/{chunk-Q5CQTBFA.js → chunk-NSIAORRY.js} +20 -30
  29. package/dist/chunk-NSIAORRY.js.map +1 -0
  30. package/dist/{chunk-MYXFNWAJ.js → chunk-QNGYQMZB.js} +4 -4
  31. package/dist/chunk-QNGYQMZB.js.map +1 -0
  32. package/dist/chunk-WT5PBPLB.js +98 -0
  33. package/dist/chunk-WT5PBPLB.js.map +1 -0
  34. package/dist/{core-DnzqWy6u.d.ts → core-BbgtiXdg.d.ts} +231 -139
  35. package/dist/do/index.d.ts +37 -33
  36. package/dist/do/index.js +21 -14
  37. package/dist/do/index.js.map +1 -1
  38. package/dist/{durable-effects-CWzA-o2B.d.ts → durable-effects-7MTK_jnj.d.ts} +1 -1
  39. package/dist/effect/index.d.ts +151 -0
  40. package/dist/effect/index.js +98 -0
  41. package/dist/effect/index.js.map +1 -0
  42. package/dist/extension/index.d.ts +6 -7
  43. package/dist/extension/index.js +3 -2
  44. package/dist/extension/index.js.map +1 -1
  45. package/dist/flow/index.d.ts +68 -59
  46. package/dist/flow/index.js +32 -27
  47. package/dist/flow/index.js.map +1 -1
  48. package/dist/idempotency/index.d.ts +6 -7
  49. package/dist/idempotency/index.js +4 -2
  50. package/dist/{index-CSyMYDAB.d.ts → index-7vV8xmsD.d.ts} +1 -1
  51. package/dist/{index-KXqTRJyb.d.ts → index-Bz5Rh9Ga.d.ts} +19 -96
  52. package/dist/index-CjFDUBeq.d.ts +207 -0
  53. package/dist/{index-CuNO9m8i.d.ts → index-CkFYA9Y6.d.ts} +14 -16
  54. package/dist/{index-CA_7I5g9.d.ts → index-Cou86-GX.d.ts} +137 -246
  55. package/dist/{index-DrIRb_Ch.d.ts → index-DU6JpQ8G.d.ts} +1 -1
  56. package/dist/{index-HSYgG2Yt.d.ts → index-Xufl55W8.d.ts} +247 -211
  57. package/dist/{index-C2DwkjlP.d.ts → index-_dOR3xqA.d.ts} +57 -45
  58. package/dist/index.d.ts +121 -385
  59. package/dist/index.js +2 -1
  60. package/dist/jev/index.d.ts +133 -97
  61. package/dist/jev/index.js +205 -161
  62. package/dist/jev/index.js.map +1 -1
  63. package/dist/{machine-DGlPWCWI.d.ts → machine-BQzTV8On.d.ts} +171 -288
  64. package/dist/machine-viz/index.d.ts +5 -5
  65. package/dist/machine-viz/index.js +8 -4
  66. package/dist/machine-viz/index.js.map +1 -1
  67. package/dist/mem/index.d.ts +3 -4
  68. package/dist/mem/index.js +2 -1
  69. package/dist/mem/index.js.map +1 -1
  70. package/dist/node/index.d.ts +119 -78
  71. package/dist/node/index.js +52 -38
  72. package/dist/node/index.js.map +1 -1
  73. package/dist/paginate/index.d.ts +27 -22
  74. package/dist/paginate/index.js +6 -4
  75. package/dist/parity/index.d.ts +4 -5
  76. package/dist/parity/index.js +3 -2
  77. package/dist/parity/index.js.map +1 -1
  78. package/dist/pbt/index.d.ts +2 -2
  79. package/dist/pbt/index.js +2 -1
  80. package/dist/pbt/index.js.map +1 -1
  81. package/dist/persistence/index.d.ts +6 -7
  82. package/dist/persistence/index.js +5 -3
  83. package/dist/promise/index.d.ts +186 -0
  84. package/dist/promise/index.js +5 -0
  85. package/dist/promise/index.js.map +1 -0
  86. package/dist/{protocol-D8VbH-VH.d.ts → protocol-ClRZBhHQ.d.ts} +7 -8
  87. package/dist/react/index.d.ts +36 -17
  88. package/dist/react/index.js +27 -4
  89. package/dist/react/index.js.map +1 -1
  90. package/dist/resilience/index.d.ts +63 -456
  91. package/dist/resilience/index.js +37 -483
  92. package/dist/resilience/index.js.map +1 -1
  93. package/dist/{runtime-types-CMF13BBh.d.ts → runtime-types-CiVpC0HN.d.ts} +131 -388
  94. package/dist/testing/index.d.ts +22 -16
  95. package/dist/testing/index.js +15 -7
  96. package/dist/testing/index.js.map +1 -1
  97. package/dist/timing/index.d.ts +25 -22
  98. package/dist/timing/index.js +4 -3
  99. package/dist/timing/index.js.map +1 -1
  100. package/dist/{types-BseNPIhr.d.ts → types-LxZxGYda.d.ts} +2 -2
  101. package/dist/work-queue/index.d.ts +5 -6
  102. package/package.json +18 -5
  103. package/dist/chunk-22POWGFA.js.map +0 -1
  104. package/dist/chunk-3B5X7SBB.js.map +0 -1
  105. package/dist/chunk-66PY5WYF.js +0 -1816
  106. package/dist/chunk-66PY5WYF.js.map +0 -1
  107. package/dist/chunk-AYS5N6WY.js.map +0 -1
  108. package/dist/chunk-L3TND7LA.js +0 -97
  109. package/dist/chunk-L3TND7LA.js.map +0 -1
  110. package/dist/chunk-MYXFNWAJ.js.map +0 -1
  111. package/dist/chunk-Q5CQTBFA.js.map +0 -1
  112. package/dist/chunk-QPEVCJ5Q.js.map +0 -1
  113. package/dist/chunk-TCLBCERH.js.map +0 -1
  114. package/dist/chunk-VTQI2NHP.js.map +0 -1
  115. package/dist/index-ZCMhnVKN.d.ts +0 -272
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
- export { Cmd, DispatchDiscardedError, DisposeTimeoutNotice, DriveFailedError, DriveStalledError, IdentityDropNotice, NO_ACK, NoCellError, PortNameCollisionError, ProvideFailedError, ProviderCycleError, QuiescenceTimeoutError, RuntimeDiscardNotice, RuntimeDiscardedError, StoreConflictError, SubIdCollisionError, UnknownProviderError, __resetPortRegistry, absurd, acceptedTypes, acceptsOf, ack, applyCell, applyCellChecked, asReducer, combineManagedResources, defineListener, defineMachine, defineManagedResource, definePort, dep, describeMachine, detectUpdateForm, driveToDone, foldMsgs, foldUpdates, formOf, fromBroadcastChannel, fromEventSource, fromEventTarget, fromInterval, fromPort, fromReconnectingWebSocket, fromTimeout, fromTransport, fromWebSocket, historyTracker, initAck, isFencedStore, isProvided, layer, liftSlice, msgKeysOf, nextSeq, noop, partitionByAck, provide, readInOrder, reconcile, replay, run, schemaMigrate, settle, structuralHash, subId, tagSeq, tryApplyCell, tryFoldMsgs, tryInterpret, value, wrapDetached } from './chunk-66PY5WYF.js';
1
+ export { NO_ACK, ack, defineListener, defineManagedResource, fromBroadcastChannel, fromEventSource, fromEventTarget, fromInterval, fromPort, fromReconnectingWebSocket, fromTimeout, fromTransport, fromWebSocket, historyTracker, initAck, liftSlice, nextSeq, partitionByAck, readInOrder, reconcile, tagSeq } from './chunk-GOX2CYIM.js';
2
+ export { AsyncSchemaError, Cmd, DispatchDiscardedError, DisposeTimeoutNotice, DriveFailedError, DriveStalledError, IdentityDropNotice, NoCellError, Outcome, OutcomeContractError, PortNameCollisionError, QuiescenceTimeoutError, RuntimeDiscardNotice, RuntimeDiscardedError, StoreConflictError, UndeclaredFailureError, __resetPortRegistry, absurd, acceptedTypes, acceptsOf, applyCell, applyCellChecked, asReducer, defineMachine, definePort, describeMachine, detectUpdateForm, foldMsgs, foldUpdates, formOf, isFencedStore, msgKeysOf, noop, replay, schemaMigrate, structuralHash, subId, subIdOf, tryApplyCell, tryFoldMsgs, tryInterpret, wrapDetached } from './chunk-CH5KTOEZ.js';
2
3
  //# sourceMappingURL=index.js.map
3
4
  //# sourceMappingURL=index.js.map
@@ -1,16 +1,13 @@
1
- import { b as CmdDef, C as Cmd } from '../core-DnzqWy6u.js';
1
+ import { R as RunCmd, F as FailMsg, S as SucceedMsg, a as ResilientState, b as ResilientTimerMsg } from '../index-Cou86-GX.js';
2
+ import { l as Outcome, b as CmdDef, T as TimerDeps, C as Cmd, o as DepKeyedSub, q as TimerSub } from '../core-BbgtiXdg.js';
2
3
  import { RetryPolicy } from '../retry-backoff/index.js';
3
- import { R as RunCmd, F as FailMsg, S as SucceedMsg, a as ResilientState } from '../index-CA_7I5g9.js';
4
- export { m as mountResilientCall } from '../index-CA_7I5g9.js';
5
- import { a as DeadlineSub, D as DeadlineExceeded, T as TtlCache, C as CacheEvictionSub, c as CacheEvictMsg } from '../index-HSYgG2Yt.js';
6
- export { b as deadlineSub, s as subscribeDeadline } from '../index-HSYgG2Yt.js';
7
- import { S as SubscribeHandler } from '../types-BseNPIhr.js';
8
- import { B as BatchWindow, a as BatchWindowSub, b as BatchWindowExpired } from '../index-C2DwkjlP.js';
9
- import { F as FanOutState } from '../index-CuNO9m8i.js';
10
- import 'zod';
11
- import '../index-CSyMYDAB.js';
12
- import '../runtime-types-CMF13BBh.js';
13
- import 'better-result';
4
+ import { D as DeadlineExceeded, a as DeadlineSub, T as TtlCache, C as CacheEvictionSub, f as CacheEvictMsg } from '../index-Xufl55W8.js';
5
+ import { S as SubscribeHandler } from '../types-LxZxGYda.js';
6
+ import { B as BatchWindow, a as BatchWindowSub, b as BatchWindowExpired } from '../index-_dOR3xqA.js';
7
+ import { F as FanOutState } from '../index-CkFYA9Y6.js';
8
+ import '@standard-schema/spec';
9
+ import '../index-7vV8xmsD.js';
10
+ import '../runtime-types-CiVpC0HN.js';
14
11
 
15
12
  /**
16
13
  * @packageDocumentation
@@ -60,19 +57,19 @@ import 'better-result';
60
57
  * network actually produced. Every `unknown` reaches a `JevErr`; nothing
61
58
  * reaches a `throw`.
62
59
  *
63
- * The check itself is a `zod` schema DERIVED from the questions map, so the
64
- * typed value is what `safeParse` returns rather than something asserted after
65
- * a hand-walk. Both halves of a choice question's claim are structural in that
66
- * schema: `choice` is a `z.enum` over the criteria keys, and `probabilities`
67
- * is a strict `z.object` whose shape IS those keys — so a distribution missing
68
- * one or carrying an extra fails the schema rather than a separate arm a later
69
- * reader has to remember. A partial distribution typed `Record<K, number>` is
60
+ * The check itself is a walk DERIVED from the questions map, one step per
61
+ * field, and the typed value is the fresh object it builds. Both halves of a
62
+ * choice question's claim are structural in that walk: `choice` must be one of
63
+ * the criteria keys, and `probabilities` must carry exactly those keys — so a
64
+ * distribution missing one or carrying an extra fails the check rather than a
65
+ * separate arm a later reader has to remember. A partial distribution typed `Record<K, number>` is
70
66
  * the representable-invalid state this module exists to refuse, and it arrives
71
67
  * through this gate or not at all. The envelope is checked by the same schema:
72
68
  * `model` is a string and `usage` carries two finite numbers.
73
69
  *
74
- * `safeParse`, never `parse`: a zod failure is turned into a `JevErr` value by
75
- * mapping its first issue's path onto the arm that names it.
70
+ * The walk stops at the first field that fails, and that field's path is
71
+ * mapped onto the `JevErr` arm that names it. It is hand-written rather than a
72
+ * schema library's so the published package depends on none (ADR 0021 §5).
76
73
  *
77
74
  * ## Why status classification lives here and not in `ask`
78
75
  *
@@ -316,39 +313,33 @@ type JevHttpStatus = "ok" | "retry" | "terminal";
316
313
  declare const classifyStatus: (status: number) => JevHttpStatus;
317
314
 
318
315
  /**
319
- * The injected HTTP caller — the one seam that touches the network.
316
+ * What an HTTP call to Jev came back with: the status and the undecoded body.
320
317
  *
321
- * It returns the status and the undecoded body rather than throwing on a
318
+ * Your handler returns this to {@link decodeJevReply} rather than throwing on a
322
319
  * non-2xx, because WHICH non-2xx it is decides whether the call backs off, and
323
- * a thrown adapter error has already lost that. `signal` is optional so a
324
- * `fetch` adapter can be cancelled; resilient-call issues no signal today, and
325
- * the slot exists so an adapter's own shape does not have to change when it
326
- * does.
327
- *
328
- * A `fetch` adapter and a scripted test fake satisfy this identically, which is
329
- * the whole reason the key lives in the adapter's closure and never in config.
320
+ * a thrown error has already lost that.
330
321
  */
331
- type JevPort<Q extends JevQuestionMap = JevQuestionMap> = (request: JevRequest<Q>, signal?: AbortSignal) => Promise<{
322
+ interface JevHttpReply {
332
323
  readonly status: number;
333
324
  readonly body: unknown;
334
- }>;
325
+ }
335
326
  /**
336
327
  * The pure decider that answers when the network cannot.
337
328
  *
338
- * Called on exactly two paths: `port` is absent (the no-key case), and the
339
- * resilient retry budget is spent. It must be a pure function of the request —
340
- * the exhaustion path runs it inside the `fail` VERB, which replay re-runs, so
341
- * a clock read or an I/O call here would make the machine unreplayable.
342
- * Returning a {@link JevErr} is how a fallback says "I have no answer for
343
- * this one"; the call then settles as that error.
329
+ * Called on exactly two paths: a handler with no key returns
330
+ * {@link offlineJevAnswer}, and the resilient retry budget is spent. It must
331
+ * be a pure function of the request — the exhaustion path runs it inside the
332
+ * `fail` VERB, which replay re-runs, so a clock read or an I/O call here would
333
+ * make the machine unreplayable. Returning a {@link JevErr} is how a fallback
334
+ * says "I have no answer for this one"; the call then settles as that error.
344
335
  */
345
336
  type JevFallback<Q extends JevQuestionMap> = (request: JevRequest<Q>) => JevAnswers<Q> | JevErr;
346
337
  /**
347
338
  * Every way an ask can fail, as DATA.
348
339
  *
349
340
  * A superset of the protocol child's {@link JevErr}: a parse failure is
350
- * reported with the protocol's own tag untouched, and the three tags below are
351
- * the ones only a caller can observe. `{_tag}`-discriminated and
341
+ * reported with the protocol's own tag untouched, and the tags below are the
342
+ * ones only a caller can observe. `{_tag}`-discriminated and
352
343
  * JSON-round-trippable like the rest (ADR 0011), because it is carried on the
353
344
  * settle Msg and stored in the slice's `failed` phase.
354
345
  *
@@ -366,12 +357,12 @@ type JevAskErr = JevErr
366
357
  readonly _tag: "http_terminal";
367
358
  readonly status: number;
368
359
  }
369
- /** The port itself rejected (a socket error, a DNS failure) — transient. */
360
+ /** The call itself threw (a socket error, a DNS failure) — transient. */
370
361
  | {
371
362
  readonly _tag: "port_threw";
372
363
  readonly reason: string;
373
364
  }
374
- /** No `port` and no `fallback`: the knob was configured with no way to answer. */
365
+ /** No key and no `fallback`: the knob was configured with no way to answer. */
375
366
  | {
376
367
  readonly _tag: "no_answer_path";
377
368
  };
@@ -385,19 +376,23 @@ type JevAskErr = JevErr
385
376
  */
386
377
  declare function isTransientJevAskErr(error: JevAskErr): boolean;
387
378
  /**
388
- * The carrier that gets a {@link JevAskErr} out of the port and through
389
- * resilient-call's throw seam intact.
390
- *
391
- * resilient-call routes a rejected port to a failure Msg carrying the raw
392
- * thrown value, so throwing is the only way the handler can say "this attempt
393
- * failed" — and a bare `Error` would arrive with its classification already
394
- * lost. The typed payload rides on `jev`; the slice never stores this object
395
- * (the verbs store `jev` itself), so nothing un-serializable reaches Model.
379
+ * How a {@link JevAskErr} crosses the handler: the run Cmd's declared
380
+ * `port_rejected` tag, with the typed error on `jev`. The engine mints it into
381
+ * `resilient_run_err` untouched, and {@link jevAskErrOf} reads it back.
396
382
  */
397
- declare class JevAskFailure extends Error {
383
+ type JevRejected = {
384
+ readonly _tag: "port_rejected";
398
385
  readonly jev: JevAskErr;
399
- constructor(jev: JevAskErr);
400
- }
386
+ };
387
+ /**
388
+ * Read a settled failure back as a {@link JevAskErr}. PURE.
389
+ *
390
+ * A {@link JevRejected} yields its `jev`. Anything else a handler returned —
391
+ * a bare `port_rejected`, a `deadline_exceeded` — is a failure this door did
392
+ * not classify, and it reads as the transient `port_threw`, exactly as a
393
+ * foreign throw always has.
394
+ */
395
+ declare function jevAskErrOf(error: unknown): JevAskErr;
401
396
  /** The model the door asks for when config names none. */
402
397
  declare const DEFAULT_JEV_MODEL = "jev-latest";
403
398
  /**
@@ -408,9 +403,7 @@ declare const DEFAULT_JEV_MODEL = "jev-latest";
408
403
  interface JevAskConfig<Q extends JevQuestionMap> {
409
404
  /** The question map every request carries; its keys type the answers. */
410
405
  readonly questions: Q;
411
- /** DI port — the HTTP caller. Absent = the no-key case; `fallback` answers instead. */
412
- readonly port?: JevPort<Q>;
413
- /** The pure decider for the no-port and budget-spent paths. Absent → those settle as an error. */
406
+ /** The pure decider for the no-key and budget-spent paths. Absent → those settle as an error. */
414
407
  readonly fallback?: JevFallback<Q>;
415
408
  /** Backoff policy, composed into `../../resilience/resilient-call`. Omit → no backoff. */
416
409
  readonly retry?: RetryPolicy;
@@ -418,7 +411,7 @@ interface JevAskConfig<Q extends JevQuestionMap> {
418
411
  readonly model?: string;
419
412
  }
420
413
  /**
421
- * The settled answer carried on `resilient_ok`.
414
+ * The settled answer carried on `resilient_run_ok`.
422
415
  *
423
416
  * `source` is not decoration: a fallback answer and a model answer are both
424
417
  * valid answers with identical shape, and a host that routes on confidence — or
@@ -435,6 +428,27 @@ interface JevOk<Q extends JevQuestionMap> {
435
428
  /** Which path produced this answer. */
436
429
  readonly source: "port" | "fallback";
437
430
  }
431
+ /**
432
+ * Turn an HTTP reply into the run Cmd's outcome. PURE: classify the status,
433
+ * then parse the body against the questions the request carried.
434
+ *
435
+ * `ok` → the typed {@link JevOk}; a 429 / 529 → the transient `http_retry`;
436
+ * any other non-2xx → the terminal `http_terminal`; a body that disagrees with
437
+ * the questions → the protocol's own {@link JevErr}. Every failure is a
438
+ * {@link JevRejected}.
439
+ */
440
+ declare function decodeJevReply<Q extends JevQuestionMap>(request: JevRequest<Q>, reply: JevHttpReply): Outcome<JevOk<Q>, JevRejected>;
441
+ /**
442
+ * The outcome for a call that threw before Jev answered — a socket error, a
443
+ * DNS failure. PURE. It is the transient `port_threw`, so it backs off.
444
+ */
445
+ declare function jevCallThrew(cause: unknown): Outcome<never, JevRejected>;
446
+ /**
447
+ * The outcome with no network at all: the fallback's answer, or its refusal,
448
+ * or `no_answer_path` when there is no fallback. PURE — what a handler with
449
+ * no key returns.
450
+ */
451
+ declare function offlineJevAnswer<Q extends JevQuestionMap>(request: JevRequest<Q>, fallback: JevFallback<Q> | undefined): Outcome<JevOk<Q>, JevRejected>;
438
452
  /**
439
453
  * The one effect this knob emits: run the ask for `key` with the plain-data
440
454
  * {@link JevRequest} (ADR 0014 — a Cmd is DECLARED, so its input, ok and err
@@ -452,15 +466,17 @@ declare function jevAskCmdDef<Q extends JevQuestionMap>(): CmdDef<"resilient_run
452
466
  } | {
453
467
  readonly [detail: string]: unknown;
454
468
  readonly _tag: "port_rejected";
455
- }, unknown>;
469
+ }>;
456
470
  /** The Cmd the verbs emit — `resilient_run` carrying the request. */
457
- type JevAskCmd<Q extends JevQuestionMap> = RunCmd<JevRequest<Q>>;
458
- /** The success settle Msg — resilient-call's, with `result` narrowed to {@link JevOk}. */
471
+ type JevAskCmd<Q extends JevQuestionMap> = RunCmd<JevRequest<Q>, "resilient", JevOk<Q>>;
472
+ /** The success settle Msg — resilient-call's, with `value` narrowed to {@link JevOk}. */
459
473
  type JevSucceedMsg<Q extends JevQuestionMap> = SucceedMsg<JevOk<Q>>;
460
- /** The failure settle Msg — resilient-call's, with `error` narrowed to {@link JevAskErr}. */
461
- type JevFailMsg = Omit<FailMsg, "error"> & {
462
- readonly error: JevAskErr;
463
- };
474
+ /**
475
+ * The failure settle Msg the engine mints — resilient-call's. Its `error` is a
476
+ * {@link JevRejected} when your handler used this door's builders; `fail`
477
+ * reads it with {@link jevAskErrOf}.
478
+ */
479
+ type JevFailMsg = FailMsg;
464
480
  /** The retry / deadline timer Msg — `DeadlineExceeded`, inherited. */
465
481
  type JevTimerMsg = DeadlineExceeded;
466
482
  /**
@@ -468,41 +484,46 @@ type JevTimerMsg = DeadlineExceeded;
468
484
  * jitter (pass a fixed `() => 0` in tests to pin backoff; defaults to
469
485
  * `Math.random`, read only at resilient-call's verb boundary).
470
486
  *
471
- * The slice and five of the six verbs are resilient-call's, forwarded. `fail` is
472
- * the one composed verb — it reads the {@link JevAskErr} the handler typed and
473
- * routes on it (see its docblock); it reimplements no backoff. `handlers` is the
474
- * new piece: the port call, the status classification, the parse, and the
475
- * enriched settle Msg.
487
+ * The slice and most verbs are resilient-call's, forwarded. `fail` is the one
488
+ * composed verb — it reads the {@link JevAskErr} back off the settled Msg and
489
+ * routes on it (see its docblock); it reimplements no backoff. `decode`,
490
+ * `rejected` and `offline` are the pure outcome builders your handler returns.
476
491
  */
477
492
  declare function createJevAsk<Q extends JevQuestionMap>(config: JevAskConfig<Q>, rng?: () => number): {
478
493
  name: "resilient";
494
+ /** The `Cmd.define`d run Cmd — list it in the machine's `cmds`. */
495
+ run: CmdDef<"resilient_run", {
496
+ readonly key: string;
497
+ readonly input: JevRequest<Q>;
498
+ }, JevOk<Q>, {
499
+ readonly [detail: string]: unknown;
500
+ readonly _tag: "deadline_exceeded";
501
+ } | {
502
+ readonly [detail: string]: unknown;
503
+ readonly _tag: "port_rejected";
504
+ }>;
479
505
  init: () => ResilientState<JevRequest<Q>, JevOk<Q>>;
480
506
  attempt: (s: ResilientState<JevRequest<Q>, JevOk<Q>>, key: string, content: JevState, at: number) => readonly [ResilientState<JevRequest<Q>, JevOk<Q>>, readonly JevAskCmd<Q>[]];
481
- succeed: (s: ResilientState<JevRequest<Q>, JevOk<Q>>, key: string, msg: JevSucceedMsg<Q>) => readonly [ResilientState<JevRequest<Q>, JevOk<Q>>, readonly JevAskCmd<Q>[]];
482
- fail: (s: ResilientState<JevRequest<Q>, JevOk<Q>>, key: string, msg: JevFailMsg) => readonly [ResilientState<JevRequest<Q>, JevOk<Q>>, readonly JevAskCmd<Q>[]];
507
+ succeed: (s: ResilientState<JevRequest<Q>, JevOk<Q>>, msg: JevSucceedMsg<Q>) => readonly [ResilientState<JevRequest<Q>, JevOk<Q>>, readonly JevAskCmd<Q>[]];
508
+ fail: (s: ResilientState<JevRequest<Q>, JevOk<Q>>, msg: JevFailMsg) => readonly [ResilientState<JevRequest<Q>, JevOk<Q>>, readonly JevAskCmd<Q>[]];
483
509
  onTimer: (s: ResilientState<JevRequest<Q>, JevOk<Q>>, msg: JevTimerMsg) => readonly [ResilientState<JevRequest<Q>, JevOk<Q>>, readonly JevAskCmd<Q>[]];
484
- subs: (s: ResilientState<JevRequest<Q>, JevOk<Q>>) => readonly DeadlineSub[];
485
- handlers: () => {
486
- resilient_run: (cmd: JevAskCmd<Q>) => Promise<JevSucceedMsg<Q> | JevFailMsg>;
487
- };
488
- ask: (request: JevRequest<Q>, signal?: AbortSignal) => Promise<JevOk<Q>>;
510
+ deadlines: (s: ResilientState<JevRequest<Q>, JevOk<Q>>) => readonly DeadlineSub[];
511
+ /** The built-in `timer` Sub's deps — resilient-call's `timer`. */
512
+ timer: (s: ResilientState<JevRequest<Q>, JevOk<Q>>) => TimerDeps<ResilientTimerMsg<"resilient">> | null;
513
+ /** Your handler's outcome for an HTTP reply — {@link decodeJevReply}. */
514
+ decode: (request: JevRequest<Q>, reply: JevHttpReply) => Outcome<JevOk<Q>, JevRejected>;
515
+ /** Your handler's outcome when the call threw — {@link jevCallThrew}. */
516
+ rejected: typeof jevCallThrew;
517
+ /** Your handler's outcome with no network — {@link offlineJevAnswer}. */
518
+ offline: (request: JevRequest<Q>) => Outcome<JevOk<Q>, JevRejected>;
489
519
  };
490
520
  /**
491
521
  * The Cmd type a host machine declares in `types.cmd` when it splices a
492
522
  * {@link createJevAsk} knob in — {@link JevAskCmd} under the name a `types`
493
523
  * block reads well with. It is stated here so a host writes `cmd: {} as
494
- * JevCmd<Questions>` rather than deriving it from the knob's shape, which is
495
- * what `ReturnType<Ask["attempt"]>[1][number]` used to be doing at every call
496
- * site: a spelling of the same type that breaks the moment `attempt`'s tuple
497
- * changes, and that reads as machinery rather than as a name.
524
+ * JevCmd<Questions>` rather than deriving it from the knob's shape.
498
525
  */
499
526
  type JevCmd<Q extends JevQuestionMap> = JevAskCmd<Q>;
500
- /**
501
- * The Sub type a host machine declares in `types.sub` — the deadline Sub
502
- * `subs` emits, inherited from resilient-call. Named here for the same reason
503
- * as {@link JevCmd}: a host names the type, it does not re-derive it.
504
- */
505
- type JevSub = DeadlineSub;
506
527
  /**
507
528
  * Lift a knob result `[slice, cmds]` into a host `[State, cmds]` where the slice
508
529
  * lives at `state.resilience` — resilient-call's convenience, re-typed for this
@@ -577,9 +598,7 @@ interface ClassifyBatchConfig<I, C extends string> {
577
598
  readonly evictEveryMs?: number;
578
599
  /** The model asked for. Forwarded to `../ask`'s default when omitted. */
579
600
  readonly model?: string;
580
- /** DI port — the HTTP caller. Forwarded to `../ask`; absent is the no-key case. */
581
- readonly port?: JevPort<ItemQuestions<C>>;
582
- /** The pure decider for the no-port path. Forwarded to `../ask`. */
601
+ /** The pure decider `offline` answers with, for a handler with no key. */
583
602
  readonly fallback?: JevFallback<ItemQuestions<C>>;
584
603
  }
585
604
  /**
@@ -593,7 +612,7 @@ interface ClassifyBatchState<I, C extends string> {
593
612
  readonly fanOut: FanOutState<Batch<I>, JevOk<ItemQuestions<C>>>;
594
613
  /** The answers, keyed by `keyOf` — `../../resilience/cache`'s slice. */
595
614
  readonly cache: TtlCache<ItemAnswer<C>>;
596
- /** Keys whose batch settled `resilient_err`, with the error that settled it. */
615
+ /** Keys whose batch settled `resilient_run_err`, with the error that settled it. */
597
616
  readonly failed: Readonly<Record<string, JevAskErr>>;
598
617
  }
599
618
  /** What {@link ClassifyBatchKnob.answerFor} reports about one key. */
@@ -603,7 +622,7 @@ type KeyAnswer<C extends string> =
603
622
  readonly status: "answered";
604
623
  readonly answer: ItemAnswer<C>;
605
624
  }
606
- /** The batch carrying this key settled `resilient_err`. Nothing was cached. */
625
+ /** The batch carrying this key settled `resilient_run_err`. Nothing was cached. */
607
626
  | {
608
627
  readonly status: "failed";
609
628
  readonly error: JevAskErr;
@@ -624,6 +643,17 @@ type KeyAnswer<C extends string> =
624
643
  * that keeps one key out of two batches at once.
625
644
  */
626
645
  declare function createClassifyBatch<I, C extends string>(config: ClassifyBatchConfig<I, C>): {
646
+ /** The ask Cmd def — list it in the machine's `cmds`. */
647
+ ask: CmdDef<"resilient_run", {
648
+ readonly key: string;
649
+ readonly input: JevRequest<Readonly<Record<string, ItemQuestion<C>>>>;
650
+ }, JevOk<Readonly<Record<string, ItemQuestion<C>>>>, {
651
+ readonly [detail: string]: unknown;
652
+ readonly _tag: "deadline_exceeded";
653
+ } | {
654
+ readonly [detail: string]: unknown;
655
+ readonly _tag: "port_rejected";
656
+ }>;
627
657
  init: () => ClassifyBatchState<I, C>;
628
658
  add: (state: ClassifyBatchState<I, C>, item: I, at: number) => readonly [ClassifyBatchState<I, C>, readonly ClassifyBatchCmd<C>[]];
629
659
  onWindow: (state: ClassifyBatchState<I, C>, at: number) => readonly [ClassifyBatchState<I, C>, readonly ClassifyBatchCmd<C>[]];
@@ -631,16 +661,22 @@ declare function createClassifyBatch<I, C extends string>(config: ClassifyBatchC
631
661
  onBatchErr: (state: ClassifyBatchState<I, C>, msg: ClassifyBatchErrMsg) => readonly [ClassifyBatchState<I, C>, readonly ClassifyBatchCmd<C>[]];
632
662
  onEvict: (state: ClassifyBatchState<I, C>, at: number) => readonly [ClassifyBatchState<I, C>, readonly ClassifyBatchCmd<C>[]];
633
663
  answerFor: (state: ClassifyBatchState<I, C>, key: string, at: number) => KeyAnswer<C>;
634
- subs: (state: ClassifyBatchState<I, C>, id?: string) => readonly (BatchWindowSub | CacheEvictionSub)[];
664
+ subs: (state: ClassifyBatchState<I, C>, id?: string) => readonly BatchWindowSub[];
665
+ subEntries: <Model>(select: (model: Model) => ClassifyBatchState<I, C>, id?: string) => readonly DepKeyedSub<Model, TimerSub<BatchWindowExpired> | CacheEvictionSub>[];
635
666
  subscribers: () => {
636
- deadline: SubscribeHandler<BatchWindowSub, BatchWindowExpired, unknown>;
637
667
  cache: SubscribeHandler<CacheEvictionSub, CacheEvictMsg, unknown>;
638
668
  };
639
- handlers: () => {
640
- resilient_run: (cmd: ClassifyBatchCmd<C>) => Promise<ClassifyBatchOkMsg<C> | ClassifyBatchErrMsg>;
641
- };
669
+ /**
670
+ * Your handler's outcome for Jev's reply to one batch — `../ask`'s
671
+ * `decodeJevReply`, parsing against the questions the batch carried.
672
+ */
673
+ decode: (request: JevRequest<ItemQuestions<C>>, reply: JevHttpReply) => Outcome<JevOk<Readonly<Record<string, ItemQuestion<C>>>>, JevRejected>;
674
+ /** Your handler's outcome when the call threw — `../ask`'s `jevCallThrew`. */
675
+ rejected: typeof jevCallThrew;
676
+ /** Your handler's outcome with no network — the configured `fallback`. */
677
+ offline: (request: JevRequest<ItemQuestions<C>>) => Outcome<JevOk<Readonly<Record<string, ItemQuestion<C>>>>, JevRejected>;
642
678
  };
643
679
  /** The bound knob {@link createClassifyBatch} returns. */
644
680
  type ClassifyBatchKnob<I, C extends string> = ReturnType<typeof createClassifyBatch<I, C>>;
645
681
 
646
- export { type Batch, type ClassifyBatchCmd, type ClassifyBatchConfig, type ClassifyBatchErrMsg, type ClassifyBatchKnob, type ClassifyBatchOkMsg, type ClassifyBatchState, type ClassifyCriteria, DEFAULT_CLASSIFY_MAX_ITEMS, DEFAULT_JEV_MODEL, DeadlineExceeded, DeadlineSub, type ItemAnswer, type ItemQuestion, type ItemQuestions, JEV_ENDPOINT, type JevAnswer, type JevAnswerFor, type JevAnswers, type JevAskCmd, type JevAskConfig, type JevAskErr, JevAskFailure, type JevChoiceAnswer, type JevChoiceCriteria, type JevChoiceQuestion, type JevCmd, type JevErr, type JevFailMsg, type JevFallback, type JevHttpStatus, type JevNoulAnswer, type JevNoulQuestion, type JevOk, type JevParse, type JevPort, type JevQuestion, type JevQuestionMap, type JevQuestionType, type JevRequest, type JevResponse, type JevScoreAnswer, type JevScoreCriteria, type JevScoreQuestion, type JevState, type JevSub, type JevSucceedMsg, type JevText, type JevTimerMsg, type JevUsage, type KeyAnswer, ResilientState, classifyStatus, createClassifyBatch, createJevAsk, isJevErr, isTransientJevAskErr, jevAskCmdDef, jevQuestions, liftJevAsk, parseAnswers };
682
+ export { type Batch, type ClassifyBatchCmd, type ClassifyBatchConfig, type ClassifyBatchErrMsg, type ClassifyBatchKnob, type ClassifyBatchOkMsg, type ClassifyBatchState, type ClassifyCriteria, DEFAULT_CLASSIFY_MAX_ITEMS, DEFAULT_JEV_MODEL, type ItemAnswer, type ItemQuestion, type ItemQuestions, JEV_ENDPOINT, type JevAnswer, type JevAnswerFor, type JevAnswers, type JevAskCmd, type JevAskConfig, type JevAskErr, type JevChoiceAnswer, type JevChoiceCriteria, type JevChoiceQuestion, type JevCmd, type JevErr, type JevFailMsg, type JevFallback, type JevHttpReply, type JevHttpStatus, type JevNoulAnswer, type JevNoulQuestion, type JevOk, type JevParse, type JevQuestion, type JevQuestionMap, type JevQuestionType, type JevRejected, type JevRequest, type JevResponse, type JevScoreAnswer, type JevScoreCriteria, type JevScoreQuestion, type JevState, type JevSucceedMsg, type JevText, type JevTimerMsg, type JevUsage, type KeyAnswer, ResilientState, classifyStatus, createClassifyBatch, createJevAsk, decodeJevReply, isJevErr, isTransientJevAskErr, jevAskCmdDef, jevAskErrOf, jevCallThrew, jevQuestions, liftJevAsk, offlineJevAnswer, parseAnswers };