@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
package/dist/chunk-EUF7XOEE.js
DELETED
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
import { MsgType } from './chunk-JELSZN25.js';
|
|
2
|
-
import { deadlineSub } from './chunk-JGVL3WPL.js';
|
|
3
|
-
import { asRng, recordFailure, shouldRetry, nextDelayMs, initRetry } from './chunk-Q2UM7BXU.js';
|
|
4
|
-
import { initBucket, tryConsume } from './chunk-S2EGRPCM.js';
|
|
5
|
-
import { initCircuit, onSuccess, onFailure, canPass } from './chunk-UF4MZSLT.js';
|
|
6
|
-
import { initCache, set, get } from './chunk-7SVIRMC6.js';
|
|
7
|
-
import { tryInterpret } from './chunk-5EHLEUTL.js';
|
|
8
|
-
import { without } from './chunk-B5VXOFMZ.js';
|
|
9
|
-
|
|
10
|
-
// src/resilient-call/index.ts
|
|
11
|
-
function circuitPolicy(config) {
|
|
12
|
-
if (config.circuit === void 0) return null;
|
|
13
|
-
return {
|
|
14
|
-
failureThreshold: config.circuit.threshold,
|
|
15
|
-
cooldownMs: config.circuit.cooldownMs,
|
|
16
|
-
halfOpenMaxProbes: config.circuit.halfOpenMaxProbes ?? 1
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
function retryTimerId(key) {
|
|
20
|
-
return `resilient:retry:${key}`;
|
|
21
|
-
}
|
|
22
|
-
function deadlineTimerId(key) {
|
|
23
|
-
return `resilient:deadline:${key}`;
|
|
24
|
-
}
|
|
25
|
-
function createResilientCall(config, rng = Math.random) {
|
|
26
|
-
const cPolicy = circuitPolicy(config);
|
|
27
|
-
const rngBranded = asRng(rng);
|
|
28
|
-
function init() {
|
|
29
|
-
return {
|
|
30
|
-
circuit: initCircuit(),
|
|
31
|
-
// The bucket carries a default value even without the rateLimit brick so
|
|
32
|
-
// the slice shape is uniform, but the rate-limit GATE is skipped entirely
|
|
33
|
-
// when the brick is absent (see `gate`) — the bucket is simply never
|
|
34
|
-
// consulted. A `0/0` placeholder bucket would be touched by `tryConsume`;
|
|
35
|
-
// a `1-cap` default is harmless because the gate never calls it.
|
|
36
|
-
bucket: config.rateLimit ? initBucket(
|
|
37
|
-
config.rateLimit.capacity,
|
|
38
|
-
config.rateLimit.refillPerSec,
|
|
39
|
-
0
|
|
40
|
-
) : initBucket(1, 1, 0),
|
|
41
|
-
retry: {},
|
|
42
|
-
cache: initCache(),
|
|
43
|
-
calls: {}
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
function retryOf(s, key) {
|
|
47
|
-
return s.retry[key] ?? initRetry();
|
|
48
|
-
}
|
|
49
|
-
function deadlineAt(at) {
|
|
50
|
-
return config.deadline ? at + config.deadline.ms : 0;
|
|
51
|
-
}
|
|
52
|
-
function gate(s, key, input, at, deadlineAtMs) {
|
|
53
|
-
if (config.cache !== void 0) {
|
|
54
|
-
const cached = get(s.cache, key, at);
|
|
55
|
-
if (cached !== void 0) {
|
|
56
|
-
return [setCall(s, key, { phase: "succeeded", result: cached }), []];
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
let bucket = s.bucket;
|
|
60
|
-
if (config.rateLimit !== void 0) {
|
|
61
|
-
const [next, hasToken] = tryConsume(bucket, at);
|
|
62
|
-
bucket = next;
|
|
63
|
-
if (!hasToken) {
|
|
64
|
-
return backoff(
|
|
65
|
-
{ ...s, bucket },
|
|
66
|
-
key,
|
|
67
|
-
input,
|
|
68
|
-
"rate_limited",
|
|
69
|
-
at,
|
|
70
|
-
deadlineAtMs
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
let circuit = s.circuit;
|
|
75
|
-
if (cPolicy !== null) {
|
|
76
|
-
const [next, ok] = canPass(circuit, cPolicy, at);
|
|
77
|
-
circuit = next;
|
|
78
|
-
if (!ok) {
|
|
79
|
-
return [
|
|
80
|
-
{ ...setCall(s, key, { phase: "circuit_open" }), bucket, circuit },
|
|
81
|
-
[]
|
|
82
|
-
];
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return [
|
|
86
|
-
{
|
|
87
|
-
...setCall(s, key, { phase: "running", input, deadlineAtMs }),
|
|
88
|
-
circuit,
|
|
89
|
-
bucket
|
|
90
|
-
},
|
|
91
|
-
[{ type: MsgType.ResilientRun, key, input }]
|
|
92
|
-
];
|
|
93
|
-
}
|
|
94
|
-
function backoff(s, key, input, error, at, deadlineAtMs) {
|
|
95
|
-
if (config.retry === void 0) {
|
|
96
|
-
return [setCall(s, key, { phase: "failed", error }), []];
|
|
97
|
-
}
|
|
98
|
-
const retry = recordFailure(retryOf(s, key), error, at);
|
|
99
|
-
const withRetry = { ...s, retry: { ...s.retry, [key]: retry } };
|
|
100
|
-
if (!shouldRetry(retry, config.retry, at)) {
|
|
101
|
-
return [setCall(withRetry, key, { phase: "failed", error }), []];
|
|
102
|
-
}
|
|
103
|
-
const retryAtMs = at + nextDelayMs(retry, config.retry, rngBranded);
|
|
104
|
-
return [
|
|
105
|
-
setCall(withRetry, key, {
|
|
106
|
-
phase: "waiting_retry",
|
|
107
|
-
input,
|
|
108
|
-
retryAtMs,
|
|
109
|
-
deadlineAtMs
|
|
110
|
-
}),
|
|
111
|
-
[]
|
|
112
|
-
];
|
|
113
|
-
}
|
|
114
|
-
function setCall(s, key, phase) {
|
|
115
|
-
return { ...s, calls: { ...s.calls, [key]: phase } };
|
|
116
|
-
}
|
|
117
|
-
function attempt(s, key, input, at) {
|
|
118
|
-
return gate(s, key, input, at, deadlineAt(at));
|
|
119
|
-
}
|
|
120
|
-
function succeed(s, key, msg) {
|
|
121
|
-
const circuit = cPolicy !== null ? onSuccess(s.circuit, cPolicy) : s.circuit;
|
|
122
|
-
const cache = config.cache !== void 0 ? set(s.cache, key, msg.result, msg.at, config.cache.ttlMs) : s.cache;
|
|
123
|
-
const retry = without(s.retry, key);
|
|
124
|
-
return [
|
|
125
|
-
{
|
|
126
|
-
...setCall(s, key, { phase: "succeeded", result: msg.result }),
|
|
127
|
-
circuit,
|
|
128
|
-
cache,
|
|
129
|
-
retry
|
|
130
|
-
},
|
|
131
|
-
[]
|
|
132
|
-
];
|
|
133
|
-
}
|
|
134
|
-
function fail(s, key, msg) {
|
|
135
|
-
const circuit = cPolicy !== null ? onFailure(s.circuit, cPolicy, msg.at) : s.circuit;
|
|
136
|
-
const withCircuit = { ...s, circuit };
|
|
137
|
-
const call = s.calls[key];
|
|
138
|
-
const input = call?.phase === "running" ? call.input : void 0;
|
|
139
|
-
const deadlineAtMs = call?.phase === "running" ? call.deadlineAtMs : deadlineAt(msg.at);
|
|
140
|
-
if (input === void 0) {
|
|
141
|
-
return [
|
|
142
|
-
setCall(withCircuit, key, { phase: "failed", error: msg.error }),
|
|
143
|
-
[]
|
|
144
|
-
];
|
|
145
|
-
}
|
|
146
|
-
return backoff(withCircuit, key, input, msg.error, msg.at, deadlineAtMs);
|
|
147
|
-
}
|
|
148
|
-
function settleFailed(s, key, error) {
|
|
149
|
-
return [setCall(s, key, { phase: "failed", error }), []];
|
|
150
|
-
}
|
|
151
|
-
function onTimer(s, msg) {
|
|
152
|
-
for (const [key, call] of Object.entries(s.calls)) {
|
|
153
|
-
if (msg.id === retryTimerId(key)) {
|
|
154
|
-
if (call.phase !== "waiting_retry") return [s, []];
|
|
155
|
-
return gate(s, key, call.input, msg.atMs, call.deadlineAtMs);
|
|
156
|
-
}
|
|
157
|
-
if (msg.id === deadlineTimerId(key)) {
|
|
158
|
-
if (call.phase !== "running" && call.phase !== "waiting_retry")
|
|
159
|
-
return [s, []];
|
|
160
|
-
return [
|
|
161
|
-
setCall(s, key, {
|
|
162
|
-
phase: "failed",
|
|
163
|
-
error: {
|
|
164
|
-
_tag: "deadline_exceeded",
|
|
165
|
-
id: msg.id,
|
|
166
|
-
atMs: msg.atMs
|
|
167
|
-
}
|
|
168
|
-
}),
|
|
169
|
-
[]
|
|
170
|
-
];
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
return [s, []];
|
|
174
|
-
}
|
|
175
|
-
function subs(s) {
|
|
176
|
-
const out = [];
|
|
177
|
-
for (const [key, call] of Object.entries(s.calls)) {
|
|
178
|
-
if (call.phase === "waiting_retry") {
|
|
179
|
-
out.push(deadlineSub(retryTimerId(key), call.retryAtMs));
|
|
180
|
-
}
|
|
181
|
-
if (config.deadline !== void 0 && (call.phase === "running" || call.phase === "waiting_retry") && call.deadlineAtMs > 0) {
|
|
182
|
-
out.push(deadlineSub(deadlineTimerId(key), call.deadlineAtMs));
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
return out;
|
|
186
|
-
}
|
|
187
|
-
function handlers(ports) {
|
|
188
|
-
return {
|
|
189
|
-
resilient_run: tryInterpret(
|
|
190
|
-
(cmd) => ports.run(cmd.input, cmd.key),
|
|
191
|
-
(result, cmd) => ({
|
|
192
|
-
type: MsgType.ResilientOk,
|
|
193
|
-
key: cmd.key,
|
|
194
|
-
result,
|
|
195
|
-
at: Date.now()
|
|
196
|
-
}),
|
|
197
|
-
(error, cmd) => ({
|
|
198
|
-
type: MsgType.ResilientErr,
|
|
199
|
-
key: cmd.key,
|
|
200
|
-
error,
|
|
201
|
-
at: Date.now()
|
|
202
|
-
})
|
|
203
|
-
)
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
return {
|
|
207
|
-
init,
|
|
208
|
-
attempt,
|
|
209
|
-
succeed,
|
|
210
|
-
fail,
|
|
211
|
-
settleFailed,
|
|
212
|
-
onTimer,
|
|
213
|
-
subs,
|
|
214
|
-
handlers
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
function liftResilience(state, [slice, cmds]) {
|
|
218
|
-
return [{ ...state, resilience: slice }, cmds];
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
export { createResilientCall, liftResilience };
|
|
222
|
-
//# sourceMappingURL=chunk-EUF7XOEE.js.map
|
|
223
|
-
//# sourceMappingURL=chunk-EUF7XOEE.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/resilient-call/index.ts"],"names":[],"mappings":"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","file":"chunk-EUF7XOEE.js","sourcesContent":["/**\n * @packageDocumentation\n *\n * @deprecated `@demlik/tea/resilient-call` is deprecated in favor of\n * `@demlik/tea/with-resilience` — the higher-order `withResilience(base,\n * config)` wrapper (TEA-idiomatic: it wraps any existing machine instead of\n * forcing a bespoke embedded slice; epic consolidation verdict, survivor\n * `with-resilience`). The APIs are NOT drop-in; migration map:\n *\n * - `createResilientCall(config, rng)` + hand-wiring `init` / the verbs /\n * `subs` / `handlers` into your machine → `withResilience(base, { target,\n * ...bricks }, rng)`. Nothing is wired by hand anymore: the wrapper\n * intercepts the `target` base Cmd and routes it through the gate.\n * - `ResilientConfig` bricks (`retry` / `circuit` / `rateLimit` / `cache` /\n * `deadline`) → unchanged; `ResilienceConfig` extends the same knob and\n * adds `target` (required), `keyOf?` (per-call key — was `attempt`'s `key`\n * argument), and `at?` (time-as-data reader — REQUIRED with any\n * time-sensitive brick; `withResilience` throws at construction without it).\n * - The slice at your chosen Model field + `liftResilience` → the wrapper\n * owns `model.$resilience`; there is nothing to lift.\n * - Verbs `attempt` / `succeed` / `fail` / `onTimer` → internal to the\n * wrapper; results route as `$resilience:ok` / `$resilience:err` /\n * `$resilience:timer` Msgs through the merged `update` (the old\n * `resilient_run` / `resilient_ok` / `resilient_err` vocabulary is renamed\n * into the `$resilience:` namespace).\n * - `settleFailed` → NO equivalent. It exists for embedded-slice consumers\n * (`authed-call`, `paginated-walk`) that settle a call without touching the\n * breaker; the wrapper exposes no caller-facing settle verb.\n * - `handlers(ports)` / `subs(state)` / the `subscribeDeadline` re-export →\n * handled by the wrapper; run the returned machine like any other.\n *\n * Removal window (\"deprecate, don't delete\"): the `./resilient-call` subpath\n * export survives one minor release after this deprecation ships, then is\n * removed. Internal sibling modules (`with-resilience` itself, `agent`,\n * `llm-call`, `authed-call`, `reconciler`, `paginated-walk`) intentionally keep\n * importing `../resilient-call` — the deprecation targets the PUBLISHED export,\n * not the module's internal role.\n *\n * @demlik/tea/resilient-call — the ROOT composition: a single resilience knob\n * that bundles cache → circuit-breaker → rate-limit → exponential-backoff retry\n * (with a deadline-driven retry timer) around any fallible `(input) => Promise`\n * port.\n *\n * This is `examples/resilient-fetch.ts`'s hand-wired `attempt()` generalized:\n *\n * - It is **keyed**. The example tracked one URL at a time; this tracks N\n * concurrent logical calls, each under a string `key`. The cache, the\n * waiting-retry bookkeeping, and the retry timers are all per-key, while the\n * circuit breaker and token bucket are shared (one downstream target, one\n * breaker / one bucket — the example's implicit single-target assumption\n * made explicit).\n * - It is **config-driven**, not hand-wired. You hand `createResilientCall`\n * a `ResilientConfig` and get back the uniform knob contract every L2\n * composition exposes: `init()`, the four verbs (`attempt` / `succeed` /\n * `fail` / `onTimer`), `subs(state)`, and `handlers(ports)`.\n * - Every brick is **optional**. Omit `cache` and the cache gate disappears\n * (`get` is never consulted); omit `circuit` and every call passes the\n * breaker; omit `rateLimit` and the bucket never throttles; omit `retry`\n * and a failure is terminal (no backoff, no timer); omit `deadline` and no\n * overall wall-clock cap is armed. \"Omit a brick → omit its gate\" is the\n * whole config story — there are no other modes.\n *\n * Four later compositions (`llm-call`, `paginated-walk`, `authed-call`,\n * `reconciler`) inherit THIS slice + verb shape, so the contract here is\n * load-bearing: the slice is a flat record of brick states, every verb returns\n * `readonly [State, Cmd[]]`, time is always an `at` / `now` parameter, and the\n * RNG used for jitter is injected on the config (never read inside a verb).\n *\n * ## The two non-negotiables (canon)\n *\n * - **Durable** — the slice is a plain-data Model field (brick states are all\n * JSON-serializable), so it survives DO eviction / reload.\n * - **Replayable** — every transition is a verb returning new state + Cmds;\n * `replay` reconstructs it exactly. Nothing here closes over time or RNG.\n *\n * ## Where the clock / RNG live\n *\n * Inside the verbs: nowhere. Time arrives as `at` on `attempt` / `onTimer` and\n * is carried on the result / timer Msgs the consumer dispatches. Jitter RNG is\n * injected once at `createResilientCall(config, rng)` and threaded into\n * `nextDelayMs` at the verb boundary — deterministic in tests, `Math.random`\n * by default. The ONLY clock read is `Date.now()` inside the `handlers` port\n * (the effect boundary), exactly as `resilient-fetch.ts` stamps its result Msgs.\n *\n * That same `at` is what makes a DURATION-bounded retry budget reachable here:\n * `recordFailure` / `shouldRetry` are fed the failure's observation instant,\n * so `config.retry` accepts any `AnyRetryPolicy` — a count, a wall-clock outage\n * budget (`maxElapsedMs`), or explicit `unbounded: true` — with no new argument\n * on any verb and no clock read inside one.\n *\n * ## Typical wiring\n *\n * const rc = createResilientCall<string, Result>({\n * cache: { ttlMs: 60_000 },\n * circuit: { threshold: 5, cooldownMs: 30_000 },\n * rateLimit: { capacity: 10, refillPerSec: 5 },\n * retry: defaultRetryPolicy,\n * deadline: { ms: 5_000 },\n * });\n *\n * // in the machine:\n * init: () => [{ resilience: rc.init() }, []],\n * update: {\n * fetch: (s, m) => lift(s, rc.attempt(s.resilience, m.key, m.input, m.at)),\n * call_ok: (s, m) => lift(s, rc.succeed(s.resilience, m.key, m)),\n * call_err:(s, m) => lift(s, rc.fail(s.resilience, m.key, m)),\n * retry_due:(s, m) => lift(s, rc.onTimer(s.resilience, m)),\n * },\n * subscriptions: (s) => rc.subs(s.resilience),\n * subscribe: { deadline: subscribeDeadline },\n * interpret: rc.handlers({ run: ctx.call }),\n */\n\nimport {\n get as cacheGet,\n set as cacheSet,\n initCache,\n type TtlCache,\n} from \"../cache\";\nimport {\n type CircuitState,\n canPass,\n initCircuit,\n onFailure,\n onSuccess,\n} from \"../circuit-breaker\";\nimport {\n type DeadlineExceeded,\n type DeadlineSub,\n deadlineSub,\n subscribeDeadline,\n} from \"../deadline\";\nimport { type Cmd, type NoCtx, tryInterpret } from \"../index\";\nimport { MsgType } from \"../protocol\";\nimport { without } from \"../pure/core\";\nimport { initBucket, type TokenBucket, tryConsume } from \"../rate-limit\";\nimport {\n type AnyRetryPolicy,\n asRng,\n initRetry,\n nextDelayMs,\n type RetryState,\n recordFailure,\n shouldRetry,\n} from \"../retry-backoff\";\n\n// ===========================================================================\n// Config — the knob. Every brick optional; omit a brick → omit its gate.\n// ===========================================================================\n\n/** Circuit-breaker knob — only the two numbers a consumer ever tunes. */\nexport interface CircuitConfig {\n /** Consecutive failures that trip the breaker open. */\n readonly threshold: number;\n /** How long the breaker stays open before admitting a probe, in ms. */\n readonly cooldownMs: number;\n /**\n * Probes admitted in `half_open` before fast-failing the rest of the round.\n * Defaults to 1 (a single probe decides recovery) — matches the circuit-\n * breaker module's `defaultCircuitPolicy`.\n */\n readonly halfOpenMaxProbes?: number;\n}\n\n/** Token-bucket rate-limit knob. */\nexport interface RateLimitConfig {\n /** Burst size — the bucket starts full at `capacity`. */\n readonly capacity: number;\n /** Steady-state refill rate, tokens per second. */\n readonly refillPerSec: number;\n}\n\n/** Per-entry TTL cache knob. */\nexport interface CacheConfig {\n /** How long a cached success stays fresh, in ms. */\n readonly ttlMs: number;\n}\n\n/** Overall wall-clock deadline knob — an absolute cap per in-flight call. */\nexport interface DeadlineConfig {\n /** Budget from the moment a call starts, in ms. */\n readonly ms: number;\n}\n\n/**\n * The resilience knob. EVERY field is optional: omit a brick and its gate is\n * skipped entirely (the slice still carries a default brick state so the shape\n * stays uniform across configs, but the gate is never consulted). An empty\n * config `{}` is a valid pass-through — a bare effect with no resilience at all.\n */\nexport interface ResilientConfig {\n /**\n * The backoff brick. Omit and a failure is terminal (no backoff, no timer).\n *\n * Any bound the `../retry-backoff` union admits: a count (`RetryPolicy`), a\n * wall-clock outage budget (`DurationRetryPolicy`), or explicit\n * `unbounded: true`. A duration bound needs no extra wiring: every path that\n * records a failure already holds the instant it was observed as DATA —\n * `fail`'s `msg.at` (stamped at the interpret boundary) and `gate`'s `at`\n * (the caller's `attempt` / the retry timer's `atMs`) — so the streak clock\n * is fed from a Msg, never from a `Date.now()` inside a verb (invariant 2).\n */\n readonly retry?: AnyRetryPolicy;\n readonly circuit?: CircuitConfig;\n readonly rateLimit?: RateLimitConfig;\n readonly cache?: CacheConfig;\n readonly deadline?: DeadlineConfig;\n}\n\n// ===========================================================================\n// Slice — the Model field this knob owns. A flat record of brick states.\n// ===========================================================================\n\n/**\n * Per-key call phase. `key` indexes a logical call; several can be in flight at\n * once (the generalization of the example's single `url`). Discriminated on\n * `phase` so each phase carries only its own data (pattern 11):\n *\n * - `idle` — never attempted, or fully settled and forgotten.\n * - `running` — the effect Cmd is out; awaiting `succeed` / `fail`.\n * Carries `deadlineAtMs` (absolute cap, `0` if no deadline\n * brick) and the last `input` so a retry can re-issue it.\n * - `waiting_retry` — a transient failure backed off; the retry timer is armed\n * for `retryAtMs`. Carries `input` for the re-attempt.\n * - `circuit_open` — the breaker fast-failed this attempt. Terminal for this\n * call until the consumer re-attempts after cooldown.\n * - `succeeded` — settled OK. `result` is the value the port produced.\n * - `failed` — settled Err (out of retries, or no retry brick). `error`\n * carries the last failure.\n */\nexport type CallPhase<I, R> =\n | { readonly phase: \"idle\" }\n | {\n readonly phase: \"running\";\n readonly input: I;\n readonly deadlineAtMs: number;\n }\n | {\n readonly phase: \"waiting_retry\";\n readonly input: I;\n readonly retryAtMs: number;\n readonly deadlineAtMs: number;\n }\n | { readonly phase: \"circuit_open\" }\n | { readonly phase: \"succeeded\"; readonly result: R }\n | { readonly phase: \"failed\"; readonly error: unknown };\n\n/**\n * The slice. `circuit` / `bucket` are SHARED across keys (one downstream target\n * → one breaker, one bucket). `retry` and `cache` are PER KEY (each logical call\n * has its own backoff count + cached result), as is the per-call `CallPhase`.\n * Every field is plain data → the whole slice serializes into a `Store<S>`.\n *\n * `retry` / `cache` keep a default brick value even when the corresponding\n * config brick is omitted, so the slice shape is identical regardless of which\n * bricks the consumer enabled — the verbs simply never consult the unused brick.\n */\nexport interface ResilientState<I, R> {\n readonly circuit: CircuitState;\n readonly bucket: TokenBucket;\n /**\n * Per-key backoff counter. Entries minted by `backoff` are `TimedRetryState`s\n * (they carry the streak's `firstFailureAtMs`, since every failure path holds\n * the observation instant); the field is typed at the `RetryState` supertype\n * because a key that has never failed has no streak, and a slice persisted\n * before the origin existed rehydrates without one. Still plain data.\n */\n readonly retry: Readonly<Record<string, RetryState>>;\n readonly cache: TtlCache<R>;\n readonly calls: Readonly<Record<string, CallPhase<I, R>>>;\n}\n\n// ===========================================================================\n// Cmds + Msgs the knob speaks. Generic over the port input `I`.\n// ===========================================================================\n\n/**\n * The one effect this knob emits: \"run the port for `key` with `input`\". The\n * consumer's `handlers(ports)` interprets it; it carries no closure — `input`\n * is plain data (invariant 3).\n */\nexport type RunCmd<I> = Cmd<typeof MsgType.ResilientRun> & {\n readonly key: string;\n readonly input: I;\n};\n\n/** Settle Msgs the `handlers` port dispatches back. `at` is stamped at the boundary. */\nexport type SucceedMsg<R> = {\n readonly type: typeof MsgType.ResilientOk;\n readonly key: string;\n readonly result: R;\n readonly at: number;\n};\nexport type FailMsg = {\n readonly type: typeof MsgType.ResilientErr;\n readonly key: string;\n readonly error: unknown;\n readonly at: number;\n};\n\n/** The retry / deadline timer Msg — `DeadlineExceeded`, keyed by the call `key`. */\nexport type ResilientTimerMsg = DeadlineExceeded;\n\n/**\n * The plain-data error a deadline-failed call settles with. A `{_tag, ...}`\n * sentinel — NEVER a `new Error(...)` — so the slice stays JSON-serializable\n * (Error objects round-trip to `{}` and carry a stack trace, both of which break\n * the slice's durability invariant). `id` / `atMs` echo the timer that fired so\n * a consumer can attribute the failure to its deadline.\n */\nexport type DeadlineExceededError = {\n readonly _tag: \"deadline_exceeded\";\n readonly id: string;\n readonly atMs: number;\n};\n\n/** Ports the consumer supplies to `handlers`. */\nexport interface ResilientPorts<I, R> {\n /** The fallible work this knob wraps. Throws on failure → routed to `fail`. */\n readonly run: (input: I, key: string) => Promise<R>;\n}\n\n// ===========================================================================\n// Internal brick-policy derivation — config → the L1 policy shapes.\n// ===========================================================================\n\n// A circuit policy is only built when the brick is configured; absence is\n// represented as `null` so the gate can short-circuit to \"always pass\".\nfunction circuitPolicy(config: ResilientConfig) {\n if (config.circuit === undefined) return null;\n return {\n failureThreshold: config.circuit.threshold,\n cooldownMs: config.circuit.cooldownMs,\n halfOpenMaxProbes: config.circuit.halfOpenMaxProbes ?? 1,\n };\n}\n\n// Sub-id families. Each call's retry timer is a deadline keyed by `key`, so a\n// machine running many concurrent calls reconciles each independently.\nfunction retryTimerId(key: string): string {\n return `resilient:retry:${key}`;\n}\nfunction deadlineTimerId(key: string): string {\n return `resilient:deadline:${key}`;\n}\n\n// ===========================================================================\n// The knob factory.\n// ===========================================================================\n\n/**\n * Build a resilient-call knob from `config`. `rng` is injected for retry\n * jitter — pass a fixed `() => 0.5` in tests to pin backoff; defaults to\n * `Math.random` (read at the verb boundary, never inside a brick op). It is\n * curried onto the factory rather than threaded through every verb so callers\n * spell the determinism choice once.\n *\n * Returns the uniform L2 knob contract. `I` is the port input type, `R` the\n * port result type.\n *\n * @deprecated Use `withResilience` from `@demlik/tea/with-resilience` — not\n * drop-in; see the migration map at the top of this module.\n */\nexport function createResilientCall<I, R>(\n config: ResilientConfig,\n rng: () => number = Math.random,\n) {\n const cPolicy = circuitPolicy(config);\n // Re-affirm the `[0, 1)` contract at the seam where the injected generator\n // feeds the backoff math (brand from `../retry-backoff`). The factory's\n // public param stays a plain `() => number` so transitive callers are\n // unchanged; `asRng` is the single point it's branded for `nextDelayMs`.\n const rngBranded = asRng(rng);\n\n /** The starting slice. Bricks not in `config` still get a default value. */\n function init(): ResilientState<I, R> {\n return {\n circuit: initCircuit(),\n // The bucket carries a default value even without the rateLimit brick so\n // the slice shape is uniform, but the rate-limit GATE is skipped entirely\n // when the brick is absent (see `gate`) — the bucket is simply never\n // consulted. A `0/0` placeholder bucket would be touched by `tryConsume`;\n // a `1-cap` default is harmless because the gate never calls it.\n bucket: config.rateLimit\n ? initBucket(\n config.rateLimit.capacity,\n config.rateLimit.refillPerSec,\n 0,\n )\n : initBucket(1, 1, 0),\n retry: {},\n cache: initCache<R>(),\n calls: {},\n };\n }\n\n /** Read this key's retry state, defaulting to a fresh one. */\n function retryOf(s: ResilientState<I, R>, key: string): RetryState {\n return s.retry[key] ?? initRetry();\n }\n\n /** Compute the absolute deadline for a call starting at `at` (0 = no cap). */\n function deadlineAt(at: number): number {\n return config.deadline ? at + config.deadline.ms : 0;\n }\n\n /**\n * The shared decision: cache → rate-limit → circuit gate, then either emit\n * the effect or schedule a retry. `deadlineAtMs` is threaded so a re-attempt\n * (from `onTimer`) keeps the ORIGINAL overall deadline rather than restarting\n * it. PURE — `at` is the only clock; `rng` is the injected jitter source.\n *\n * Used by both `attempt` (fresh call) and `onTimer` (retry timer fired) so\n * the gate logic lives in exactly one place — the example's shared `attempt`\n * helper, lifted to a keyed knob.\n *\n * ## Why rate-limit is gated BEFORE the circuit probe\n *\n * The circuit-breaker's `canPass` is not a passive read: in `half_open` it\n * *consumes* a probe slot (advancing `probes`), and the consumed slot is only\n * released when a probe RESOLVES via `onSuccess` / `onFailure`. So a probe\n * slot may only be taken when this attempt is actually going to reach the\n * backend (i.e. emit the `resilient_run` Cmd). The rate-limit gate can reject\n * an attempt and return a backoff WITHOUT any Cmd — no backend call, so no\n * settle Msg ever comes back. If the circuit probe were consumed first, that\n * rate-limited attempt would burn the half-open probe budget on a call that\n * never happened, wedging the breaker `half_open` at its probe cap forever\n * (nothing moves it out of `half_open` but a resolved probe). Running the\n * rate-limit gate first means the circuit probe is consumed ONLY on the path\n * that emits the effect.\n */\n function gate(\n s: ResilientState<I, R>,\n key: string,\n input: I,\n at: number,\n deadlineAtMs: number,\n ): readonly [ResilientState<I, R>, readonly RunCmd<I>[]] {\n // 1) Serve from cache if fresh — no effect at all. Skipped when no cache brick.\n if (config.cache !== undefined) {\n const cached = cacheGet(s.cache, key, at);\n if (cached !== undefined) {\n return [setCall(s, key, { phase: \"succeeded\", result: cached }), []];\n }\n }\n\n // 2) Rate-limit gate FIRST — it may reject with no Cmd, so it must run\n // before any circuit probe is consumed (see header note). Skipped entirely\n // when no rateLimit brick — the bucket is never consulted, so the default\n // placeholder bucket stays untouched.\n let bucket = s.bucket;\n if (config.rateLimit !== undefined) {\n const [next, hasToken] = tryConsume(bucket, at);\n bucket = next;\n if (!hasToken) {\n // Rate-limited: treat as a transient failure and back off via retry.\n // The circuit is untouched — no probe is spent on a call that never ran.\n return backoff(\n { ...s, bucket },\n key,\n input,\n \"rate_limited\",\n at,\n deadlineAtMs,\n );\n }\n }\n\n // 3) Circuit-breaker gate. `null` policy → no breaker → always pass. Reached\n // only once a token is secured, so a half-open probe is consumed exclusively\n // on the path that emits the effect below.\n let circuit = s.circuit;\n if (cPolicy !== null) {\n const [next, ok] = canPass(circuit, cPolicy, at);\n circuit = next;\n if (!ok) {\n return [\n { ...setCall(s, key, { phase: \"circuit_open\" }), bucket, circuit },\n [],\n ];\n }\n }\n\n // 4) All gates passed — emit the effect as data.\n return [\n {\n ...setCall(s, key, { phase: \"running\", input, deadlineAtMs }),\n circuit,\n bucket,\n },\n [{ type: MsgType.ResilientRun, key, input }],\n ];\n }\n\n /**\n * Back off after a transient failure: record it, and if `retry` permits\n * another attempt, enter `waiting_retry` with the retry timer armed; else\n * settle `failed`. When no `retry` brick is configured the call fails on the\n * first failure (no backoff, no timer). PURE.\n *\n * `at` is both the backoff anchor AND the streak clock: it is passed to\n * `recordFailure` (which starts `firstFailureAtMs` on the streak's first\n * failure and preserves it on every later one) and to `shouldRetry`, so a\n * `DurationRetryPolicy` on `config.retry` is honoured with no extra wiring.\n * A success drops `retry[key]` entirely, which drops the origin with it —\n * only an unbroken run of failures grows toward a duration budget.\n */\n function backoff(\n s: ResilientState<I, R>,\n key: string,\n input: I,\n error: unknown,\n at: number,\n deadlineAtMs: number,\n ): readonly [ResilientState<I, R>, readonly RunCmd<I>[]] {\n if (config.retry === undefined) {\n return [setCall(s, key, { phase: \"failed\", error }), []];\n }\n const retry = recordFailure(retryOf(s, key), error, at);\n const withRetry = { ...s, retry: { ...s.retry, [key]: retry } };\n if (!shouldRetry(retry, config.retry, at)) {\n return [setCall(withRetry, key, { phase: \"failed\", error }), []];\n }\n const retryAtMs = at + nextDelayMs(retry, config.retry, rngBranded);\n return [\n setCall(withRetry, key, {\n phase: \"waiting_retry\",\n input,\n retryAtMs,\n deadlineAtMs,\n }),\n [],\n ];\n }\n\n // Set the phase for one key, leaving every other field untouched.\n function setCall(\n s: ResilientState<I, R>,\n key: string,\n phase: CallPhase<I, R>,\n ): ResilientState<I, R> {\n return { ...s, calls: { ...s.calls, [key]: phase } };\n }\n\n // === Verb: attempt =======================================================\n\n /**\n * Start (or restart) the call for `key` with `input` at time `at`. Runs the\n * cache → circuit → rate-limit gate and either emits the `resilient_run`\n * effect, schedules a retry, fast-fails (circuit open), or serves the cache.\n * PURE.\n */\n function attempt(\n s: ResilientState<I, R>,\n key: string,\n input: I,\n at: number,\n ): readonly [ResilientState<I, R>, readonly RunCmd<I>[]] {\n return gate(s, key, input, at, deadlineAt(at));\n }\n\n // === Verb: succeed =======================================================\n\n /**\n * Record a success for `key`: close the breaker, fill the cache (if a cache\n * brick exists), reset this key's retry count, and settle `succeeded`. PURE —\n * `msg.at` is the cache write clock.\n */\n function succeed(\n s: ResilientState<I, R>,\n key: string,\n msg: SucceedMsg<R>,\n ): readonly [ResilientState<I, R>, readonly RunCmd<I>[]] {\n const circuit =\n cPolicy !== null ? onSuccess(s.circuit, cPolicy) : s.circuit;\n const cache =\n config.cache !== undefined\n ? cacheSet(s.cache, key, msg.result, msg.at, config.cache.ttlMs)\n : s.cache;\n // Drop this key's retry counter — a success ends the retry run.\n const retry = without(s.retry, key);\n return [\n {\n ...setCall(s, key, { phase: \"succeeded\", result: msg.result }),\n circuit,\n cache,\n retry,\n },\n [],\n ];\n }\n\n // === Verb: fail ==========================================================\n\n /**\n * Record a failure for `key`: trip the breaker (it may open), then back off —\n * schedule a retry if `retry` permits, else settle `failed`. PURE — `msg.at`\n * stamps the breaker trip + the retry delay base. Re-issues from the call's\n * remembered `input` and preserves the original overall `deadlineAtMs`.\n */\n function fail(\n s: ResilientState<I, R>,\n key: string,\n msg: FailMsg,\n ): readonly [ResilientState<I, R>, readonly RunCmd<I>[]] {\n const circuit =\n cPolicy !== null ? onFailure(s.circuit, cPolicy, msg.at) : s.circuit;\n const withCircuit = { ...s, circuit };\n const call = s.calls[key];\n const input = call?.phase === \"running\" ? call.input : undefined;\n const deadlineAtMs =\n call?.phase === \"running\" ? call.deadlineAtMs : deadlineAt(msg.at);\n // No remembered input (e.g. a stray fail for a key not running) → just\n // settle failed after tripping the breaker; nothing to re-issue.\n if (input === undefined) {\n return [\n setCall(withCircuit, key, { phase: \"failed\", error: msg.error }),\n [],\n ];\n }\n return backoff(withCircuit, key, input, msg.error, msg.at, deadlineAtMs);\n }\n\n // === Verb: settleFailed ==================================================\n\n /**\n * Settle `key` to terminal `failed` with `error` WITHOUT touching the circuit\n * breaker or this key's retry counter. PURE.\n *\n * This is the verb for a failure that is NOT a downstream-health signal: the\n * call must end now, but the breaker must not trip and the backoff run must\n * not advance. `fail` is the opposite — it records the failure against the\n * breaker (it may open) and feeds the retry policy (it may back off). Use\n * `settleFailed` when the *reason* the call cannot proceed has nothing to do\n * with downstream health:\n *\n * - `authed-call` settles a 401 it cannot fix (e.g. the refresh budget is\n * spent): a bad token is the caller's problem, not the backend's —\n * tripping the breaker on it would punish a healthy target, and backing\n * off would just retry a request that will 401 again.\n * - `paginated-walk` settles a terminal walk error (e.g. a malformed page\n * the consumer rejects) that should stop the walk without poisoning the\n * shared breaker the next page fetch passes through.\n *\n * Because it leaves `circuit` and `retry[key]` untouched, the breaker keeps\n * its health view of the actual backend and a later `attempt` for this key\n * starts a fresh retry run. Both sibling knobs previously hand-rolled this by\n * splicing `calls` directly; this verb gives them one named, tested entry\n * point so the slice's settle invariants live in exactly one place.\n */\n function settleFailed(\n s: ResilientState<I, R>,\n key: string,\n error: unknown,\n ): readonly [ResilientState<I, R>, readonly RunCmd<I>[]] {\n return [setCall(s, key, { phase: \"failed\", error }), []];\n }\n\n // === Verb: onTimer =======================================================\n\n /**\n * A timer fired for some key. Two kinds, disambiguated by the Sub id:\n *\n * - retry timer → re-run the gate for that key's remembered input,\n * re-checking the circuit + bucket at THIS time.\n * - deadline timer → the overall budget elapsed → settle `failed` with a\n * deadline error, no matter the current phase.\n *\n * A timer for a key no longer `waiting_retry` (retry) / no longer in flight\n * (deadline) is a no-op — the reconcile pass races the result; the verb must\n * tolerate a stale fire. PURE.\n */\n function onTimer(\n s: ResilientState<I, R>,\n msg: ResilientTimerMsg,\n ): readonly [ResilientState<I, R>, readonly RunCmd<I>[]] {\n for (const [key, call] of Object.entries(s.calls)) {\n if (msg.id === retryTimerId(key)) {\n if (call.phase !== \"waiting_retry\") return [s, []];\n return gate(s, key, call.input, msg.atMs, call.deadlineAtMs);\n }\n if (msg.id === deadlineTimerId(key)) {\n // Deadline only fires for a still-active call. A settled call has no\n // armed deadline Sub, but tolerate a stale fire defensively.\n if (call.phase !== \"running\" && call.phase !== \"waiting_retry\")\n return [s, []];\n // Plain-data sentinel, NOT a `new Error(...)`: an Error object is not\n // JSON-serializable (it round-trips to `{}`) and captures a stack trace,\n // both of which break the slice's durability invariant once it is\n // persisted into a `Store<S>` and reloaded. A `{_tag, ...}` record keeps\n // the slice round-trip-equal under JSON.parse(JSON.stringify(...)).\n return [\n setCall(s, key, {\n phase: \"failed\",\n error: {\n _tag: \"deadline_exceeded\",\n id: msg.id,\n atMs: msg.atMs,\n } satisfies DeadlineExceededError,\n }),\n [],\n ];\n }\n }\n return [s, []];\n }\n\n // === Subs ================================================================\n\n /**\n * Pre-wired subscriptions: a retry timer for every `waiting_retry` call, and\n * (when the `deadline` brick is configured) an overall deadline timer for\n * every still-active call. Both are `DeadlineSub`s reconciled by id, so a\n * phase change cancels the matching timer automatically — no manual\n * `clearTimeout`. Wire `subscribe: { deadline: subscribeDeadline }`.\n */\n function subs(s: ResilientState<I, R>): readonly DeadlineSub[] {\n const out: DeadlineSub[] = [];\n for (const [key, call] of Object.entries(s.calls)) {\n if (call.phase === \"waiting_retry\") {\n out.push(deadlineSub(retryTimerId(key), call.retryAtMs));\n }\n if (\n config.deadline !== undefined &&\n (call.phase === \"running\" || call.phase === \"waiting_retry\") &&\n call.deadlineAtMs > 0\n ) {\n out.push(deadlineSub(deadlineTimerId(key), call.deadlineAtMs));\n }\n }\n return out;\n }\n\n // === Handlers ============================================================\n\n /**\n * Pre-wired interpret handler for `resilient_run`. Wraps the consumer's\n * `run` port via `tryInterpret` (Railway): success → `resilient_ok`, failure\n * → `resilient_err`, each stamped with `Date.now()` at the effect boundary —\n * the ONE permitted clock read (interpret is impure; the reducer never reads\n * the clock). Assign to the machine's `interpret`:\n *\n * interpret: rc.handlers({ run: (input, key) => ctx.callBackend(input) })\n */\n function handlers(ports: ResilientPorts<I, R>) {\n return {\n resilient_run: tryInterpret<\n RunCmd<I>,\n R,\n SucceedMsg<R> | FailMsg,\n // The work fn reads nothing from ctx — it forwards `cmd.input` to the\n // consumer-supplied `run` port. `NoCtx` (not `unknown`) marks this as a\n // DELIBERATE context-free seam, so callers see intent, not looseness.\n NoCtx\n >(\n (cmd) => ports.run(cmd.input, cmd.key),\n (result, cmd): SucceedMsg<R> => ({\n type: MsgType.ResilientOk,\n key: cmd.key,\n result,\n at: Date.now(),\n }),\n (error, cmd): FailMsg => ({\n type: MsgType.ResilientErr,\n key: cmd.key,\n error,\n at: Date.now(),\n }),\n ),\n };\n }\n\n return {\n init,\n attempt,\n succeed,\n fail,\n settleFailed,\n onTimer,\n subs,\n handlers,\n };\n}\n\n/**\n * Lift a knob result `[slice, cmds]` into a host `[State, cmds]` where the\n * slice lives at `state.resilience`. A convenience for the common single-slice\n * host; consumers with a differently-named field spread by hand. Pure — a thin\n * record rebuild, no clock / RNG.\n *\n * @deprecated Use `withResilience` from `@demlik/tea/with-resilience` — the\n * wrapper owns `model.$resilience`, so there is nothing to lift; see the\n * migration map at the top of this module.\n */\nexport function liftResilience<\n S extends { resilience: ResilientState<I, R> },\n I,\n R,\n C extends Cmd,\n>(\n state: S,\n [slice, cmds]: readonly [ResilientState<I, R>, readonly C[]],\n): readonly [S, readonly C[]] {\n return [{ ...state, resilience: slice }, cmds];\n}\n\n/**\n * Re-export the deadline Sub primitives so consumers (and tests) wire one\n * import: `subscribeDeadline` is the `subscribe` cell, `deadlineSub` builds the\n * Sub literal this knob's `subs` emits.\n */\nexport { subscribeDeadline, deadlineSub };\nexport type { DeadlineSub, DeadlineExceeded };\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/trace-replay/state-walk.ts"],"names":[],"mappings":";AAoBO,SAAS,OACd,CAAA,EACyD;AACzD,EAAA,IAAI,CAAA,KAAM,MAAM,OAAO,MAAA;AACvB,EAAA,IAAI,CAAA,KAAM,QAAW,OAAO,WAAA;AAC5B,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,EAAG,OAAO,OAAA;AAC7B,EAAA,IAAI,OAAO,CAAA,KAAM,QAAA,EAAU,OAAO,QAAA;AAClC,EAAA,OAAO,WAAA;AACT;AAGO,SAAS,SAAA,CAAU,MAAc,CAAA,EAAmB;AACzD,EAAA,OAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA,CAAA;AACrB;AAGO,SAAS,OAAA,CAAQ,MAAc,GAAA,EAAqB;AACzD,EAAA,OAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA;AACvB;AAQO,SAAS,SAAA,CACd,GACA,CAAA,EACU;AACV,EAAA,OAAO,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,OAAO,IAAA,CAAK,CAAC,CAAA,EAAG,GAAG,OAAO,IAAA,CAAK,CAAC,CAAC,CAAC,CAAC,EAAE,IAAA,EAAK;AACnE","file":"chunk-EWJP3YYP.js","sourcesContent":["// ---------------------------------------------------------------------------\n// state-walk — the structural-walk primitives the record/replay lane owns and\n// devtools' `diffState` reuses.\n//\n// Two walkers cross this substrate: `trace-replay`'s `firstDivergence` (first\n// differing cell, for a regression verdict) and `devtools`' `diffState` (EVERY\n// differing cell, classified add/remove/change, for a human diff). They diverge\n// on PURPOSE at the leaf — first-hit vs collect-all, length-mismatch-at-node vs\n// per-element — but they MUST agree on the path grammar: the same cell has to\n// print the same path in both, so a `divergence.path` from a replay result\n// indexes straight into a `StateChange[]`.\n//\n// That agreement used to be enforced by copy-paste discipline plus a comment.\n// Here it is enforced by construction: both walkers import the same `typeOf`,\n// the same `indexPath`/`keyPath` segment builders, and the same `unionKeys`\n// sorted-union order, so key-sorting and leaf equality cannot silently drift\n// between the two. Pure + zero-dep — it runs anywhere a machine runs.\n// ---------------------------------------------------------------------------\n\n/** Coarse type tag both walkers use to decide how to recurse. */\nexport function typeOf(\n v: unknown,\n): \"null\" | \"undefined\" | \"array\" | \"object\" | \"primitive\" {\n if (v === null) return \"null\";\n if (v === undefined) return \"undefined\";\n if (Array.isArray(v)) return \"array\";\n if (typeof v === \"object\") return \"object\";\n return \"primitive\";\n}\n\n/** Path to the `i`-th element of an array node, e.g. `state.queue[2]`. */\nexport function indexPath(path: string, i: number): string {\n return `${path}[${i}]`;\n}\n\n/** Path to a keyed child of an object node, e.g. `state.user.name`. */\nexport function keyPath(path: string, key: string): string {\n return `${path}.${key}`;\n}\n\n/**\n * Sorted union of both sides' own keys — the deterministic, insertion-order-\n * independent child order both walkers traverse. Shared so two states with the\n * same data in different key order compare equal in BOTH, and the reported path\n * for a real mismatch is reproducible run-to-run and identical across walkers.\n */\nexport function unionKeys(\n a: Record<string, unknown>,\n b: Record<string, unknown>,\n): string[] {\n return [...new Set([...Object.keys(a), ...Object.keys(b)])].sort();\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/at.ts","../src/work-queue/ops.ts"],"names":[],"mappings":";AAcO,SAAS,EAAA,CAAM,KAAmB,KAAA,EAA8B;AACrE,EAAA,OAAO,QAAQ,CAAA,IAAK,KAAA,IAAS,IAAI,MAAA,GAAS,MAAA,GAAY,IAAI,KAAK,CAAA;AACjE;;;ACQO,SAAS,SAAA,CACd,KAAA,EACA,KAAA,EACA,GAAA,EACA,EAAA,EAC8C;AAC9C,EAAA,MAAM,IAAA,GAAqB;AAAA,IACzB,EAAA;AAAA,IACA,MAAA,EAAQ,SAAA;AAAA,IACR,KAAA;AAAA,IACA,UAAA,EAAY;AAAA,GACd;AACA,EAAA,OAAO,EAAE,IAAA,EAAM,CAAC,GAAG,KAAA,EAAO,IAAI,GAAG,IAAA,EAAK;AACxC;AAOO,SAAS,WAAA,CACd,OACA,GAAA,EACwD;AACxD,EAAA,MAAM,MAAM,KAAA,CAAM,SAAA,CAAU,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,SAAS,CAAA;AAIzD,EAAA,MAAM,MAAA,GAAS,EAAA,CAAG,KAAA,EAAO,GAAG,CAAA;AAC5B,EAAA,IAAI,MAAA,KAAW,QAAW,OAAO,IAAA;AACjC,EAAA,MAAM,OAAA,GAAwB;AAAA,IAC5B,GAAG,MAAA;AAAA,IACH,MAAA,EAAQ,SAAA;AAAA,IACR,SAAA,EAAW;AAAA,GACb;AACA,EAAA,MAAM,IAAA,GAAO,MAAM,KAAA,EAAM;AACzB,EAAA,IAAA,CAAK,GAAG,CAAA,GAAI,OAAA;AACZ,EAAA,OAAO,EAAE,MAAM,OAAA,EAAQ;AACzB;AAOO,SAAS,UAAA,CACd,OACA,EAAA,EAC4C;AAC5C,EAAA,MAAM,OAAO,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,EAAE,CAAA;AAC5C,EAAA,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,IAAA,CAAK,MAAA,KAAW,MAAM,MAAA,EAAO;AACvD;AAQO,SAAS,WAAA,CACd,KAAA,EACA,EAAA,EACA,KAAA,EAC4C;AAC5C,EAAA,MAAM,MAAM,KAAA,CAAM,SAAA,CAAU,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,EAAE,CAAA;AAI9C,EAAA,MAAM,MAAA,GAAS,EAAA,CAAG,KAAA,EAAO,GAAG,CAAA;AAC5B,EAAA,IAAI,MAAA,KAAW,QAAW,OAAO,EAAE,MAAM,KAAA,CAAM,KAAA,EAAM,EAAG,OAAA,EAAS,KAAA,EAAM;AACvE,EAAA,MAAM,IAAA,GAAO,MAAM,KAAA,EAAM;AACzB,EAAA,IAAA,CAAK,GAAG,CAAA,GAAI,KAAA,CAAM,MAAM,CAAA;AACxB,EAAA,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,IAAA,EAAK;AAC/B;AAGO,SAAS,eAAkB,KAAA,EAGhC;AACA,EAAA,IAAI,OAAA,GAAU,KAAA;AACd,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,KAAoB;AAC1C,IAAA,IAAI,CAAA,CAAE,MAAA,KAAW,SAAA,EAAW,OAAO,CAAA;AACnC,IAAA,OAAA,GAAU,IAAA;AACV,IAAA,OAAO,EAAE,GAAG,CAAA,EAAG,MAAA,EAAQ,SAAA,EAAW,WAAW,MAAA,EAAU;AAAA,EACzD,CAAC,CAAA;AACD,EAAA,OAAO,EAAE,MAAM,OAAA,EAAQ;AACzB;AAGO,SAAS,QAAA,CACd,OACA,EAAA,EAC4C;AAC5C,EAAA,MAAM,OAAO,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,EAAE,CAAA;AAC5C,EAAA,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,IAAA,CAAK,MAAA,KAAW,MAAM,MAAA,EAAO;AACvD","file":"chunk-FV3Z5MBE.js","sourcesContent":["// ---------------------------------------------------------------------------\n// at — indexed array read that returns `T | undefined`, stating this package's\n// findIndex-narrowing convention once.\n//\n// Without `noUncheckedIndexedAccess`, `arr[idx]` is typed `T` even when `idx`\n// is `-1` (findIndex's \"no match\") or past the end — so the recurring\n// \"locate by findIndex, then use the element\" pattern has to hand-collapse\n// `idx === -1 ? undefined : arr[idx]` to get an honest `T | undefined` and\n// early-out without a non-null assertion. That collapse (plus a justifying\n// comment) was re-derived at every such site (work-queue/ops, fan-out). `at`\n// owns the convention: pass the `findIndex` result straight in, branch on the\n// `undefined` it returns, and keep `idx` around for any subsequent splice.\n// ---------------------------------------------------------------------------\n\nexport function at<T>(arr: readonly T[], index: number): T | undefined {\n return index < 0 || index >= arr.length ? undefined : arr[index];\n}\n","/**\n * Pure queue-lifecycle ops over `QueueItem<I>[]` — the BLESSED delegation\n * surface for this package.\n *\n * Each op is `(queue, ...args) => { next, result? }`. No I/O, no Date.now\n * indirection beyond a plain call site — the adapter in `./index.ts` injects\n * `Store<QueueItem<I>[]>` and orchestrates `load → mutate → save`.\n *\n * Substrate-agnostic by construction: nothing here references chrome.storage,\n * Cloudflare, or any concrete persistence layer. The audit-specific shape\n * (journeyId, projectId, ...) is lifted into the caller's `I` parameter.\n *\n * Importable two ways. The `createQueue(...)` adapter in `./index.ts` binds\n * these ops to a `Store` for in-process use (same one-shape-per-package rule\n * as `@demlik/tea/do`). L2 compositions that own their own Model slice\n * (`monitored-run`, `idempotent-intake`, …) instead reach these ops directly\n * via the `@demlik/tea/work-queue/ops` subpath, so a status flip is delegated\n * here rather than re-rolled per call site.\n */\n\nimport { at } from \"../at\";\nimport type { QueueItem } from \"./index\";\n\n/** Append a new pending item. Returns the new queue and the created item. */\nexport function enqueueOp<I>(\n queue: readonly QueueItem<I>[],\n input: I,\n now: number,\n id: string,\n): { next: QueueItem<I>[]; item: QueueItem<I> } {\n const item: QueueItem<I> = {\n id,\n status: \"pending\",\n input,\n enqueuedAt: now,\n };\n return { next: [...queue, item], item };\n}\n\n/**\n * Claim the first pending item by flipping it to `running` and stamping\n * `startedAt`. Returns the new queue and the claimed item, or `null` if no\n * pending item exists.\n */\nexport function claimNextOp<I>(\n queue: readonly QueueItem<I>[],\n now: number,\n): { next: QueueItem<I>[]; claimed: QueueItem<I> } | null {\n const idx = queue.findIndex((i) => i.status === \"pending\");\n // `at` collapses \"no pending item\" (idx === -1) into the same `undefined`\n // early-out, so the element is typed `QueueItem<I>` below without a non-null\n // assertion; `idx` stays around for the write.\n const target = at(queue, idx);\n if (target === undefined) return null;\n const claimed: QueueItem<I> = {\n ...target,\n status: \"running\",\n startedAt: now,\n };\n const next = queue.slice();\n next[idx] = claimed;\n return { next, claimed };\n}\n\n/**\n * Done items leave the queue — completed runs live wherever the caller\n * persists their output. Returns the new queue (or the original reference if\n * no item matched, so the adapter can skip a save).\n */\nexport function markDoneOp<I>(\n queue: readonly QueueItem<I>[],\n id: string,\n): { next: QueueItem<I>[]; changed: boolean } {\n const next = queue.filter((i) => i.id !== id);\n return { next, changed: next.length !== queue.length };\n}\n\n/**\n * Generic single-item status transition. Used by `markFailed`,\n * `markCancelled`, `retryItem`, `bindOutput`. The patch closure receives the\n * matched item and returns its replacement; returning the same reference is\n * fine (the adapter only saves on `changed`).\n */\nexport function patchItemOp<I>(\n queue: readonly QueueItem<I>[],\n id: string,\n patch: (item: QueueItem<I>) => QueueItem<I>,\n): { next: QueueItem<I>[]; changed: boolean } {\n const idx = queue.findIndex((i) => i.id === id);\n // `at` collapses the no-match case into an `undefined` early-out, narrowing\n // `target` to `QueueItem<I>` for `patch` without a non-null assertion; `idx`\n // stays around for the write.\n const target = at(queue, idx);\n if (target === undefined) return { next: queue.slice(), changed: false };\n const next = queue.slice();\n next[idx] = patch(target);\n return { next, changed: true };\n}\n\n/** Reset every `running` item back to `pending`, clearing `startedAt`. */\nexport function resetRunningOp<I>(queue: readonly QueueItem<I>[]): {\n next: QueueItem<I>[];\n changed: boolean;\n} {\n let changed = false;\n const next = queue.map((i): QueueItem<I> => {\n if (i.status !== \"running\") return i;\n changed = true;\n return { ...i, status: \"pending\", startedAt: undefined };\n });\n return { next, changed };\n}\n\n/** Hard-delete an item regardless of status. */\nexport function removeOp<I>(\n queue: readonly QueueItem<I>[],\n id: string,\n): { next: QueueItem<I>[]; changed: boolean } {\n const next = queue.filter((i) => i.id !== id);\n return { next, changed: next.length !== queue.length };\n}\n"]}
|
package/dist/chunk-HCEVHFJ7.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
// src/throttle/index.ts
|
|
2
|
-
function throttle(fn, ms, opts) {
|
|
3
|
-
const leading = opts?.leading ?? true;
|
|
4
|
-
const trailing = opts?.trailing ?? true;
|
|
5
|
-
let handle = null;
|
|
6
|
-
let pendingArgs = null;
|
|
7
|
-
function clearHandle() {
|
|
8
|
-
if (handle !== null) {
|
|
9
|
-
clearTimeout(handle);
|
|
10
|
-
handle = null;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
function onWindowExpired() {
|
|
14
|
-
if (trailing && pendingArgs !== null) {
|
|
15
|
-
const args = pendingArgs;
|
|
16
|
-
pendingArgs = null;
|
|
17
|
-
handle = setTimeout(onWindowExpired, ms);
|
|
18
|
-
fn(...args);
|
|
19
|
-
} else {
|
|
20
|
-
handle = null;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
const throttled = (...args) => {
|
|
24
|
-
if (handle === null) {
|
|
25
|
-
if (leading) {
|
|
26
|
-
fn(...args);
|
|
27
|
-
} else if (trailing) {
|
|
28
|
-
pendingArgs = args;
|
|
29
|
-
}
|
|
30
|
-
handle = setTimeout(onWindowExpired, ms);
|
|
31
|
-
} else if (trailing) {
|
|
32
|
-
pendingArgs = args;
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
throttled.cancel = () => {
|
|
36
|
-
clearHandle();
|
|
37
|
-
pendingArgs = null;
|
|
38
|
-
};
|
|
39
|
-
throttled.flush = () => {
|
|
40
|
-
if (pendingArgs !== null) {
|
|
41
|
-
const args = pendingArgs;
|
|
42
|
-
pendingArgs = null;
|
|
43
|
-
clearHandle();
|
|
44
|
-
fn(...args);
|
|
45
|
-
} else {
|
|
46
|
-
clearHandle();
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
return throttled;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export { throttle };
|
|
53
|
-
//# sourceMappingURL=chunk-HCEVHFJ7.js.map
|
|
54
|
-
//# sourceMappingURL=chunk-HCEVHFJ7.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/throttle/index.ts"],"names":[],"mappings":";AAkIO,SAAS,QAAA,CACd,EAAA,EACA,EAAA,EACA,IAAA,EACc;AACd,EAAA,MAAM,OAAA,GAAU,MAAM,OAAA,IAAW,IAAA;AACjC,EAAA,MAAM,QAAA,GAAW,MAAM,QAAA,IAAY,IAAA;AAMnC,EAAA,IAAI,MAAA,GAA+C,IAAA;AAOnD,EAAA,IAAI,WAAA,GAAwB,IAAA;AAE5B,EAAA,SAAS,WAAA,GAAoB;AAC3B,IAAA,IAAI,WAAW,IAAA,EAAM;AACnB,MAAA,YAAA,CAAa,MAAM,CAAA;AACnB,MAAA,MAAA,GAAS,IAAA;AAAA,IACX;AAAA,EACF;AAOA,EAAA,SAAS,eAAA,GAAwB;AAC/B,IAAA,IAAI,QAAA,IAAY,gBAAgB,IAAA,EAAM;AACpC,MAAA,MAAM,IAAA,GAAO,WAAA;AACb,MAAA,WAAA,GAAc,IAAA;AAId,MAAA,MAAA,GAAS,UAAA,CAAW,iBAAiB,EAAE,CAAA;AACvC,MAAA,EAAA,CAAG,GAAG,IAAI,CAAA;AAAA,IACZ,CAAA,MAAO;AAEL,MAAA,MAAA,GAAS,IAAA;AAAA,IACX;AAAA,EACF;AAEA,EAAA,MAAM,SAAA,GAAY,IAAI,IAAA,KAAkB;AACtC,IAAA,IAAI,WAAW,IAAA,EAAM;AAEnB,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,EAAA,CAAG,GAAG,IAAI,CAAA;AAAA,MACZ,WAAW,QAAA,EAAU;AAInB,QAAA,WAAA,GAAc,IAAA;AAAA,MAChB;AACA,MAAA,MAAA,GAAS,UAAA,CAAW,iBAAiB,EAAE,CAAA;AAAA,IACzC,WAAW,QAAA,EAAU;AAGnB,MAAA,WAAA,GAAc,IAAA;AAAA,IAChB;AAAA,EAEF,CAAA;AAEA,EAAA,SAAA,CAAU,SAAS,MAAY;AAC7B,IAAA,WAAA,EAAY;AACZ,IAAA,WAAA,GAAc,IAAA;AAAA,EAChB,CAAA;AAEA,EAAA,SAAA,CAAU,QAAQ,MAAY;AAI5B,IAAA,IAAI,gBAAgB,IAAA,EAAM;AACxB,MAAA,MAAM,IAAA,GAAO,WAAA;AACb,MAAA,WAAA,GAAc,IAAA;AACd,MAAA,WAAA,EAAY;AACZ,MAAA,EAAA,CAAG,GAAG,IAAI,CAAA;AAAA,IACZ,CAAA,MAAO;AAGL,MAAA,WAAA,EAAY;AAAA,IACd;AAAA,EACF,CAAA;AAEA,EAAA,OAAO,SAAA;AACT","file":"chunk-HCEVHFJ7.js","sourcesContent":["/**\n * @demlik/tea/throttle — a timer-based call transformer that caps invocation\n * to at most once per `ms` window.\n *\n * Sibling of `@demlik/tea/debounce` — the two share a SYMMETRIC surface\n * (`Throttled<A>` / `Debounced<A>`, both callable + `.cancel()` + `.flush()`,\n * both `{ leading?, trailing? }`) so they read as a pair. They are kept in\n * separate files with NO cross-import: each is a self-contained timer, and the\n * coalesce-vs-drop policies differ enough that sharing code would hide the\n * distinction. The contrast IS the lesson:\n *\n * - **debounce** waits for quiet — fires once AFTER a burst settles.\n * - **throttle** enforces a rate — fires AT MOST once per `ms` while the\n * burst is ongoing, dropping the calls in between.\n *\n * Layering with `@demlik/tea/throttled-input`: `throttle` and `debounce` are\n * the two host-boundary PRIMITIVES — two distinct algorithms\n * (at-most-once-per-window vs collapse-a-burst) behind one signature shape.\n * `throttled-input` is NOT a third primitive: it is a TEA machine composed\n * OVER them (the same semantics, reimplemented as pure, durable Model state)\n * that re-exports both. Wrapping a raw host event → these primitives; durable, replayable\n * gating inside a machine → `throttled-input` (see its module doc for the full\n * layering map).\n *\n * WHAT THIS IS NOT — and why it lives outside `update`:\n *\n * - NOT a reducer / Transitions cell. Reducers are PURE (invariant 2 — same\n * inputs → same outputs, no `Date.now`, no timers). A throttle holds a live\n * `setTimeout` handle and a window cursor; folding it into `update` would\n * smuggle a timer into the pure core.\n * - NOT a Sub. A Sub is a continuous SOURCE of Msgs the substrate reconciles\n * by id every transition (invariant 4). A throttle is a SINK transformer:\n * it wraps a `void`-returning handler (the canonical one is\n * `Runtime.dispatch`) so a high-frequency HOST event is rate-limited BEFORE\n * it ever becomes a Msg.\n *\n * It is a higher-order function at the host boundary (pattern 14 — TEA owns\n * state, JS owns timing). The host attaches the wrapped function to a\n * high-frequency event source (`mousemove`, `scroll`, `pointermove`, a game\n * loop) and the substrate downstream only ever sees the rate-limited Msg:\n *\n * const onMoved = throttle(\n * (e: PointerEvent) =>\n * runtime.dispatch({ type: \"UserMovedCursor\", x: e.clientX, y: e.clientY }),\n * 16, // ~60fps cap\n * );\n * window.addEventListener(\"pointermove\", onMoved);\n * // cleanup: onMoved.cancel(); window.removeEventListener(\"pointermove\", onMoved);\n *\n * NOT exported from the package root — reached via the `@demlik/tea/throttle`\n * subpath, same one-shape-per-package rule as `rate-limit`, `deadline`, and\n * `work-queue`.\n *\n * Uses the universal `setTimeout` / `clearTimeout` timer idiom (same discipline\n * as `subs/from-timeout.ts`): exactly one live handle at a time, the window\n * timer clears itself on expiry, `cancel` / `flush` clear and null it so a\n * stale callback can never run.\n */\n\n/**\n * A throttled wrapper around `fn`. Callable with the SAME argument tuple as\n * `fn` — `(...args: A) => void` — plus two control methods that share names and\n * shapes with `Debounced<A>` so the two modules read as a symmetric pair.\n */\nexport interface Throttled<A extends readonly unknown[]> {\n /** Invoke `fn` if the window is open, else record args for the trailing fire. */\n (...args: A): void;\n /**\n * Drop any pending trailing fire WITHOUT invoking `fn`, and close the active\n * window. Clears the timer, forgets the captured trailing args, and resets\n * the cursor so the next call fires immediately on the leading edge (if\n * `leading` is enabled). Idempotent.\n *\n * The host-cleanup partner of `removeEventListener`: cancel the pending fire\n * when the component unmounts / the listener detaches, so a queued\n * `dispatch` can't land after teardown.\n */\n cancel(): void;\n /**\n * Fire any pending trailing call IMMEDIATELY with its latest captured args,\n * then close the window. No-op when nothing is pending. Use to force the last\n * dropped call out early — e.g. flush the final cursor position when a drag\n * ends, so the rest state isn't a stale mid-drag sample.\n */\n flush(): void;\n}\n\n/**\n * Wrap `fn` so it runs AT MOST once per `ms` window, no matter how often it is\n * called.\n *\n * Leading + trailing (the default): the first call fires `fn` IMMEDIATELY (the\n * leading edge) and opens a `ms` window. Calls during the window are dropped\n * from immediate firing but their args are remembered; when the window closes,\n * `fn` fires ONCE more with the LATEST dropped args (the trailing edge) and a\n * new window opens. A call after the window has already closed leads a fresh\n * window immediately. Spacing every call at least `ms` apart therefore fires\n * each one on its own leading edge.\n *\n * @param fn The handler to rate-limit. Typically `(...) => runtime.dispatch(...)`,\n * but any `(...args: A) => void` works. The return value is\n * ignored — throttle is a fire transformer, not a value pipe.\n * @param ms Window length in milliseconds. `fn` fires at most once per `ms`.\n * @param opts.leading Fire on the FIRST call of a window (the leading edge),\n * immediately. Default `true`.\n * @param opts.trailing Fire once at window END with the latest args dropped\n * during the window. Default `true`.\n *\n * Edge combinations (matching lodash's settled semantics, the de-facto\n * standard the ecosystem rediscovered):\n *\n * - `{ leading: true, trailing: true }` (default): immediate fire + a\n * trailing fire per window while calls keep arriving. The trailing fire is\n * SUPPRESSED when no extra call arrived during the window (a lone call\n * already fired on the leading edge — no stale trailing double-fire).\n * - `{ leading: true, trailing: false }`: only the immediate fire; everything\n * in the window is dropped with no catch-up at the end.\n * - `{ leading: false, trailing: true }`: no immediate fire; the FIRST call\n * opens a window and `fn` fires at the window's end with the latest args.\n * Steady \"sample every `ms`\" behavior with no instant response.\n * - `{ leading: false, trailing: false }`: never fires. Degenerate but legal;\n * we don't throw — the caller asked for a no-op transformer.\n *\n * WHY a default of leading + trailing both `true`: a throttle's job is \"respond\n * now, then keep responding at a steady rate.\" Leading gives the instant\n * response (the first `mousemove` updates immediately); trailing guarantees the\n * FINAL sample of a window isn't lost (the cursor ends where the user actually\n * left it, not one window-width behind). Dropping either loses one of those two\n * guarantees, so both default on.\n */\nexport function throttle<A extends readonly unknown[]>(\n fn: (...args: A) => void,\n ms: number,\n opts?: { leading?: boolean; trailing?: boolean },\n): Throttled<A> {\n const leading = opts?.leading ?? true;\n const trailing = opts?.trailing ?? true;\n\n // Exactly one live handle at a time (the from-timeout discipline). `null`\n // when no window is open — the single source of truth for \"is a window\n // active?\". The window timer arms on a fire and clears itself on expiry; the\n // call path never stacks overlapping timers.\n let handle: ReturnType<typeof setTimeout> | null = null;\n // The latest args seen DURING an open window, held for the trailing fire.\n // Overwritten by every dropped call (the trailing edge fires with the LAST\n // args), cleared the instant we fire / cancel. `null` (not `undefined`) is\n // the empty sentinel because `A` may itself contain `undefined` elements — a\n // present-but-empty tuple is still a pending call, distinct from \"nothing\n // pending\".\n let pendingArgs: A | null = null;\n\n function clearHandle(): void {\n if (handle !== null) {\n clearTimeout(handle);\n handle = null;\n }\n }\n\n // Window expiry: the `ms` window just closed. If a call arrived during the\n // window (`pendingArgs !== null`) and trailing is enabled, fire it now and\n // open a FRESH window so the rate cap continues across a sustained burst.\n // If nothing was dropped, let the window close (handle → null) so the next\n // call leads a new window immediately.\n function onWindowExpired(): void {\n if (trailing && pendingArgs !== null) {\n const args = pendingArgs;\n pendingArgs = null;\n // Re-arm BEFORE firing so a re-entrant call from inside `fn` sees an open\n // window (and is correctly dropped/queued) rather than leading a second\n // window — keeps the \"at most once per `ms`\" invariant under re-entry.\n handle = setTimeout(onWindowExpired, ms);\n fn(...args);\n } else {\n // No trailing fire owed — close the window.\n handle = null;\n }\n }\n\n const throttled = (...args: A): void => {\n if (handle === null) {\n // Window is closed → this call leads a new window.\n if (leading) {\n fn(...args);\n } else if (trailing) {\n // No leading fire, but trailing wants the first call's args so the\n // window's end has something to fire. Without this, a leading:false\n // throttle would swallow a lone call entirely.\n pendingArgs = args;\n }\n handle = setTimeout(onWindowExpired, ms);\n } else if (trailing) {\n // Window is open → drop this call from immediate firing, but remember its\n // args as the latest candidate for the trailing edge.\n pendingArgs = args;\n }\n // Window open + trailing disabled → pure drop, nothing to remember.\n };\n\n throttled.cancel = (): void => {\n clearHandle();\n pendingArgs = null;\n };\n\n throttled.flush = (): void => {\n // Force the pending trailing fire out now and close the window. Mirrors\n // `onWindowExpired`'s fire branch but is caller-driven, so it tears the\n // timer down rather than re-arming.\n if (pendingArgs !== null) {\n const args = pendingArgs;\n pendingArgs = null;\n clearHandle();\n fn(...args);\n } else {\n // Nothing pending — still close a lingering window so a post-flush call\n // leads cleanly.\n clearHandle();\n }\n };\n\n return throttled;\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/paginated-walk/index.ts"],"names":["start","drain","resume"],"mappings":"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","file":"chunk-I5OV65MS.js","sourcesContent":["/**\n * @demlik/tea/paginated-walk — traverse a paginated API / sitemap end to end\n * WITHOUT a fake clock, without 429s, and resumable across a Durable-Object\n * eviction. The L2 composition that bolts `../resilient-call`'s resilience onto\n * `../paginator`'s cursor walk: each page is fetched as ONE keyed resilient\n * call (retry + backoff + rate-limit gate), and the cursor advances only once a\n * page settles `ok`.\n *\n * ## The recipe (the two siblings it composes)\n *\n * - **`../paginator`** owns the walk loop: the opaque `Cursor`, the `seen` /\n * `pages` counters, and the `idle → fetching → … → done` phase machine.\n * `paginated-walk` never re-implements cursor advancement — it folds each\n * settled page through `recordPage`, letting the paginator decide\n * `done` / `fetching(next)` / `paused`. Backpressure is a TWO-way valve:\n * `recordPage` parks the walk in `paused` once `seen >= highWaterMark`, and\n * the `drain` / `resume` verbs (delegating to the paginator's own\n * `drain` / `resume`) lower the gauge and re-open the parked fetch — without\n * them `highWaterMark` would be a one-way valve that strands a paused walk.\n * - **`../resilient-call`** owns the page fetch: the single `resilient_run`\n * effect per page is gated through that knob's cache → circuit → rate-limit\n * → retry pipeline. A transient page failure backs off and re-issues the\n * SAME cursor (idempotent retry); the walk does not advance until the page\n * genuinely settles.\n *\n * Those are the only two siblings this module calls into. The resilience knobs\n * (`retry` / `circuit` / `rateLimit` / `deadline`) are NOT separate bricks\n * `paginated-walk` composes — they belong to `resilient-call`, which owns the\n * rate-limit gate internally. This module merely passes them through to\n * `createResilientCall` and re-uses two config TYPES at the boundary:\n * `RateLimitConfig` (re-exported by `resilient-call`) and `RetryPolicy` (from\n * `../retry-backoff`). Pass a `rateLimit` and `resilient-call`'s token bucket\n * throttles page fetches (\"don't 429 the upstream\"); omit it and the walk runs\n * as fast as the upstream answers.\n *\n * Because the page-fetch resilience IS a `resilient-call` slice, this knob\n * **inherits that knob's contract verbatim**: the slice is a flat record, every\n * verb returns `readonly [State, Cmd[]]`, time is always an `at` parameter, and\n * the jitter RNG is injected once at `createPaginatedWalk(config, rng)` — never\n * read inside a verb (per the spec, `paginated-walk` *extends* `resilient-call`).\n *\n * ## The two non-negotiables (canon)\n *\n * - **Durable** — the slice is plain data: the paginator phase + counters, and\n * the resilient-call brick states (all JSON-serializable). The cursor lives\n * in the Model, not a closure, so a walk survives eviction mid-traversal and\n * resumes from the exact page it was fetching.\n * - **Replayable** — every transition is a verb returning new state + Cmds.\n * `nextCursor` / `onPage` are pure config functions applied at the verb\n * boundary; the Cmds they yield are plain data. `replay` reconstructs the\n * whole walk exactly.\n *\n * ## Where the clock / RNG live\n *\n * Inside the verbs: nowhere. `at` arrives on `start` / `pageOk` / `pageErr` /\n * `onTimer` and is threaded straight into the underlying resilient-call gate (so\n * a rate-limited or retried page measures backoff from that `at`). The jitter\n * RNG is injected at construction. The only clock read is `Date.now()` inside\n * the resilient-call `handlers` port (the effect boundary), inherited unchanged.\n *\n * ## The fixed fetch key\n *\n * A walk fetches one page at a time, so the resilient-call layer tracks exactly\n * one logical call under the constant key `PAGE_KEY`. The cursor being fetched\n * is the resilient call's `input`, so a post-eviction resume re-issues the same\n * page request. (`resilient-call` is keyed to support N concurrent calls; a walk\n * deliberately uses a single key — the paginator is the sequencer.)\n *\n * ## Typical wiring\n *\n * const walk = createPaginatedWalk<PageToken, ApiPage>({\n * firstPage: null, // the API's \"page one\" sentinel\n * nextCursor: (page) => page.nextToken ?? null,\n * onPage: (page) => [{ type: \"index_rows\", rows: page.items }],\n * rateLimit: { capacity: 10, refillPerSec: 5 },\n * retry: defaultRetryPolicy,\n * });\n *\n * // in the machine:\n * init: () => [{ walk: walk.init() }, []],\n * update: {\n * start: (s, m) => lift(s, walk.start(s.walk, m.at)),\n * page_ok: (s, m) => lift(s, walk.pageOk(s.walk, m.result, m.at)),\n * page_err: (s, m) => lift(s, walk.pageErr(s.walk, m.error, m.at)),\n * retry_due:(s, m) => lift(s, walk.onTimer(s.walk, m)),\n * drained: (s, m) => lift(s, walk.drain(s.walk, m.n)),\n * resume: (s, m) => lift(s, walk.resume(s.walk, m.at)),\n * },\n * subscriptions: (s) => walk.subs(s.walk),\n * subscribe: { deadline: subscribeDeadline },\n * interpret: walk.handlers({ run: (cursor) => api.fetchPage(cursor) }),\n */\n\nimport type { Cmd } from \"../index\";\nimport {\n drain as drainWalk,\n initPaginator,\n isDone,\n type PaginatorPolicy,\n type PaginatorState,\n recordPage,\n resume as resumeWalk,\n start as startWalk,\n} from \"../paginator\";\nimport { MsgType } from \"../protocol\";\nimport {\n type CircuitConfig,\n createResilientCall,\n type DeadlineConfig,\n type DeadlineSub,\n deadlineSub,\n type FailMsg,\n type RateLimitConfig,\n type ResilientPorts,\n type ResilientState,\n type ResilientTimerMsg,\n type RunCmd,\n type SucceedMsg,\n subscribeDeadline,\n} from \"../resilient-call\";\nimport type { RetryPolicy } from \"../retry-backoff\";\n\n// ===========================================================================\n// Config — the knob. `firstPage` / `nextCursor` / `onPage` describe the walk;\n// the resilience bricks are inherited from resilient-call (every one optional —\n// omit a brick, omit its gate).\n// ===========================================================================\n\n/**\n * The paginated-walk knob. Generic in `Cursor` (the opaque page handle the\n * upstream API hands back — offset, page token, \"next\" URL, …) and `Page` (the\n * shape your fetch port resolves with).\n *\n * `nextCursor` and `onPage` are PURE config functions applied at the verb\n * boundary, never stored in the slice or in a Cmd (invariant 3 — Cmds are\n * plain data, not closures). `nextCursor(page)` extracts the API's next-page\n * handle (or `null` at the end); `onPage(page)` yields the Cmds the consumer\n * wants emitted for each successfully fetched page (index rows, write to R2,\n * dispatch a downstream Msg — whatever; an empty array is fine).\n *\n * The resilience bricks (`retry` / `circuit` / `rateLimit` / `deadline`) are\n * the SAME optional knobs `resilient-call` exposes — paginated-walk extends it.\n * `rateLimit` is the brick that keeps the walk from 429-ing the upstream.\n */\nexport interface PaginatedWalkConfig<Cursor, Page, EmittedCmd extends Cmd> {\n /**\n * The cursor the walk fetches first. For an offset API this is typically `0`;\n * for a token API, whatever sentinel the API treats as \"page one\" (often\n * `null` or `\"\"`). Threaded into `paginator`'s `firstCursor`.\n */\n readonly firstPage: Cursor;\n /**\n * Extract the next cursor from a just-fetched page. Return a `Cursor` to keep\n * walking, or `null` when the API signalled the end (the walk finishes). PURE\n * + consumer-specific (only the consumer knows the API's pagination shape).\n */\n readonly nextCursor: (page: Page) => Cursor | null;\n /**\n * The Cmds to emit for each successfully fetched page — the consumer's work\n * per page (index, persist, fan out, …). Returns plain-data Cmds; `[]` is a\n * valid \"I process the page synchronously elsewhere\" answer. PURE.\n */\n readonly onPage: (page: Page) => readonly EmittedCmd[];\n /**\n * How many items a page contributes to the paginator's backpressure gauge\n * (`seen`). Defaults to `1` per page (count pages, not items) when omitted; a\n * consumer that wants per-item backpressure returns `page.items.length`. PURE.\n */\n readonly pageSize?: (page: Page) => number;\n /**\n * Backpressure threshold handed to the paginator. `seen >= highWaterMark`\n * parks the walk in `paused` instead of fetching the next page. Non-positive\n * (the default `0`) disables backpressure — the walk runs flat out until the\n * API exhausts. See `../paginator`'s `highWaterMark` docs.\n */\n readonly highWaterMark?: number;\n\n // --- resilience bricks, inherited from resilient-call (all optional) ---\n /** Exponential-backoff retry policy for a transient page-fetch failure. */\n readonly retry?: RetryPolicy;\n /** Circuit breaker around the page fetch (one upstream → one breaker). */\n readonly circuit?: CircuitConfig;\n /** Token-bucket rate limit — the \"don't 429 the upstream\" knob. */\n readonly rateLimit?: RateLimitConfig;\n /** Overall wall-clock deadline per individual page fetch. */\n readonly deadline?: DeadlineConfig;\n}\n\n// ===========================================================================\n// Slice — the Model field this knob owns. The paginator walk state + the\n// resilient-call slice for the page fetch. Both are flat plain data.\n// ===========================================================================\n\n/**\n * The slice. `walk` is the cursor/phase/counters from `../paginator`;\n * `resilience` is the `../resilient-call` slice that gates the page fetch.\n * Every field is JSON-serializable, so the whole walk survives a reload.\n *\n * The two move in lockstep: `walk` decides WHICH cursor to fetch next, while\n * `resilience` decides HOW that fetch is attempted (gated, retried, backed\n * off). `pageOk` advances `walk`; `pageErr` defers to `resilience` and leaves\n * `walk` parked on the same cursor until the page truly settles.\n */\nexport interface PaginatedWalkState<Cursor, Page> {\n readonly walk: PaginatorState<Cursor>;\n readonly resilience: ResilientState<Cursor, Page>;\n}\n\n// ===========================================================================\n// Cmds + Msgs the knob speaks.\n// ===========================================================================\n\n/**\n * The page-fetch effect this knob emits: the inherited `resilient_run` Cmd from\n * resilient-call, whose `input` is the `Cursor` to fetch and whose `key` is the\n * fixed `PAGE_KEY`. The consumer's `handlers(ports)` interprets it.\n */\nexport type FetchPageCmd<Cursor> = RunCmd<Cursor>;\n\n/** Page-settled Msgs the `handlers` port dispatches back (inherited verbatim). */\nexport type PageOkMsg<Page> = SucceedMsg<Page>;\nexport type PageErrMsg = FailMsg;\n\n/** The retry / deadline timer Msg — inherited from resilient-call. */\nexport type PaginatedWalkTimerMsg = ResilientTimerMsg;\n\n/**\n * Ports the consumer supplies to `handlers`. `run(cursor)` fetches ONE page for\n * the given cursor; throwing routes to `pageErr` (and thus the resilience\n * backoff). Same shape as resilient-call's port, specialized to the page fetch.\n */\nexport interface PaginatedWalkPorts<Cursor, Page>\n extends ResilientPorts<Cursor, Page> {}\n\n// ===========================================================================\n// The fixed key. A walk fetches one page at a time → exactly one logical\n// resilient call. The paginator is the sequencer; resilient-call's keying is\n// pinned to this single key.\n// ===========================================================================\n\n/** The single resilient-call key every page fetch runs under. */\nexport const PAGE_KEY = \"page\";\n\n// ===========================================================================\n// The knob factory.\n// ===========================================================================\n\n/**\n * Build a paginated-walk knob from `config`. `rng` is injected for the\n * underlying retry jitter — pass a fixed `() => 0` in tests to pin backoff;\n * defaults to `Math.random` (read at the verb boundary inside resilient-call,\n * never in a `paginated-walk` verb). Inherited straight from resilient-call.\n *\n * Returns the uniform L2 knob contract: `init()`, the verbs `start` / `pageOk`\n * / `pageErr` / `onTimer`, `subs(state)`, and `handlers(ports)`. `Cursor` is\n * the page handle, `Page` the fetch result, `EmittedCmd` the consumer's\n * per-page Cmds plus the inherited `FetchPageCmd`.\n */\nexport function createPaginatedWalk<Cursor, Page, EmittedCmd extends Cmd = Cmd>(\n config: PaginatedWalkConfig<Cursor, Page, EmittedCmd>,\n rng: () => number = Math.random,\n) {\n // The page fetch is a resilient call keyed by Cursor input → Page result.\n // We feed it only the resilience bricks; the walk-loop knobs are ours.\n const rc = createResilientCall<Cursor, Page>(\n {\n retry: config.retry,\n circuit: config.circuit,\n rateLimit: config.rateLimit,\n deadline: config.deadline,\n },\n rng,\n );\n\n // The paginator policy: our firstPage is the paginator's firstCursor; the\n // high-water mark gates backpressure (0 / omitted → unbounded).\n const paginatorPolicy: PaginatorPolicy<Cursor> = {\n firstCursor: config.firstPage,\n highWaterMark: config.highWaterMark ?? 0,\n };\n\n // The combined Cmd type the verbs can emit: the inherited page-fetch effect\n // plus whatever `onPage` yields.\n type OutCmd = FetchPageCmd<Cursor> | EmittedCmd;\n\n /** Replace the resilience slice, leaving `walk` untouched. */\n function withResilience(\n s: PaginatedWalkState<Cursor, Page>,\n resilience: ResilientState<Cursor, Page>,\n ): PaginatedWalkState<Cursor, Page> {\n return { ...s, resilience };\n }\n\n /** The starting slice: an idle paginator + a fresh resilient-call slice. */\n function init(): PaginatedWalkState<Cursor, Page> {\n return {\n walk: initPaginator<Cursor>(),\n resilience: rc.init(),\n };\n }\n\n /**\n * Issue a resilient page fetch for `cursor` at `at`. The cursor is the\n * resilient call's `input` (so a retry / resume re-fetches the same page) and\n * `PAGE_KEY` is the fixed key. Returns the advanced resilience slice + the\n * `resilient_run` Cmd (or none, if the gate cached / fast-failed / backed off).\n * PURE — `at` is the only clock. Shared by `start` and `pageOk`'s advance.\n */\n function fetch(\n s: PaginatedWalkState<Cursor, Page>,\n cursor: Cursor,\n at: number,\n ): readonly [\n PaginatedWalkState<Cursor, Page>,\n readonly FetchPageCmd<Cursor>[],\n ] {\n const [resilience, cmds] = rc.attempt(s.resilience, PAGE_KEY, cursor, at);\n return [withResilience(s, resilience), cmds];\n }\n\n /**\n * Issue the page fetch for a freshly-armed paginator transition, else a pure\n * no-op. `walk` is the result of a paginator verb (`startWalk` / `resumeWalk`)\n * applied to `s.walk`; this states the arm-and-fetch contract ONCE for the two\n * verbs that share it (`start`, `resume`).\n *\n * A paginator verb is a pure no-op on any phase it does not act on — it returns\n * the SAME state object. Reference identity (not phase) is the honest \"did the\n * verb arm a fresh fetch?\" check: a walk already `fetching` would also satisfy\n * `phase === \"fetching\"` yet must NOT re-issue a fetch (page-one skip /\n * double-fetch). So we proceed ONLY when the verb produced a fresh state. The\n * `phase === \"fetching\"` narrow that follows is therefore always true here\n * (both verbs only ever produce a `fetching` arm), and also narrows `.cursor`\n * for the type checker. PURE — `at` threads into the fetch gate.\n */\n function armAndFetch(\n s: PaginatedWalkState<Cursor, Page>,\n walk: PaginatorState<Cursor>,\n at: number,\n ): readonly [PaginatedWalkState<Cursor, Page>, readonly OutCmd[]] {\n if (walk === s.walk || walk.phase !== \"fetching\") {\n return [s, []];\n }\n return fetch({ ...s, walk }, walk.cursor, at);\n }\n\n // === Verb: start =========================================================\n\n /**\n * Begin the walk: arm the paginator's first cursor and issue the first page\n * fetch (gated through resilience). On any non-`idle` paginator phase this is\n * a no-op — re-starting a walk in flight would skip back to page one and\n * double-count, so a stray `start` after launch is absorbed (the paginator's\n * own `start` guard). PURE — `at` threads into the fetch gate.\n */\n function start(\n s: PaginatedWalkState<Cursor, Page>,\n at: number,\n ): readonly [PaginatedWalkState<Cursor, Page>, readonly OutCmd[]] {\n // `startWalk` is a pure no-op on any non-`idle` phase (same reference); a\n // fresh `fetching(firstCursor)` arm → issue the first page fetch.\n return armAndFetch(s, startWalk(s.walk, paginatorPolicy), at);\n }\n\n // === Verb: pageOk ========================================================\n\n /**\n * Record a successfully fetched `page` and decide what comes next. PURE —\n * `at` is the cache / next-fetch clock.\n *\n * 1. Settle the resilient call OK (closes the breaker, fills the cache,\n * resets the page-fetch retry counter) — inherited from resilient-call.\n * 2. Fold the page through the paginator: add `pageSize(page)` to `seen`,\n * bump `pages`, and branch on `nextCursor(page)`:\n * - `null` → the API is exhausted → paginator goes `done`.\n * - a cursor → advance, then either fetch it (backpressure room) or\n * park in `paused` (high-water mark reached).\n * 3. Emit the consumer's `onPage(page)` Cmds either way, PLUS the next\n * page-fetch effect when the paginator stays `fetching`.\n *\n * A `pageOk` that arrives when the paginator is not `fetching` (a late\n * duplicate, a double-dispatch) is absorbed by `recordPage` — the cursor does\n * not advance and `seen` is not double-counted; only the resilient settle +\n * `onPage` Cmds happen. The walk is a coordination aid, not a correctness\n * gate.\n */\n function pageOk(\n s: PaginatedWalkState<Cursor, Page>,\n page: Page,\n at: number,\n ): readonly [PaginatedWalkState<Cursor, Page>, readonly OutCmd[]] {\n // 1) Settle the underlying resilient call as a success.\n const [resilience] = rc.succeed(s.resilience, PAGE_KEY, {\n type: MsgType.ResilientOk,\n key: PAGE_KEY,\n result: page,\n at,\n });\n\n // 2) Advance the paginator with the page's contribution + the next cursor.\n const count = config.pageSize ? config.pageSize(page) : 1;\n const next = config.nextCursor(page);\n const walk = recordPage(s.walk, count, next, paginatorPolicy);\n\n const advanced: PaginatedWalkState<Cursor, Page> = { walk, resilience };\n\n // 3) The consumer's per-page work, always emitted on a successful page.\n const pageCmds: readonly EmittedCmd[] = config.onPage(page);\n\n // If the paginator stayed `fetching`, issue the next page fetch (gated).\n if (walk.phase === \"fetching\") {\n const [withFetch, fetchCmds] = fetch(advanced, walk.cursor, at);\n return [withFetch, [...pageCmds, ...fetchCmds]];\n }\n\n // `done` (exhausted) or `paused` (backpressure) → no further fetch now.\n return [advanced, pageCmds];\n }\n\n // === Verb: pageErr =======================================================\n\n /**\n * Record a failed page fetch and back off via resilience. PURE — `at` stamps\n * the breaker trip + the retry-delay base.\n *\n * Defers to the resilient-call `fail` verb: it trips the breaker and either\n * schedules a retry (paginator stays parked on the SAME cursor — no advance)\n * or settles the resilient call `failed` once retries are exhausted. The\n * paginator is deliberately untouched: a failed fetch must NOT advance the\n * cursor or skip a page. When the retry timer later fires, `onTimer` re-issues\n * the same page fetch.\n *\n * GUARDED by the paginator phase, exactly as `pageOk` is guarded by\n * `recordPage`'s `fetching`-only check. A `pageErr` only makes sense while a\n * page fetch is outstanding (`walk.phase === \"fetching\"`). A stray `pageErr`\n * that arrives after the walk has settled — `done` (exhausted), `paused`\n * (backpressure), or `idle` (not started) — has NO outstanding fetch to fail.\n * Without this guard it would still call `rc.fail`, which trips the SHARED\n * circuit breaker (dinging a healthy upstream) and overwrites the settled\n * `PAGE_KEY` resilient slot with `failed` (clobbering the succeeded result a\n * resume would otherwise observe). So a stray `pageErr` is absorbed as a pure\n * no-op — identity preserved — matching `pageOk`'s \"the walk is a coordination\n * aid, not a correctness gate\" stance.\n */\n function pageErr(\n s: PaginatedWalkState<Cursor, Page>,\n error: unknown,\n at: number,\n ): readonly [PaginatedWalkState<Cursor, Page>, readonly OutCmd[]] {\n // Only a `fetching` paginator has an outstanding page fetch to fail. On any\n // other phase the fail would corrupt shared resilience state for a fetch\n // that is not in flight — absorb it as a pure no-op.\n if (s.walk.phase !== \"fetching\") {\n return [s, []];\n }\n const [resilience, cmds] = rc.fail(s.resilience, PAGE_KEY, {\n type: MsgType.ResilientErr,\n key: PAGE_KEY,\n error,\n at,\n });\n return [withResilience(s, resilience), cmds];\n }\n\n // === Verb: onTimer =======================================================\n\n /**\n * A retry / deadline timer fired. Defers to resilient-call's `onTimer`: a\n * retry timer re-runs the gate for the page-fetch's remembered cursor (re-\n * issuing the SAME page); a deadline timer settles the resilient call failed.\n * The paginator stays parked on its cursor throughout — only `pageOk` advances\n * it. A stale fire is a no-op (inherited). PURE.\n *\n * GUARDED by the paginator phase, for the same reason as `pageErr`. A timer is\n * only meaningful while a page fetch is outstanding (`walk.phase ===\n * \"fetching\"`). A stray timer that fires after the walk has settled (`done` /\n * `paused` / `idle`) would otherwise re-enter `rc.onTimer` — re-issuing a fetch\n * the paginator no longer wants (a deadline timer could even overwrite the\n * settled `PAGE_KEY` slot with a deadline `failed`). On any non-`fetching`\n * phase the timer is absorbed as a pure no-op.\n */\n function onTimer(\n s: PaginatedWalkState<Cursor, Page>,\n msg: PaginatedWalkTimerMsg,\n ): readonly [PaginatedWalkState<Cursor, Page>, readonly OutCmd[]] {\n if (s.walk.phase !== \"fetching\") {\n return [s, []];\n }\n const [resilience, cmds] = rc.onTimer(s.resilience, msg);\n if (resilience === s.resilience) {\n // Inherited no-op identity → keep our slice identity too (pure no-op).\n return [s, []];\n }\n return [withResilience(s, resilience), cmds];\n }\n\n // === Verb: drain =========================================================\n\n /**\n * Acknowledge that the consumer finished processing `n` items, lowering the\n * paginator's backpressure gauge (`seen`). PURE — no clock. Delegates to\n * `paginator.drain`: subtracts `n` (floored at 0), leaves the phase untouched.\n *\n * The OTHER half of the backpressure valve `highWaterMark` opens: `recordPage`\n * parks the walk in `paused` once `seen >= highWaterMark`, and `drain` is how a\n * consumer lowers `seen` back below the mark so `resume` can re-open the fetch.\n * Without it `highWaterMark` would be a one-way valve — a walk could pause but\n * never continue. Emits no Cmds: draining only frees headroom; `resume` is the\n * separate, explicit \"continue now\" decision.\n */\n function drain(\n s: PaginatedWalkState<Cursor, Page>,\n n: number,\n ): readonly [PaginatedWalkState<Cursor, Page>, readonly OutCmd[]] {\n const walk = drainWalk(s.walk, n);\n if (walk === s.walk) {\n // Pure no-op identity (n <= 0, or seen already at floor).\n return [s, []];\n }\n return [{ ...s, walk }, []];\n }\n\n // === Verb: resume ========================================================\n\n /**\n * Re-open the backpressure valve after a `drain`: if the walk is `paused` and\n * `seen` has dropped below `highWaterMark`, re-arm the parked cursor and issue\n * its page fetch (gated through resilience). PURE — `at` threads into the fetch\n * gate. Delegates the phase decision to `paginator.resume`:\n *\n * - `paused` AND `seen < highWaterMark` → `fetching(cursor)` → emit the fetch.\n * - `paused` but still over the mark → no-op (the valve stays shut until a\n * further `drain` frees real headroom).\n * - any other phase → no-op (nothing to resume).\n *\n * Together with `drain` this completes the valve: `recordPage` shuts it\n * (`paused`), `drain` lowers the gauge, `resume` re-opens it and fires the next\n * page fetch — the same `fetch` helper `start` / `pageOk` use, so a resumed\n * fetch is gated identically (cache / circuit / rate-limit / retry).\n */\n function resume(\n s: PaginatedWalkState<Cursor, Page>,\n at: number,\n ): readonly [PaginatedWalkState<Cursor, Page>, readonly OutCmd[]] {\n // `resumeWalk` is a pure no-op (same reference) on any phase but `paused`, or\n // when `seen` is still at/over the mark. Only a fresh `fetching` arm means\n // the valve actually re-opened — issue the page fetch only then.\n return armAndFetch(s, resumeWalk(s.walk, paginatorPolicy), at);\n }\n\n // === Derived predicates ==================================================\n\n /**\n * Whether the walk has finished — the API returned a null next cursor and the\n * paginator is `done`. PURE, read-only. Lets a consumer's reducer fire a\n * \"walk complete\" Cmd (`if (walk.isDone(s.walk)) …`) without re-checking the\n * paginator phase by hand.\n */\n function isComplete(s: PaginatedWalkState<Cursor, Page>): boolean {\n return isDone(s.walk);\n }\n\n /**\n * The terminal page-fetch failure that stranded the walk, or `undefined` if no\n * page has terminally failed. PURE, read-only. Errors are data: a page that\n * exhausts its retries (or trips the deadline) settles the `PAGE_KEY` resilient\n * slot to `failed` while the paginator stays parked on its cursor — the walk is\n * stuck and will never advance on its own. Without a way to read that phase the\n * failure is unobservable: the walk simply stops emitting fetches with no\n * signal. `failure(s)` surfaces the settled error (the same plain-data sentinel\n * resilient-call records) so a consumer can fire a \"walk dead\" Cmd, alert, or\n * re-`start` a fresh walk.\n */\n function failure(s: PaginatedWalkState<Cursor, Page>): unknown {\n const call = s.resilience.calls[PAGE_KEY];\n return call?.phase === \"failed\" ? call.error : undefined;\n }\n\n /**\n * Whether the walk is STUCK: a page fetch has terminally `failed` yet the\n * paginator is still parked on a cursor (not `done`), so no further fetch will\n * ever be issued without intervention. PURE, read-only.\n *\n * This is the dead-walk predicate the consumer polls (`if (walk.isStuck(s)) …`)\n * to distinguish a healthy finish (`isComplete`) from a silent death. A walk is\n * stuck precisely when the resilient slot settled `failed` AND the paginator\n * has NOT reached `done` — a terminal failure on the final page that also\n * finished the walk is `isComplete`, not stuck. Pairs with `failure(s)`, which\n * hands back the error that stuck it.\n */\n function isStuck(s: PaginatedWalkState<Cursor, Page>): boolean {\n return s.resilience.calls[PAGE_KEY]?.phase === \"failed\" && !isDone(s.walk);\n }\n\n // === Subs ================================================================\n\n /**\n * Pre-wired subscriptions: exactly the resilient-call subs for the page\n * fetch — a retry timer while the fetch is `waiting_retry`, and (with the\n * `deadline` brick) a per-fetch deadline timer while it is active. Reconciled\n * by id, so a phase change cancels the matching timer automatically. Wire\n * `subscribe: { deadline: subscribeDeadline }` (re-exported below).\n */\n function subs(s: PaginatedWalkState<Cursor, Page>): readonly DeadlineSub[] {\n return rc.subs(s.resilience);\n }\n\n // === Handlers ============================================================\n\n /**\n * Pre-wired interpret handler for the page-fetch effect. Inherited from\n * resilient-call (`resilient_run`): wraps the consumer's `run(cursor)` port\n * via `tryInterpret` (Railway) — success → `resilient_ok` (handled by\n * `pageOk`), failure → `resilient_err` (handled by `pageErr`), each stamped\n * with `Date.now()` at the effect boundary (the ONE permitted clock read).\n *\n * interpret: walk.handlers({ run: (cursor) => api.fetchPage(cursor) })\n *\n * The consumer maps the inherited Msg types to their `pageOk` / `pageErr`\n * reducer cells (the wire shape is `resilient_ok` / `resilient_err`).\n */\n function handlers(ports: PaginatedWalkPorts<Cursor, Page>) {\n return rc.handlers(ports);\n }\n\n return {\n init,\n start,\n pageOk,\n pageErr,\n onTimer,\n drain,\n resume,\n isComplete,\n failure,\n isStuck,\n subs,\n handlers,\n };\n}\n\n/**\n * Lift a knob result `[slice, cmds]` into a host `[State, cmds]` where the slice\n * lives at `state.walk`. 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 liftWalk<\n S extends { walk: PaginatedWalkState<Cursor, Page> },\n Cursor,\n Page,\n C extends Cmd,\n>(\n state: S,\n [slice, cmds]: readonly [PaginatedWalkState<Cursor, Page>, readonly C[]],\n): readonly [S, readonly C[]] {\n return [{ ...state, walk: slice }, cmds];\n}\n\n/**\n * Re-export the deadline Sub primitives (inherited from resilient-call) so\n * consumers wire one import: `subscribeDeadline` is the `subscribe` cell,\n * `deadlineSub` builds the Sub literal this knob's `subs` emits.\n */\nexport { subscribeDeadline, deadlineSub };\nexport type { DeadlineSub };\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/debounce/index.ts"],"names":[],"mappings":";AAoHO,SAAS,QAAA,CACd,EAAA,EACA,EAAA,EACA,IAAA,EACc;AACd,EAAA,MAAM,OAAA,GAAU,MAAM,OAAA,IAAW,KAAA;AACjC,EAAA,MAAM,QAAA,GAAW,MAAM,QAAA,IAAY,IAAA;AAMnC,EAAA,IAAI,MAAA,GAA+C,IAAA;AAOnD,EAAA,IAAI,WAAA,GAAwB,IAAA;AAK5B,EAAA,IAAI,YAAA,GAAe,KAAA;AAEnB,EAAA,SAAS,WAAA,GAAoB;AAC3B,IAAA,IAAI,WAAW,IAAA,EAAM;AACnB,MAAA,YAAA,CAAa,MAAM,CAAA;AACnB,MAAA,MAAA,GAAS,IAAA;AAAA,IACX;AAAA,EACF;AAKA,EAAA,SAAS,cAAA,GAAuB;AAC9B,IAAA,MAAA,GAAS,IAAA;AAQT,IAAA,IAAI,QAAA,IAAY,gBAAgB,IAAA,EAAM;AACpC,MAAA,MAAM,IAAA,GAAO,WAAA;AACb,MAAA,WAAA,GAAc,IAAA;AACd,MAAA,EAAA,CAAG,GAAG,IAAI,CAAA;AAAA,IACZ;AAEA,IAAA,YAAA,GAAe,KAAA;AAAA,EACjB;AAEA,EAAA,MAAM,SAAA,GAAY,IAAI,IAAA,KAAkB;AAItC,IAAA,MAAM,eAAe,MAAA,KAAW,IAAA;AAChC,IAAA,IAAI,OAAA,IAAW,YAAA,IAAgB,CAAC,YAAA,EAAc;AAC5C,MAAA,YAAA,GAAe,IAAA;AACf,MAAA,EAAA,CAAG,GAAG,IAAI,CAAA;AAAA,IACZ,WAAW,QAAA,EAAU;AAGnB,MAAA,WAAA,GAAc,IAAA;AAAA,IAChB;AAKA,IAAA,WAAA,EAAY;AACZ,IAAA,MAAA,GAAS,UAAA,CAAW,gBAAgB,EAAE,CAAA;AAAA,EACxC,CAAA;AAEA,EAAA,SAAA,CAAU,SAAS,MAAY;AAC7B,IAAA,WAAA,EAAY;AACZ,IAAA,WAAA,GAAc,IAAA;AACd,IAAA,YAAA,GAAe,KAAA;AAAA,EACjB,CAAA;AAEA,EAAA,SAAA,CAAU,QAAQ,MAAY;AAI5B,IAAA,IAAI,gBAAgB,IAAA,EAAM;AACxB,MAAA,MAAM,IAAA,GAAO,WAAA;AACb,MAAA,WAAA,GAAc,IAAA;AACd,MAAA,WAAA,EAAY;AAEZ,MAAA,YAAA,GAAe,KAAA;AACf,MAAA,EAAA,CAAG,GAAG,IAAI,CAAA;AAAA,IACZ,CAAA,MAAO;AAGL,MAAA,WAAA,EAAY;AACZ,MAAA,YAAA,GAAe,KAAA;AAAA,IACjB;AAAA,EACF,CAAA;AAEA,EAAA,OAAO,SAAA;AACT","file":"chunk-J6527VRQ.js","sourcesContent":["/**\n * @demlik/tea/debounce — a timer-based call transformer that coalesces a burst\n * of calls into a single fire.\n *\n * Sibling of `@demlik/tea/throttle` — the two share a SYMMETRIC surface\n * (`Debounced<A>` / `Throttled<A>`, both callable + `.cancel()` + `.flush()`,\n * both `{ leading?, trailing? }`) so they read as a pair. They are kept in\n * separate files with NO cross-import: each is a self-contained timer, and the\n * coalesce-vs-drop policies are different enough that sharing code would hide\n * the distinction. Read one to understand the other; do not couple them.\n *\n * Layering with `@demlik/tea/throttled-input`: `debounce` and `throttle` are\n * the two host-boundary PRIMITIVES — two distinct algorithms (collapse-a-burst\n * vs at-most-once-per-window) behind one signature shape. `throttled-input` is\n * NOT a third primitive: it is a TEA machine composed OVER them that\n * re-exports both (see its module doc for the full layering map).\n *\n * WHAT THIS IS NOT — and why it lives outside `update`:\n *\n * - NOT a reducer / Transitions cell. Reducers are PURE (invariant 2 — same\n * inputs → same outputs, no `Date.now`, no timers). A debounce holds a live\n * `setTimeout` handle and mutable pending-args state; folding it into\n * `update` would smuggle a timer into the pure core.\n * - NOT a Sub. A Sub is a continuous SOURCE of Msgs the substrate reconciles\n * by id every transition (invariant 4). A debounce is a SINK transformer:\n * it wraps a `void`-returning handler (the canonical one is\n * `Runtime.dispatch`) so bursty HOST events coalesce BEFORE they ever\n * become a Msg.\n *\n * It is a higher-order function at the host boundary (pattern 14 — TEA owns\n * state, JS owns timing). The host attaches the wrapped function to a noisy\n * event source (`scroll`, `resize`, `input`, a ResizeObserver) and the\n * substrate downstream only ever sees the coalesced Msg:\n *\n * const onResized = debounce(\n * () => runtime.dispatch({ type: \"BrowserResizedWindow\" }),\n * 150,\n * );\n * window.addEventListener(\"resize\", onResized);\n * // cleanup: onResized.cancel(); window.removeEventListener(\"resize\", onResized);\n *\n * NOT exported from the package root — reached via the `@demlik/tea/debounce`\n * subpath, same one-shape-per-package rule as `rate-limit`, `deadline`, and\n * `work-queue`.\n *\n * Uses the universal `setTimeout` / `clearTimeout` timer idiom (same discipline\n * as `subs/from-timeout.ts`): exactly one live handle at a time, every arm\n * clears the previous, every fire / cancel clears the handle and nulls it so a\n * stale callback can never run.\n */\n\n/**\n * A debounced wrapper around `fn`. Callable with the SAME argument tuple as\n * `fn` — `(...args: A) => void` — plus two control methods that share names and\n * shapes with `Throttled<A>` so the two modules read as a symmetric pair.\n */\nexport interface Debounced<A extends readonly unknown[]> {\n /** Schedule (or re-schedule) a fire of the wrapped `fn`. See `debounce`. */\n (...args: A): void;\n /**\n * Drop any pending trailing fire WITHOUT invoking `fn`. Clears the timer and\n * forgets the captured args. Idempotent — calling it with nothing pending is\n * a no-op. The leading-edge latch (if `leading` is enabled) also resets, so\n * the next call after `cancel` is treated as a fresh burst.\n *\n * The host-cleanup partner of `removeEventListener`: cancel the pending fire\n * when the component unmounts / the listener detaches, so a queued\n * `dispatch` can't land after teardown.\n */\n cancel(): void;\n /**\n * Fire any pending trailing call IMMEDIATELY with its captured args, then\n * clear the timer. No-op when nothing is pending. Use to force the last\n * coalesced call out early — e.g. flush a debounced save on `beforeunload`,\n * or flush a debounced search when the user presses Enter.\n */\n flush(): void;\n}\n\n/**\n * Wrap `fn` so a BURST of calls collapses to a single invocation.\n *\n * Trailing edge (the default): each call (re)starts a `ms` timer; `fn` fires\n * once with the LAST args after `ms` of quiet. Every call within `ms` of the\n * previous resets the timer — the classic \"wait until the user stops typing\"\n * behavior.\n *\n * @param fn The handler to coalesce. Typically `(...) => runtime.dispatch(...)`,\n * but any `(...args: A) => void` works. The return value is\n * ignored — debounce is a fire transformer, not a value pipe.\n * @param ms Quiet window in milliseconds. Calls closer together than `ms`\n * coalesce; a gap of at least `ms` lets the trailing fire through.\n * @param opts.leading Fire on the FIRST call of a burst (the leading edge),\n * with that first call's args. Default `false`.\n * @param opts.trailing Fire on the trailing edge with the LAST call's args.\n * Default `true`.\n *\n * Edge combinations (matching lodash's settled semantics, the de-facto\n * standard the ecosystem rediscovered):\n *\n * - `{ trailing: true }` (default): one fire, after the burst, last args.\n * - `{ leading: true, trailing: false }`: one fire, at the burst START,\n * first args. Subsequent calls within the window are swallowed; the timer\n * only re-opens the \"can lead again\" latch after `ms` of quiet.\n * - `{ leading: true, trailing: true }`: fires at the start AND end of a\n * burst — BUT the trailing fire is SUPPRESSED for a burst of exactly ONE\n * call (the leading fire already covered it, so a lone call doesn't\n * double-fire). This matches lodash and is the behavior tests pin.\n * - `{ leading: false, trailing: false }`: never fires. Degenerate but legal;\n * we don't throw — the caller asked for a no-op transformer.\n *\n * WHY a default of trailing-only: a debounce's whole job is \"act after the\n * activity settles.\" The trailing edge IS that semantic — fire with the final\n * state of the burst (the last keystroke, the final scroll position). Leading\n * is the opt-in for \"respond instantly, then go quiet.\"\n */\nexport function debounce<A extends readonly unknown[]>(\n fn: (...args: A) => void,\n ms: number,\n opts?: { leading?: boolean; trailing?: boolean },\n): Debounced<A> {\n const leading = opts?.leading ?? false;\n const trailing = opts?.trailing ?? true;\n\n // Exactly one live handle at a time (the from-timeout discipline). `null`\n // when no fire is pending — the single source of truth for \"is a timer\n // armed?\". Every arm clears the previous handle before opening a new one, so\n // we never leak overlapping timers across a burst.\n let handle: ReturnType<typeof setTimeout> | null = null;\n // The most recent args, held only while a trailing fire is pending. Captured\n // on every call (the trailing edge fires with the LAST args), cleared the\n // instant we fire / cancel so a stale tuple can never leak into a later\n // burst. `null` (not `undefined`) is the empty sentinel because `A` may\n // itself contain `undefined` elements — a present-but-empty tuple is still a\n // pending call, distinct from \"nothing pending\".\n let pendingArgs: A | null = null;\n // Leading-edge latch: true once a leading fire has happened for the current\n // burst, reset to false after `ms` of quiet (the timer's expiry) or on\n // `cancel`. Gates the \"fire on first call of a burst, then stay quiet\" rule\n // so mid-burst calls don't re-trigger the leading fire.\n let leadingFired = false;\n\n function clearHandle(): void {\n if (handle !== null) {\n clearTimeout(handle);\n handle = null;\n }\n }\n\n // Timer expiry: the burst has gone quiet for `ms`. Fire the trailing edge if\n // one is owed, then reset all burst state so the NEXT call starts a fresh\n // burst (re-arming the leading latch, clearing pending args).\n function onTimerExpired(): void {\n handle = null;\n // Suppress the trailing fire for a lone leading-only-eligible call:\n // when `leadingFired` is true AND trailing is enabled, a burst of exactly\n // one call already fired on the leading edge — `pendingArgs` was cleared\n // at that point, so there is nothing to fire here. A burst of 2+ calls\n // re-captured `pendingArgs` after the leading fire, so the trailing fire\n // lands with the last args. The `pendingArgs !== null` guard encodes\n // exactly that distinction; no separate call-count needed.\n if (trailing && pendingArgs !== null) {\n const args = pendingArgs;\n pendingArgs = null;\n fn(...args);\n }\n // Burst over — re-open the leading latch for the next burst.\n leadingFired = false;\n }\n\n const debounced = (...args: A): void => {\n // Leading edge: the FIRST call of a burst (no timer armed yet, latch open).\n // Fire immediately with this call's args; do NOT stash them as pending so a\n // lone call won't also fire on the trailing edge.\n const isBurstStart = handle === null;\n if (leading && isBurstStart && !leadingFired) {\n leadingFired = true;\n fn(...args);\n } else if (trailing) {\n // Capture the latest args for the trailing fire. Overwrites any prior\n // pending tuple — the trailing edge fires with the LAST args, by design.\n pendingArgs = args;\n }\n\n // (Re)arm the quiet-window timer. Clearing the previous handle is what\n // makes the window SLIDE: every call within `ms` pushes the trailing fire\n // out to `ms` after THIS call.\n clearHandle();\n handle = setTimeout(onTimerExpired, ms);\n };\n\n debounced.cancel = (): void => {\n clearHandle();\n pendingArgs = null;\n leadingFired = false;\n };\n\n debounced.flush = (): void => {\n // Force the pending trailing fire out now. Mirrors `onTimerExpired`'s fire\n // branch but is caller-driven rather than timer-driven, so it also tears\n // down the armed timer (a timer-driven expiry already nulled `handle`).\n if (pendingArgs !== null) {\n const args = pendingArgs;\n pendingArgs = null;\n clearHandle();\n // A flushed trailing fire ends the burst, same as a natural expiry.\n leadingFired = false;\n fn(...args);\n } else {\n // Nothing pending — still tear down a lingering leading-only timer so a\n // post-flush call leads cleanly.\n clearHandle();\n leadingFired = false;\n }\n };\n\n return debounced;\n}\n"]}
|
package/dist/chunk-JELSZN25.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
// src/protocol.ts
|
|
2
|
-
var MsgType = {
|
|
3
|
-
// --- resilient-call: the run Cmd + its two settle Msgs -------------------
|
|
4
|
-
/** The "run the port for `key`" effect Cmd resilient-call emits. */
|
|
5
|
-
ResilientRun: "resilient_run",
|
|
6
|
-
/** PRIVATE success settle Msg (read only by `agentEvents`, #47). */
|
|
7
|
-
ResilientOk: "resilient_ok",
|
|
8
|
-
/** Failure settle Msg — routed to the `fail` verb (back off via retry). */
|
|
9
|
-
ResilientErr: "resilient_err",
|
|
10
|
-
// --- agent: the wired machine's own entry-point Msgs ---------------------
|
|
11
|
-
/** Begin a run. */
|
|
12
|
-
AgentStart: "agent_start",
|
|
13
|
-
/** PRIVATE tool-fan-out success settle Msg (read only by `agentEvents`, #47). */
|
|
14
|
-
AgentToolOk: "agent_tool_ok",
|
|
15
|
-
/** Tool-fan-out failure settle Msg. */
|
|
16
|
-
AgentToolErr: "agent_tool_err",
|
|
17
|
-
/**
|
|
18
|
-
* Re-fire the one outstanding effect on rehydrate (the do↔agent seam). Fired
|
|
19
|
-
* by `do/host`'s `autoBoot` via the typed `agentBootMsg` constructor, matched
|
|
20
|
-
* by the agent reducer — see `AgentBootPort` in `../agent`.
|
|
21
|
-
*/
|
|
22
|
-
AgentBoot: "agent_boot",
|
|
23
|
-
// --- agent: the context-compaction round-trip (#85) ----------------------
|
|
24
|
-
/**
|
|
25
|
-
* The "summarize the oldest N turns" effect Cmd the agent emits when its
|
|
26
|
-
* `CompactionPolicy` asks to compact before a brain call. A DEDICATED
|
|
27
|
-
* round-trip (design B1), distinct from the brain call's `resilient_run`, so
|
|
28
|
-
* compaction is its own honest `Awaiting` state — see `../agent`.
|
|
29
|
-
*/
|
|
30
|
-
CompactRun: "compact_run",
|
|
31
|
-
/** Compaction round-trip resolved — carries the summary text the fold-back folds. */
|
|
32
|
-
CompactOk: "compact_ok",
|
|
33
|
-
/** Compaction round-trip failed (exhausted retry) — surfaced as data, not a stall. */
|
|
34
|
-
CompactErr: "compact_err",
|
|
35
|
-
// --- token-refresh: the two refresh-result Msgs --------------------------
|
|
36
|
-
/** Refresh port resolved — carries the fresh `Token`. */
|
|
37
|
-
TokenRefreshed: "token_refreshed",
|
|
38
|
-
/** Refresh port rejected — carries the rejection (errors are data). */
|
|
39
|
-
TokenRefreshFailed: "token_refresh_failed",
|
|
40
|
-
// --- authed-call: the 401 trigger ----------------------------------------
|
|
41
|
-
/** The 401 the consumer dispatches when a guarded call comes back unauthorized. */
|
|
42
|
-
Unauthorized: "unauthorized"
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export { MsgType };
|
|
46
|
-
//# sourceMappingURL=chunk-JELSZN25.js.map
|
|
47
|
-
//# sourceMappingURL=chunk-JELSZN25.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/protocol.ts"],"names":[],"mappings":";AAmCO,IAAM,OAAA,GAAU;AAAA;AAAA;AAAA,EAGrB,YAAA,EAAc,eAAA;AAAA;AAAA,EAEd,WAAA,EAAa,cAAA;AAAA;AAAA,EAEb,YAAA,EAAc,eAAA;AAAA;AAAA;AAAA,EAId,UAAA,EAAY,aAAA;AAAA;AAAA,EAEZ,WAAA,EAAa,eAAA;AAAA;AAAA,EAEb,YAAA,EAAc,gBAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMd,SAAA,EAAW,YAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASX,UAAA,EAAY,aAAA;AAAA;AAAA,EAEZ,SAAA,EAAW,YAAA;AAAA;AAAA,EAEX,UAAA,EAAY,aAAA;AAAA;AAAA;AAAA,EAIZ,cAAA,EAAgB,iBAAA;AAAA;AAAA,EAEhB,kBAAA,EAAoB,sBAAA;AAAA;AAAA;AAAA,EAIpB,YAAA,EAAc;AAChB","file":"chunk-JELSZN25.js","sourcesContent":["// ===========================================================================\n// Protocol — the ONE typed source of truth for the cross-module Msg/Cmd\n// discriminant strings (issue #60).\n// ===========================================================================\n//\n// The resilient/agent/auth plumbing speaks a small fixed vocabulary of\n// discriminant strings on `{ type: ... }` Msgs and Cmds. Before this module\n// those literals were retyped inline across ~8 modules — `resilient_ok` alone\n// appeared as a hand-written `\"resilient_ok\"` in resilient-call, with-resilience,\n// llm-call, agent, do/host, paginated-walk, reconciler. Adding a variant or\n// renaming one was shotgun surgery with no compiler to catch a missed site.\n//\n// `MsgType` is that vocabulary, declared ONCE `as const`. Each entry is BOTH:\n// - a value — `MsgType.ResilientOk` is the string `\"resilient_ok\"`, used at\n// construction sites (`{ type: MsgType.ResilientOk, ... }`), reducer keys\n// (`[MsgType.ResilientOk]: ...`), and switch labels (`case MsgType.ResilientOk:`).\n// - a type — `typeof MsgType.ResilientOk` is the literal type `\"resilient_ok\"`,\n// used in the `readonly type:` field of every Msg/Cmd interface.\n//\n// Because the value and the type both derive from the single `as const`\n// declaration, a new variant or a rename is a ONE-LINE change here that\n// propagates with full exhaustiveness — not an 8-file edit.\n//\n// This module is BEHAVIOR-PRESERVING: every string is byte-identical to the\n// literal it replaces. It is internal plumbing vocabulary, NOT a public event\n// surface — `resilient_ok` / `agent_tool_ok` stay PRIVATE (the agent's\n// `agentEvents` projector is the ONE place they are read; #47). Centralizing\n// the literal here does NOT re-expose them to consumers.\n\n/**\n * The closed set of cross-module Msg/Cmd discriminant strings. Declared `as\n * const` so each entry is usable as both a value (construction / reducer keys /\n * switch labels) and, via `typeof MsgType.X`, a literal type (`readonly type:`\n * fields). The single source of truth for issue #60.\n */\nexport const MsgType = {\n // --- resilient-call: the run Cmd + its two settle Msgs -------------------\n /** The \"run the port for `key`\" effect Cmd resilient-call emits. */\n ResilientRun: \"resilient_run\",\n /** PRIVATE success settle Msg (read only by `agentEvents`, #47). */\n ResilientOk: \"resilient_ok\",\n /** Failure settle Msg — routed to the `fail` verb (back off via retry). */\n ResilientErr: \"resilient_err\",\n\n // --- agent: the wired machine's own entry-point Msgs ---------------------\n /** Begin a run. */\n AgentStart: \"agent_start\",\n /** PRIVATE tool-fan-out success settle Msg (read only by `agentEvents`, #47). */\n AgentToolOk: \"agent_tool_ok\",\n /** Tool-fan-out failure settle Msg. */\n AgentToolErr: \"agent_tool_err\",\n /**\n * Re-fire the one outstanding effect on rehydrate (the do↔agent seam). Fired\n * by `do/host`'s `autoBoot` via the typed `agentBootMsg` constructor, matched\n * by the agent reducer — see `AgentBootPort` in `../agent`.\n */\n AgentBoot: \"agent_boot\",\n\n // --- agent: the context-compaction round-trip (#85) ----------------------\n /**\n * The \"summarize the oldest N turns\" effect Cmd the agent emits when its\n * `CompactionPolicy` asks to compact before a brain call. A DEDICATED\n * round-trip (design B1), distinct from the brain call's `resilient_run`, so\n * compaction is its own honest `Awaiting` state — see `../agent`.\n */\n CompactRun: \"compact_run\",\n /** Compaction round-trip resolved — carries the summary text the fold-back folds. */\n CompactOk: \"compact_ok\",\n /** Compaction round-trip failed (exhausted retry) — surfaced as data, not a stall. */\n CompactErr: \"compact_err\",\n\n // --- token-refresh: the two refresh-result Msgs --------------------------\n /** Refresh port resolved — carries the fresh `Token`. */\n TokenRefreshed: \"token_refreshed\",\n /** Refresh port rejected — carries the rejection (errors are data). */\n TokenRefreshFailed: \"token_refresh_failed\",\n\n // --- authed-call: the 401 trigger ----------------------------------------\n /** The 401 the consumer dispatches when a guarded call comes back unauthorized. */\n Unauthorized: \"unauthorized\",\n} as const;\n\n/** The union of every discriminant string in the protocol. */\nexport type MsgTypeValue = (typeof MsgType)[keyof typeof MsgType];\n"]}
|