@demlik/tea 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -9
- package/dist/agent/index.d.ts +638 -45
- package/dist/agent/index.js +9 -19
- package/dist/{chunk-25LBDCBC.js → chunk-6IQPODUF.js} +2 -2
- package/dist/{chunk-25LBDCBC.js.map → chunk-6IQPODUF.js.map} +1 -1
- package/dist/chunk-AQ6ZIMEA.js +421 -0
- package/dist/chunk-AQ6ZIMEA.js.map +1 -0
- package/dist/{chunk-MUUROGIH.js → chunk-BLJ2JQSH.js} +62 -12
- package/dist/chunk-BLJ2JQSH.js.map +1 -0
- package/dist/{chunk-7SVIRMC6.js → chunk-F2US5BW6.js} +25 -5
- package/dist/chunk-F2US5BW6.js.map +1 -0
- package/dist/{batch-window/index.js → chunk-F7FMAWLA.js} +4 -8
- package/dist/chunk-F7FMAWLA.js.map +1 -0
- package/dist/{chunk-7V4EVLZA.js → chunk-HUKZQX6U.js} +20 -16
- package/dist/chunk-HUKZQX6U.js.map +1 -0
- package/dist/{chunk-EWJP3YYP.js → chunk-HWVW4AXC.js} +3 -3
- package/dist/chunk-HWVW4AXC.js.map +1 -0
- package/dist/{chunk-WLGO64WC.js → chunk-HYDWG35Q.js} +23 -6
- package/dist/chunk-HYDWG35Q.js.map +1 -0
- package/dist/{chunk-I5OV65MS.js → chunk-I5MQMJDW.js} +57 -7
- package/dist/chunk-I5MQMJDW.js.map +1 -0
- package/dist/{chunk-J6527VRQ.js → chunk-LFZUK6J2.js} +3 -3
- package/dist/chunk-LFZUK6J2.js.map +1 -0
- package/dist/{chunk-ZVJZ72HY.js → chunk-LYLTKJWM.js} +25 -11
- package/dist/chunk-LYLTKJWM.js.map +1 -0
- package/dist/{chunk-D736QUGF.js → chunk-MYXFNWAJ.js} +4 -5
- package/dist/chunk-MYXFNWAJ.js.map +1 -0
- package/dist/{chunk-K575PT4S.js → chunk-PR6TB3BL.js} +15 -4
- package/dist/chunk-PR6TB3BL.js.map +1 -0
- package/dist/chunk-RQULHGYH.js +1804 -0
- package/dist/chunk-RQULHGYH.js.map +1 -0
- package/dist/{chunk-FV3Z5MBE.js → chunk-TXN2KFHF.js} +14 -4
- package/dist/chunk-TXN2KFHF.js.map +1 -0
- package/dist/{chunk-Q2UM7BXU.js → chunk-VBDU4JL6.js} +2 -2
- package/dist/chunk-VBDU4JL6.js.map +1 -0
- package/dist/chunk-Z2L3LSNV.js +1470 -0
- package/dist/chunk-Z2L3LSNV.js.map +1 -0
- package/dist/core-CTzMJ82M.d.ts +562 -0
- package/dist/devtools/index.d.ts +2 -2
- package/dist/devtools/index.js +207 -2
- package/dist/devtools/index.js.map +1 -1
- package/dist/do/index.d.ts +48 -31
- package/dist/do/index.js +36 -25
- package/dist/do/index.js.map +1 -1
- package/dist/{durable-effects-D8SqU_if.d.ts → durable-effects-B0-qGQDy.d.ts} +2 -2
- package/dist/extension/index.d.ts +301 -3
- package/dist/extension/index.js +596 -5
- package/dist/extension/index.js.map +1 -1
- package/dist/flow/index.d.ts +1295 -0
- package/dist/flow/index.js +732 -0
- package/dist/flow/index.js.map +1 -0
- package/dist/idempotency/index.d.ts +90 -116
- package/dist/idempotency/index.js +4 -1
- package/dist/{batch-window/index.d.ts → index-4vZzljCD.d.ts} +7 -11
- package/dist/{fan-out/index.d.ts → index-6A7dB8f6.d.ts} +7 -8
- package/dist/index-B5BZ-_cT.d.ts +616 -0
- package/dist/index-Bc40JWVl.d.ts +131 -0
- package/dist/{debounce/index.d.ts → index-DHSUmQTR.d.ts} +7 -7
- package/dist/index-DJWIER_3.d.ts +69 -0
- package/dist/{snapshot/index.d.ts → index-DMCeMPMJ.d.ts} +15 -77
- package/dist/{monitored-run/index.d.ts → index-NjrT3fL2.d.ts} +37 -12
- package/dist/{recorder/index.d.ts → index-TvRb1KVf.d.ts} +4 -6
- package/dist/{deadline/index.d.ts → index-q0hXFeZ0.d.ts} +155 -8
- package/dist/index.d.ts +719 -6
- package/dist/index.js +1 -2
- package/dist/jev/index.d.ts +634 -0
- package/dist/jev/index.js +433 -0
- package/dist/jev/index.js.map +1 -0
- package/dist/machine-CdIcN2Xm.d.ts +1773 -0
- package/dist/machine-viz/index.d.ts +2 -1
- package/dist/machine-viz/index.js +12 -5
- package/dist/machine-viz/index.js.map +1 -1
- package/dist/mem/index.d.ts +19 -3
- package/dist/mem/index.js +22 -2
- package/dist/mem/index.js.map +1 -1
- package/dist/node/index.d.ts +130 -4
- package/dist/node/index.js +222 -10
- package/dist/node/index.js.map +1 -1
- package/dist/{paginator → paginate}/index.d.ts +151 -6
- package/dist/paginate/index.js +7 -0
- package/dist/parity/index.d.ts +5 -10
- package/dist/parity/index.js +4 -7
- package/dist/parity/index.js.map +1 -1
- package/dist/pbt/index.d.ts +248 -5
- package/dist/pbt/index.js +124 -5
- package/dist/pbt/index.js.map +1 -1
- package/dist/{trace-replay → persistence}/index.d.ts +7 -4
- package/dist/persistence/index.js +6 -0
- package/dist/react/index.d.ts +4 -3
- package/dist/react/index.js +1 -2
- package/dist/react/index.js.map +1 -1
- package/dist/resilience/index.d.ts +743 -0
- package/dist/resilience/index.js +657 -0
- package/dist/resilience/index.js.map +1 -0
- package/dist/retry-backoff/index.d.ts +3 -2
- package/dist/retry-backoff/index.js +1 -1
- package/dist/runtime-types-LWDoi943.d.ts +998 -0
- package/dist/testing/index.d.ts +3 -2
- package/dist/testing/index.js +1 -2
- package/dist/testing/index.js.map +1 -1
- package/dist/{throttled-input → timing}/index.d.ts +144 -12
- package/dist/{throttled-input → timing}/index.js +57 -12
- package/dist/timing/index.js.map +1 -0
- package/dist/{types-D7u9DkH7.d.ts → types-DP3f5NIl.d.ts} +1 -1
- package/dist/work-queue/index.d.ts +131 -54
- package/dist/work-queue/index.js +3 -2
- package/dist/work-queue/index.js.map +1 -1
- package/package.json +50 -216
- package/dist/authed-call/index.d.ts +0 -119
- package/dist/authed-call/index.js +0 -134
- package/dist/authed-call/index.js.map +0 -1
- package/dist/await-terminal/index.d.ts +0 -100
- package/dist/await-terminal/index.js +0 -76
- package/dist/await-terminal/index.js.map +0 -1
- package/dist/batch-window/index.js.map +0 -1
- package/dist/cache/index.d.ts +0 -151
- package/dist/cache/index.js +0 -8
- package/dist/chart/index.d.ts +0 -217
- package/dist/chart/index.js +0 -16
- package/dist/chart/index.js.map +0 -1
- package/dist/chart/inspect/index.d.ts +0 -85
- package/dist/chart/inspect/index.js +0 -5
- package/dist/chart/inspect/react.d.ts +0 -112
- package/dist/chart/inspect/react.js +0 -11
- package/dist/chart/inspect/react.js.map +0 -1
- package/dist/chart/inspect/styles.css +0 -286
- package/dist/chart/lane/index.d.ts +0 -361
- package/dist/chart/lane/index.js +0 -9
- package/dist/chart/lane/index.js.map +0 -1
- package/dist/chart/lane/react.d.ts +0 -83
- package/dist/chart/lane/react.js +0 -559
- package/dist/chart/lane/react.js.map +0 -1
- package/dist/chart/lane/server.d.ts +0 -148
- package/dist/chart/lane/server.js +0 -209
- package/dist/chart/lane/server.js.map +0 -1
- package/dist/chart/lane/styles.css +0 -498
- package/dist/chart/lane/viewer/assets/abnfDiagram-N423BO3Z-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/architectureDiagram-T3A2C74G-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/blockDiagram-VBNYF7ZC-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/c4Diagram-5PPSVZJV-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/chunk-2GRJ4B5K-HdDf8SI3.js +0 -1
- package/dist/chart/lane/viewer/assets/chunk-5RXB4S5H-CcNtpUd7.js +0 -231
- package/dist/chart/lane/viewer/assets/chunk-5VM5RSS4-BP4fRS_5.js +0 -15
- package/dist/chart/lane/viewer/assets/chunk-KBJHAD2P-DZOw7xU6.js +0 -1
- package/dist/chart/lane/viewer/assets/chunk-NSK5VX7P-CBCyTZMs.js +0 -128
- package/dist/chart/lane/viewer/assets/classDiagram-JCYQIIEL-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/classDiagram-v2-OCEON4UE-D4uAiFr8.js +0 -206
- package/dist/chart/lane/viewer/assets/cose-bilkent-JH36ORCC-DOwCrGXH.js +0 -1
- package/dist/chart/lane/viewer/assets/cynefinDiagram-MW4NZA55-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/dagre-K_PewWfS.js +0 -1
- package/dist/chart/lane/viewer/assets/dagre-VZM6K2ZE-831qZcA8.js +0 -4
- package/dist/chart/lane/viewer/assets/diagram-7IWD3JNH-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/diagram-B4RE2ZJO-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/diagram-LBJQPF4R-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/diagram-Q27KOJAE-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/diagram-UB23O5K3-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/ebnfDiagram-BXEA7PRR-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/erDiagram-JOGREHBK-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/flowDiagram-UKHOOZJN-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/ganttDiagram-PKOTCBZU-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/gitGraphDiagram-DS77QQ5N-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/index-9SkH5NA3.css +0 -1
- package/dist/chart/lane/viewer/assets/index-Bgt4sXpW.js +0 -195
- package/dist/chart/lane/viewer/assets/infoDiagram-6WML65LV-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/ishikawaDiagram-WSZJBQD7-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/journeyDiagram-NVQOT4AX-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/kanban-definition-27J2QSJJ-G7PaPzy-.js +0 -89
- package/dist/chart/lane/viewer/assets/katex-DOwCrGXH.js +0 -1
- package/dist/chart/lane/viewer/assets/mindmap-definition-FAOFIHXS-CGj9nrVk.js +0 -96
- package/dist/chart/lane/viewer/assets/path-fybaL0A-.js +0 -1
- package/dist/chart/lane/viewer/assets/pegDiagram-VL7TDLO6-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/pieDiagram-7S7Q4E2Y-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/quadrantDiagram-CIZ2JOQS-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/railroadDiagram-AXF67PYL-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/requirementDiagram-LRYGKXZP-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/sankeyDiagram-W5VNT64P-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/sequenceDiagram-SI44F4Z6-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/stateDiagram-OKZ733FA-B_88AzBS.js +0 -1
- package/dist/chart/lane/viewer/assets/stateDiagram-v2-UEYNNEHI-CR5gcgq6.js +0 -1
- package/dist/chart/lane/viewer/assets/swimlanes-SLNWSIFB-B4xK-rwg.js +0 -1
- package/dist/chart/lane/viewer/assets/swimlanesDiagram-ULZ7WXOC-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/timeline-definition-Z64GVDOM-CCv52MfY.js +0 -120
- package/dist/chart/lane/viewer/assets/vennDiagram-T6HMQDX7-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/wardleyDiagram-T6FBY63Y-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/xychartDiagram-ELKLHX3M-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/index.html +0 -15
- package/dist/chart/report/index.d.ts +0 -116
- package/dist/chart/report/index.js +0 -32
- package/dist/chart/report/index.js.map +0 -1
- package/dist/chunk-2YFLOCWX.js +0 -15
- package/dist/chunk-2YFLOCWX.js.map +0 -1
- package/dist/chunk-3JU6657S.js +0 -372
- package/dist/chunk-3JU6657S.js.map +0 -1
- package/dist/chunk-4KTWLPL5.js +0 -33
- package/dist/chunk-4KTWLPL5.js.map +0 -1
- package/dist/chunk-5EHLEUTL.js +0 -686
- package/dist/chunk-5EHLEUTL.js.map +0 -1
- package/dist/chunk-5KJKJOFC.js +0 -758
- package/dist/chunk-5KJKJOFC.js.map +0 -1
- package/dist/chunk-7SVIRMC6.js.map +0 -1
- package/dist/chunk-7V4EVLZA.js.map +0 -1
- package/dist/chunk-A56OR5RF.js +0 -184
- package/dist/chunk-A56OR5RF.js.map +0 -1
- package/dist/chunk-AZZLE7XR.js +0 -62
- package/dist/chunk-AZZLE7XR.js.map +0 -1
- package/dist/chunk-B5VXOFMZ.js +0 -266
- package/dist/chunk-B5VXOFMZ.js.map +0 -1
- package/dist/chunk-BYQUGDD3.js +0 -16
- package/dist/chunk-BYQUGDD3.js.map +0 -1
- package/dist/chunk-D736QUGF.js.map +0 -1
- package/dist/chunk-E6GEDSF4.js +0 -307
- package/dist/chunk-E6GEDSF4.js.map +0 -1
- package/dist/chunk-EUF7XOEE.js +0 -223
- package/dist/chunk-EUF7XOEE.js.map +0 -1
- package/dist/chunk-EWJP3YYP.js.map +0 -1
- package/dist/chunk-FV3Z5MBE.js.map +0 -1
- package/dist/chunk-HCEVHFJ7.js +0 -54
- package/dist/chunk-HCEVHFJ7.js.map +0 -1
- package/dist/chunk-I5OV65MS.js.map +0 -1
- package/dist/chunk-J6527VRQ.js.map +0 -1
- package/dist/chunk-JELSZN25.js +0 -47
- package/dist/chunk-JELSZN25.js.map +0 -1
- package/dist/chunk-JER5O7PQ.js +0 -416
- package/dist/chunk-JER5O7PQ.js.map +0 -1
- package/dist/chunk-JGVL3WPL.js +0 -26
- package/dist/chunk-JGVL3WPL.js.map +0 -1
- package/dist/chunk-JP5D6GSL.js +0 -71
- package/dist/chunk-JP5D6GSL.js.map +0 -1
- package/dist/chunk-K575PT4S.js.map +0 -1
- package/dist/chunk-MU6MCIAC.js +0 -15
- package/dist/chunk-MU6MCIAC.js.map +0 -1
- package/dist/chunk-MUUROGIH.js.map +0 -1
- package/dist/chunk-ND3DH6KM.js +0 -88
- package/dist/chunk-ND3DH6KM.js.map +0 -1
- package/dist/chunk-Q2UM7BXU.js.map +0 -1
- package/dist/chunk-S2EGRPCM.js +0 -47
- package/dist/chunk-S2EGRPCM.js.map +0 -1
- package/dist/chunk-SINXE47Y.js +0 -55
- package/dist/chunk-SINXE47Y.js.map +0 -1
- package/dist/chunk-SUST46KO.js +0 -53
- package/dist/chunk-SUST46KO.js.map +0 -1
- package/dist/chunk-TP5UPGLY.js +0 -61
- package/dist/chunk-TP5UPGLY.js.map +0 -1
- package/dist/chunk-UF4MZSLT.js +0 -53
- package/dist/chunk-UF4MZSLT.js.map +0 -1
- package/dist/chunk-UOC2PL46.js +0 -13
- package/dist/chunk-UOC2PL46.js.map +0 -1
- package/dist/chunk-WLGO64WC.js.map +0 -1
- package/dist/chunk-WRAA7GVZ.js +0 -209
- package/dist/chunk-WRAA7GVZ.js.map +0 -1
- package/dist/chunk-ZCL7SCBK.js +0 -685
- package/dist/chunk-ZCL7SCBK.js.map +0 -1
- package/dist/chunk-ZD6PNZBK.js +0 -457
- package/dist/chunk-ZD6PNZBK.js.map +0 -1
- package/dist/chunk-ZF6WDK2D.js +0 -519
- package/dist/chunk-ZF6WDK2D.js.map +0 -1
- package/dist/chunk-ZJ5AOYBH.js +0 -8
- package/dist/chunk-ZJ5AOYBH.js.map +0 -1
- package/dist/chunk-ZVJZ72HY.js.map +0 -1
- package/dist/circuit-breaker/index.d.ts +0 -197
- package/dist/circuit-breaker/index.js +0 -3
- package/dist/circuit-breaker/index.js.map +0 -1
- package/dist/core-Bjc0bS8j.d.ts +0 -326
- package/dist/deadline/index.js +0 -6
- package/dist/deadline/index.js.map +0 -1
- package/dist/debounce/index.js +0 -3
- package/dist/debounce/index.js.map +0 -1
- package/dist/extension/react.d.ts +0 -121
- package/dist/extension/react.js +0 -75
- package/dist/extension/react.js.map +0 -1
- package/dist/extension/subs/index.d.ts +0 -44
- package/dist/extension/subs/index.js +0 -80
- package/dist/extension/subs/index.js.map +0 -1
- package/dist/extension/test-utils.d.ts +0 -128
- package/dist/extension/test-utils.js +0 -277
- package/dist/extension/test-utils.js.map +0 -1
- package/dist/fan-out/index.js +0 -5
- package/dist/fan-out/index.js.map +0 -1
- package/dist/fold-Blbhru48.d.ts +0 -435
- package/dist/graph-CcjWZVrd.d.ts +0 -923
- package/dist/idempotency/adapter.d.ts +0 -62
- package/dist/idempotency/adapter.js +0 -4
- package/dist/idempotency/adapter.js.map +0 -1
- package/dist/idempotent-intake/index.d.ts +0 -187
- package/dist/idempotent-intake/index.js +0 -7
- package/dist/idempotent-intake/index.js.map +0 -1
- package/dist/llm-call/index.d.ts +0 -310
- package/dist/llm-call/index.js +0 -16
- package/dist/llm-call/index.js.map +0 -1
- package/dist/machine-0OmPvsy_.d.ts +0 -804
- package/dist/monitored-run/index.js +0 -10
- package/dist/monitored-run/index.js.map +0 -1
- package/dist/paginated-walk/index.d.ts +0 -234
- package/dist/paginated-walk/index.js +0 -16
- package/dist/paginated-walk/index.js.map +0 -1
- package/dist/paginator/index.js +0 -3
- package/dist/paginator/index.js.map +0 -1
- package/dist/pbt/arbitraries/index.d.ts +0 -135
- package/dist/pbt/arbitraries/index.js +0 -3
- package/dist/pbt/arbitraries/index.js.map +0 -1
- package/dist/pbt/runners/index.d.ts +0 -117
- package/dist/pbt/runners/index.js +0 -5
- package/dist/pbt/runners/index.js.map +0 -1
- package/dist/poller/index.d.ts +0 -351
- package/dist/poller/index.js +0 -115
- package/dist/poller/index.js.map +0 -1
- package/dist/prediction/index.d.ts +0 -130
- package/dist/prediction/index.js +0 -4
- package/dist/prediction/index.js.map +0 -1
- package/dist/protocol-B5YmJr0d.d.ts +0 -45
- package/dist/pure/index.d.ts +0 -2
- package/dist/pure/index.js +0 -4
- package/dist/pure/index.js.map +0 -1
- package/dist/rate-limit/index.d.ts +0 -115
- package/dist/rate-limit/index.js +0 -3
- package/dist/rate-limit/index.js.map +0 -1
- package/dist/reconciler/index.d.ts +0 -192
- package/dist/reconciler/index.js +0 -164
- package/dist/reconciler/index.js.map +0 -1
- package/dist/recorder/index.js +0 -3
- package/dist/recorder/index.js.map +0 -1
- package/dist/reducer-BqyoVyBG.d.ts +0 -447
- package/dist/resilient-call/index.d.ts +0 -319
- package/dist/resilient-call/index.js +0 -14
- package/dist/resilient-call/index.js.map +0 -1
- package/dist/retry-to-success/index.d.ts +0 -109
- package/dist/retry-to-success/index.js +0 -37
- package/dist/retry-to-success/index.js.map +0 -1
- package/dist/run-BVeqJDBF.d.ts +0 -713
- package/dist/runtime-types-Bxc637bp.d.ts +0 -502
- package/dist/saga/index.d.ts +0 -240
- package/dist/saga/index.js +0 -150
- package/dist/saga/index.js.map +0 -1
- package/dist/samples-DCt6nF8H.d.ts +0 -59
- package/dist/snapshot/index.js +0 -5
- package/dist/snapshot/index.js.map +0 -1
- package/dist/subs/index.d.ts +0 -471
- package/dist/subs/index.js +0 -7
- package/dist/subs/index.js.map +0 -1
- package/dist/throttle/index.d.ts +0 -134
- package/dist/throttle/index.js +0 -3
- package/dist/throttle/index.js.map +0 -1
- package/dist/throttled-input/index.js.map +0 -1
- package/dist/token-refresh/index.d.ts +0 -215
- package/dist/token-refresh/index.js +0 -6
- package/dist/token-refresh/index.js.map +0 -1
- package/dist/trace-replay/index.js +0 -6
- package/dist/trace-replay/index.js.map +0 -1
- package/dist/with-deadline/index.d.ts +0 -196
- package/dist/with-deadline/index.js +0 -111
- package/dist/with-deadline/index.js.map +0 -1
- package/dist/with-resilience/index.d.ts +0 -224
- package/dist/with-resilience/index.js +0 -240
- package/dist/with-resilience/index.js.map +0 -1
- package/dist/with-telemetry/index.d.ts +0 -149
- package/dist/with-telemetry/index.js +0 -70
- package/dist/with-telemetry/index.js.map +0 -1
- package/dist/work-queue/adapter.d.ts +0 -83
- package/dist/work-queue/adapter.js +0 -4
- package/dist/work-queue/adapter.js.map +0 -1
- package/dist/work-queue/ops.d.ts +0 -70
- package/dist/work-queue/ops.js +0 -3
- package/dist/work-queue/ops.js.map +0 -1
- package/dist/workflow/index.d.ts +0 -484
- package/dist/workflow/index.js +0 -244
- package/dist/workflow/index.js.map +0 -1
- /package/dist/{cache → paginate}/index.js.map +0 -0
- /package/dist/{chart/inspect → persistence}/index.js.map +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/internal/resilience/token-refresh/index.ts","../../src/internal/resilience/authed-call/index.ts","../../src/internal/resilience/retry-to-success/index.ts","../../src/internal/resilience/with-deadline/index.ts","../../src/internal/resilience/with-resilience/index.ts","../../src/internal/resilience/with-telemetry/index.ts"],"names":["z"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * internal/resilience/token-refresh — a credential's lifecycle as pure state + verbs,\n * with the actual token fetch deferred to a single injected port.\n *\n * This is the L1 brick `authed-call` (#10 in the composition specs) stacks on:\n * a token slice `{ token, stale }` plus pure transitions that decide *when* a\n * credential must be re-minted, and one `handlers(ports)` splice that performs\n * the re-mint. It follows the uniform knob contract every composition wears —\n * `createTokenRefresh(config) → { init, <verbs>, handlers }` — so a consumer\n * spreads ~3 hooks into their machine instead of hand-wiring the refresh dance.\n *\n * It is a LEAF module in the same mold as `@demlik/tea/retry-backoff`: it\n * depends only on the core (`../index`), never on a sibling brick. The two\n * non-negotiables of every knob hold here by construction:\n *\n * - **Durable** — the token slice is plain JSON-serializable data, so it\n * survives a Durable Object eviction / page reload. A rehydrated machine\n * resumes knowing exactly which token it holds and whether it is stale.\n * - **Replayable** — every transition is a pure verb returning\n * `readonly [State, Cmd[]]`. No verb reads the wall clock or performs I/O,\n * so `replay` reconstructs the slice exactly. Time enters ONLY as an `at`\n * parameter the caller stamps; the network fetch enters ONLY at the\n * `handlers` boundary. This keeps the substrate's purity invariants intact\n * (invariant 2: pure transitions; invariant 4: I/O is an effect, not a\n * reducer body).\n *\n * ## The staleness model — two independent reasons to refresh\n *\n * A token becomes unusable for two unrelated reasons, and the slice tracks both\n * without conflating them:\n *\n * 1. **Expiry** — the token has a known `expiresAt` (epoch ms). It is \"near\n * expiry\" once `at >= expiresAt - skewMs`. The `skewMs` skew refreshes\n * *ahead* of the hard deadline so an in-flight call never races a token\n * that expires mid-request. This is the proactive, time-driven reason and\n * is computed purely from the injected `at` — no clock in the verb.\n *\n * 2. **Server rejection (401)** — the server rejected a request the client\n * believed was still valid (clock skew, a server-side revocation, an early\n * rotation). `on401` flips a `stale` flag regardless of `expiresAt`. This\n * is the reactive reason: the client's belief about validity was wrong, so\n * the next `needsRefresh` returns true even though the clock says the\n * token is fine.\n *\n * `needsRefresh` is the union of the two (plus \"no token at all\"). One source\n * of truth for \"should I fetch a fresh credential before the next call?\", read\n * by the consumer's reducer at the call boundary.\n *\n * Typical wiring (inside a consumer machine):\n *\n * const tr = createTokenRefresh({ skewMs: 30_000 });\n *\n * // in init:\n * init: (loaded) => [loaded ?? { auth: tr.init() }, Cmd.none],\n *\n * // in a reducer cell that is about to make an authed call:\n * before_call: (s, msg) => {\n * const [auth, cmds] = tr.ensureFresh(s.auth, msg.at);\n * return [{ ...s, auth }, cmds]; // emits a refresh Cmd iff a refresh is due\n * },\n *\n * // on a 401 from a guarded call:\n * got_401: (s) => [{ ...s, auth: tr.on401(s.auth) }, []],\n *\n * // when the refresh port resolves:\n * token_refreshed: (s, msg) => [{ ...s, auth: tr.refreshed(s.auth, msg.token) }, []],\n *\n * // splice the I/O:\n * interpret: { ...tr.handlers({ refresh: () => mySdk.mintToken() }) },\n *\n * NOT a substrate primitive: from `../index` it reuses only the `Cmd` /\n * `Interpret` types and the `tryInterpret` Railway helper (a runtime function,\n * not a type) that every effectful brick uses — and no sibling brick. It is a\n * leaf utility internal to the package (`src/internal/resilience/`, #46).\n */\n\nimport { z } from \"zod\";\nimport { Cmd, type CmdOf, type Interpret, tryInterpret } from \"../../../index\";\nimport { MsgType } from \"../../../protocol\";\n\n/**\n * A minted credential: the opaque `value` to send on the wire, and the absolute\n * `expiresAt` (epoch milliseconds — the `Date.now()` scale) the issuer stamped\n * it with. Both fields are plain data so a `Token` is trivially serializable\n * into a consumer's `Store<S>`.\n *\n * `value` is `string` because that is the universal shape of a bearer token /\n * API key / session cookie on the wire. A consumer whose refresh port yields a\n * richer object can JSON-encode it into `value`, or keep this module's slice as\n * the \"is it fresh?\" gate and hold the richer object elsewhere in their Model.\n */\nexport interface Token {\n /** The opaque credential to present on each request (bearer token, API key). */\n readonly value: string;\n /** Absolute expiry instant, epoch milliseconds. The `Date.now()` scale. */\n readonly expiresAt: number;\n}\n\n/**\n * Pure configuration — the knob's only field. Carries no mutable state;\n * `TokenState` does. One config is shared across all the refreshes of one\n * logical credential (often a module-scope const).\n */\nexport interface TokenRefreshConfig {\n /**\n * Refresh-ahead skew, in milliseconds. A token is treated as needing a\n * refresh once `at >= expiresAt - skewMs`, i.e. `skewMs` BEFORE its hard\n * expiry. This buys headroom so a call that starts just under the wire never\n * races a token that lapses mid-flight, and absorbs small client/server clock\n * disagreement. `0` means \"refresh exactly at expiry\"; a negative value is\n * clamped to `0` (a skew that pushes the trigger past expiry is meaningless).\n *\n * @default 0\n */\n readonly skewMs?: number;\n}\n\n/**\n * The token slice this knob owns — the Model field a consumer spreads in via\n * `init()`. A two-field record rather than a phase union because the two\n * dimensions are orthogonal: a token can be present-and-fresh, present-but-stale\n * (a 401 came back), absent, or absent-and-stale (cleared after a failed\n * refresh). Every combination is meaningful, so neither field implies the\n * other's value and a discriminated union would only manufacture impossible\n * arms.\n *\n * - `token` — the currently held credential, or `null` when none has been\n * minted yet (fresh boot) or the last refresh failed.\n * - `stale` — set by `on401` when the server rejected a request the client\n * believed valid. Forces the next `needsRefresh` to true regardless of\n * `expiresAt`; cleared by `refreshed` once a new credential lands.\n *\n * Both fields `readonly` so the whole slice threads safely through a pure\n * reducer and serializes into a `Store<S>`.\n */\nexport interface TokenState {\n /** The held credential, or `null` if none is available (boot / failed refresh). */\n readonly token: Token | null;\n /** Whether a 401 has marked the held token unusable ahead of its `expiresAt`. */\n readonly stale: boolean;\n}\n\n/**\n * The starting slice: no token held, not stale. The first `needsRefresh` after\n * this returns `true` (no token), so a consumer's first guarded call mints a\n * credential before going out.\n */\nexport function initTokenRefresh(): TokenState {\n return { token: null, stale: false };\n}\n\n/**\n * The Cmd this knob emits to ask the runtime to mint a fresh token. Plain data\n * (no closure — invariant 1) carrying nothing: the refresh port takes no input,\n * and the slice the result installs is read off the follow-up Msg, not this\n * Cmd. The consumer unions this into their machine's Cmd type and lets\n * `handlers` interpret it.\n */\nexport const refreshToken = Cmd.define(\"refresh_token\", {\n input: z.object({}),\n ok: z.custom<Token>(),\n err: [\"token_refresh_failed\"],\n});\nexport type RefreshTokenCmd = CmdOf<typeof refreshToken>;\n\n/** Construct a `refresh_token` Cmd. */\nexport function refreshTokenCmd(): RefreshTokenCmd {\n return refreshToken({});\n}\n\n/**\n * The Msg the refresh port dispatches on success — carries the freshly minted\n * `Token`. The consumer unions this into their Msg type and handles it by\n * folding `refreshed(state, msg.token)` into the slice.\n */\nexport interface TokenRefreshedMsg {\n readonly type: typeof MsgType.TokenRefreshed;\n readonly token: Token;\n}\n\n/** Construct a `token_refreshed` Msg carrying the new token. */\nexport function tokenRefreshedMsg(token: Token): TokenRefreshedMsg {\n return { type: MsgType.TokenRefreshed, token };\n}\n\n/**\n * The Msg the refresh port dispatches on failure — carries the rejection so the\n * consumer's reducer can decide whether to back off, surface an error, or give\n * up (errors are data: it is dispatched, never swallowed). The slice itself is\n * left untouched by a failed refresh — the held token (if any) stays held and\n * stale stays set, so the consumer can retry; clearing it is the consumer's\n * policy, expressed in their reducer.\n */\nexport interface TokenRefreshFailedMsg {\n readonly type: typeof MsgType.TokenRefreshFailed;\n readonly error: unknown;\n}\n\n/** Construct a `token_refresh_failed` Msg carrying the rejection. */\nexport function tokenRefreshFailedMsg(error: unknown): TokenRefreshFailedMsg {\n return { type: MsgType.TokenRefreshFailed, error };\n}\n\n/** The two Msgs the refresh port can produce. Union for a consumer's Msg type. */\nexport type TokenRefreshMsg = TokenRefreshedMsg | TokenRefreshFailedMsg;\n\n/** The ports this knob's `handlers` splice needs — the single refresh DI seam. */\nexport interface TokenRefreshPorts {\n /**\n * Mint a fresh credential. Called ONLY from the `refresh_token` interpret\n * handler — never from a verb — so the network I/O and any clock the issuer\n * reads stay at the effect boundary. May reject; the rejection is routed to\n * `token_refresh_failed` (errors are data), never thrown into the runtime.\n */\n readonly refresh: () => Promise<Token>;\n}\n\n/**\n * The knob: hand it a config, get back the slice initializer, the pure verbs,\n * and the `handlers` splice. Mirrors every L2 composition's uniform contract so\n * the call sites read identically across bricks.\n *\n * @example\n * const tr = createTokenRefresh({ skewMs: 30_000 });\n * const s0 = tr.init();\n * const [s1, cmds] = tr.ensureFresh(s0, Date.now()); // cmds = [refreshTokenCmd()]\n */\nexport function createTokenRefresh(config: TokenRefreshConfig = {}) {\n // Clamp once at construction: a negative skew would push the refresh trigger\n // PAST expiry, which inverts the knob's intent (\"refresh ahead\"). NaN (a\n // miswired config) collapses to 0 so `needsRefresh`'s comparison stays total.\n const skewMs =\n config.skewMs !== undefined && config.skewMs > 0 ? config.skewMs : 0;\n\n /**\n * Whether the held token must be refreshed before the next guarded call, at\n * the injected instant `at` (epoch ms). PURE — reads only, no clock, no\n * mutation. True iff ANY of:\n *\n * - no token is held (`token === null`) — nothing to present;\n * - the token was marked `stale` by a 401 — the server disagrees with the\n * client's belief that it is valid;\n * - the token's `expiresAt` is not a finite number (`NaN` / `±Infinity`) —\n * a miswired issuer or a corrupted slice; we cannot reason about when it\n * lapses, so we fail SAFE toward minting a fresh one rather than letting\n * `at >= NaN` (always `false`) or `at >= Infinity` (always `false`) mask\n * a broken expiry as \"fresh forever\";\n * - the token is at or past its skewed expiry (`at >= expiresAt - skewMs`)\n * — the proactive refresh-ahead window has opened.\n *\n * The expiry cutoff is half-open (`>=`), matching the window edges in\n * `rate-limit` / `cache` / `circuit-breaker`: a token minted to expire at `t`\n * with zero skew is considered due at exactly `t`.\n */\n function needsRefresh(state: TokenState, at: number): boolean {\n if (state.token === null) return true;\n if (state.stale) return true;\n // Non-finite expiry (NaN/±Infinity) can never be compared into a \"due\"\n // verdict — `at >= NaN` and `at >= Infinity` are both `false`, which would\n // pin a broken token as fresh forever. Fail safe: treat it as needing a\n // refresh so the next call mints a credential with a real deadline.\n if (!Number.isFinite(state.token.expiresAt)) return true;\n return at >= state.token.expiresAt - skewMs;\n }\n\n /**\n * Mark the held token unusable because a request the client believed valid\n * came back 401. PURE — returns a new slice; the input is never mutated.\n * Sets `stale` regardless of `expiresAt`, so the next `needsRefresh` returns\n * true even when the clock still says the token is fine. The token VALUE is\n * kept (not nulled) — it is the consumer's last-known credential until a\n * refresh replaces it, and keeping it lets observability show what was\n * rejected.\n *\n * Idempotent: a second 401 on an already-stale slice returns the same shape.\n * A 401 with no token held is a no-op (already needs a refresh).\n */\n function on401(state: TokenState): TokenState {\n if (state.stale) return state;\n return { ...state, stale: true };\n }\n\n /**\n * Install a freshly minted `token`, clearing `stale`. PURE — returns a new\n * slice; the input is never mutated. This is the fold for the\n * `token_refreshed` Msg: after it, `needsRefresh(state, at)` is false for any\n * `at` below the new skewed expiry, and the stale flag is gone (the new\n * credential supersedes whatever the 401 rejected).\n *\n * This is the slice's WRITE boundary for a credential, so it is where the\n * durability invariant is paid for: it normalizes a negative-zero `expiresAt`\n * to `+0` before the value enters the slice. `-0` is the one finite double\n * JSON cannot round-trip — `JSON.stringify(-0)` is `\"0\"`, which parses back as\n * `+0`, so a slice carrying `-0` would diverge from its persisted form across\n * a Durable Object eviction / page reload (invariant: the boundary parses, the\n * core trusts). `-0` and `+0` denote the same epoch-ms instant, so collapsing\n * them loses no information and makes the un-round-trippable state\n * unrepresentable in the slice by construction.\n */\n function refreshed(state: TokenState, token: Token): TokenState {\n const normalized: Token = Object.is(token.expiresAt, -0)\n ? { ...token, expiresAt: 0 }\n : token;\n return { ...state, token: normalized, stale: false };\n }\n\n /**\n * The verb a consumer calls at the call boundary: \"make sure I have a fresh\n * credential before the next request.\" PURE — returns `[next, cmds]`. When a\n * refresh is due (`needsRefresh(state, at)`), emits a single `refresh_token`\n * Cmd; otherwise emits none. The slice is returned UNCHANGED in both branches\n * — the refresh itself is async and lands later via `refreshed`, so there is\n * no in-flight phase to record here. (A consumer that wants single-flight —\n * \"don't fire a second refresh while one is pending\" — layers that in their\n * own reducer, e.g. by tracking a pending flag; this brick stays minimal and\n * lets the consumer own that policy.)\n *\n * The `at` is the caller's stamped clock reading (epoch ms), never read here —\n * keeping the verb pure and `replay`-able.\n */\n function ensureFresh(\n state: TokenState,\n at: number,\n ): readonly [TokenState, readonly Cmd[]] {\n if (needsRefresh(state, at)) {\n return [state, [refreshTokenCmd()]];\n }\n return [state, []];\n }\n\n /**\n * The interpret splice: wraps the injected `refresh` port and routes its\n * Ok/Err to `token_refreshed` / `token_refresh_failed` Msgs via the core's\n * `tryInterpret` Railway helper. Spread the result into a consumer's\n * `interpret` map:\n *\n * interpret: { ...other, ...tr.handlers({ refresh: () => sdk.mintToken() }) }\n *\n * The port is the ONLY place the network (and any clock the issuer reads) is\n * touched — every verb above stays pure. `tryInterpret` guarantees the\n * handler never rejects: a port rejection becomes a `token_refresh_failed`\n * Msg (errors are data), so the runtime's dispatch loop is never poisoned by\n * an unhandled rejection.\n */\n function handlers(\n ports: TokenRefreshPorts,\n ): Interpret<TokenRefreshMsg, RefreshTokenCmd, unknown> {\n return {\n refresh_token: tryInterpret<\n RefreshTokenCmd,\n Token,\n TokenRefreshMsg,\n unknown\n >(\n () => ports.refresh(),\n (token) => tokenRefreshedMsg(token),\n (error) => tokenRefreshFailedMsg(error),\n ),\n };\n }\n\n return {\n /** The slice initializer — spread into the consumer's `init`. */\n init: initTokenRefresh,\n needsRefresh,\n on401,\n refreshed,\n ensureFresh,\n handlers,\n };\n}\n\n/** The shape `createTokenRefresh` returns — useful for typing a held knob. */\nexport type TokenRefresh = ReturnType<typeof createTokenRefresh>;\n","/**\n * internal/resilience/authed-call — resilient-call with one extra dimension: a bearer\n * credential that must be minted before a call goes out and re-minted when the\n * server says it is no longer good (a 401). It is composition #10 in the specs:\n * *extends resilient-call; needs the L1 `token-refresh` brick*.\n *\n * The recipe — two existing bricks, stacked, nothing hand-wired:\n *\n * - `../resilient-call` owns ALL the call resilience: cache → circuit-breaker\n * → rate-limit → exponential-backoff retry, plus the per-call deadline. This\n * knob does not re-implement a single line of it. The `attempt` / `succeed`\n * / `fail` / `onTimer` verbs here are thin delegations that thread the\n * composed slice's `resilience` field through the resilient-call verb of the\n * same name. Whatever resilience config a consumer passes flows straight\n * down — every `ResilientConfig` field is still optional, still \"omit a\n * brick → omit its gate\".\n *\n * - `../token-refresh` owns the credential lifecycle: the `{ token, stale }`\n * slice and the decisions about *when* a token must be refreshed (expiry\n * skew, or a reactive 401). This knob adds the one verb resilient-call has\n * no concept of — `on401` — and routes the refresh I/O through token-\n * refresh's `refresh_token` handler.\n *\n * So the slice is exactly *resilient-call's slice + token-refresh's slice*:\n *\n * { resilience: ResilientState<I,R>, auth: TokenState }\n *\n * and the verb set is *resilient-call's four verbs + `on401`*, precisely the\n * spec's \"resilient-call's + `on401(s)` (refresh → retry once)\".\n *\n * ## The 401 dance — \"refresh → retry once\"\n *\n * A 401 is special: it is not a transient failure (backing off and retrying the\n * SAME credential just earns another 401), and it is not a terminal failure (a\n * fresh token usually fixes it). So `on401(s, key, at)` does three things:\n *\n * 1. marks the held token `stale` (via token-refresh's `on401`) and emits a\n * `refresh_token` Cmd to mint a new one;\n * 2. parks the in-flight call in a per-key `authRetry` budget so that, *once*,\n * the refresh landing re-issues that call with the new credential;\n * 3. caps that to a SINGLE auth-retry per call. A second 401 on the same call\n * after we already refreshed and retried does NOT loop — it settles the\n * call `failed` (errors are data: the failure is recorded, never swallowed\n * or spun on forever). The budget resets on the next fresh `attempt`.\n *\n * When the refresh resolves, the consumer folds `refreshed` into the auth slice\n * and calls `onRefreshed(s, at)`, which re-attempts every parked call through\n * the resilient gate with the new token in hand.\n *\n * ## The two non-negotiables (canon — inherited from both bricks)\n *\n * - **Durable** — the slice is `ResilientState` (plain data) + `TokenState`\n * (plain data) + a plain `Record<string, number>` retry budget. All JSON-\n * serializable, so it survives a Durable Object eviction / reload.\n * - **Replayable** — every verb returns `readonly [State, Cmd[]]` and never\n * reads the wall clock or RNG. Time arrives as an `at` parameter; the RNG\n * for retry jitter is injected once at `createAuthedCall(config, rng)` and\n * handed straight to the resilient-call knob. The only clock / network reads\n * live in `handlers` (the effect boundary) — resilient-call's `run` port and\n * token-refresh's `refresh` port.\n *\n * ## Typical wiring\n *\n * const ac = createAuthedCall<string, Resp>({\n * refresh: () => sdk.mintToken(),\n * retry: defaultRetryPolicy,\n * circuit: { threshold: 5, cooldownMs: 30_000 },\n * deadline: { ms: 5_000 },\n * skewMs: 30_000,\n * });\n *\n * // in the machine:\n * init: () => [ac.init(), []],\n * update: {\n * fetch: (s, m) => ac.attempt(s, m.key, m.input, m.at),\n * call_ok: (s, m) => ac.succeed(s, m.key, m),\n * call_err:(s, m) => ac.fail(s, m.key, m),\n * got_401: (s, m) => ac.on401(s, m.key, m.at),\n * token_refreshed: (s, m) => ac.onRefreshed(ac.installToken(s, m.token), m.at),\n * retry_due: (s, m) => ac.onTimer(s, m),\n * },\n * subscriptions: (s) => ac.subs(s),\n * subscribe: { deadline: subscribeDeadline },\n * interpret: ac.handlers({ run: ctx.call, refresh: () => sdk.mintToken() }),\n */\n\nimport type { Cmd } from \"../../../index\";\nimport type { MsgType } from \"../../../protocol\";\nimport { without } from \"../../../pure/core\";\nimport {\n createResilientCall,\n type DeadlineExceeded,\n type DeadlineSub,\n deadlineSub,\n type FailMsg,\n type ResilientConfig,\n type ResilientPorts,\n type ResilientState,\n type ResilientTimerMsg,\n type RunCmd,\n type SucceedMsg,\n subscribeDeadline,\n} from \"../resilient-call\";\nimport {\n createTokenRefresh,\n type RefreshTokenCmd,\n refreshTokenCmd,\n type Token,\n type TokenRefreshConfig,\n type TokenRefreshMsg,\n type TokenRefreshPorts,\n type TokenState,\n} from \"../token-refresh\";\n\n// ===========================================================================\n// Config — the knob. The resilient-call config PLUS the two token-refresh\n// fields. Every field optional except `refresh` (the credential is the whole\n// point: without a mint port there is nothing to authenticate with).\n// ===========================================================================\n\n/**\n * The authed-call knob. It is `ResilientConfig` widened by the token dimension:\n *\n * - `refresh` — the ONLY required field: the port that mints a fresh `Token`.\n * Identical to token-refresh's `TokenRefreshPorts.refresh`; it is hoisted\n * onto the config (not the ports) so the consumer spells the credential\n * source once, the same way `rng` is curried onto the factory.\n * - `skewMs` — token-refresh's refresh-ahead skew (optional, defaults to 0).\n * - every `ResilientConfig` field (`retry` / `circuit` / `rateLimit` /\n * `cache` / `deadline`) — passed straight through to the resilient-call\n * knob, each still optional, each still \"omit a brick → omit its gate\".\n */\nexport interface AuthedConfig extends ResilientConfig, TokenRefreshConfig {\n /** Mint a fresh credential. The single DI seam the auth dimension adds. */\n readonly refresh: () => Promise<Token>;\n}\n\n// ===========================================================================\n// Slice — resilient-call's slice + token-refresh's slice + the auth-retry\n// budget. A flat record, every field plain data.\n// ===========================================================================\n\n/**\n * The composed slice. Three plain-data fields, no closures:\n *\n * - `resilience` — resilient-call's entire slice (circuit, bucket, retry,\n * cache, calls). Owned and mutated only via resilient-call's verbs.\n * - `auth` — token-refresh's `{ token, stale }` slice. Owned and mutated only\n * via token-refresh's verbs.\n * - `authRetry` — per-key count of auth-retries (401 → refresh → retry) spent\n * on a call. Caps the dance at one retry per call so a credential the server\n * keeps rejecting cannot spin forever. A key absent from the record has\n * spent zero. Cleared when a call settles or a fresh `attempt` starts.\n *\n * `pendingAuthRetry` carries the inputs of calls parked waiting for the refresh\n * to land, keyed so `onRefreshed` can re-issue exactly those calls. Plain data —\n * `input` is the same payload the call was issued with.\n */\nexport interface AuthedState<I, R> {\n readonly resilience: ResilientState<I, R>;\n readonly auth: TokenState;\n readonly authRetry: Readonly<Record<string, number>>;\n readonly pendingAuthRetry: Readonly<Record<string, I>>;\n}\n\n// ===========================================================================\n// Cmds + Msgs. The union of both bricks' Cmds/Msgs plus a 401 trigger Msg.\n// ===========================================================================\n\n/** The two effects this knob emits: resilient-call's run, token-refresh's mint. */\nexport type AuthedCmd<I> = RunCmd<I> | RefreshTokenCmd;\n\n/**\n * Every Msg the knob's verbs fold. Resilient-call's settle + timer Msgs, token-\n * refresh's refresh-result Msgs, and the 401 trigger the consumer dispatches\n * when a guarded call comes back unauthorized.\n */\nexport type Unauthorized = {\n readonly type: typeof MsgType.Unauthorized;\n readonly key: string;\n readonly at: number;\n};\n\n/**\n * The plain-data error a 401 we cannot fix settles with. A `{_tag, ...}`\n * sentinel — NEVER a `new Error(...)` — so the slice stays JSON-serializable\n * (an Error object round-trips to `{}` under JSON and carries a stack trace,\n * both of which break the slice's durability invariant once it is persisted\n * into a `Store<S>` and reloaded). Mirrors resilient-call's `DeadlineExceededError`\n * sentinel discipline. `key` echoes the call that was rejected so a consumer can\n * attribute the failure.\n */\nexport type UnauthorizedError = {\n readonly _tag: \"unauthorized\";\n readonly key: string;\n};\n\n/** Ports `handlers` needs — resilient-call's run port AND token-refresh's refresh port. */\nexport interface AuthedPorts<I, R> extends ResilientPorts<I, R> {\n /** Mint a fresh credential. Mirrors `AuthedConfig.refresh` for symmetry at the splice site. */\n readonly refresh: () => Promise<Token>;\n}\n\n// ===========================================================================\n// The knob factory.\n// ===========================================================================\n\n/**\n * Build an authed-call knob from `config`. `rng` is injected for retry jitter\n * and threaded straight into the underlying resilient-call knob — pass a fixed\n * `() => 0.5` in tests to pin backoff; defaults to `Math.random` (read only at\n * the verb boundary inside resilient-call, never in a brick op).\n *\n * Returns the uniform L2 knob contract, widened by the auth verbs (`on401`,\n * `onRefreshed`, `installToken`). `I` is the port input type, `R` the result.\n */\nexport function createAuthedCall<I, R>(\n config: AuthedConfig,\n rng: () => number = Math.random,\n) {\n // Delegate ALL call resilience to the root composition. The resilient config\n // is exactly `config` minus the two auth-only fields — but since\n // `ResilientConfig` only reads the brick fields it knows, passing the wider\n // `config` is harmless. We pass it directly so future resilient bricks flow\n // through without a re-spread.\n const rc = createResilientCall<I, R>(config, rng);\n // Delegate the credential lifecycle to the L1 token brick.\n const tr = createTokenRefresh({ skewMs: config.skewMs });\n\n /** The starting slice — both bricks' inits plus empty auth-retry bookkeeping. */\n function init(): AuthedState<I, R> {\n return {\n resilience: rc.init(),\n auth: tr.init(),\n authRetry: {},\n pendingAuthRetry: {},\n };\n }\n\n // Rebuild the host record after a resilient-call verb, preserving the auth\n // dimension. The single seam where a `[ResilientState, Cmd[]]` becomes a\n // `[AuthedState, Cmd[]]`.\n function liftResilient(\n s: AuthedState<I, R>,\n [resilience, cmds]: readonly [ResilientState<I, R>, readonly RunCmd<I>[]],\n ): readonly [AuthedState<I, R>, readonly AuthedCmd<I>[]] {\n return [{ ...s, resilience }, cmds];\n }\n\n // Forget a key's auth bookkeeping: the 401 budget (`authRetry`) and any\n // parked input (`pendingAuthRetry`) that a settled or restarted call must\n // clear TOGETHER. These two records form a coupled invariant — a call that\n // settles, restarts, or gives up on its 401 dance drops both — so the joint\n // clear lives in one place rather than being open-coded at each site.\n function clearAuthKey(s: AuthedState<I, R>, key: string): AuthedState<I, R> {\n return {\n ...s,\n authRetry: without(s.authRetry, key),\n pendingAuthRetry: without(s.pendingAuthRetry, key),\n };\n }\n\n // === Verb: attempt =======================================================\n\n /**\n * Start (or restart) the call for `key`. Delegates the gate entirely to\n * resilient-call. A fresh attempt resets this key's auth-retry budget (a new\n * logical call gets its own single 401 retry) and drops any stale parked\n * input. PURE — `at` is the only clock.\n *\n * Note this knob does NOT proactively refresh on expiry inside `attempt`: the\n * expiry-driven refresh is the consumer's call-boundary concern (token-refresh\n * exposes `ensureFresh` for exactly that, re-exported below). `attempt` owns\n * the *reactive* path — it issues the call, and a 401 coming back triggers the\n * refresh. Keeping the two seams separate means a consumer who wants only\n * reactive auth (no proactive refresh) wires nothing extra.\n */\n function attempt(\n s: AuthedState<I, R>,\n key: string,\n input: I,\n at: number,\n ): readonly [AuthedState<I, R>, readonly AuthedCmd<I>[]] {\n const cleared = clearAuthKey(s, key);\n return liftResilient(\n cleared,\n rc.attempt(cleared.resilience, key, input, at),\n );\n }\n\n // === Verb: succeed =======================================================\n\n /**\n * Record a success for `key`: delegate to resilient-call (closes the breaker,\n * fills the cache, resets retry) and clear this key's auth-retry bookkeeping —\n * the call settled, so its 401 budget and any parked input are forgotten.\n * PURE.\n */\n function succeed(\n s: AuthedState<I, R>,\n key: string,\n msg: SucceedMsg<R>,\n ): readonly [AuthedState<I, R>, readonly AuthedCmd<I>[]] {\n const settled = clearAuthKey(s, key);\n return liftResilient(settled, rc.succeed(settled.resilience, key, msg));\n }\n\n // === Verb: fail ==========================================================\n\n /**\n * Record a NON-auth failure for `key` (a 5xx, a network drop — anything that\n * is not a 401). Delegate to resilient-call's `fail`, which trips the breaker\n * and backs off / settles per the retry policy. The auth dimension is\n * untouched: a generic failure says nothing about the credential. PURE.\n *\n * A 401 is NOT routed here — the consumer dispatches `unauthorized` and the\n * machine calls `on401` instead. Routing a 401 through `fail` would burn the\n * resilient retry budget on a credential that a plain re-issue cannot fix.\n */\n function fail(\n s: AuthedState<I, R>,\n key: string,\n msg: FailMsg,\n ): readonly [AuthedState<I, R>, readonly AuthedCmd<I>[]] {\n // If the resilient verb settles this call, forget its auth bookkeeping too.\n const [resilience, cmds] = rc.fail(s.resilience, key, msg);\n const next = settleAuthIfDone({ ...s, resilience }, key, resilience);\n return [next, cmds];\n }\n\n // === Verb: on401 =========================================================\n\n /**\n * The auth dimension's one verb: the server rejected `key`'s call as\n * unauthorized. \"Refresh → retry once\":\n *\n * - First 401 on this call → mark the token stale, emit a `refresh_token`\n * Cmd, and PARK the call's input so the refresh landing re-issues it. The\n * resilient call phase is left as-is (still `running`, or `waiting_retry`\n * if a transient failure had already backed it off); the in-flight\n * resilient effect is abandoned in favour of the post-refresh re-issue.\n * - Second 401 (the budget is already spent) → settle the call `failed`\n * with the unauthorized error. No second refresh, no loop. Errors are\n * data: the failure is recorded on the resilient slice, visible to the\n * consumer.\n *\n * A 401 is NOT a downstream-health signal — a credential the server rejected\n * says nothing about the backend's health. So the terminal path routes through\n * resilient-call's `settleFailed` (which settles `failed` WITHOUT tripping the\n * shared breaker or advancing this key's retry counter), never `fail` (which\n * would punish a healthy target and burn the retry budget on a request that a\n * plain re-issue cannot fix).\n *\n * PURE — `at` is carried for symmetry with the other verbs (the refresh Cmd\n * itself carries no time; the refresh port stamps its own result Msg).\n */\n function on401(\n s: AuthedState<I, R>,\n key: string,\n at: number,\n ): readonly [AuthedState<I, R>, readonly AuthedCmd<I>[]] {\n void at; // carried for symmetry; the async refresh's result Msg stamps the clock.\n const spent = s.authRetry[key] ?? 0;\n const call = s.resilience.calls[key];\n // A 401 can arrive while the call is `running` OR after a transient failure\n // backed it off to `waiting_retry`; both hold the input needed to re-issue.\n // Reading only `running` would drop a 401 that races a backoff — the call\n // would never refresh.\n const input =\n call?.phase === \"running\" || call?.phase === \"waiting_retry\"\n ? call.input\n : undefined;\n\n // Budget exhausted (already refreshed + retried once), or nothing to\n // re-issue: settle the call failed with the unauthorized error. Through\n // `settleFailed`, NOT `fail` — a 401 is not a breaker / retry signal.\n if (spent >= 1 || input === undefined) {\n const error: UnauthorizedError = { _tag: \"unauthorized\", key };\n const [settled] = rc.settleFailed(s.resilience, key, error);\n return [{ ...clearAuthKey(s, key), resilience: settled }, []];\n }\n\n // First 401: mark stale, park the call, ask for a fresh token.\n return [\n {\n ...s,\n auth: tr.on401(s.auth),\n authRetry: { ...s.authRetry, [key]: spent + 1 },\n pendingAuthRetry: { ...s.pendingAuthRetry, [key]: input },\n },\n [refreshTokenCmd()],\n ];\n }\n\n // === Verb: installToken ==================================================\n\n /**\n * Fold a freshly minted `token` into the auth slice (delegates to token-\n * refresh's `refreshed`: installs the token, clears `stale`). PURE. Call this\n * from the `token_refreshed` reducer cell, then chain `onRefreshed` to re-fire\n * the parked calls. Split from `onRefreshed` so a consumer can install a token\n * without auto-retrying (e.g. a proactive expiry refresh with nothing parked).\n */\n function installToken(s: AuthedState<I, R>, token: Token): AuthedState<I, R> {\n return { ...s, auth: tr.refreshed(s.auth, token) };\n }\n\n // === Verb: onRefreshed ===================================================\n\n /**\n * Re-issue every call parked by a 401 now that a fresh token has landed. Runs\n * each parked input back through resilient-call's `attempt` gate (so the\n * circuit / rate-limit / cache are all re-checked against the new `at`),\n * clears the parked set, and accumulates the run Cmds. The auth-retry COUNT is\n * preserved (each re-issued call has already spent one auth-retry, so a second\n * 401 on it settles failed). PURE — `at` is the gate's clock.\n *\n * No parked calls → a no-op that returns the slice unchanged by reference, so\n * a proactive (expiry) refresh with nothing in flight costs nothing.\n */\n function onRefreshed(\n s: AuthedState<I, R>,\n at: number,\n ): readonly [AuthedState<I, R>, readonly AuthedCmd<I>[]] {\n const parked = Object.entries(s.pendingAuthRetry);\n if (parked.length === 0) return [s, []];\n\n let resilience = s.resilience;\n const cmds: AuthedCmd<I>[] = [];\n for (const [key, input] of parked) {\n const [next, runCmds] = rc.attempt(resilience, key, input, at);\n resilience = next;\n cmds.push(...runCmds);\n }\n return [{ ...s, resilience, pendingAuthRetry: {} }, cmds];\n }\n\n // === Verb: onTimer =======================================================\n\n /**\n * A retry / deadline timer fired — delegate straight to resilient-call. If the\n * delegated verb settled the call, forget its auth bookkeeping. PURE.\n */\n function onTimer(\n s: AuthedState<I, R>,\n msg: ResilientTimerMsg,\n ): readonly [AuthedState<I, R>, readonly AuthedCmd<I>[]] {\n const [resilience, cmds] = rc.onTimer(s.resilience, msg);\n const next = settleAuthIfDone({ ...s, resilience }, undefined, resilience);\n return [next, cmds];\n }\n\n // --- helpers --------------------------------------------------------------\n\n // After a resilient verb, drop auth bookkeeping for any key the resilient\n // slice now reports as settled (succeeded / failed). `onlyKey` narrows the\n // scan to one key when the verb targeted one (fail); `undefined` scans all\n // (onTimer can settle a deadline on any key).\n function settleAuthIfDone(\n s: AuthedState<I, R>,\n onlyKey: string | undefined,\n resilience: ResilientState<I, R>,\n ): AuthedState<I, R> {\n const keys = onlyKey !== undefined ? [onlyKey] : Object.keys(s.authRetry);\n let next = s;\n for (const key of keys) {\n const phase = resilience.calls[key]?.phase;\n if (phase === \"succeeded\" || phase === \"failed\") {\n next = clearAuthKey(next, key);\n }\n }\n return next;\n }\n\n // === Subs ================================================================\n\n /**\n * Pre-wired subscriptions — exactly resilient-call's (retry + deadline timers\n * keyed per call). The auth dimension arms NO timers: a refresh is a one-shot\n * Cmd, not a recurring sub, and the parked-call re-issue is driven by the\n * `token_refreshed` Msg, not a timer. Wire `subscribe: { deadline:\n * subscribeDeadline }`.\n */\n function subs(s: AuthedState<I, R>): readonly DeadlineSub[] {\n return rc.subs(s.resilience);\n }\n\n // === Handlers ============================================================\n\n /**\n * Pre-wired interpret handlers: resilient-call's `resilient_run` (wraps the\n * `run` port) AND token-refresh's `refresh_token` (wraps the `refresh` port).\n * Both route Ok/Err through `tryInterpret`, stamping `Date.now()` at the\n * effect boundary — the only clock reads in the whole module. Assign to the\n * machine's `interpret`:\n *\n * interpret: ac.handlers({ run: ctx.call, refresh: () => sdk.mintToken() })\n */\n function handlers(ports: AuthedPorts<I, R>) {\n const trPorts: TokenRefreshPorts = { refresh: ports.refresh };\n return {\n ...rc.handlers({ run: ports.run }),\n ...tr.handlers(trPorts),\n };\n }\n\n return {\n init,\n attempt,\n succeed,\n fail,\n on401,\n installToken,\n onRefreshed,\n onTimer,\n /** token-refresh's call-boundary verb, re-exposed for proactive expiry refresh. */\n needsRefresh: (s: AuthedState<I, R>, at: number) =>\n tr.needsRefresh(s.auth, at),\n subs,\n handlers,\n };\n}\n\n/** The shape `createAuthedCall` returns — useful for typing a held knob. */\nexport type AuthedCall<I, R> = ReturnType<typeof createAuthedCall<I, R>>;\n\n/**\n * Lift a knob result `[slice, cmds]` into a host `[State, cmds]` where the slice\n * lives at `state.authed`. A convenience for the common single-slice host;\n * consumers with a differently-named field spread by hand. Pure — a thin record\n * rebuild, no clock / RNG.\n */\nexport function liftAuthed<\n S extends { authed: AuthedState<I, R> },\n I,\n R,\n C extends Cmd,\n>(\n state: S,\n [slice, cmds]: readonly [AuthedState<I, R>, readonly C[]],\n): readonly [S, readonly C[]] {\n return [{ ...state, authed: slice }, cmds];\n}\n\n/**\n * Re-export the deadline Sub primitives (this knob's `subs` emits `DeadlineSub`s,\n * inherited from resilient-call) and the token-refresh Msg constructors a\n * consumer wires into their reducer, so the whole composition imports from one\n * subpath.\n */\nexport { subscribeDeadline, deadlineSub };\nexport type {\n DeadlineSub,\n DeadlineExceeded,\n ResilientState,\n TokenState,\n Token,\n TokenRefreshMsg,\n SucceedMsg,\n FailMsg,\n ResilientTimerMsg,\n RunCmd,\n};\n","/**\n * internal/resilience/retry-to-success — run a fallible async port through BOUNDED\n * retry + exponential backoff to success-or-terminal-give-up, and hand the\n * caller a `Promise<R>` that resolves on the first success or REJECTS with a\n * checkable {@link RetryExhaustedError} the moment the retry bound is hit.\n *\n * This is the retry-side parallel to `./await-terminal`. `runToTerminal` gives a\n * caller with a one-shot decision *machine* a fire-and-await `Promise<State>`\n * without wiring `observe`; this gives a caller with a one-shot fallible *port*\n * a fire-and-await `Promise<R>` without either hand-folding the\n * `./retry-backoff` primitives (`recordFailure` / `shouldRetry` / `nextDelayMs`)\n * into their own reducer each time, or standing up the full `./resilient-call`\n * verb contract (`init` + `attempt`/`succeed`/`fail`/`onTimer` + `subs` +\n * `handlers`) when they want retry only and none of cache / circuit / rate-limit\n * / deadline.\n *\n * It adds NO new runtime capability and NO new backoff math — the whole retry\n * decision is `./retry-backoff` exactly as `resilient-call`'s `backoff` verb\n * wires it:\n * - `initRetry()` seeds the per-call attempt counter.\n * - `recordFailure(retry, error)` folds each thrown failure (attempt++).\n * - `shouldRetry(retry, policy)` is the terminal-at-`maxAttempts` bound — the\n * `maxAttempts`-th recorded failure refuses another attempt (attempts\n * `0 .. maxAttempts-1` run; the port is invoked at most `maxAttempts` times).\n * - `nextDelayMs(retry, policy, rng)` is the exp+jitter+cap delay before the\n * next attempt, computed on the incremented state — same call order as\n * `resilient-call`.\n *\n * Where the clock / RNG live: injected, never read on the module's own behalf,\n * mirroring `retry-backoff`'s purity discipline. `rng` is an {@link Rng} (branded\n * `[0, 1)` via `asRng` at the caller boundary) threaded straight into\n * `nextDelayMs`; the wait itself is a `sleep(ms)` port defaulting to a real\n * `setTimeout`, injectable so a test can drive the backoff schedule\n * deterministically without touching wall-clock timers.\n *\n * Exhaustion is NEVER a silent swallow: at the bound the returned promise\n * rejects with {@link RetryExhaustedError} (carrying the attempt count and the\n * final failure), the retry-side dialect of `await-terminal`'s\n * `TerminalTimeoutError` — a distinct `instanceof`- and `_tag`-checkable\n * rejection.\n *\n * NOT a substrate primitive: it depends on nothing from `../index`, only on the\n * leaf `retry-backoff` utility. Internal to the package\n * (`src/internal/resilience/`, #46), not a published subpath.\n */\n\nimport {\n defaultRng,\n initRetry,\n nextDelayMs,\n type RetryPolicy,\n type Rng,\n recordFailure,\n shouldRetry,\n} from \"../../../retry-backoff\";\n\n/**\n * Raised when `retryToSuccess` exhausts the retry bound without a success — the\n * `maxAttempts`-th recorded failure refuses another attempt. Follows the tea\n * error dialect (`override readonly name`) and carries a `_tag` discriminant, so\n * a caller can branch on it by `instanceof` or on the tag. It carries the number\n * of attempts made and the final failure (`lastError`) so the terminal give-up\n * is a distinct, checkable rejection — never a silent resolve, and never a\n * swallowed error.\n */\nexport class RetryExhaustedError extends Error {\n override readonly name = \"RetryExhaustedError\";\n readonly _tag = \"RetryExhaustedError\" as const;\n constructor(\n /** How many times the port was invoked before giving up (= `policy.maxAttempts`). */\n public readonly attempts: number,\n /** The failure the final attempt threw — carried, never interpreted. */\n public readonly lastError: unknown,\n ) {\n super(\n `@demlik/tea: retryToSuccess gave up after ${attempts} attempt(s) — the ` +\n `bounded retry reached maxAttempts without a success. See .lastError ` +\n `for the final failure.`,\n );\n }\n}\n\n/** Default wait: a real `setTimeout(ms)`, the sole clock read this module makes. */\nconst defaultSleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\n/** Options for {@link retryToSuccess}. */\nexport interface RetryToSuccessOptions {\n /**\n * The `[0, 1)` jitter source threaded into `nextDelayMs`, branded via\n * `asRng` at construction (a raw `() => number` is rejected by the type).\n * Injected for deterministic backoff in tests; defaults to `defaultRng`\n * (`Math.random`), read only at the delay boundary — never inside the loop's\n * decision.\n */\n readonly rng?: Rng;\n /**\n * The wait between attempts, given the backoff delay in ms. Injectable so a\n * test can drive the retry schedule without wall-clock timers (and assert the\n * exact delays); defaults to a real `setTimeout`. The delay value is always\n * `./retry-backoff`'s `nextDelayMs` — this port only realizes the wait.\n */\n readonly sleep?: (ms: number) => Promise<void>;\n}\n\n/**\n * Fire-and-await bounded retry: invoke the fallible `port`, and on each thrown\n * failure fold it through `./retry-backoff` — record it, and if the policy\n * still permits an attempt, back off `nextDelayMs` and retry; otherwise REJECT\n * with {@link RetryExhaustedError}. Resolves with the port's value on the first\n * success.\n *\n * The port is invoked at most `policy.maxAttempts` times (attempts\n * `0 .. maxAttempts-1`); the `maxAttempts`-th failure is terminal. Every failure\n * is either retried or surfaced on the rejection's `lastError` — none is\n * swallowed.\n *\n * @param port the fallible work — throws on failure, resolves with `R` on success.\n * @param policy the bounded-retry curve (`baseMs` / `factor` / `capMs` /\n * `maxAttempts` / `jitter`) from `./retry-backoff`.\n * @param opts optional injected `rng` (jitter) and `sleep` (the wait) — see\n * {@link RetryToSuccessOptions}.\n */\nexport async function retryToSuccess<R>(\n port: () => Promise<R>,\n policy: RetryPolicy,\n opts: RetryToSuccessOptions = {},\n): Promise<R> {\n const rng = opts.rng ?? defaultRng;\n const sleep = opts.sleep ?? defaultSleep;\n\n // The retry counter folds over `./retry-backoff` exactly as resilient-call's\n // `backoff` verb does — no local attempt bookkeeping, no local backoff math.\n let retry = initRetry();\n for (;;) {\n try {\n return await port();\n } catch (error) {\n // Fold the failure first (attempt++), then consult the bound on the\n // incremented state — same order as resilient-call so the semantics of\n // `maxAttempts` are identical across both surfaces.\n retry = recordFailure(retry, error);\n if (!shouldRetry(retry, policy)) {\n // Terminal give-up at the bound: reject, never swallow. `retry.attempt`\n // is the number of failures = the number of port invocations made.\n throw new RetryExhaustedError(retry.attempt, error);\n }\n await sleep(nextDelayMs(retry, policy, rng));\n }\n }\n}\n","/**\n * internal/resilience/with-deadline — auto-fail a wrapped machine at T+N, re-arm on\n * progress. A **pure function over machine data**: `withDeadline(base, config)`\n * takes any `Machine<S, M, C, U, Ctx>` and returns a NEW `Machine` over the\n * composed Model `{ base, $deadline }`. You `run()` / `replay()` the result\n * exactly like any other machine — there is no new runtime, no privileged\n * interception path.\n *\n * ## What it does\n *\n * The wrapper watches the base Msg stream. While the deadline is `armed`, a\n * RELATIVE timeout Sub counts down `config.ms`. Every base Msg the\n * `config.progress` predicate accepts (default: every base Msg) is treated as\n * activity: the wrapper bumps a numeric `seq`, which CHANGES the timer Sub's id,\n * so the substrate's reconcile pass retires the old countdown and starts a fresh\n * one — \"re-arm on progress\". If `config.ms` elapses with NO accepted progress,\n * the timeout Sub dispatches `$deadline:exceeded`; the merged `update` folds it\n * by flipping `phase` to `exceeded`, and from then on `subscriptions` returns no\n * timer (the machine has auto-failed). The expiry is a slice transition visible\n * in the Msg log — the auto-fail is never an off-ledger side effect.\n *\n * This is an OBSERVE-ONLY wrapper in the same sense as `withTelemetry`: it never\n * intercepts a base Cmd and never gates a base Msg. `state.base` after wrapping\n * is BYTE-IDENTICAL to running the base alone, so the shared\n * `assertWrapperFaithful` gate passes with the deadline bolted on.\n *\n * ## The 5 rules it satisfies (from the wrapper-tier contract)\n *\n * 1. **Named, serializable slice.** Wrapper state lives at `model.$deadline`,\n * a plain `{ phase, seq }` — JSON-serializable, never a closure. There is\n * NO absolute timestamp in the slice: the clock is never read in `update`.\n * 2. **Retag-and-re-emit, never swallow.** The merged `update` runs the base\n * reducer, passes its Cmds through UNCHANGED, and APPENDS its own\n * `$deadline:rearm` / `$deadline:expire` decision Cmd. No base Cmd ever\n * vanishes; nothing is gated.\n * 3. **Every decision is a Msg/Cmd.** Re-arm is a `$deadline:rearm` Cmd; the\n * auto-fail expiry is the `$deadline:exceeded` Msg the Sub delivers, folded\n * into the slice and echoed as a `$deadline:expire` Cmd. \"Why did this\n * fire\" is answerable from reducer + log alone.\n * 4. **Subs merge by id.** `subscriptions = [...base, ...deadlineSubs]`; the\n * timeout id is `$deadline:timeout:{seq}`, so a progress bump (seq+1)\n * yields a NEW id — the substrate retires the old timer and arms a fresh\n * one. When `exceeded`, no deadline sub is returned.\n * 5. **Clock out of update.** The countdown is a relative-timeout Sub; the\n * clock is read at subscribe time inside the Sub (`setTimeout`), NEVER in a\n * verb. The slice carries `seq`, not a deadline timestamp.\n *\n * ## Typical wiring\n *\n * const guarded = withDeadline(baseMachine, {\n * ms: 900_000, // auto-fail after 15 minutes of inactivity\n * progress: (msg) => msg.type !== \"heartbeat\", // heartbeats don't re-arm\n * });\n * const runtime = run(guarded, { ctx: baseCtx });\n */\n\nimport { z } from \"zod\";\nimport {\n applyCell,\n Cmd,\n type CmdOf,\n type Interpret,\n type Machine,\n msgKeysOf,\n type Reducer,\n type Sub,\n type Subscribe,\n subId,\n} from \"../../../index\";\nimport { fromTimeout } from \"../../../subs/from-timeout\";\n\n// ===========================================================================\n// The slice + the Sub + the Msg + the Cmds — the deadline vocabulary.\n// ===========================================================================\n\n/**\n * The wrapper's Model slice. `phase` is the lifecycle (`armed` while the\n * countdown runs, `exceeded` once the deadline fired); `seq` is the monotonic\n * re-arm counter that keys the timer Sub's id so each accepted progress Msg\n * retires the old timer and starts a fresh one.\n *\n * PURE and SERIALIZABLE: there is deliberately NO absolute timestamp here. A\n * deadline timestamp would force the merged `update` to read the wall clock to\n * compute it, which the conformance gate (property 2 — two replays under\n * distinct ambient clocks) is built to catch. Instead, the timer arms a fresh\n * full `ms` countdown per generation; no remaining-delay computation and no\n * clock read occur in the slice or `update` — the only clock is `setTimeout`\n * inside the Sub.\n */\nexport interface DeadlineSlice {\n /** `armed` while the countdown is live; `exceeded` once the deadline fired. */\n readonly phase: \"armed\" | \"exceeded\";\n /**\n * Monotonic re-arm counter. Starts at 0; each accepted progress Msg (while\n * armed) bumps it by one. Folds into the timer Sub's id, so a bump = a new id\n * = the substrate retires the old timer and arms a fresh `ms` countdown.\n */\n readonly seq: number;\n}\n\n/**\n * The composed Model. The base machine's state is nested under `base`; the\n * wrapper's state lives in the NAMED `$deadline` slice — never hidden in a\n * closure. Both fields are plain data, so the whole composed Model round-trips\n * through `JSON.parse(JSON.stringify(...))` iff the base state does.\n */\nexport interface DeadlineModel<S> {\n readonly base: S;\n readonly $deadline: DeadlineSlice;\n}\n\n/**\n * The relative-timeout Sub the wrapper arms while `phase === \"armed\"`. `delayMs`\n * is the window `config.ms`; the id is `$deadline:timeout:{seq}`, so each\n * progress bump produces a distinct id and the reconcile pass churns the timer.\n * Same `delayMs`-on-the-Sub shape `fromTimeout` consumes.\n */\nexport type DeadlineTimeoutSub = Sub<\"$deadline:timeout\"> & {\n readonly delayMs: number;\n};\n\n/**\n * The Msg the timeout Sub dispatches when `config.ms` elapses with no accepted\n * progress. `seq` echoes the re-arm generation the timer was armed against, so a\n * stale timer's Msg (one whose id was already retired) is identifiable; the\n * merged `update` only honors it when it matches the current slice `seq`.\n */\nexport interface DeadlineExceededMsg {\n readonly type: \"$deadline:exceeded\";\n /** The re-arm generation this timer was armed against. */\n readonly seq: number;\n}\n\n/**\n * Construct the deadline-exceeded Msg. Exported so the subscribe cell and tests\n * share one constructor rather than two literals that can drift.\n */\nexport function deadlineExceededMsg(seq: number): DeadlineExceededMsg {\n return { type: \"$deadline:exceeded\", seq };\n}\n\n/**\n * The fire-and-forget decision Cmd the merged `update` appends on every\n * transition, so the wrapper's choice is visible in the replayed Cmd log\n * (rule 3) — `rearm` when an accepted progress Msg bumped `seq`, `expire` when\n * the deadline-exceeded Msg flipped the phase, `idle` otherwise (a non-progress\n * Msg, or a Msg after the machine already auto-failed). Plain data; its\n * interpret handler is a no-op (the decision is the Cmd's presence in the log,\n * not a side effect).\n */\nexport const deadlineDecision = Cmd.define(\"$deadline:decision\", {\n input: z.object({\n decision: z.enum([\"rearm\", \"expire\", \"idle\"]),\n /** The slice `seq` AFTER this transition (the re-arm generation now armed). */\n seq: z.number(),\n }),\n ok: z.void(),\n err: [],\n});\nexport type DeadlineDecisionCmd = CmdOf<typeof deadlineDecision>;\n\n/**\n * A predicate over a Msg that decides whether it re-arms the deadline.\n *\n * The argument is `Readonly<M>` and the result is `boolean`: this is the\n * STRONGEST purity TS can express here. `Readonly<M>` removes the most common\n * impurity at compile time — the predicate cannot reassign the Msg's own\n * fields — and `boolean` pins the return so a side-effecting `(msg) => { … }`\n * with an implicit `undefined`/`void` return is rejected.\n *\n * What the type system CANNOT encode (TS has no effect tracking): observational\n * purity. A body that reads `Date.now()`, calls `Math.random()`, performs IO,\n * or closes over and mutates external state still type-checks. Those remain a\n * CONVENTION enforced by review, not the compiler — the predicate runs inside\n * the pure merged `update` (invariant 2), so it must be a pure function of the\n * Msg alone: no clock, no RNG, no IO, no captured mutable state.\n */\nexport type ProgressPredicate<M extends { type: string }> = (\n msg: Readonly<M>,\n) => boolean;\n\n/**\n * The deadline knob. `ms` is the inactivity window; `progress` is an OPTIONAL\n * predicate picking which base Msgs count as activity (default: EVERY base Msg\n * re-arms). The predicate runs INSIDE the pure merged `update`, so it must be a\n * pure function of the Msg — see {@link ProgressPredicate} for what the type\n * enforces vs. what stays a convention.\n */\nexport interface DeadlineConfig<M extends { type: string }> {\n /** The inactivity window in milliseconds. Auto-fail after `ms` with no progress. */\n readonly ms: number;\n /**\n * Predicate picking which base Msgs re-arm the timer. Default: every base Msg\n * counts as progress. Pure — a function of the Msg alone (see\n * {@link ProgressPredicate}).\n */\n readonly progress?: ProgressPredicate<M>;\n}\n\n// ===========================================================================\n// withDeadline — the wrapper.\n// ===========================================================================\n\n/**\n * Wrap `base` with an inactivity deadline. Returns a NEW `Machine` over the\n * composed Model `{ base, $deadline }`, with the base's Msgs/Cmds/Subs extended\n * by the wrapper's own (`$deadline:exceeded` Msg, `$deadline:decision` Cmd,\n * `$deadline:timeout` Sub).\n *\n * The composed machine:\n * - `init` rehydrates the base (honoring the `[loaded, []]` contract) and\n * seeds `$deadline: { phase: \"armed\", seq: 0 }`. Base init Cmds pass\n * through unchanged.\n * - `update` (Reducer form) runs the base reducer for base Msgs — base Cmds\n * pass through UNCHANGED — and on an accepted progress Msg bumps `seq`\n * (re-arm). The `$deadline:exceeded` Msg cell flips `phase` to `exceeded`.\n * Every transition appends a `$deadline:decision` marker Cmd.\n * - `subscriptions` is the base's, plus a `$deadline:timeout` Sub keyed on\n * `seq` while `phase === \"armed\"`.\n * - `subscribe` is the base's, plus the `$deadline:timeout` cell.\n * - `interpret` is the base's, plus a no-op `$deadline:decision` handler.\n *\n * @param base any `Machine<S, M, C, U, Ctx>`.\n * @param config the deadline knob (`ms` window + optional `progress` predicate).\n */\nexport function withDeadline<\n S,\n M extends { type: string },\n C extends Cmd,\n U extends Sub,\n Ctx,\n>(\n base: Machine<S, M, C, U, Ctx>,\n config: DeadlineConfig<M>,\n): Machine<\n DeadlineModel<S>,\n M | DeadlineExceededMsg,\n C | DeadlineDecisionCmd,\n U | DeadlineTimeoutSub,\n Ctx\n> {\n const windowMs = config.ms;\n const isProgress = config.progress;\n\n // The merged update is a flat Reducer over the composed Model. The composed\n // Model is NOT discriminated on `.type`, so every (base Msg variant + the\n // wrapper's own `$deadline:exceeded`) gets exactly one cell.\n type Next = readonly [DeadlineModel<S>, readonly (C | DeadlineDecisionCmd)[]];\n const update = {} as Record<\n string,\n (state: DeadlineModel<S>, msg: M | DeadlineExceededMsg) => Next\n >;\n\n // Namespace guard for the Msg/update surface (mirrors the interpret +\n // subscribe guards below). The `$deadline:exceeded` cell is assigned into\n // `update` after this loop; if a base Msg.type already lives in the\n // `$deadline:` namespace, that assignment — or this loop — would SILENTLY\n // clobber / be clobbered by a base cell. The `$deadline:` Msg namespace is\n // the wrapper's: refuse to wrap a base that squats on it.\n // Base Msg keys enumerated via `msgKeysOf(base)` — keyed on the\n // authoritative `__form` tag, no structural re-derivation here (#275).\n const baseMsgKeys = msgKeysOf(base);\n for (const key of baseMsgKeys) {\n if (key.startsWith(\"$deadline:\")) {\n throw new Error(\n `withDeadline: the base machine declares a reserved \"${key}\" update ` +\n 'cell — the wrapper owns the \"$deadline:\" Msg namespace. ' +\n \"Rename the base Msg.\",\n );\n }\n }\n\n for (const key of baseMsgKeys) {\n update[key] = (state, msg) => {\n // 1) Run the base reducer — its result passes through UNCHANGED.\n const [nextBase, baseCmds] = applyCell<S, M, C>(\n base,\n state.base,\n msg as M,\n );\n // 2) Re-arm decision: a progress Msg WHILE armed bumps `seq` (new timer\n // id → fresh countdown). After auto-fail, or for a non-progress Msg,\n // the slice is unchanged and the decision is `idle`.\n const armed = state.$deadline.phase === \"armed\";\n const counts =\n armed && (isProgress === undefined || isProgress(msg as M));\n const $deadline: DeadlineSlice = counts\n ? { phase: \"armed\", seq: state.$deadline.seq + 1 }\n : state.$deadline;\n const next: DeadlineModel<S> = { base: nextBase, $deadline };\n // 3) Append the visible decision marker. Base Cmds come FIRST, unchanged.\n const decision = deadlineDecision({\n decision: counts ? \"rearm\" : \"idle\",\n seq: $deadline.seq,\n });\n return [next, [...baseCmds, decision]];\n };\n }\n\n // The wrapper's own Msg cell. The timeout Sub delivers `$deadline:exceeded`\n // carrying the `seq` it was armed against. Honor it ONLY while armed and ONLY\n // when the `seq` matches the current generation — a stale timer's Msg (from a\n // generation already retired by a re-arm, or arriving after auto-fail) is a\n // no-op that still records a visible `idle` decision. The expiry flips `phase`\n // to `exceeded`; the slice transition IS the auto-fail, visible in the log.\n update[\"$deadline:exceeded\"] = (state, msg) => {\n const m = msg as DeadlineExceededMsg;\n const fires =\n state.$deadline.phase === \"armed\" && m.seq === state.$deadline.seq;\n const $deadline: DeadlineSlice = fires\n ? { phase: \"exceeded\", seq: state.$deadline.seq }\n : state.$deadline;\n const next: DeadlineModel<S> = { base: state.base, $deadline };\n const decision = deadlineDecision({\n decision: fires ? \"expire\" : \"idle\",\n seq: $deadline.seq,\n });\n return [next, [decision]];\n };\n\n // The base's interpret, extended with the one no-op decision handler. The\n // `$deadline:decision` Cmd has no I/O — its purpose is log visibility (rule 3),\n // so the handler returns void and dispatches nothing. Namespace guard mirrors\n // withTelemetry: refuse to wrap a base that squats on the reserved Cmd key.\n const baseInterpret =\n (base as { interpret?: Interpret<M, C, Ctx> }).interpret ??\n ({} as Interpret<M, C, Ctx>);\n if (Object.hasOwn(baseInterpret as object, \"$deadline:decision\")) {\n throw new Error(\n 'withDeadline: the base machine declares a reserved \"$deadline:decision\" ' +\n 'interpret handler — the wrapper owns the \"$deadline:\" Cmd namespace. ' +\n \"Rename the base handler.\",\n );\n }\n const interpret = {\n ...(baseInterpret as Record<string, unknown>),\n \"$deadline:decision\": async (): Promise<void> => {},\n } as Interpret<M | DeadlineExceededMsg, C | DeadlineDecisionCmd, Ctx>;\n\n // Subs merge by id: the base's, plus the deadline countdown while armed. The\n // timeout id folds in `seq`, so each progress bump yields a NEW id and the\n // reconcile pass retires the old timer + arms a fresh `ms` countdown. When\n // exceeded, no deadline sub is returned (the machine has auto-failed).\n const baseSubscriptions = base.subscriptions;\n const subscriptions = (\n state: DeadlineModel<S>,\n ): readonly (U | DeadlineTimeoutSub)[] => {\n const baseSubs = baseSubscriptions ? baseSubscriptions(state.base) : [];\n if (state.$deadline.phase !== \"armed\") return baseSubs;\n const timeout: DeadlineTimeoutSub = {\n id: subId(`$deadline:timeout:${state.$deadline.seq}`),\n type: \"$deadline:timeout\",\n delayMs: windowMs,\n };\n return [...baseSubs, timeout];\n };\n\n // The base's subscribe cells, plus the timeout cell. The clock is read here —\n // at subscribe time, inside the Sub's `setTimeout` — NEVER in a verb. The\n // dispatched Msg carries the `seq` the timer was armed against so the merged\n // update can reject a stale generation.\n const baseSubscribe =\n (base as { subscribe?: Subscribe<M, U, Ctx> }).subscribe ??\n ({} as Subscribe<M, U, Ctx>);\n if (Object.hasOwn(baseSubscribe as object, \"$deadline:timeout\")) {\n throw new Error(\n 'withDeadline: the base machine declares a reserved \"$deadline:timeout\" ' +\n 'subscribe handler — the wrapper owns the \"$deadline:\" Sub namespace. ' +\n \"Rename the base handler.\",\n );\n }\n const timeoutCell = fromTimeout<DeadlineTimeoutSub, DeadlineExceededMsg>(\n (sub) => {\n // The sub id is `$deadline:timeout:{seq}`; recover the generation it was\n // armed against so a stale timer's Msg is identifiable in the reducer.\n const seq = Number(sub.id.slice(sub.id.lastIndexOf(\":\") + 1));\n return deadlineExceededMsg(seq);\n },\n );\n const subscribe = {\n ...(baseSubscribe as Record<string, unknown>),\n \"$deadline:timeout\": timeoutCell,\n } as Subscribe<M | DeadlineExceededMsg, U | DeadlineTimeoutSub, Ctx>;\n\n return {\n init: (loaded, ctx) => {\n // Rehydrate path: `loaded !== null` MUST return `[loaded, []]` (no Cmds) —\n // the substrate's replay enforces this. We split the composed loaded Model\n // into its base slice and feed the base its own loaded snapshot.\n if (loaded !== null) {\n return [loaded, []];\n }\n const [base0, cmds] = base.init(null, ctx);\n const model: DeadlineModel<S> = {\n base: base0,\n $deadline: { phase: \"armed\", seq: 0 },\n };\n // Base init Cmds pass through unchanged; no deadline Cmd on boot (boot is\n // not a base Msg transition, so it does not re-arm).\n return [model, cmds];\n },\n update: update as unknown as Reducer<\n DeadlineModel<S>,\n M | DeadlineExceededMsg,\n C | DeadlineDecisionCmd\n >,\n subscriptions,\n subscribe,\n interpret,\n // The base's `Cmd.define` list rides through so `run`'s interpret edge\n // still parses / stamps the base's settled Msgs behind the wrap (#66).\n ...(base.cmds ? { cmds: base.cmds } : {}),\n } as Machine<\n DeadlineModel<S>,\n M | DeadlineExceededMsg,\n C | DeadlineDecisionCmd,\n U | DeadlineTimeoutSub,\n Ctx\n >;\n}\n","/**\n * @packageDocumentation\n *\n * internal/resilience/with-resilience — the INTERCEPTING wrapper of the wrapper tier.\n *\n * `withResilience(base, config)` is a **pure function over machine data**: it\n * takes any `Machine<S, M, C, U, Ctx>`, a chosen TARGET base Cmd type, and a\n * resilience knob, and returns a NEW `Machine` over the composed Model\n * `{ base, $resilience }`. You `run()` / `replay()` the result exactly like any\n * other machine — there is no new runtime, no privileged interception path.\n *\n * This is the HARDEST wrapper. `withTelemetry` only OBSERVES; this one\n * INTERCEPTS. It bolts the resilient-call concern (cache → circuit-breaker →\n * rate-limit → exponential-backoff retry, with a deadline cap) onto a chosen\n * base Cmd WITHOUT the base authoring any of it. The base keeps emitting its\n * plain effect Cmd; the wrapper diverts each one through the resilience gate.\n *\n * ## Retag, never swallow (rule 2 — the whole danger)\n *\n * The merged `update` delegates to `base.update`, then PARTITIONS the base Cmds\n * by type:\n *\n * - A NON-target base Cmd passes through UNCHANGED — byte-identical, in the\n * same slot. The wrapper does not touch effects it was not asked to harden.\n * - A TARGET base Cmd is RETAGGED: it becomes the `input` payload of a\n * `$resilience:run` carrier Cmd (when the gate admits it), OR its gating is\n * RECORDED as a `$resilience:*` decision in the SAME transition (cache hit,\n * circuit-open fast-fail, rate-limited backoff). It is NEVER emitted raw,\n * and it NEVER vanishes without a `$resilience:*` Cmd recording where it\n * went. That recorded divergence is exactly what the conformance gate's\n * `intercepting` option verifies.\n *\n * The resilient-call result Msgs route back through the merged `update`:\n * `$resilience:ok` → `succeed` (close the breaker, fill the cache, reset the\n * retry run), `$resilience:err` → `fail` (trip the breaker, then back off or\n * settle), `$resilience:timer` → `onTimer` (a retry timer re-runs the gate; a\n * deadline timer settles the call failed). Every decision is a Msg/Cmd through\n * the reducer + log — \"why did this fire\" is answerable from the log alone.\n *\n * ## The base's follow-up is DELIVERED, not just recorded\n *\n * The base interpret handler resolves `M | void` exactly as it would unwrapped.\n * The wrapper never inspects that value, but it does deliver it: once the\n * resilience verbs settle a call — `succeed` on `$resilience:ok`, or the cache\n * serving a fresh hit with no run at all — a resolved Msg is folded through the\n * base reducer in the same transition, by the same delegate-then-partition path\n * a host-dispatched base Msg takes. So the base's own `fetch_ok` / `fetch_err`\n * cell runs behind the wrap, a follow-up that re-emits the target is retagged\n * like any other, and a `void` resolution delivers nothing. The settled value\n * stays in `$resilience.calls[key].result` too — the retry / circuit / cache\n * verbs read it there. A thrown handler never reaches the base: it is a\n * `$resilience:err`, the resilience layer's to retry or settle failed.\n *\n * Delivery is a fold, not a dispatch: the follow-up never appears in the Msg\n * log as its own entry (an update cell cannot dispatch a Msg — rule 5 keeps\n * the reducer pure), so replaying `$resilience:ok` reproduces the base's cell\n * run exactly. And it is bounded within one transition: under `cache`, a\n * delivered follow-up that re-emits the target under the key just filled is\n * served from the cache and recorded in the slice, but the served Msg — the one\n * already in the base's hand — is not folded a second time.\n *\n * ## The slice + verbs are REUSED, not reinvented\n *\n * The `$resilience` slice IS resilient-call's `ResilientState<I, R>` (per-key\n * call / retry / circuit / bucket / cache), and the gate / backoff / breaker\n * logic IS its `attempt` / `succeed` / `fail` / `onTimer` verbs + `subs`. The\n * wrapper only ADAPTS the boundary: the verb's `input` is the ORIGINAL base\n * Cmd, the verb's `resilient_run` carrier is renamed to `$resilience:run`, and\n * the sub / timer ids are re-keyed into the `$resilience:` namespace (rule 4).\n *\n * ## The 5 rules it satisfies\n *\n * 1. **Named, serializable slice.** `model.$resilience` is resilient-call's\n * plain-data `ResilientState` — JSON-serializable (the deadline error is a\n * `{_tag,...}` sentinel, never a `new Error`), never a closure.\n * 2. **Retag-and-re-emit, never swallow.** See above — a target base Cmd is\n * always inside a `$resilience:run` inner payload or recorded by a\n * `$resilience:*` divergence Cmd in the same transition.\n * 3. **Every decision is a Msg/Cmd.** Gate / retry-schedule / fast-fail /\n * settle are all `$resilience:*` Cmds and Msgs through the merged `update`.\n * 4. **Subs merge by id.** Base subs ⧺ resilient-call retry/deadline timers,\n * re-keyed `$resilience:retry:{key}` / `$resilience:deadline:{key}`.\n * 5. **Clock out of update.** Backoff jitter RNG is injected at construction;\n * the only clock read is `Date.now()` at the interpret boundary (the\n * `$resilience:run` handler stamps the ok/err Msg `at`) and in the timer\n * Sub. The merged `update` is PURE — `at` arrives as Msg data.\n *\n * ## The retry bound may be a DURATION, not only a count\n *\n * `config.retry` is resilient-call's `AnyRetryPolicy`: a count (`RetryPolicy`),\n * a wall-clock outage budget (`DurationRetryPolicy`, `maxElapsedMs`), or an\n * explicit `unbounded: true`. Nothing extra is wired for the duration bound and\n * nothing extra is required of the base machine — rule 5 already made the clock\n * arrive as DATA on exactly the Msgs the streak is measured from:\n * `$resilience:err.at` (stamped by the wrapper's own `$resilience:run` handler\n * at the interpret boundary) and `$resilience:timer.atMs` (the Sub's fire\n * instant). Those are the two instants `recordFailure` / `shouldRetry` are fed,\n * so an outage budget is measured against true wall time even when\n * `config.at` is absent — the cold gate's `at` never records a failure.\n *\n * `config.at` therefore stays REQUIRED-when-time-sensitive-brick and OPTIONAL\n * otherwise, unchanged: a duration-bounded retry does NOT make it required,\n * because the cold attempt is not a failure observation.\n */\n\nimport { z } from \"zod\";\nimport type {\n CmdOf,\n Interpret,\n Machine,\n Reducer,\n Sub,\n UpdateForm,\n} from \"../../../index\";\nimport {\n applyCell,\n Cmd,\n formOf,\n msgKeysOf,\n subId,\n tryInterpret,\n} from \"../../../index\";\nimport { MsgType } from \"../../../protocol\";\nimport { cmdEdgeOf } from \"../../../pure/core\";\nimport { type DeadlineSub, subscribeDeadline } from \"../deadline\";\nimport {\n createResilientCall,\n type ResilientConfig,\n type ResilientState,\n} from \"../resilient-call\";\n\n// ===========================================================================\n// Config — the target + the resilience knob + an optional key deriver.\n// ===========================================================================\n\n/**\n * The `withResilience` knob. Extends resilient-call's `ResilientConfig` (every\n * brick optional — omit a brick, omit its gate) with the two fields the wrapper\n * needs that the bare knob does not:\n *\n * - `target` — the `Cmd.type` discriminant of the ONE base Cmd this wrapper\n * hardens. Every other base Cmd passes through untouched.\n * - `keyOf` — OPTIONAL. Derives the per-call resilience `key` from the target\n * base Cmd, so distinct logical calls (distinct urls, distinct ids) get\n * independent retry / cache state. Pure — it runs inside the merged\n * `update`, so it must NOT read the clock / RNG. Defaults to a single\n * shared key (`target`), i.e. one logical call at a time.\n */\nexport interface ResilienceConfig<TC extends Cmd, TM extends { type: string }>\n extends ResilientConfig {\n /** The base `Cmd.type` to make resilient. */\n readonly target: TC[\"type\"];\n /** Optional per-call key deriver. Pure. Defaults to the target type itself. */\n readonly keyOf?: (cmd: TC) => string;\n /**\n * Extracts the real wall-clock time (ms) the TRIGGERING base Msg carries as\n * data — the time-as-data convention `resilient-call` expects on `attempt`.\n *\n * The merged `update` is PURE: it cannot read `Date.now()` (rule 5). The COLD\n * attempt's gate (the very first `attempt` for a target Cmd in a transition)\n * still needs a real instant — the breaker compares `at` against its recorded\n * `openedAtMs`, the cache against its write `at`, the bucket against its last\n * refill `at`, and the deadline cap anchors at `at + deadline.ms`. Fabricating\n * `at = 0` is the betrayal: a cold attempt after a real-time breaker trip then\n * computes cooldown = `0 - realTripTime < 0` forever, so the breaker NEVER\n * recovers, and a `0`-anchored deadline brick fires immediately.\n *\n * So the base Msg that drove this transition MUST carry its own wall time as\n * data, and `at` reads it off that Msg. The merged update passes\n * `at(currentBaseMsg)` into `rc.attempt` for every target Cmd that transition\n * emitted — real time enters the cold gate as Msg data, never `0`.\n *\n * REQUIRED whenever any time-sensitive brick (`circuit`, `rateLimit`, `cache`,\n * `deadline`) is configured — `withResilience` THROWS at construction if such\n * a brick is set and `at` is absent (errors are data: the cold gate needs real\n * time, refuse to build a breaker that can never recover). OPTIONAL when only\n * `retry` is configured: retry backoff reads its time off the result / timer\n * Msgs (`$resilience:err.at`, `$resilience:timer.atMs`), never the cold attempt\n * — so a `0` cold `at` is harmless there. Pure: it runs inside the merged\n * `update`, so it must NOT read the clock / RNG.\n */\n readonly at?: (msg: TM) => number;\n}\n\n// ===========================================================================\n// The slice + the wrapper Cmds/Msgs/Subs/Ports vocabulary.\n// ===========================================================================\n\n/**\n * The composed Model. The base machine's state nests under `base`; the wrapper\n * owns the NAMED `$resilience` slice — resilient-call's `ResilientState` keyed\n * by the per-call `key`, with `I = TC` (the original target base Cmd is the\n * port input) and `R = unknown` (the base interpret handler's resolution — the\n * wrapper never inspects it; it routes Ok/Err and delivers a Msg to the base).\n * Plain data → round-trips through `JSON.parse(JSON.stringify(...))` iff the\n * base state does.\n */\nexport interface ResilienceModel<S, TC extends Cmd> {\n readonly base: S;\n readonly $resilience: ResilientState<TC, unknown>;\n}\n\n/**\n * The carrier Cmd the wrapper emits when the gate ADMITS a target base Cmd. It\n * RETAGS the original base Cmd into `input` — the base Cmd is plain data, so no\n * closure (invariant 3). The interpret handler unwraps `input` and runs it\n * through the BASE interpret for that Cmd type. `key` indexes the resilient\n * call this run belongs to.\n */\nexport function resilienceRunCmdDef<TC extends Cmd, TM>() {\n return Cmd.define(\"$resilience:run\", {\n input: z.custom<{\n readonly key: string;\n /** The ORIGINAL base Cmd, retagged — never swallowed. */\n readonly input: TC;\n }>(),\n // The carried result is the base interpret handler's resolution (`M | void`).\n // biome-ignore lint/suspicious/noConfusingVoidType: mirrors `Interpret`'s own `Promise<M | void>`\n ok: z.custom<TM | void>(),\n err: [\"base_rejected\", \"deadline_exceeded\"],\n });\n}\nexport type ResilienceRunCmd<TC extends Cmd> = CmdOf<\n ReturnType<typeof resilienceRunCmdDef<TC, unknown>>\n>;\n\n/**\n * The success Msg the `$resilience:run` handler dispatches back when the base\n * interpret resolved OK. Routes to `succeed`, then `result` — the base\n * handler's follow-up, when it is a Msg — is folded through the base reducer.\n * `at` is stamped at the interpret boundary (the one permitted clock read).\n */\nexport type ResilienceOkMsg = {\n readonly type: \"$resilience:ok\";\n readonly key: string;\n readonly result: unknown;\n readonly at: number;\n};\n\n/**\n * The error Msg the `$resilience:run` handler dispatches back when the base\n * interpret threw / rejected. Routes to `fail` (trip the breaker, then back off\n * or settle). `at` is stamped at the interpret boundary.\n */\nexport type ResilienceErrMsg = {\n readonly type: \"$resilience:err\";\n readonly key: string;\n readonly error: unknown;\n readonly at: number;\n};\n\n/**\n * The retry / deadline timer Msg the `$resilience:timer` Sub dispatches when\n * the wall clock crosses the armed instant. Routes to `onTimer`. `id` is the\n * `$resilience:`-namespaced timer id; `atMs` is the fire instant (Msg data, the\n * clock that drove it lives in the Sub).\n */\nexport type ResilienceTimerMsg = {\n readonly type: \"$resilience:timer\";\n readonly id: string;\n readonly atMs: number;\n};\n\n/** Every Msg the wrapper adds to the base's Msg union. */\nexport type ResilienceMsg =\n | ResilienceOkMsg\n | ResilienceErrMsg\n | ResilienceTimerMsg;\n\n/** Every Cmd the wrapper adds to the base's Cmd union. */\nexport type ResilienceCmd<TC extends Cmd> = ResilienceRunCmd<TC>;\n\n/** The Sub the wrapper adds — a deadline-style timer in the `$resilience` family. */\nexport type ResilienceTimerSub = Sub<\"$resilience:timer\"> & {\n readonly atMs: number;\n};\n\n// ===========================================================================\n// Boundary re-keying — the resilient-call namespace ↔ the `$resilience` one.\n// ===========================================================================\n\n// resilient-call emits its carrier as `resilient_run` and keys its timer Subs\n// `resilient:retry:{key}` / `resilient:deadline:{key}`. The wrapper presents the\n// `$resilience:` namespace to the outside world (rule 4) while REUSING the\n// unmodified verbs underneath. These two pure string maps are the only seam:\n// rename the carrier on the way OUT, re-key the timer id on the way IN.\n\nconst RC_RETRY_PREFIX = \"resilient:retry:\";\nconst RC_DEADLINE_PREFIX = \"resilient:deadline:\";\nconst WX_RETRY_PREFIX = \"$resilience:retry:\";\nconst WX_DEADLINE_PREFIX = \"$resilience:deadline:\";\n\n/** resilient-call internal sub id → the `$resilience:`-namespaced public id. */\nfunction toWrapperTimerId(rcId: string): string {\n if (rcId.startsWith(RC_RETRY_PREFIX))\n return WX_RETRY_PREFIX + rcId.slice(RC_RETRY_PREFIX.length);\n if (rcId.startsWith(RC_DEADLINE_PREFIX))\n return WX_DEADLINE_PREFIX + rcId.slice(RC_DEADLINE_PREFIX.length);\n return rcId;\n}\n\n/** The `$resilience:`-namespaced timer id → the resilient-call internal id. */\nfunction toRcTimerId(wxId: string): string {\n if (wxId.startsWith(WX_RETRY_PREFIX))\n return RC_RETRY_PREFIX + wxId.slice(WX_RETRY_PREFIX.length);\n if (wxId.startsWith(WX_DEADLINE_PREFIX))\n return RC_DEADLINE_PREFIX + wxId.slice(WX_DEADLINE_PREFIX.length);\n return wxId;\n}\n\n/**\n * Does the base machine declare `key` as a Msg.type cell, in EITHER update\n * form? The reserved-namespace guard checks the correct level per form (keyed\n * on `formOf`, the same classification `applyCell` / `msgKeysOf` use):\n *\n * - Reducer form (`{ [msgType]: cell }`, values are functions) — the\n * msg-type keys live at the TOP level, so `Object.hasOwn(update, key)`.\n * - Transitions form (`{ [stateType]: { [msgType]: cell } }`, values are\n * records) — the msg-type keys live in the INNER tables, one per state.\n * A reserved msg-type can hide in ANY inner table, so scan EVERY inner\n * table; a collision in even one inner cell would let a transitions-form\n * base squat on e.g. an inner `$resilience:ok` cell that the wrapper's\n * merged update would silently clobber. Top-level `Object.hasOwn` (the\n * old check) only sees state-type keys here and would MISS it entirely.\n */\nfunction updateDeclaresMsgKey(\n machine: { update: object; __form?: UpdateForm },\n key: string,\n): boolean {\n if (formOf(machine) === \"reducer\") {\n // Reducer form — msg-type keys at the top level.\n return Object.hasOwn(machine.update, key);\n }\n // Transitions form — msg-type keys live in each inner state-type table. An\n // inner table can be a callable object (the shape `__form` disambiguates),\n // so accept \"function\" alongside \"object\" here.\n for (const innerTable of Object.values(machine.update)) {\n if (\n innerTable !== null &&\n (typeof innerTable === \"object\" || typeof innerTable === \"function\") &&\n Object.hasOwn(innerTable, key)\n ) {\n return true;\n }\n }\n return false;\n}\n\n// ===========================================================================\n// withResilience — the wrapper.\n// ===========================================================================\n\n/**\n * Wrap `base` so its `config.target` Cmd is run through the resilient-call\n * concern (cache → circuit → rate-limit → retry, deadline-capped). Returns a\n * NEW `Machine` over the composed Model `{ base, $resilience }`, with the\n * base's Msgs/Cmds/Subs/Ctx extended by the wrapper's own.\n *\n * @param base any `Machine<S, M, C, U, Ctx>`.\n * @param config the resilience knob: `target`, the optional bricks, `keyOf`.\n * @param rng injected backoff jitter source. Pass a fixed `() => 0.5` in\n * tests to pin retry delays; defaults to `Math.random` (read only\n * at the verb boundary, never inside the merged `update`).\n */\nexport function withResilience<\n S,\n M extends { type: string },\n C extends Cmd,\n U extends Sub,\n Ctx,\n>(\n base: Machine<S, M, C, U, Ctx>,\n config: ResilienceConfig<C, M>,\n rng: () => number = Math.random,\n): Machine<\n ResilienceModel<S, C>,\n M | ResilienceMsg,\n C | ResilienceCmd<C>,\n U | ResilienceTimerSub,\n Ctx\n> {\n type WM = ResilienceModel<S, C>;\n type WMsg = M | ResilienceMsg;\n type WCmd = C | ResilienceCmd<C>;\n\n const { target } = config;\n const keyOf = config.keyOf ?? (() => target);\n const runCmd = resilienceRunCmdDef<C, M>();\n\n // A time-sensitive brick gates the COLD attempt against real wall time read\n // off the triggering base Msg (`config.at`). Without `at` the cold gate would\n // have to fabricate `0` — and a cold attempt after a real-time breaker trip\n // then computes cooldown = `0 - realTripTime < 0` forever (the breaker NEVER\n // recovers), while a `0`-anchored deadline fires immediately. Refuse to build\n // such a machine: errors are data, surfaced at construction, never a silent\n // breaker that can't recover. Retry alone reads time off the result/timer\n // Msgs, not the cold attempt, so `at` stays optional there.\n const timeSensitiveBrick =\n config.circuit !== undefined ||\n config.rateLimit !== undefined ||\n config.cache !== undefined ||\n config.deadline !== undefined;\n if (timeSensitiveBrick && config.at === undefined) {\n throw new Error(\n \"withResilience: a time-sensitive brick (circuit / rateLimit / cache / \" +\n \"deadline) is configured but `config.at` is missing. The cold-attempt \" +\n \"gate needs the REAL wall time the triggering base Msg carries as data \" +\n \"(time-as-data) — without it the gate would fabricate `at = 0`, so a \" +\n \"cold attempt after a real-time breaker trip computes a negative \" +\n \"cooldown and the breaker NEVER recovers (and a deadline brick fires \" +\n \"immediately). Provide `at: (msg) => msg.<wallTimeField>`.\",\n );\n }\n // Read the triggering base Msg's wall time as data for the cold gate. When no\n // time-sensitive brick is configured `at` may be omitted; the cold attempt\n // then gates at `0`, which is harmless because retry backoff reads its time\n // off the result / timer Msgs, never the cold attempt.\n const atOf = config.at ?? (() => 0);\n\n // The REUSED knob: I = the original target base Cmd, R = the base interpret\n // resolution (uninspected here). Its verbs / subs / gate are used unmodified;\n // the wrapper only adapts the boundary (carrier rename + timer-id re-keying).\n const rc = createResilientCall<C, unknown>(config, rng);\n\n // -------------------------------------------------------------------------\n // The merged update — a flat Reducer over the composed (non-discriminated)\n // Model. Cells: every base Msg.type (delegating to base.update + partition),\n // plus the three `$resilience:*` Msgs (delegating to the reused verbs).\n // -------------------------------------------------------------------------\n\n type Cell = (state: WM, msg: WMsg) => readonly [WM, readonly WCmd[]];\n const update: Record<string, Cell> = {};\n\n // The base handler resolves `M | void`; only a Msg is deliverable.\n function isBaseMsg(result: unknown): result is M {\n return typeof result === \"object\" && result !== null && \"type\" in result;\n }\n\n // --- The base-Msg fold: delegate, then PARTITION + retag the target Cmd. --\n // One path for every base Msg, whichever door it arrives through — dispatched\n // by the host, delivered as a settled follow-up (`$resilience:ok`), or\n // served from the cache in the same transition. A follow-up that re-emits\n // the target is retagged like any other; a non-target Cmd passes through.\n //\n // `delivering` is the set of call keys whose settled follow-up is being\n // folded higher up THIS transition's call chain. It bounds the one loop a\n // fold can enter: under `cache`, a delivered follow-up that re-emits the\n // target under the same key (the default `keyOf` is one shared key) hits the\n // cache `succeed` just filled with the very Msg being delivered; folding that\n // hit again re-emits, hits again, and recurses without bound. A hit on a key\n // already in `delivering` is therefore RECORDED in the slice (the call is\n // `succeeded`, served from cache — the divergence stays on the ledger) but\n // not folded a second time: the base already has this Msg in hand. The next\n // transition starts with an empty set, so a later host Msg hitting the same\n // cache is delivered as usual.\n function foldBase(\n state: WM,\n msg: M,\n delivering: ReadonlySet<string> = new Set(),\n ): readonly [WM, readonly WCmd[]] {\n // 1) Run the base reducer. Its NON-target Cmds pass through unchanged.\n const [nextBase, baseCmds] = applyCell<S, M, C>(base, state.base, msg);\n\n // 2) Partition base Cmds: non-target pass straight through; each target\n // Cmd is routed through the resilient-call `attempt` gate, which either\n // emits a `resilient_run` carrier (→ renamed `$resilience:run`,\n // retagging the ORIGINAL base Cmd into `input`), or records the gate\n // decision in the slice with NO carrier (cache hit / circuit-open /\n // rate-limited backoff). Either way the target Cmd never escapes raw\n // and never vanishes off-ledger.\n let next: WM = { base: nextBase, $resilience: state.$resilience };\n const outCmds: WCmd[] = [];\n // The COLD attempt's gate time — the REAL wall time the triggering base\n // Msg carries as data (rule 5: the merged `update` stays pure; the clock\n // does not enter here, the Msg's own `at` data does). With this real\n // instant the breaker compares `at - openedAtMs` against its cooldown\n // (set by a prior real-time `$resilience:err`), so a cold attempt during\n // cooldown fast-fails and one AFTER cooldown is admitted — the breaker\n // RECOVERS. The cache compares `at` against its stored write `at`, the\n // bucket refills from `at`, and the deadline cap anchors at\n // `at + deadline.ms` — all against true wall time, never a fabricated\n // `0`. Every SUBSEQUENT gate run (`fail` → backoff, retry-timer\n // `onTimer` → re-gate) reads time off the result / timer Msgs the same\n // way. `atOf` defaults to `0` ONLY when no time-sensitive brick is\n // configured (construction throws otherwise), where retry backoff reads\n // its time off the result/timer Msgs and the cold `at` is never compared.\n const at = atOf(msg);\n for (const cmd of baseCmds) {\n if (cmd.type !== target) {\n outCmds.push(cmd);\n continue;\n }\n const callKey = keyOf(cmd);\n const [nextSlice, runCmds] = rc.attempt(\n next.$resilience,\n callKey,\n cmd,\n at,\n );\n next = { ...next, $resilience: nextSlice };\n // rc.attempt emits 0 or 1 `resilient_run` carriers. `renameRunCmds`\n // renames each into the `$resilience:run` namespace, preserving the\n // retagged `input` (the ORIGINAL base Cmd). Zero carriers = the gate\n // recorded a divergence in `nextSlice` (cache/circuit/backoff) —\n // visible in the slice + log.\n outCmds.push(...renameRunCmds(runCmds));\n // A cache hit is the one divergence that SETTLES the call: the gate\n // parked the cached follow-up as `result` with no carrier, so nothing\n // will come back through `$resilience:ok` to deliver it. Deliver it\n // here, in the same transition — the base learns of a served call the\n // same way it learns of a performed one.\n if (runCmds.length === 0 && !delivering.has(callKey)) {\n const call = nextSlice.calls[callKey];\n if (call?.phase === \"succeeded\" && isBaseMsg(call.result)) {\n const [delivered, moreCmds] = foldBase(\n next,\n call.result,\n new Set([...delivering, callKey]),\n );\n next = delivered;\n outCmds.push(...moreCmds);\n }\n }\n }\n\n return [next, outCmds];\n }\n\n // Base Msg keys enumerated via `msgKeysOf(base)` — keyed on the\n // authoritative `__form` tag, no structural re-derivation here (#275).\n for (const key of msgKeysOf(base)) {\n update[key] = (state, msg) => foldBase(state, msg as M);\n }\n\n // --- `$resilience:ok` → succeed, then DELIVER the follow-up ---------------\n update[\"$resilience:ok\"] = (state, msg) => {\n const m = msg as ResilienceOkMsg;\n const [slice, runCmds] = rc.succeed(state.$resilience, m.key, {\n type: MsgType.ResilientOk,\n key: m.key,\n result: m.result,\n at: m.at,\n });\n const settled: WM = { ...state, $resilience: slice };\n const settleCmds = renameRunCmds(runCmds);\n // The slice keeps the settled result for the retry / circuit / cache verbs;\n // the base gets it as the Msg its handler resolved. `void` delivers nothing.\n if (!isBaseMsg(m.result)) return [settled, settleCmds];\n // `m.key` is being delivered: a cache hit on it inside this fold is the\n // same Msg coming back, and is recorded but not folded again (see foldBase).\n const [next, followCmds] = foldBase(settled, m.result, new Set([m.key]));\n return [next, [...settleCmds, ...followCmds]];\n };\n\n // --- `$resilience:err` → fail --------------------------------------------\n update[\"$resilience:err\"] = (state, msg) => {\n const m = msg as ResilienceErrMsg;\n const [slice, runCmds] = rc.fail(state.$resilience, m.key, {\n type: MsgType.ResilientErr,\n key: m.key,\n error: m.error,\n at: m.at,\n });\n return [{ ...state, $resilience: slice }, renameRunCmds(runCmds)];\n };\n\n // --- `$resilience:timer` → onTimer (retry re-runs gate / deadline settles) -\n update[\"$resilience:timer\"] = (state, msg) => {\n const m = msg as ResilienceTimerMsg;\n // Re-key the public `$resilience:`-id back to the resilient-call internal\n // id the `onTimer` verb matches against, then run the unmodified verb.\n const [slice, runCmds] = rc.onTimer(state.$resilience, {\n type: \"deadline_exceeded\",\n id: toRcTimerId(m.id),\n atMs: m.atMs,\n });\n return [{ ...state, $resilience: slice }, renameRunCmds(runCmds)];\n };\n\n // Rename any `resilient_run` carriers a verb produced (the retry re-attempt\n // path) into the `$resilience:run` namespace, preserving the retagged input.\n function renameRunCmds(\n runCmds: readonly { type: string; key: string; input: C }[],\n ): readonly WCmd[] {\n return runCmds.map((r) => runCmd({ key: r.key, input: r.input }));\n }\n\n // -------------------------------------------------------------------------\n // Subs — base subs ⧺ resilient-call timers, re-keyed into `$resilience:`.\n // -------------------------------------------------------------------------\n\n const baseSubscriptions = base.subscriptions;\n const baseSubscribe = (base as { subscribe?: unknown }).subscribe;\n\n function subscriptions(state: WM): readonly (U | ResilienceTimerSub)[] {\n const baseSubs = baseSubscriptions\n ? baseSubscriptions(state.base)\n : ([] as readonly U[]);\n // rc.subs returns DeadlineSubs keyed `resilient:retry:{k}` /\n // `resilient:deadline:{k}`. Re-key each into the `$resilience:` namespace\n // and re-type to the wrapper's `$resilience:timer` Sub family (rule 4).\n const rcSubs: readonly DeadlineSub[] = rc.subs(state.$resilience);\n const timerSubs: ResilienceTimerSub[] = rcSubs.map((s) => ({\n id: subId(toWrapperTimerId(s.id)),\n type: \"$resilience:timer\",\n atMs: s.atMs,\n }));\n return [...baseSubs, ...timerSubs];\n }\n\n // -------------------------------------------------------------------------\n // Interpret — base.interpret for non-target + the `$resilience:run` handler\n // that COMPOSES base.interpret for the retagged inner Cmd.\n // -------------------------------------------------------------------------\n\n const baseInterpret =\n (base as { interpret?: Interpret<M, C, Ctx> }).interpret ??\n ({} as Interpret<M, C, Ctx>);\n\n // Reserved-namespace guard (mirrors withTelemetry + the substrate's\n // definePort / SubId collision asserts). The wrapper OWNS four reserved keys:\n // the `$resilience:run` carrier Cmd, the `$resilience:ok` / `$resilience:err`\n // result Msgs, and the `$resilience:timer` Sub Msg. The merges below spread\n // the wrapper's cells over the base's update / interpret / subscribe maps; if\n // the base already declares ANY reserved key on ANY of those three surfaces,\n // the spread would SILENTLY clobber it (or the base's own key would shadow the\n // wrapper's). The `$resilience:` namespace is the wrapper's — refuse to wrap a\n // base that squats on any of the four across any surface.\n //\n // Ordered BEFORE the target-handler guard below: squatting a reserved key is a\n // target-INDEPENDENT structural defect of the base, so it is the more\n // fundamental rejection and must report first. Otherwise a base that BOTH\n // squats `$resilience:*` AND omits the target handler would surface the\n // narrower missing-target error and mask the namespace collision — exactly the\n // regression #111's construction-time hoist introduced (the hoisted target\n // check shadowed this guard for such a base), fixed by #112.\n //\n // `update` is checked PER FORM (the same `formOf` classification the wrapper\n // already uses via `msgKeysOf` / `applyCell`): a Reducer-form\n // base keys its msg-types at the TOP level, but a Transitions-form base keys\n // them in the INNER `{ [stateType]: { [msgType]: cell } }` tables — so a flat\n // top-level `Object.hasOwn` would MISS a reserved msg-type squatting inside an\n // inner table (e.g. an inner `$resilience:ok` cell) and let the merged update\n // silently clobber it. `interpret` and `subscribe` are always flat keyed-by\n // -type maps, so the direct `Object.hasOwn` is correct there.\n const RESERVED = [\n \"$resilience:run\",\n \"$resilience:ok\",\n \"$resilience:err\",\n \"$resilience:timer\",\n ] as const;\n const surfaces: readonly {\n readonly name: string;\n readonly declares: (reserved: string) => boolean;\n }[] = [\n {\n name: \"update\",\n declares: (reserved) => updateDeclaresMsgKey(base, reserved),\n },\n {\n name: \"interpret\",\n declares: (reserved) => Object.hasOwn(baseInterpret as object, reserved),\n },\n {\n name: \"subscribe\",\n declares: (reserved) =>\n Object.hasOwn((baseSubscribe as object | undefined) ?? {}, reserved),\n },\n ];\n for (const reserved of RESERVED) {\n for (const surface of surfaces) {\n if (surface.declares(reserved)) {\n throw new Error(\n `withResilience: the base machine declares a reserved \"${reserved}\" ` +\n `${surface.name} key — the wrapper owns the \"$resilience:\" ` +\n `namespace ($resilience:run / :ok / :err / :timer across update, ` +\n `interpret, and subscribe). Rename the base key.`,\n );\n }\n }\n }\n\n // Construction guard — the target Cmd MUST have a base interpret handler. This\n // is a property of the (base, config) pair, fully known here at construction:\n // the `$resilience:run` carrier delegates to `baseInterpret[target]`, so a\n // missing handler means the resilient effect has nothing to perform. Surface\n // it now — refuse to build a machine whose target can never run — rather than\n // lazily on the first effect (errors are data, surfaced at construction, like\n // the time-sensitive-`at` and reserved-namespace guards above). Ordered AFTER\n // the reserved-namespace guard so a base that squats `$resilience:*` is\n // rejected for the namespace collision first, not masked by this narrower\n // missing-target error (#112).\n if (!Object.hasOwn(baseInterpret as object, target)) {\n throw new Error(\n `withResilience: no base interpret handler for target Cmd \"${target}\" ` +\n `— the resilient effect has nothing to perform. The base machine must ` +\n `declare an interpret handler for its target Cmd type.`,\n );\n }\n\n // The `$resilience:run` handler delegates to the BASE interpret handler for\n // the retagged inner Cmd's type, wrapped via tryInterpret so Ok routes to\n // `$resilience:ok` and Err to `$resilience:err`. `Date.now()` is stamped here\n // — the ONE permitted clock read (interpret is impure; update is pure).\n const runHandler = tryInterpret<\n ResilienceRunCmd<C>,\n // The carried result is the base interpret handler's resolution, whose\n // contract is `Promise<M | void>` (a follow-up base Msg or nothing — see\n // `Interpret<M, C, Ctx>`). Carrying `M | void` here (not bare `unknown`)\n // keeps the base's follow-up Msg type at the seam; `ResilienceOkMsg.result`\n // then narrows from genuine looseness to \"a base Msg or void\".\n // biome-ignore lint/suspicious/noConfusingVoidType: mirrors `Interpret`'s own `Promise<M | void>` — the base handler resolves to a follow-up Msg OR nothing; `M | undefined` would reject no-return bodies\n M | void,\n ResilienceOkMsg | ResilienceErrMsg,\n unknown\n >(\n async (cmd, ctx) => {\n // Compose the base interpret: run the ORIGINAL base Cmd through the base's\n // own handler for its type. The base handler may itself return a follow-up\n // Msg or void; the resilience layer treats its RESOLUTION (resolve vs\n // throw) as the success/failure signal, and carries whatever it returned\n // as `result`. A throw → tryInterpret routes to `$resilience:err`.\n const inner = cmd.input;\n // The base handler's own type is `Interpret<M, C, Ctx>[type]`, i.e.\n // `(cmd, ctx & PortEmitter) => Promise<M | void>`. We read it off the\n // erased `Record` and re-narrow to that contract — the result type is\n // KNOWN (the base Msg union or void), so it is not widened to `unknown`.\n // biome-ignore lint/suspicious/noConfusingVoidType: the base handler contract is `Promise<M | void>` (follow-up Msg or no-return); narrowing to `undefined` would reject void-returning base handlers\n type BaseHandler = (c: C, ctx: Ctx) => Promise<M | void>;\n const handler = (baseInterpret as Record<string, unknown>)[inner.type] as\n | BaseHandler\n | undefined;\n if (handler === undefined) {\n // Unreachable in practice: the construction guard above already refused\n // to build this machine if `baseInterpret[target]` was missing, and the\n // retagged inner Cmd's type is always the target. Kept as defense in\n // depth on the erased-Record read — if it ever fires it routes to\n // `$resilience:err` (errors are data, never swallowed).\n throw new Error(\n `withResilience: no base interpret handler for target Cmd ` +\n `\"${inner.type}\" — the resilient effect has nothing to perform.`,\n );\n }\n // The base handler's follow-up crosses the interpret edge HERE, not in\n // `run`: `run`'s edge keys on the Cmd it handed us — the carrier — so a\n // `Cmd.define`d target's settled Msg would reach the slice unparsed and\n // unstamped (#66). `cmdEdgeOf` is the same edge `run` applies to a bare\n // machine, read off the ctx it augmented; a pass-through outside `run`.\n return cmdEdgeOf(ctx)(\n inner,\n await handler(inner, ctx as unknown as Ctx),\n ) as M | undefined;\n },\n (result, cmd): ResilienceOkMsg => ({\n type: \"$resilience:ok\",\n key: cmd.key,\n result,\n at: Date.now(),\n }),\n (error, cmd): ResilienceErrMsg => ({\n type: \"$resilience:err\",\n key: cmd.key,\n error,\n at: Date.now(),\n }),\n );\n\n const interpret = {\n ...(baseInterpret as Record<string, unknown>),\n \"$resilience:run\": runHandler,\n } as Interpret<WMsg, WCmd, Ctx>;\n\n // -------------------------------------------------------------------------\n // The `subscribe` map — base cells ⧺ the `$resilience:timer` cell, which\n // delegates the timer lifecycle to the deadline Sub primitive (re-keying the\n // dispatched Msg into the `$resilience:timer` shape). Clock lives here.\n // -------------------------------------------------------------------------\n\n const subscribeMap = {\n ...((baseSubscribe as Record<string, unknown> | undefined) ?? {}),\n \"$resilience:timer\": (\n sub: ResilienceTimerSub,\n ctx: Ctx,\n dispatch: (msg: WMsg) => void,\n ): (() => void) =>\n // Reuse the deadline subscribe cell wholesale: it arms a one-shot timer\n // for `max(0, atMs - Date.now())` and fires when the wall clock crosses\n // `atMs`. We hand it a `DeadlineSub` shape and translate its\n // `deadline_exceeded` Msg into the wrapper's `$resilience:timer` Msg.\n subscribeDeadline(\n { id: sub.id as DeadlineSub[\"id\"], type: \"deadline\", atMs: sub.atMs },\n ctx,\n (dl) =>\n dispatch({ type: \"$resilience:timer\", id: dl.id, atMs: dl.atMs }),\n ),\n };\n\n return {\n init: (loaded, ctx) => {\n // Rehydrate: `loaded !== null` MUST return `[loaded, []]` (no Cmds) — the\n // substrate's replay enforces it. Split the composed loaded Model into its\n // base slice and feed the base its own snapshot so the base rehydrate\n // contract is honored transitively.\n if (loaded !== null) {\n return [loaded, []];\n }\n const [base0, baseCmds] = base.init(null, ctx);\n // The base's OWN init Cmds: NON-target Cmds pass straight through; a\n // TARGET Cmd is RETAGGED (admitted) so it is observed, never raw — the\n // same retag-not-swallow contract the merged update enforces (rule 2). A\n // target Cmd that escaped init raw would bypass the gate AND the carrier,\n // so the resilience layer would never see the effect resolve. At a fresh\n // boot the breaker is closed and the bucket full, so the gate decision is\n // unambiguously ADMIT — but the Cmd must still travel inside a\n // `$resilience:run` carrier (the slice records its `running` phase). Boot\n // is the resilience epoch: the cold gate runs at `at = 0`, harmless here\n // because the breaker is closed (nothing to compare), the cache empty, and\n // the bucket full. Wall time enters once the effect resolves (the\n // `$resilience:ok` / `:err` Msgs carry `at`), exactly as in a transition.\n let resilience = rc.init();\n const initCmds: WCmd[] = [];\n for (const cmd of baseCmds) {\n if (cmd.type !== target) {\n initCmds.push(cmd);\n continue;\n }\n // The boot cold attempt gates at `at = 0` (boot is the resilience epoch:\n // no real Msg drove it, so there is no time-as-data to read). For the\n // circuit / rateLimit / cache bricks that is harmless at a fresh boot —\n // the breaker is closed (nothing to compare), the bucket full, the cache\n // empty, so the gate ADMITS unambiguously and the `0` is never compared\n // against a real instant. The DEADLINE brick is the exception: it anchors\n // the cap at `at + deadline.ms = 0 + ms`, so its `$resilience:deadline`\n // Sub arms at `atMs = ms` and `subscribeDeadline` fires after\n // `max(0, atMs - Date.now()) === 0` ms — i.e. IMMEDIATELY at boot,\n // settling the boot call failed before it can run. A `0`-anchored boot\n // deadline is never the author's intent; it is the same trap the\n // construction guard refuses for transitions (a fabricated `at` the\n // deadline cannot honor). Fail loud: a boot effect that needs a real\n // deadline belongs behind a post-run boot Msg (where a real `at` exists),\n // not an init Cmd. Mirrors the substrate guidance \"boot effects belong in\n // a boot Msg, not init Cmds.\"\n if (config.deadline !== undefined) {\n throw new Error(\n `withResilience: base.init emits the target Cmd \"${target}\" while a ` +\n `deadline brick is configured. The boot cold attempt has no real ` +\n `wall time (boot is gated at at=0), so the deadline would anchor at ` +\n `0 + ${config.deadline.ms}ms and its $resilience:deadline Sub would ` +\n `fire IMMEDIATELY (max(0, atMs - now) === 0), failing the boot call ` +\n `instantly. Move the boot effect out of base.init and into a boot ` +\n `Msg dispatched after run() (where the triggering Msg carries a real ` +\n `at via config.at), so the deadline anchors at a real instant. (Boot ` +\n `effects belong in a boot Msg, not init Cmds.)`,\n );\n }\n const callKey = keyOf(cmd);\n const [nextSlice, runCmds] = rc.attempt(resilience, callKey, cmd, 0);\n resilience = nextSlice;\n // Same `$resilience:run` retag as the update loop — one helper.\n initCmds.push(...renameRunCmds(runCmds));\n }\n const model: WM = { base: base0, $resilience: resilience };\n return [model, initCmds];\n },\n update: update as unknown as Reducer<WM, WMsg, WCmd>,\n subscriptions,\n subscribe: subscribeMap as unknown as Machine<\n WM,\n WMsg,\n WCmd,\n U | ResilienceTimerSub,\n Ctx\n >[\"subscribe\"],\n interpret,\n // The base's `Cmd.define` list rides through so `run`'s interpret edge\n // still parses / stamps the base's NON-target settled Msgs behind the\n // wrap; the target's settle through the carrier above (#66).\n ...(base.cmds ? { cmds: base.cmds } : {}),\n } as Machine<WM, WMsg, WCmd, U | ResilienceTimerSub, Ctx>;\n}\n","/**\n * internal/resilience/with-telemetry — the pattern-setting wrapper of the wrapper tier.\n *\n * `withTelemetry(base, config)` is a **pure function over machine data**: it\n * takes any `Machine<S, M, C, U, Ctx>` and returns a NEW `Machine` over the\n * composed Model `{ base, $telemetry }`. You `run()` / `replay()` the result\n * exactly like any other machine — there is no new runtime, no privileged\n * interception path.\n *\n * This is the SAFEST wrapper and the one every future wrapper (`withDeadline`,\n * `withResilience`) copies: it is **OBSERVE-ONLY**. It observes every base Msg\n * + transition, increments a monotonic counter, and emits a fire-and-forget\n * telemetry Cmd whose interpret handler hands the event to a sink Port. It must\n * NOT transform base Cmds or gate base Msgs — base behavior is byte-identical\n * with or without it. The moment a telemetry wrapper alters the Msg/Cmd stream\n * instead of observing it, it has become saga middleware (the betrayal the\n * research warned of).\n *\n * ## The 5 rules it satisfies (from the wrapper-tier contract)\n *\n * 1. **Named, serializable slice.** Wrapper state lives at `model.$telemetry`,\n * a plain `{ seq: number }` — JSON-serializable, never a closure.\n * 2. **Retag-and-re-emit, never swallow.** The merged `update` runs the base\n * reducer, passes its Cmds through UNCHANGED, and APPENDS its own\n * `$telemetry:emit` Cmd. No base Cmd ever vanishes; nothing is gated.\n * 3. **Every decision is a Msg/Cmd.** Each telemetry emission is a\n * `$telemetry:emit` Cmd through the merged `update`, so \"why did this fire\"\n * is answerable from reducer + log alone, and `runtime.observe` sees it.\n * 4. **Subs merge by id.** Telemetry has no timers — merged subs/subscribe are\n * the base's, verbatim.\n * 5. **Clock out of update.** The default event carries no wall-clock read.\n * The optional `at` is stamped at the interpret boundary (the `clock`\n * port), never inside the merged `update`.\n *\n * ## Where the clock lives\n *\n * Inside the merged `update`: nowhere. The reducer is pure — it reads `seq` from\n * the slice and projects the event from `(msg, prev, next)`. The ONLY clock read\n * is at the interpret boundary: the `$telemetry:emit` handler stamps `event.at`\n * from the injected `clock` port (if supplied and the projector left `at`\n * unset), exactly as `resilient-call` reads `Date.now()` only inside `handlers`.\n *\n * ## Typical wiring\n *\n * const observed = withTelemetry(baseMachine, {\n * event: (msg, _prev, next) => ({ seq: next.$telemetry.seq, msgType: msg.type }),\n * });\n * const runtime = run(observed, {\n * ctx: { ...baseCtx, telemetrySink: (e) => posthog.capture(e), clock: Date.now },\n * });\n */\n\nimport { z } from \"zod\";\nimport type { CmdOf, Interpret, Machine, Reducer, Sub } from \"../../../index\";\nimport { applyCell, Cmd, msgKeysOf } from \"../../../index\";\n\n// ===========================================================================\n// The event + the slice + the ports — the telemetry vocabulary.\n// ===========================================================================\n\n/**\n * The datum handed to the sink. The default projector emits `{ seq, msgType }`;\n * a custom `event` projector may return any extra fields. `at` is OPTIONAL and\n * plain data — it is stamped at the interpret boundary by the `clock` port, not\n * inside the (pure, clock-free) merged `update`. Every field is JSON-round-trip\n * serializable so a recorded telemetry stream stays durable.\n */\nexport interface TelemetryEvent {\n /** Monotonic event counter — equals `$telemetry.seq` after the transition. */\n readonly seq: number;\n /** The `Msg.type` discriminant that drove this transition. */\n readonly msgType: string;\n /**\n * Wall-clock instant the event was emitted, ms since epoch. Absent until the\n * interpret boundary stamps it (the `clock` port). Optional because the\n * merged `update` is clock-free — a verb must never read `Date.now()`.\n */\n readonly at?: number;\n}\n\n/**\n * The wrapper's Model slice. A monotonic event counter — minimal but real, so\n * the named-slice mechanism is exercised for the richer-slice wrappers that\n * follow. `seq` equals the number of base Msgs folded so far: after replaying\n * `N` msgs, `$telemetry.seq === N`. Plain data → serializes into a `Store<S>`.\n */\nexport interface TelemetrySlice {\n readonly seq: number;\n}\n\n/**\n * The composed Model. The base machine's state is nested under `base`; the\n * wrapper's state lives in the NAMED `$telemetry` slice — never hidden in a\n * closure. Both fields are plain data, so the whole composed Model round-trips\n * through `JSON.parse(JSON.stringify(...))` iff the base state does.\n */\nexport interface TelemetryModel<S> {\n readonly base: S;\n readonly $telemetry: TelemetrySlice;\n}\n\n/**\n * The fire-and-forget Cmd the merged `update` appends after every base\n * transition. It carries the projected `event` as plain data (invariant 3 —\n * no closure). The interpret handler hands `event` to the sink and dispatches\n * NOTHING back, so there is no feedback loop.\n */\nexport const telemetryEmit = Cmd.define(\"$telemetry:emit\", {\n input: z.object({ event: z.custom<TelemetryEvent>() }),\n ok: z.void(),\n err: [],\n requirements: Cmd.requirements<TelemetryPorts>(),\n});\nexport type TelemetryEmitCmd = CmdOf<typeof telemetryEmit>;\n\n/**\n * The side-effecting ports the wrapper adds to `Ctx`. The sink (PostHog / Sentry\n * bridge) lives at the interpret boundary, never in a verb. `clock` is the\n * optional wall-clock source used to stamp `event.at` at that same boundary —\n * pass `Date.now` in production, a fixed `() => 1000` in tests; omit it to leave\n * `at` unset.\n */\nexport interface TelemetryPorts {\n /** The side-effecting sink. Fire-and-forget — its result is never awaited into a Msg. */\n readonly telemetrySink: (event: TelemetryEvent) => void | Promise<void>;\n /** Optional clock for stamping `event.at` at the interpret boundary. */\n readonly clock?: () => number;\n}\n\n/**\n * The telemetry knob. `event` is an OPTIONAL projector mapping\n * `(msg, prev, next)` to a `TelemetryEvent`; omit it and the default emits\n * `{ seq, msgType }` where `seq` is the post-transition counter. The projector\n * runs INSIDE the pure merged `update`, so it must not read the clock — stamp\n * `at` at the sink boundary via the `clock` port instead.\n */\nexport interface TelemetryConfig<S, M extends { type: string }> {\n readonly event?: (\n msg: M,\n prev: TelemetryModel<S>,\n next: TelemetryModel<S>,\n ) => TelemetryEvent;\n}\n\n// ===========================================================================\n// withTelemetry — the wrapper.\n// ===========================================================================\n\n/**\n * Wrap `base` with observe-only telemetry. Returns a NEW `Machine` over the\n * composed Model `{ base, $telemetry }`, with the base's Msgs/Cmds/Subs/Ctx\n * extended by the wrapper's own.\n *\n * The composed machine:\n * - `init` rehydrates the base (honoring the `[loaded, []]` contract) and\n * seeds `$telemetry: { seq: 0 }`. Base init Cmds pass through unchanged.\n * - `update` (Reducer form, keyed by every base `Msg.type`) runs the base\n * reducer, increments `seq`, and appends a `$telemetry:emit` Cmd carrying\n * the projected event. Base Cmds pass through UNCHANGED — the observe-only\n * property.\n * - `subscriptions` / `subscribe` are the base's, verbatim (no timers).\n * - `interpret` is `{ ...base.interpret, \"$telemetry:emit\": sink-handler }`.\n *\n * @param base any `Machine<S, M, C, U, Ctx>`.\n * @param config the telemetry knob (optional `event` projector).\n */\nexport function withTelemetry<\n S,\n M extends { type: string },\n C extends Cmd,\n U extends Sub,\n Ctx,\n>(\n base: Machine<S, M, C, U, Ctx>,\n config: TelemetryConfig<S, M> = {},\n): Machine<\n TelemetryModel<S>,\n M,\n C | TelemetryEmitCmd,\n U,\n Ctx & TelemetryPorts\n> {\n const project = config.event;\n\n // The merged update is a flat Reducer over the composed Model. The composed\n // Model is NOT discriminated on `.type`, so the Transitions form is never an\n // option here — every base Msg variant gets exactly one cell, enumerated via\n // `msgKeysOf(base)` (keyed on the authoritative `__form` tag; #275).\n const msgKeys = msgKeysOf(base);\n\n const update = {} as Record<\n string,\n (\n state: TelemetryModel<S>,\n msg: M,\n ) => readonly [TelemetryModel<S>, readonly (C | TelemetryEmitCmd)[]]\n >;\n for (const key of msgKeys) {\n update[key] = (state, msg) => {\n // 1) Run the base reducer — its result passes through UNCHANGED.\n const [nextBase, baseCmds] = applyCell<S, M, C>(base, state.base, msg);\n // 2) Advance the wrapper slice (monotonic counter). New object — no mutation.\n const $telemetry: TelemetrySlice = { seq: state.$telemetry.seq + 1 };\n const next: TelemetryModel<S> = { base: nextBase, $telemetry };\n // 3) Project the event (pure — no clock). Default: { seq, msgType }.\n const event: TelemetryEvent = project\n ? project(msg, state, next)\n : { seq: $telemetry.seq, msgType: msg.type };\n // 4) Append the fire-and-forget emit Cmd. Base Cmds come FIRST, unchanged.\n const emit = telemetryEmit({ event });\n return [next, [...baseCmds, emit]];\n };\n }\n\n // The base's interpret, extended with the one telemetry handler. The sink is\n // the ONLY side effect, and it lives here at the interpret boundary — never in\n // a verb. `clock` (if provided) stamps `event.at` here too, the one permitted\n // clock read. The handler returns void synchronously — it dispatches NOTHING\n // back (no feedback loop) AND it does NOT await the sink (no backpressure /\n // crash from a slow or failing sink). See the fire-and-forget note below.\n const baseInterpret =\n (base as { interpret?: Interpret<M, C, Ctx> }).interpret ??\n ({} as Interpret<M, C, Ctx>);\n // Namespace guard (mirrors the substrate's SubId / definePort collision\n // asserts). The spread below merges `$telemetry:emit` into the base's\n // interpret map; if the base already declares that key, the spread would\n // SILENTLY clobber the base handler. The `$telemetry:` Cmd namespace is the\n // wrapper's — refuse to wrap a base that squats on it instead of stealing it.\n if (Object.hasOwn(baseInterpret as object, \"$telemetry:emit\")) {\n throw new Error(\n 'withTelemetry: the base machine declares a reserved \"$telemetry:emit\" ' +\n 'interpret handler — the wrapper owns the \"$telemetry:\" Cmd namespace. ' +\n \"Rename the base handler.\",\n );\n }\n const interpret = {\n ...(baseInterpret as Record<string, unknown>),\n // OBSERVE-ONLY at the boundary: the sink is fire-and-forget. The runtime\n // `await`s every interpret handler in its dispatch loop, so awaiting the\n // sink here would let a SLOW sink backpressure the wrapped machine (its\n // next dispatch waits) and a FAILING sink crash dispatch (the throw would\n // propagate out of the transition). Both violate the contract: telemetry\n // must never affect base behavior OR latency. So we DO NOT await — we hand\n // the event to the sink, normalize its result to a Promise, swallow any\n // rejection/throw, and return immediately. The handler resolves in the same\n // microtask the dispatch loop reaches it; the machine never waits on the\n // sink, and a rejected sink can never become an unhandled rejection.\n \"$telemetry:emit\": (\n cmd: TelemetryEmitCmd,\n ctx: Ctx & TelemetryPorts,\n ): void => {\n const event =\n cmd.event.at === undefined && ctx.clock !== undefined\n ? { ...cmd.event, at: ctx.clock() }\n : cmd.event;\n // `Promise.resolve(fn())` covers BOTH failure shapes: a sync `throw` is\n // caught by `Promise.resolve` (the call is the argument, so a throw here\n // would escape — guard it), and an async rejection is caught by `.catch`.\n try {\n Promise.resolve(ctx.telemetrySink(event)).catch(() => {});\n } catch {\n // A sink that throws SYNCHRONOUSLY (before returning a Promise) is\n // swallowed here. Either way the slow/failing sink never reaches the\n // dispatch loop's `await`.\n }\n },\n } as Interpret<M, C | TelemetryEmitCmd, Ctx & TelemetryPorts>;\n\n // Capture once so the narrowing survives into the spread (no non-null assert).\n const baseSubscriptions = base.subscriptions;\n const baseSubscribe = (base as { subscribe?: unknown }).subscribe;\n\n return {\n init: (loaded, ctx) => {\n // Rehydrate path: `loaded !== null` MUST return `[loaded, []]` (no Cmds) —\n // the substrate's replay enforces this. We split the composed loaded Model\n // into its base slice and feed the base its own loaded snapshot, so the\n // base's rehydrate contract is honored transitively.\n if (loaded !== null) {\n return [loaded, []];\n }\n const [base0, cmds] = base.init(null, ctx);\n const model: TelemetryModel<S> = { base: base0, $telemetry: { seq: 0 } };\n // Base init Cmds pass through unchanged; no telemetry Cmd on boot (boot is\n // not a base Msg transition, so it does not advance `seq`).\n return [model, cmds];\n },\n update: update as unknown as Reducer<\n TelemetryModel<S>,\n M,\n C | TelemetryEmitCmd\n >,\n // Subs merge to the base's, verbatim — telemetry owns no timers. The base\n // subscribes against its own nested slice.\n ...(baseSubscriptions\n ? {\n subscriptions: (state: TelemetryModel<S>) =>\n baseSubscriptions(state.base),\n }\n : {}),\n ...(baseSubscribe ? { subscribe: baseSubscribe } : {}),\n interpret,\n // The base's `Cmd.define` list rides through so `run`'s interpret edge\n // still parses / stamps the base's settled Msgs behind the wrap (#66).\n ...(base.cmds ? { cmds: base.cmds } : {}),\n } as Machine<\n TelemetryModel<S>,\n M,\n C | TelemetryEmitCmd,\n U,\n Ctx & TelemetryPorts\n >;\n}\n"]}
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* retry-attempt state every fallible `interpret` handler folds over.
|
|
5
5
|
*
|
|
6
6
|
* This is a "pure state + ops" module in the same mold as
|
|
7
|
-
*
|
|
7
|
+
* the internal work queue (`src/internal/work-queue/ops.ts`): a state type
|
|
8
|
+
* plus pure transition functions,
|
|
8
9
|
* storage- and host-agnostic, that a consumer wires into their own reducer /
|
|
9
10
|
* interpret. Nothing here reads the clock or the RNG on its own behalf —
|
|
10
11
|
* randomness is *injected* (`rng`) and time is *computed by the caller* from
|
|
@@ -204,7 +205,7 @@ interface Unbounded {
|
|
|
204
205
|
*/
|
|
205
206
|
type RetryBudget = CountBound | DurationBound | Unbounded;
|
|
206
207
|
/**
|
|
207
|
-
* A retry policy is pure configuration — the
|
|
208
|
+
* A retry policy is pure configuration — the shape of the backoff curve plus
|
|
208
209
|
* the bound that ends the retrying. It carries no mutable state; `RetryState`
|
|
209
210
|
* does. One policy is shared across all the attempts of one logical operation
|
|
210
211
|
* (often a module-scope const).
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { asRng, backoffDelay, defaultRetryPolicy, defaultRng, initRetry, nextDelayMs, recordFailure, retryElapsedMs, shouldRetry } from '../chunk-
|
|
1
|
+
export { asRng, backoffDelay, defaultRetryPolicy, defaultRng, initRetry, nextDelayMs, recordFailure, retryElapsedMs, shouldRetry } from '../chunk-VBDU4JL6.js';
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
3
3
|
//# sourceMappingURL=index.js.map
|