@demlik/tea 0.13.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 +637 -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-RH5EFRVJ.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-O4MVQTEJ.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-DMYGQB4O.js → chunk-HYDWG35Q.js} +23 -6
- package/dist/chunk-HYDWG35Q.js.map +1 -0
- package/dist/{chunk-YUXP55T2.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-Co0LWkIA.d.ts → core-CTzMJ82M.d.ts} +72 -23
- 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 +42 -29
- package/dist/do/index.js +36 -25
- package/dist/do/index.js.map +1 -1
- package/dist/{durable-effects-C6uwzjb5.d.ts → durable-effects-B0-qGQDy.d.ts} +2 -2
- package/dist/extension/index.d.ts +300 -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 -12
- package/dist/{fan-out/index.d.ts → index-6A7dB8f6.d.ts} +7 -9
- 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 -78
- package/dist/{monitored-run/index.d.ts → index-NjrT3fL2.d.ts} +37 -13
- package/dist/{recorder/index.d.ts → index-TvRb1KVf.d.ts} +4 -7
- package/dist/{deadline/index.d.ts → index-q0hXFeZ0.d.ts} +155 -9
- package/dist/index.d.ts +711 -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 +1 -1
- package/dist/machine-viz/index.js +12 -5
- package/dist/machine-viz/index.js.map +1 -1
- package/dist/mem/index.d.ts +18 -3
- package/dist/mem/index.js +22 -2
- package/dist/mem/index.js.map +1 -1
- package/dist/node/index.d.ts +104 -6
- package/dist/node/index.js +132 -9
- 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 +4 -10
- package/dist/parity/index.js +4 -7
- package/dist/parity/index.js.map +1 -1
- package/dist/pbt/index.d.ts +247 -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 -5
- package/dist/persistence/index.js +6 -0
- package/dist/react/index.d.ts +2 -2
- 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 +2 -2
- package/dist/testing/index.js +1 -2
- package/dist/testing/index.js.map +1 -1
- package/dist/{throttled-input → timing}/index.d.ts +143 -12
- package/dist/{throttled-input → timing}/index.js +57 -12
- package/dist/timing/index.js.map +1 -0
- package/dist/{types-XS_miRnB.d.ts → types-DP3f5NIl.d.ts} +1 -1
- package/dist/work-queue/index.d.ts +130 -54
- package/dist/work-queue/index.js +3 -2
- package/dist/work-queue/index.js.map +1 -1
- package/package.json +45 -218
- package/dist/authed-call/index.d.ts +0 -120
- 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 -101
- 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 -152
- package/dist/cache/index.js +0 -8
- package/dist/chart/index.d.ts +0 -218
- package/dist/chart/index.js +0 -16
- package/dist/chart/index.js.map +0 -1
- package/dist/chart/inspect/index.d.ts +0 -86
- package/dist/chart/inspect/index.js +0 -5
- package/dist/chart/inspect/react.d.ts +0 -113
- 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 -362
- 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 -84
- 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 -117
- 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-3I52QZZ5.js +0 -519
- package/dist/chunk-3I52QZZ5.js.map +0 -1
- package/dist/chunk-3ZAFFRRB.js +0 -457
- package/dist/chunk-3ZAFFRRB.js.map +0 -1
- package/dist/chunk-4EQZ76JC.js +0 -33
- package/dist/chunk-4EQZ76JC.js.map +0 -1
- package/dist/chunk-4KLG43GY.js +0 -223
- package/dist/chunk-4KLG43GY.js.map +0 -1
- package/dist/chunk-7FRZ2CT2.js +0 -424
- package/dist/chunk-7FRZ2CT2.js.map +0 -1
- package/dist/chunk-AZZLE7XR.js +0 -62
- package/dist/chunk-AZZLE7XR.js.map +0 -1
- package/dist/chunk-BYQUGDD3.js +0 -16
- package/dist/chunk-BYQUGDD3.js.map +0 -1
- package/dist/chunk-CIQG5L42.js +0 -685
- package/dist/chunk-CIQG5L42.js.map +0 -1
- package/dist/chunk-CLM6ERNO.js +0 -61
- package/dist/chunk-CLM6ERNO.js.map +0 -1
- package/dist/chunk-COS5MSTO.js +0 -88
- package/dist/chunk-COS5MSTO.js.map +0 -1
- package/dist/chunk-CRPZJVD2.js +0 -71
- package/dist/chunk-CRPZJVD2.js.map +0 -1
- package/dist/chunk-D62FDQKE.js +0 -53
- package/dist/chunk-D62FDQKE.js.map +0 -1
- package/dist/chunk-D736QUGF.js.map +0 -1
- package/dist/chunk-DGE4PV4A.js +0 -26
- package/dist/chunk-DGE4PV4A.js.map +0 -1
- package/dist/chunk-DMYGQB4O.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-J6527VRQ.js.map +0 -1
- package/dist/chunk-JELSZN25.js +0 -47
- package/dist/chunk-JELSZN25.js.map +0 -1
- package/dist/chunk-K575PT4S.js.map +0 -1
- package/dist/chunk-L57ZOT5K.js +0 -184
- package/dist/chunk-L57ZOT5K.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-NR7BU22N.js +0 -758
- package/dist/chunk-NR7BU22N.js.map +0 -1
- package/dist/chunk-O4MVQTEJ.js.map +0 -1
- package/dist/chunk-OOYD44JI.js +0 -317
- package/dist/chunk-OOYD44JI.js.map +0 -1
- package/dist/chunk-Q2UM7BXU.js.map +0 -1
- package/dist/chunk-RH5EFRVJ.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-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-VYFAZN3F.js +0 -372
- package/dist/chunk-VYFAZN3F.js.map +0 -1
- package/dist/chunk-WRAA7GVZ.js +0 -209
- package/dist/chunk-WRAA7GVZ.js.map +0 -1
- package/dist/chunk-XGELA764.js +0 -163
- package/dist/chunk-XGELA764.js.map +0 -1
- package/dist/chunk-YUXP55T2.js.map +0 -1
- package/dist/chunk-YWIKDKHY.js +0 -307
- package/dist/chunk-YWIKDKHY.js.map +0 -1
- package/dist/chunk-ZJ5AOYBH.js +0 -8
- package/dist/chunk-ZJ5AOYBH.js.map +0 -1
- package/dist/chunk-ZSUUOEPL.js +0 -731
- package/dist/chunk-ZSUUOEPL.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/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 -45
- 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-BJPdjc9w.d.ts +0 -435
- package/dist/graph-B3L5e0N1.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 -188
- package/dist/idempotent-intake/index.js +0 -7
- package/dist/idempotent-intake/index.js.map +0 -1
- package/dist/journal/index.d.ts +0 -373
- package/dist/journal/index.js +0 -3
- package/dist/journal/index.js.map +0 -1
- package/dist/llm-call/index.d.ts +0 -311
- package/dist/llm-call/index.js +0 -16
- package/dist/llm-call/index.js.map +0 -1
- package/dist/machine-BtFWQmmq.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 -235
- 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 -136
- 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 -118
- package/dist/pbt/runners/index.js +0 -5
- package/dist/pbt/runners/index.js.map +0 -1
- package/dist/poller/index.d.ts +0 -352
- package/dist/poller/index.js +0 -115
- package/dist/poller/index.js.map +0 -1
- package/dist/prediction/index.d.ts +0 -131
- 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 -3
- 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 -193
- 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-4GNR6b8B.d.ts +0 -447
- package/dist/resilient-call/index.d.ts +0 -320
- 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-pAcmBpah.d.ts +0 -713
- package/dist/runtime-types-CNLmhWif.d.ts +0 -517
- package/dist/saga/index.d.ts +0 -241
- package/dist/saga/index.js +0 -150
- package/dist/saga/index.js.map +0 -1
- package/dist/samples-B3My5oh2.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 -472
- 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 -216
- 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 -197
- 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 -225
- 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 -150
- 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 -84
- 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 -71
- package/dist/work-queue/ops.js +0 -3
- package/dist/work-queue/ops.js.map +0 -1
- package/dist/workflow/index.d.ts +0 -485
- 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
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/throttled-input/index.ts"],"names":[],"mappings":";;;;;;;;;;;;AAkQA,IAAM,cAAA,GAAiB,wBAAA;AAOhB,SAAS,kBAAA,GAA2C;AACzD,EAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,EAAM,OAAA,EAAS,IAAA,EAAK;AACvC;AASA,SAAS,KAAA,CACP,QACA,KAAA,EACQ;AACR,EAAA,OAAO,MAAA,CAAO,SAAS,KAAK,CAAA;AAC9B;AAWA,SAAS,WAAA,CACP,QACA,KAAA,EAIO;AACP,EAAA,OAAO,MAAA,CAAO,UAAA,KAAe,MAAA,IAAa,KAAA,CAAM,KAAA,KAAU,MAAA,GACtD,EAAE,MAAA,EAAQ,KAAA,EAAO,KAAA,CAAM,KAAA,EAAM,GAC7B,IAAA;AACN;AAQA,SAAS,UAAA,CACP,MAAA,EACA,KAAA,EACA,KAAA,EACA,EAAA,EACS;AACT,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,MAAA,EAAQ,KAAK,CAAA;AACxC,EAAA,IAAI,MAAA,KAAW,MAAM,OAAO,KAAA;AAC5B,EAAA,OAAO,GAAA,CAAS,OAAO,KAAA,EAAO,KAAA,CAAM,OAAO,MAAA,EAAQ,KAAK,CAAA,EAAG,EAAE,CAAA,KAAM,MAAA;AACrE;AAcA,SAAS,UAAA,CACP,MAAA,EACA,KAAA,EACA,KAAA,EACA,EAAA,EAC4C;AAC5C,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,MAAA,EAAQ,KAAK,CAAA;AACxC,EAAA,MAAM,KAAA,GACJ,WAAW,IAAA,GACP,GAAA;AAAA,IACE,MAAA,CAAO,KAAA;AAAA,IACP,KAAA,CAAM,MAAA,CAAO,MAAA,EAAQ,KAAK,CAAA;AAAA,IAC1B,KAAA;AAAA,IACA,EAAA;AAAA,IACA,OAAO,MAAA,CAAO;AAAA,MAEhB,KAAA,CAAM,KAAA;AACZ,EAAA,MAAM,IAAA,GAA0B;AAAA,IAC9B,GAAG,KAAA;AAAA,IACH,MAAA,EAAQ,EAAA;AAAA,IACR,OAAA,EAAS,IAAA;AAAA,IACT,GAAI,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,KAAU;AAAC,GACzC;AACA,EAAA,OAAO,CAAC,IAAA,EAAM,CAAC,OAAO,IAAA,CAAK,KAAK,CAAC,CAAC,CAAA;AACpC;AA8BO,SAAS,KAAA,CACd,MAAA,EACA,KAAA,EACA,KAAA,EACA,EAAA,EAC4C;AAE5C,EAAA,IAAI,UAAA,CAAW,MAAA,EAAQ,KAAA,EAAO,KAAA,EAAO,EAAE,CAAA,EAAG;AACxC,IAAA,OAAO,CAAC,KAAA,EAAO,EAAE,CAAA;AAAA,EACnB;AAMA,EAAA,IAAI,aAAA,CAAc,MAAA,EAAQ,KAAA,EAAO,EAAE,CAAA,EAAG;AAGpC,IAAA,IAAI,MAAA,CAAO,eAAe,MAAA,EAAW;AACnC,MAAA,OAAO,CAAC,EAAE,GAAG,KAAA,EAAO,OAAA,EAAS,EAAE,KAAA,EAAO,EAAA,EAAG,EAAE,EAAG,EAAE,CAAA;AAAA,IAClD;AACA,IAAA,OAAO,CAAC,KAAA,EAAO,EAAE,CAAA;AAAA,EACnB;AAIA,EAAA,IAAI,MAAA,CAAO,eAAe,MAAA,EAAW;AACnC,IAAA,OAAO,CAAC,EAAE,GAAG,KAAA,EAAO,OAAA,EAAS,EAAE,KAAA,EAAO,EAAA,EAAG,EAAE,EAAG,EAAE,CAAA;AAAA,EAClD;AAGA,EAAA,OAAO,UAAA,CAAW,MAAA,EAAQ,KAAA,EAAO,KAAA,EAAO,EAAE,CAAA;AAC5C;AAWA,SAAS,aAAA,CACP,MAAA,EACA,KAAA,EACA,EAAA,EACS;AACT,EAAA,OACE,MAAA,CAAO,eAAe,MAAA,IACtB,KAAA,CAAM,WAAW,IAAA,IACjB,EAAA,GAAK,KAAA,CAAM,MAAA,GAAS,MAAA,CAAO,UAAA;AAE/B;AA6BO,SAAS,OAAA,CACd,MAAA,EACA,KAAA,EACA,EAAA,EAC4C;AAG5C,EAAA,IAAI,MAAM,OAAA,KAAY,IAAA,SAAa,CAAC,KAAA,EAAO,EAAE,CAAA;AAM7C,EAAA,IAAI,aAAA,CAAc,QAAQ,KAAA,EAAO,EAAE,GAAG,OAAO,CAAC,KAAA,EAAO,EAAE,CAAA;AACvD,EAAA,OAAO,WAAW,MAAA,EAAQ,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,OAAO,EAAE,CAAA;AAC1D;AAsCO,SAAS,OAAA,CACd,MAAA,EACA,KAAA,EACA,EAAA,GAAK,cAAA,EACyB;AAC9B,EAAA,IAAI,OAAO,UAAA,KAAe,MAAA,IAAa,MAAM,OAAA,KAAY,IAAA,SAAa,EAAC;AACvE,EAAA,MAAM,QAAA,GAAW,KAAA,CAAM,OAAA,CAAQ,EAAA,GAAK,MAAA,CAAO,UAAA;AAI3C,EAAA,MAAM,MAAA,GACJ,MAAA,CAAO,UAAA,KAAe,MAAA,IAAa,KAAA,CAAM,WAAW,IAAA,GAChD,KAAA,CAAM,MAAA,GAAS,MAAA,CAAO,UAAA,GACtB,QAAA;AACN,EAAA,OAAO,CAAC,YAAY,EAAA,EAAI,IAAA,CAAK,IAAI,QAAA,EAAU,MAAM,CAAC,CAAC,CAAA;AACrD;AAsDO,SAAS,qBACd,MAAA,EAC0B;AAC1B,EAAA,SAAS,IAAA,GAA0B;AACjC,IAAA,MAAM,OAAO,kBAAA,EAAsB;AAGnC,IAAA,OAAO,MAAA,CAAO,eAAe,MAAA,GACzB,EAAE,GAAG,IAAA,EAAM,KAAA,EAAO,SAAA,EAAa,EAAE,GACjC,IAAA;AAAA,EACN;AAEA,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IACA,KAAA,EAAO,CAAC,KAAA,EAAO,KAAA,EAAO,OAAO,KAAA,CAAM,MAAA,EAAQ,KAAA,EAAO,KAAA,EAAO,EAAE,CAAA;AAAA,IAC3D,SAAS,CAAC,KAAA,EAAO,OAAO,OAAA,CAAQ,MAAA,EAAQ,OAAO,EAAE,CAAA;AAAA,IACjD,MAAM,CAAC,KAAA,EAAO,OAAO,OAAA,CAAQ,MAAA,EAAQ,OAAO,EAAE;AAAA,GAChD;AACF","file":"index.js","sourcesContent":["/**\n * @demlik/tea/throttled-input — gate a high-frequency input stream into a\n * SETTLED, RATE-CAPPED, optionally DEDUPED sequence of emits, as a TEA knob: one\n * config object + a few pre-wired hooks you spread into your machine.\n *\n * Layering (the throttle-family map): `../throttle` and `../debounce` are the\n * two host-boundary PRIMITIVES — two distinct algorithms\n * (at-most-once-per-window vs collapse-a-burst) behind one signature shape.\n * THIS module is the third name but NOT a third primitive: a TEA machine\n * composed OVER them that re-exports both. Three exports, one layering — not\n * duplication. The reuse list below spells out composition vs reimplemented\n * semantic per sibling.\n *\n * What it reuses, and HOW (composition vs. reimplemented semantic — the two are\n * not the same, so this list keeps them apart):\n *\n * - `../cache` — COMPOSED directly. The DEDUPE / memoize layer is `../cache`'s\n * `TtlCache` plus its `get` / `set` / `initCache` ops, called at runtime —\n * not reinvented. While `cacheTtlMs` is set, an input whose `cacheKey` is\n * already cached and unexpired is served from the cache and emits NOTHING\n * (the downstream effect ran once for that key within its TTL); a fresh emit\n * writes the value into the cache so the next identical input within\n * `cacheTtlMs` is suppressed. The optional eviction Sub is the consumer's to\n * wire if they want memory reclaim (this knob's correctness needs only TTL\n * reads).\n * - `../deadline` — COMPOSED directly. The settle timer IS a `../deadline`\n * Sub: `subsFor` builds it via `deadlineSub`, and the subscribe cell +\n * Msg constructor are RE-EXPORTS of `../deadline`'s own (`subscribeDeadline`\n * → `subscribeThrottledInput`, `deadlineExceeded` → `throttledInputSettled`).\n * The timer lifecycle stays owned by `../deadline`; this knob redraws none\n * of it.\n * - `../throttle` / `../debounce` — TYPE + SEMANTIC reuse only, NOT composed.\n * Those siblings are host-boundary SINK transformers that hold a live\n * `setTimeout`; a `setTimeout` in a closure is exactly what a durable,\n * replayable knob must NOT hold. So their CODE is never called here. Instead\n * the RATE-cap semantic (\"at most once per `ms`\", leading-edge) and the\n * SETTLE semantic (\"wait until quiet\", trailing-edge) are REIMPLEMENTED as\n * pure Model state: `lastAt` is the durable rate cursor (half-open cutoff\n * `at - lastAt >= throttleMs`), and `pending` + the `../deadline` Sub realize\n * the debounce window inside `update`. The `throttle` / `debounce`\n * transformers themselves are RE-EXPORTED (the only reuse of their actual\n * code) so a consumer can pre-throttle / pre-coalesce a genuinely bursty\n * HOST event at the boundary BEFORE it ever becomes an `input` Msg — a\n * separate, optional escape hatch, not part of this knob's gates.\n *\n * \"Omit a brick, omit its gate\" (the resilient-call config rule): every gate\n * field is optional. Omit `throttleMs` → no rate cap (every input passes the\n * rate gate). Omit `debounceMs` → no settle wait (an input that clears the rate\n * gate emits IMMEDIATELY rather than being held). Omit `cacheTtlMs` → no cache\n * slice at all (the `cache` field is absent; no dedupe). A config with all three\n * omitted is a pass-through: `input` always emits.\n *\n * Why this is a knob and not hand-wired logic: the managed state (`lastAt`,\n * `pending`, `cache`) lives in the Model, so it survives DO eviction / reload\n * (durable) and every transition is still a Msg through `update` (replayable). A\n * closure holding a `setTimeout` and a mutable \"last value\" would break both —\n * banned. `input` / `onFlush` are PURE: time arrives as an `at` parameter, never\n * `Date.now()`; they return NEW slice values, never mutate.\n *\n * Typical wiring (combinator form):\n *\n * const search = createThrottledInput<string, Msg>({\n * debounceMs: 200, // wait for the user to stop typing\n * throttleMs: 1_000, // but never fire more than 1/s during a long burst\n * cacheTtlMs: 30_000, // skip a query repeated within 30s\n * cacheKey: (q) => q,\n * emit: (q) => ({ type: \"RunSearch\", query: q }),\n * });\n *\n * // Model: { search: ThrottledInput<string>, ... }\n * // init: (loaded) => [loaded ?? { search: search.init(), ... }, []]\n * // update cells:\n * // QueryTyped: (s, m) => mapInput(s, search.input(s.search, m.value, m.at))\n * // SettleFired: (s, m) => mapInput(s, search.onFlush(s.search, m.atMs))\n * // subscriptions: (s) => search.subs(s.search)\n * // subscribe: { ...search.handlers() }\n *\n * where `mapInput(s, [slice, cmds]) => [{ ...s, search: slice }, cmds]` lifts the\n * slice transition into the consumer's Model. The `RunSearch` Cmd's interpret\n * handler is the consumer's — it is where the settled input meets I/O.\n *\n * NOT a substrate primitive: it depends only on sibling subpaths (`../throttle`,\n * `../debounce`, `../cache`, `../deadline`) and the core `Cmd` / `Sub` types.\n * Consumers reach it via the `@demlik/tea/throttled-input` subpath; the L1\n * escape hatch is those sibling subpaths threaded by hand. NOT exported from the\n * package root — same one-shape-per-package rule as `batch-window` and `poller`.\n */\n\nimport {\n get as cacheGet,\n set as cacheSet,\n initCache,\n type TtlCache,\n} from \"../cache\";\nimport { type DeadlineSub, deadlineSub } from \"../deadline\";\nimport type { Cmd, Sub } from \"../index\";\n\n// `../throttle` + `../debounce` — host-boundary pre-transformers (see file\n// header). Re-exported so a consumer that wants to throttle/debounce a bursty\n// HOST source BEFORE it becomes an `input` Msg reaches them from the same\n// import as the durable gate.\nexport { type Debounced, debounce } from \"../debounce\";\nexport { type Throttled, throttle } from \"../throttle\";\n\n/**\n * The gate fields every throttled-input config shares, regardless of whether\n * dedupe is on. The two dedupe variants below extend this with mutually\n * exclusive cache fields.\n *\n * `emit` is a pure Cmd CONSTRUCTOR, not a closure-with-state: it maps a settled\n * value to the single Cmd the runtime performs when the gates let a value\n * through. Keeping it `(value) => Cmd` (not `(value) => void`) is what keeps the\n * trigger replayable — the emit is a Cmd in the transition's output, never a\n * side effect inside the verb (mirrors `batch-window`'s `flush`).\n */\ninterface ThrottledInputGates<V, C extends Cmd> {\n /**\n * Rate cap, in milliseconds. An input that lands within `throttleMs` of the\n * last EMIT (`at - lastAt < throttleMs`) is dropped from immediate firing —\n * the leading-edge \"at most once per `throttleMs`\" rate-cap rule, applied to\n * emits. The half-open cutoff (`>=` passes) matches `../throttle` and\n * `../cache`'s window-edge convention. Omit for no rate cap.\n *\n * Interacts with `debounceMs`: when both are set, a rate-blocked input is\n * still HELD as `pending` (so the settle timer eventually trails it out at a\n * legal moment) rather than silently dropped — the trailing-edge guarantee\n * that the FINAL sample of a window is never lost.\n */\n readonly throttleMs?: number;\n /**\n * Settle wait, in milliseconds. An input that clears the rate gate is not\n * emitted immediately; it is held as `pending` and a debounce deadline is\n * armed at `pendingAt + debounceMs`. A fresh input re-arms (slides) the\n * window. `onFlush` emits the pending value when the window finally expires.\n * Omit for no settle wait — a passing input emits on arrival.\n */\n readonly debounceMs?: number;\n /**\n * Map a settled value to the single Cmd the runtime performs. Called with the\n * value the gates let through; the returned Cmd is what `input` / `onFlush`\n * emit. PURE constructor — no I/O, no clock; the I/O happens later in the\n * consumer's interpret handler for the returned Cmd.\n */\n readonly emit: (value: V) => C;\n}\n\n/**\n * Configuration for a throttled input — the knob. Pure config, no mutable state\n * (the `ThrottledInput<V>` slice carries that). One config object is shared\n * across every input of one logical stream (often a module-scope const).\n *\n * A DISCRIMINATED UNION on the presence of dedupe, so the type system makes a\n * cache-key collision UNREPRESENTABLE (\"omit a brick, omit its gate\"):\n *\n * - **No dedupe** (`ThrottledInputNoCache`): `cacheTtlMs` absent ⇒ no cache\n * slice, no dedupe. `cacheKey` is statically forbidden here (`never`) — a\n * key with no cache to feed is dead config, so the type rejects it rather\n * than silently ignoring it.\n * - **Dedupe** (`ThrottledInputWithCache`): `cacheTtlMs` set ⇒ `cacheKey` is\n * REQUIRED. There is no `String(value)` default to fall back to, so a\n * structured value can NEVER collapse two distinct values to one slot (the\n * `\"[object Object]\"` collision). The consumer must state the identity that\n * keys the cache; a primitive stream still trivially passes `(v) => v` /\n * `String`, but it does so EXPLICITLY.\n */\nexport type ThrottledInputConfig<V, C extends Cmd> =\n | ThrottledInputNoCache<V, C>\n | ThrottledInputWithCache<V, C>;\n\n/**\n * The no-dedupe config variant: gates only, no cache. `cacheTtlMs` is absent\n * and `cacheKey` is statically `never` so a stray key (which would feed no\n * cache) is a type error, not a silently-ignored field.\n */\nexport interface ThrottledInputNoCache<V, C extends Cmd>\n extends ThrottledInputGates<V, C> {\n readonly cacheTtlMs?: undefined;\n readonly cacheKey?: never;\n}\n\n/**\n * The dedupe config variant: a per-entry TTL plus a REQUIRED `cacheKey`. An\n * input whose `cacheKey` is already cached and unexpired emits NOTHING (the\n * downstream effect ran once for that key within its TTL); a fresh emit writes\n * the value into the cache.\n *\n * `cacheKey` is required (no `String(value)` default) precisely so a structured\n * value cannot silently collide — the consumer names the identity, the cache\n * keys on exactly that.\n */\nexport interface ThrottledInputWithCache<V, C extends Cmd>\n extends ThrottledInputGates<V, C> {\n /**\n * Dedupe / memoize TTL, in milliseconds. An input whose `cacheKey` is already\n * cached and unexpired emits NOTHING; a fresh emit writes the value into the\n * cache so the next identical input within `cacheTtlMs` is suppressed.\n */\n readonly cacheTtlMs: number;\n /**\n * Key a value for the dedupe cache. REQUIRED whenever `cacheTtlMs` is set:\n * there is no `String(value)` fallback, so a structured value's identity is\n * always the consumer's explicit choice and two distinct values can never\n * collapse to one slot. A primitive stream passes `(v) => v` / `String`.\n */\n readonly cacheKey: (value: V) => string;\n}\n\n/**\n * The Model slice a throttled input owns — its visible slice (the knob\n * principle: managed state lives in the Model, never a closure, so it is durable\n * and replayable).\n *\n * - `lastAt` — the `at` of the most recent EMIT, or `null` before the first\n * emit. The `../throttle` rate cap measures against it: an input\n * within `throttleMs` of `lastAt` is rate-blocked. Persisted so a\n * resumed gate keeps its rate cursor.\n * - `pending` — the value HELD for the settle (debounce) window, paired with the\n * `at` it was held (the anchor the deadline targets), or `null`\n * when nothing is waiting. The single source of truth for \"is a\n * settle window open?\" — the debounce timer Sub arms iff this is\n * non-null.\n * - `cache` — the `../cache` TTL store backing dedupe, present IFF\n * `cacheTtlMs` is configured. Absent (the field omitted) for a\n * gate with no dedupe — no per-op cost, nothing to serialize.\n */\nexport interface ThrottledInput<V> {\n readonly lastAt: number | null;\n readonly pending: PendingInput<V> | null;\n readonly cache?: TtlCache<V>;\n}\n\n/**\n * A value held for the settle window: the `value` itself and the `at` it was\n * held (the anchor the debounce deadline targets, `at + debounceMs`). A distinct\n * type (not a bare `V`) because `V` may itself be `null` — a present-but-null\n * value is still a real pending input, distinct from \"nothing pending\", exactly\n * the `null`-sentinel discipline `../throttle` / `../debounce` use for their\n * `pendingArgs`.\n */\nexport interface PendingInput<V> {\n readonly value: V;\n readonly at: number;\n}\n\n/**\n * The Sub variant a throttled input's settle timer produces — a `../deadline`\n * Sub (so the window fires at the correct ABSOLUTE moment even after a late\n * subscribe / rehydrate, and so a consumer running several gates routes each by\n * `id`). `atMs` is the absolute settle-by instant (`pendingAt + debounceMs`).\n */\nexport type ThrottledInputSub = DeadlineSub;\n\n/**\n * The stable Sub id the gate arms its settle deadline under. A single gate arms\n * exactly one settle timer at a time, so one id suffices; a consumer running\n * several gates on one machine namespaces them by composing the knob under\n * distinct slices with distinct ids (the `subs(state, id)` parameter).\n */\nconst DEFAULT_SUB_ID = \"throttled-input:settle\";\n\n/**\n * The starting slice: no prior emit, nothing pending. The `cache` field is\n * seeded only when `cacheTtlMs` is configured (see `createThrottledInput`); the\n * free `initThrottledInput` leaves it absent (the no-dedupe shape).\n */\nexport function initThrottledInput<V>(): ThrottledInput<V> {\n return { lastAt: null, pending: null };\n}\n\n/**\n * Resolve a value's cache key under a DEDUPE config. PURE. Takes the narrowed\n * `ThrottledInputWithCache` (not the union) because `cacheKey` is only present —\n * and only meaningful — when dedupe is on; there is no `String(value)` default\n * to fall back to, so a structured value's identity is always the consumer's\n * explicit choice and two distinct values can never collapse to one slot.\n */\nfunction keyOf<V, C extends Cmd>(\n config: ThrottledInputWithCache<V, C>,\n value: V,\n): string {\n return config.cacheKey(value);\n}\n\n/**\n * Narrow `config` to its dedupe variant iff a cache slice is actually wired —\n * `cacheTtlMs` set AND a `cache` store present. Returns the narrowed config\n * (carrying the required `cacheKey`) paired with the resolved `cache` store, or\n * `null` when no dedupe is configured. The single place the union is\n * discriminated, so `isCacheHit` / `commitEmit` share one narrowing — and reuse\n * the resolved `cache` — rather than re-deriving the predicate and re-narrowing\n * `state.cache`.\n */\nfunction cacheConfig<V, C extends Cmd>(\n config: ThrottledInputConfig<V, C>,\n state: ThrottledInput<V>,\n): {\n readonly config: ThrottledInputWithCache<V, C>;\n readonly cache: TtlCache<V>;\n} | null {\n return config.cacheTtlMs !== undefined && state.cache !== undefined\n ? { config, cache: state.cache }\n : null;\n}\n\n/**\n * Whether `value` is a cache HIT under `config` at `at` — present and unexpired.\n * PURE — reads only. Always `false` when `cacheTtlMs` is unset or no `cache`\n * slice exists (no dedupe configured), so the dedupe gate is a no-op for an\n * unconfigured gate.\n */\nfunction isCacheHit<V, C extends Cmd>(\n config: ThrottledInputConfig<V, C>,\n state: ThrottledInput<V>,\n value: V,\n at: number,\n): boolean {\n const cached = cacheConfig(config, state);\n if (cached === null) return false;\n return cacheGet(cached.cache, keyOf(cached.config, value), at) !== undefined;\n}\n\n/**\n * Emit `value` at clock `at`: bump the rate cursor, refresh the dedupe cache,\n * and clear any pending hold. PURE. The single place an emit's bookkeeping\n * lives, shared by `input` (immediate emit) and `onFlush` (trailing emit) so the\n * two paths can never drift on what an emit updates.\n *\n * - `lastAt` advances to `at` — the next input is rate-measured against this\n * emit, the `../throttle` window cursor.\n * - `cache` (when configured) records `value` under its key with `cacheTtlMs`\n * from `at` — so the next identical input within the TTL is suppressed.\n * - `pending` clears — the value just went out; nothing is waiting.\n */\nfunction commitEmit<V, C extends Cmd>(\n config: ThrottledInputConfig<V, C>,\n state: ThrottledInput<V>,\n value: V,\n at: number,\n): readonly [ThrottledInput<V>, readonly C[]] {\n const cached = cacheConfig(config, state);\n const cache =\n cached !== null\n ? cacheSet(\n cached.cache,\n keyOf(cached.config, value),\n value,\n at,\n cached.config.cacheTtlMs,\n )\n : state.cache;\n const next: ThrottledInput<V> = {\n ...state,\n lastAt: at,\n pending: null,\n ...(cache !== undefined ? { cache } : {}),\n };\n return [next, [config.emit(value)]];\n}\n\n/**\n * Feed a new input `value` arriving at clock `at` through the gates. PURE.\n *\n * The gate order is DEDUPE → RATE → SETTLE (each skipped when its config field\n * is omitted), the same cache-first-then-gate order `resilient-call` uses (a hit\n * short-circuits before the expensive path):\n *\n * 1. **Dedupe** (`cacheTtlMs` set): if `value`'s key is cached and unexpired,\n * suppress — return the slice UNCHANGED (no emit, no pending, no re-arm).\n * The downstream effect already ran for this key within its TTL.\n * 2. **Rate** (`throttleMs` set): if `at` is within `throttleMs` of the last\n * emit (`at - lastAt < throttleMs`), this input is rate-blocked.\n * - With `debounceMs` set → HOLD it as `pending` (the trailing edge: the\n * settle timer will emit it at a legal moment, so the final sample is\n * never lost). The deadline `subs` arms targets `at + debounceMs`.\n * - Without `debounceMs` → DROP it (pure rate cap, no catch-up).\n * 3. **Settle** (`debounceMs` set): the input cleared the rate gate. HOLD it\n * as `pending` and let the debounce window slide; `onFlush` emits it once\n * the window expires. A fresh input before expiry overwrites `pending` (the\n * trailing edge fires with the LAST value, the `../debounce` default).\n * 4. **Pass-through**: no `debounceMs`, cleared the rate gate → EMIT now.\n *\n * @param config the knob (the three optional gates + `emit`)\n * @param state the current slice\n * @param value the input value\n * @param at the arrival instant (epoch ms) — the caller stamps it; the verb\n * never reads the clock\n */\nexport function input<V, C extends Cmd>(\n config: ThrottledInputConfig<V, C>,\n state: ThrottledInput<V>,\n value: V,\n at: number,\n): readonly [ThrottledInput<V>, readonly C[]] {\n // 1. Dedupe gate — a cached, unexpired key short-circuits everything.\n if (isCacheHit(config, state, value, at)) {\n return [state, []];\n }\n\n // 2. Rate gate — half-open cutoff (`>=` passes). `lastAt === null` (no prior\n // emit) always passes: the first input is never rate-blocked. Shared with\n // `onFlush` via `rateBlockedAt` so the arrival and trailing-edge paths agree\n // on the window.\n if (rateBlockedAt(config, state, at)) {\n // With a settle window, a rate-blocked input is HELD (trailing edge) so it\n // emits at the next legal moment; without one, it is a pure drop.\n if (config.debounceMs !== undefined) {\n return [{ ...state, pending: { value, at } }, []];\n }\n return [state, []];\n }\n\n // 3. Settle gate — passed the rate gate; if a debounce window is configured,\n // hold the value and (re)arm the settle deadline rather than emit now.\n if (config.debounceMs !== undefined) {\n return [{ ...state, pending: { value, at } }, []];\n }\n\n // 4. Pass-through — no settle wait, cleared the rate gate: emit immediately.\n return commitEmit(config, state, value, at);\n}\n\n/**\n * Whether emitting at clock `at` would breach the rate cap — `at` lands within\n * `throttleMs` of the last emit (`at - lastAt < throttleMs`). PURE — reads only.\n * Always `false` when `throttleMs` is unset (no rate cap) or before the first\n * emit (`lastAt === null`), so an unconfigured / never-fired gate never holds on\n * the rate gate. The single rate-gate predicate, shared by `input` (drop / hold\n * on arrival) and `onFlush` (re-hold a still-early trailing edge) so the two\n * paths can never drift on what \"within the rate window\" means.\n */\nfunction rateBlockedAt<V, C extends Cmd>(\n config: ThrottledInputConfig<V, C>,\n state: ThrottledInput<V>,\n at: number,\n): boolean {\n return (\n config.throttleMs !== undefined &&\n state.lastAt !== null &&\n at - state.lastAt < config.throttleMs\n );\n}\n\n/**\n * Emit the pending value because the settle (debounce) window closed. PURE.\n *\n * - Pending present, rate gate CLEAR → emit `config.emit(pending.value)`,\n * advance the rate cursor (`lastAt = at`), refresh the dedupe cache, and clear\n * `pending`. The trailing edge of `../debounce` realized as a Model transition.\n * - Pending present, rate gate STILL BLOCKED → re-HOLD: return the slice with\n * `pending` intact and NO Cmds. A settle Msg can fire at `pending.at +\n * debounceMs`, which may still be inside the rate window (`lastAt +\n * throttleMs`) — emitting then would breach the headline \"at most once per\n * `throttleMs`\" cap. Re-holding keeps the value waiting; `subs` re-arms the\n * deadline at `max(pending.at + debounceMs, lastAt + throttleMs)` so the next\n * timer fires at a LEGAL moment and the trailing edge is deferred, never lost.\n * - Pending absent → no-op: return the same slice and no Cmds. Guards the race\n * where an `input` already emitted (or a dedupe hit cleared interest) before\n * the settle timer's Msg lands — a stale `onFlush` must NOT emit. Symmetric\n * with `batch-window`'s closed-window guard.\n *\n * `at` is the firing instant the settle Msg carried (the caller stamps it; the\n * verb never reads the clock). It becomes the new rate cursor and the cache\n * write's `nowMs`, so a settled emit rate-blocks subsequent inputs from its\n * actual fire moment, not the moment the value was first held.\n *\n * @param config the knob (`throttleMs`, `emit`, cache config)\n * @param state the current slice\n * @param at the settle-timer firing instant (epoch ms)\n */\nexport function onFlush<V, C extends Cmd>(\n config: ThrottledInputConfig<V, C>,\n state: ThrottledInput<V>,\n at: number,\n): readonly [ThrottledInput<V>, readonly C[]] {\n // No pending value = an immediate emit already fired, or a dedupe hit cleared\n // interest. A stale timer Msg must not emit — return the slice untouched.\n if (state.pending === null) return [state, []];\n // Rate gate re-check: a settle Msg can land before the rate window opens (its\n // naive deadline is pending.at + debounceMs, which `subs` lifts to a legal\n // target — but a stale / early timer can still arrive). Emitting now would\n // breach \"at most once per throttleMs\", so re-hold and let `subs` re-arm at\n // the legal moment. The value stays pending; nothing is dropped.\n if (rateBlockedAt(config, state, at)) return [state, []];\n return commitEmit(config, state, state.pending.value, at);\n}\n\n/**\n * The settle timer Sub, derived from the slice. PURE.\n *\n * Returns the single `../deadline` Sub while a value is held AND a settle window\n * is configured, or `[]` otherwise. The deadline target is the LATER of two\n * constraints (so the timer never fires before BOTH are satisfied):\n *\n * - `pending.at + debounceMs` — the settle (debounce) deadline: the value has\n * stopped sliding, the burst has gone quiet.\n * - `lastAt + throttleMs` — the rate cap: emitting earlier would breach \"at\n * most once per `throttleMs`\". Only applies once a prior emit exists\n * (`lastAt !== null`) and a rate cap is configured (`throttleMs` set).\n *\n * `max(settleAt, rateAt)` is the earliest LEGAL trailing-edge moment. Anchoring\n * the timer here — rather than the naive `pending.at + debounceMs` — is what\n * keeps the rate cap intact across the trailing edge: a value held while still\n * inside the rate window arms its timer at `lastAt + throttleMs`, so `onFlush`\n * fires at a moment the rate gate already permits. (`onFlush` re-checks the gate\n * anyway and re-holds if an early/stale timer slips through, so the cap holds\n * even if a timer fires ahead of this target.)\n *\n * The substrate's reconcile pass arms the timer when the array gains the Sub and\n * disarms it (clearing the pending `setTimeout`) when the array loses it — so an\n * `onFlush` (or a dedupe hit) that clears `pending` auto-cancels the now-stale\n * settle timer on the next transition, and a sliding input that re-stamps\n * `pending.at` re-arms a fresh absolute target.\n *\n * `debounceMs` undefined ⇒ no settle window ⇒ `[]` even with a `pending` value\n * (an unconfigured settle never holds, but the guard keeps `subs` total).\n *\n * @param config the knob (`debounceMs`, `throttleMs`)\n * @param state the current slice\n * @param id stable identity for this gate's settle timer (default\n * `\"throttled-input:settle\"`); pass a distinct id per gate when a\n * machine runs several so the dispatched Msg routes distinctly.\n */\nexport function subsFor<V, C extends Cmd>(\n config: ThrottledInputConfig<V, C>,\n state: ThrottledInput<V>,\n id = DEFAULT_SUB_ID,\n): readonly ThrottledInputSub[] {\n if (config.debounceMs === undefined || state.pending === null) return [];\n const settleAt = state.pending.at + config.debounceMs;\n // The rate floor: the earliest moment the rate cap permits an emit. Absent\n // when no rate cap is configured or no prior emit set a cursor — then the\n // settle deadline alone governs.\n const rateAt =\n config.throttleMs !== undefined && state.lastAt !== null\n ? state.lastAt + config.throttleMs\n : settleAt;\n return [deadlineSub(id, Math.max(settleAt, rateAt))];\n}\n\n/**\n * The bound knob returned by `createThrottledInput`. `init` + the two pure verbs\n * + `subs`, all closing over one `ThrottledInputConfig`. The verbs return\n * `readonly [ThrottledInput<V>, readonly C[]]`: the next slice and the Cmds to\n * emit (one `emit` Cmd when a value passes, none while held / dropped / deduped).\n *\n * Pure-ops + subs module: there is no `handlers(ports)` cell. The settle timer's\n * subscribe cell IS `../deadline`'s `subscribeDeadline` (re-exported below) —\n * the consumer wires it into `subscribe` directly; the knob redraws no timer\n * lifecycle of its own. (Compare `poller`, identical: it too reuses\n * `../deadline`'s cell and ships no `handlers`.)\n */\nexport interface ThrottledInputKnob<V, C extends Cmd> {\n /** Seed the Model slice (with a cache iff `cacheTtlMs` is configured). */\n init(): ThrottledInput<V>;\n /**\n * Feed a new input through the dedupe → rate → settle gates. See `input`.\n */\n input(\n state: ThrottledInput<V>,\n value: V,\n at: number,\n ): readonly [ThrottledInput<V>, readonly C[]];\n /**\n * Emit the held value because the settle window closed. See `onFlush`.\n */\n onFlush(\n state: ThrottledInput<V>,\n at: number,\n ): readonly [ThrottledInput<V>, readonly C[]];\n /**\n * The settle timer Sub, armed only while a value is held. See `subsFor`.\n * `id` keys the deadline so several gates on one machine route distinctly.\n */\n subs(state: ThrottledInput<V>, id?: string): readonly Sub[];\n}\n\n/**\n * Build a throttled-input knob from `config`. Combinator form (the default L2\n * ergonomic): hand it the config, splice the returned hooks into your machine.\n * The pure verbs (`input` / `onFlush`) close over the config so the consumer's\n * reducer cells stay a uniform `(state, ...args)` shape; `subs` pre-wires the\n * settle timer.\n *\n * `init()` seeds a `cache` slice IFF `cacheTtlMs` is configured — an unconfigured\n * gate carries no cache field (nothing to serialize, no dedupe). Pure factory —\n * no clock read, no timer; everything happens when the consumer calls the\n * returned verbs / `subs` with an injected `at`.\n *\n * @typeParam V the input value type\n * @typeParam C the Cmd type `config.emit` returns\n */\nexport function createThrottledInput<V, C extends Cmd>(\n config: ThrottledInputConfig<V, C>,\n): ThrottledInputKnob<V, C> {\n function init(): ThrottledInput<V> {\n const base = initThrottledInput<V>();\n // Seed the cache only when dedupe is configured — an unconfigured gate\n // carries no cache field at all (the no-dedupe shape).\n return config.cacheTtlMs !== undefined\n ? { ...base, cache: initCache<V>() }\n : base;\n }\n\n return {\n init,\n input: (state, value, at) => input(config, state, value, at),\n onFlush: (state, at) => onFlush(config, state, at),\n subs: (state, id) => subsFor(config, state, id),\n };\n}\n\n/**\n * The settle-timer wiring, RE-EXPORTED from `../deadline` (not redrawn) so the\n * timer lifecycle stays owned there. Consolidated into one `export ... from`:\n *\n * - `subscribeThrottledInput` (= `../deadline`'s `subscribeDeadline`) — the\n * `subscribe[\"deadline\"]` cell. Arms a one-shot timer for `max(0, atMs -\n * now)`, dispatches the deadline Msg, returns a cleanup that clears it. The\n * consumer assigns it: `subscribe: { deadline: subscribeThrottledInput }`.\n * - `throttledInputSettled` (= `../deadline`'s `deadlineExceeded`) +\n * `ThrottledInputSettled` (= `DeadlineExceeded`) — the settle-timer Msg\n * constructor and type the consumer handles via `onFlush`. Sharing one\n * constructor with the subscribe cell keeps the two from drifting; the\n * reducer reads `msg.atMs` as the `at` it threads into `onFlush`.\n */\nexport {\n type DeadlineExceeded as ThrottledInputSettled,\n deadlineExceeded as throttledInputSettled,\n subscribeDeadline as subscribeThrottledInput,\n} from \"../deadline\";\n"]}
|
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import { C as Cmd, I as Interpret } from '../core-Co0LWkIA.js';
|
|
2
|
-
import { M as MsgType } from '../protocol-B5YmJr0d.js';
|
|
3
|
-
import 'zod';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @demlik/tea/token-refresh — a credential's lifecycle as pure state + verbs,
|
|
7
|
-
* with the actual token fetch deferred to a single injected port.
|
|
8
|
-
*
|
|
9
|
-
* This is the L1 brick `authed-call` (#10 in the composition specs) stacks on:
|
|
10
|
-
* a token slice `{ token, stale }` plus pure transitions that decide *when* a
|
|
11
|
-
* credential must be re-minted, and one `handlers(ports)` splice that performs
|
|
12
|
-
* the re-mint. It follows the uniform knob contract every composition wears —
|
|
13
|
-
* `createTokenRefresh(config) → { init, <verbs>, handlers }` — so a consumer
|
|
14
|
-
* spreads ~3 hooks into their machine instead of hand-wiring the refresh dance.
|
|
15
|
-
*
|
|
16
|
-
* It is a LEAF module in the same mold as `@demlik/tea/retry-backoff`: it
|
|
17
|
-
* depends only on the core (`../index`), never on a sibling brick. The two
|
|
18
|
-
* non-negotiables of every knob hold here by construction:
|
|
19
|
-
*
|
|
20
|
-
* - **Durable** — the token slice is plain JSON-serializable data, so it
|
|
21
|
-
* survives a Durable Object eviction / page reload. A rehydrated machine
|
|
22
|
-
* resumes knowing exactly which token it holds and whether it is stale.
|
|
23
|
-
* - **Replayable** — every transition is a pure verb returning
|
|
24
|
-
* `readonly [State, Cmd[]]`. No verb reads the wall clock or performs I/O,
|
|
25
|
-
* so `replay` reconstructs the slice exactly. Time enters ONLY as an `at`
|
|
26
|
-
* parameter the caller stamps; the network fetch enters ONLY at the
|
|
27
|
-
* `handlers` boundary. This keeps the substrate's purity invariants intact
|
|
28
|
-
* (invariant 2: pure transitions; invariant 4: I/O is an effect, not a
|
|
29
|
-
* reducer body).
|
|
30
|
-
*
|
|
31
|
-
* ## The staleness model — two independent reasons to refresh
|
|
32
|
-
*
|
|
33
|
-
* A token becomes unusable for two unrelated reasons, and the slice tracks both
|
|
34
|
-
* without conflating them:
|
|
35
|
-
*
|
|
36
|
-
* 1. **Expiry** — the token has a known `expiresAt` (epoch ms). It is "near
|
|
37
|
-
* expiry" once `at >= expiresAt - skewMs`. The `skewMs` skew refreshes
|
|
38
|
-
* *ahead* of the hard deadline so an in-flight call never races a token
|
|
39
|
-
* that expires mid-request. This is the proactive, time-driven reason and
|
|
40
|
-
* is computed purely from the injected `at` — no clock in the verb.
|
|
41
|
-
*
|
|
42
|
-
* 2. **Server rejection (401)** — the server rejected a request the client
|
|
43
|
-
* believed was still valid (clock skew, a server-side revocation, an early
|
|
44
|
-
* rotation). `on401` flips a `stale` flag regardless of `expiresAt`. This
|
|
45
|
-
* is the reactive reason: the client's belief about validity was wrong, so
|
|
46
|
-
* the next `needsRefresh` returns true even though the clock says the
|
|
47
|
-
* token is fine.
|
|
48
|
-
*
|
|
49
|
-
* `needsRefresh` is the union of the two (plus "no token at all"). One source
|
|
50
|
-
* of truth for "should I fetch a fresh credential before the next call?", read
|
|
51
|
-
* by the consumer's reducer at the call boundary.
|
|
52
|
-
*
|
|
53
|
-
* Typical wiring (inside a consumer machine):
|
|
54
|
-
*
|
|
55
|
-
* const tr = createTokenRefresh({ skewMs: 30_000 });
|
|
56
|
-
*
|
|
57
|
-
* // in init:
|
|
58
|
-
* init: (loaded) => [loaded ?? { auth: tr.init() }, Cmd.none],
|
|
59
|
-
*
|
|
60
|
-
* // in a reducer cell that is about to make an authed call:
|
|
61
|
-
* before_call: (s, msg) => {
|
|
62
|
-
* const [auth, cmds] = tr.ensureFresh(s.auth, msg.at);
|
|
63
|
-
* return [{ ...s, auth }, cmds]; // emits a refresh Cmd iff a refresh is due
|
|
64
|
-
* },
|
|
65
|
-
*
|
|
66
|
-
* // on a 401 from a guarded call:
|
|
67
|
-
* got_401: (s) => [{ ...s, auth: tr.on401(s.auth) }, []],
|
|
68
|
-
*
|
|
69
|
-
* // when the refresh port resolves:
|
|
70
|
-
* token_refreshed: (s, msg) => [{ ...s, auth: tr.refreshed(s.auth, msg.token) }, []],
|
|
71
|
-
*
|
|
72
|
-
* // splice the I/O:
|
|
73
|
-
* interpret: { ...tr.handlers({ refresh: () => mySdk.mintToken() }) },
|
|
74
|
-
*
|
|
75
|
-
* NOT a substrate primitive: from `../index` it reuses only the `Cmd` /
|
|
76
|
-
* `Interpret` types and the `tryInterpret` Railway helper (a runtime function,
|
|
77
|
-
* not a type) that every effectful brick uses — and no sibling brick. It is a
|
|
78
|
-
* leaf utility consumers reach via the `@demlik/tea/token-refresh` subpath.
|
|
79
|
-
*/
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* A minted credential: the opaque `value` to send on the wire, and the absolute
|
|
83
|
-
* `expiresAt` (epoch milliseconds — the `Date.now()` scale) the issuer stamped
|
|
84
|
-
* it with. Both fields are plain data so a `Token` is trivially serializable
|
|
85
|
-
* into a consumer's `Store<S>`.
|
|
86
|
-
*
|
|
87
|
-
* `value` is `string` because that is the universal shape of a bearer token /
|
|
88
|
-
* API key / session cookie on the wire. A consumer whose refresh port yields a
|
|
89
|
-
* richer object can JSON-encode it into `value`, or keep this module's slice as
|
|
90
|
-
* the "is it fresh?" gate and hold the richer object elsewhere in their Model.
|
|
91
|
-
*/
|
|
92
|
-
interface Token {
|
|
93
|
-
/** The opaque credential to present on each request (bearer token, API key). */
|
|
94
|
-
readonly value: string;
|
|
95
|
-
/** Absolute expiry instant, epoch milliseconds. The `Date.now()` scale. */
|
|
96
|
-
readonly expiresAt: number;
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Pure configuration — the knob's only field. Carries no mutable state;
|
|
100
|
-
* `TokenState` does. One config is shared across all the refreshes of one
|
|
101
|
-
* logical credential (often a module-scope const).
|
|
102
|
-
*/
|
|
103
|
-
interface TokenRefreshConfig {
|
|
104
|
-
/**
|
|
105
|
-
* Refresh-ahead skew, in milliseconds. A token is treated as needing a
|
|
106
|
-
* refresh once `at >= expiresAt - skewMs`, i.e. `skewMs` BEFORE its hard
|
|
107
|
-
* expiry. This buys headroom so a call that starts just under the wire never
|
|
108
|
-
* races a token that lapses mid-flight, and absorbs small client/server clock
|
|
109
|
-
* disagreement. `0` means "refresh exactly at expiry"; a negative value is
|
|
110
|
-
* clamped to `0` (a skew that pushes the trigger past expiry is meaningless).
|
|
111
|
-
*
|
|
112
|
-
* @default 0
|
|
113
|
-
*/
|
|
114
|
-
readonly skewMs?: number;
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* The token slice this knob owns — the Model field a consumer spreads in via
|
|
118
|
-
* `init()`. A two-field record rather than a phase union because the two
|
|
119
|
-
* dimensions are orthogonal: a token can be present-and-fresh, present-but-stale
|
|
120
|
-
* (a 401 came back), absent, or absent-and-stale (cleared after a failed
|
|
121
|
-
* refresh). Every combination is meaningful, so neither field implies the
|
|
122
|
-
* other's value and a discriminated union would only manufacture impossible
|
|
123
|
-
* arms.
|
|
124
|
-
*
|
|
125
|
-
* - `token` — the currently held credential, or `null` when none has been
|
|
126
|
-
* minted yet (fresh boot) or the last refresh failed.
|
|
127
|
-
* - `stale` — set by `on401` when the server rejected a request the client
|
|
128
|
-
* believed valid. Forces the next `needsRefresh` to true regardless of
|
|
129
|
-
* `expiresAt`; cleared by `refreshed` once a new credential lands.
|
|
130
|
-
*
|
|
131
|
-
* Both fields `readonly` so the whole slice threads safely through a pure
|
|
132
|
-
* reducer and serializes into a `Store<S>`.
|
|
133
|
-
*/
|
|
134
|
-
interface TokenState {
|
|
135
|
-
/** The held credential, or `null` if none is available (boot / failed refresh). */
|
|
136
|
-
readonly token: Token | null;
|
|
137
|
-
/** Whether a 401 has marked the held token unusable ahead of its `expiresAt`. */
|
|
138
|
-
readonly stale: boolean;
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* The starting slice: no token held, not stale. The first `needsRefresh` after
|
|
142
|
-
* this returns `true` (no token), so a consumer's first guarded call mints a
|
|
143
|
-
* credential before going out.
|
|
144
|
-
*/
|
|
145
|
-
declare function initTokenRefresh(): TokenState;
|
|
146
|
-
/**
|
|
147
|
-
* The Cmd this knob emits to ask the runtime to mint a fresh token. Plain data
|
|
148
|
-
* (no closure — invariant 1) carrying nothing: the refresh port takes no input,
|
|
149
|
-
* and the slice the result installs is read off the follow-up Msg, not this
|
|
150
|
-
* Cmd. The consumer unions this into their machine's Cmd type and lets
|
|
151
|
-
* `handlers` interpret it.
|
|
152
|
-
*/
|
|
153
|
-
interface RefreshTokenCmd extends Cmd<"refresh_token"> {
|
|
154
|
-
}
|
|
155
|
-
/** Construct a `refresh_token` Cmd. */
|
|
156
|
-
declare function refreshTokenCmd(): RefreshTokenCmd;
|
|
157
|
-
/**
|
|
158
|
-
* The Msg the refresh port dispatches on success — carries the freshly minted
|
|
159
|
-
* `Token`. The consumer unions this into their Msg type and handles it by
|
|
160
|
-
* folding `refreshed(state, msg.token)` into the slice.
|
|
161
|
-
*/
|
|
162
|
-
interface TokenRefreshedMsg {
|
|
163
|
-
readonly type: typeof MsgType.TokenRefreshed;
|
|
164
|
-
readonly token: Token;
|
|
165
|
-
}
|
|
166
|
-
/** Construct a `token_refreshed` Msg carrying the new token. */
|
|
167
|
-
declare function tokenRefreshedMsg(token: Token): TokenRefreshedMsg;
|
|
168
|
-
/**
|
|
169
|
-
* The Msg the refresh port dispatches on failure — carries the rejection so the
|
|
170
|
-
* consumer's reducer can decide whether to back off, surface an error, or give
|
|
171
|
-
* up (errors are data: it is dispatched, never swallowed). The slice itself is
|
|
172
|
-
* left untouched by a failed refresh — the held token (if any) stays held and
|
|
173
|
-
* stale stays set, so the consumer can retry; clearing it is the consumer's
|
|
174
|
-
* policy, expressed in their reducer.
|
|
175
|
-
*/
|
|
176
|
-
interface TokenRefreshFailedMsg {
|
|
177
|
-
readonly type: typeof MsgType.TokenRefreshFailed;
|
|
178
|
-
readonly error: unknown;
|
|
179
|
-
}
|
|
180
|
-
/** Construct a `token_refresh_failed` Msg carrying the rejection. */
|
|
181
|
-
declare function tokenRefreshFailedMsg(error: unknown): TokenRefreshFailedMsg;
|
|
182
|
-
/** The two Msgs the refresh port can produce. Union for a consumer's Msg type. */
|
|
183
|
-
type TokenRefreshMsg = TokenRefreshedMsg | TokenRefreshFailedMsg;
|
|
184
|
-
/** The ports this knob's `handlers` splice needs — the single refresh DI seam. */
|
|
185
|
-
interface TokenRefreshPorts {
|
|
186
|
-
/**
|
|
187
|
-
* Mint a fresh credential. Called ONLY from the `refresh_token` interpret
|
|
188
|
-
* handler — never from a verb — so the network I/O and any clock the issuer
|
|
189
|
-
* reads stay at the effect boundary. May reject; the rejection is routed to
|
|
190
|
-
* `token_refresh_failed` (errors are data), never thrown into the runtime.
|
|
191
|
-
*/
|
|
192
|
-
readonly refresh: () => Promise<Token>;
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* The knob: hand it a config, get back the slice initializer, the pure verbs,
|
|
196
|
-
* and the `handlers` splice. Mirrors every L2 composition's uniform contract so
|
|
197
|
-
* the call sites read identically across bricks.
|
|
198
|
-
*
|
|
199
|
-
* @example
|
|
200
|
-
* const tr = createTokenRefresh({ skewMs: 30_000 });
|
|
201
|
-
* const s0 = tr.init();
|
|
202
|
-
* const [s1, cmds] = tr.ensureFresh(s0, Date.now()); // cmds = [refreshTokenCmd()]
|
|
203
|
-
*/
|
|
204
|
-
declare function createTokenRefresh(config?: TokenRefreshConfig): {
|
|
205
|
-
/** The slice initializer — spread into the consumer's `init`. */
|
|
206
|
-
init: typeof initTokenRefresh;
|
|
207
|
-
needsRefresh: (state: TokenState, at: number) => boolean;
|
|
208
|
-
on401: (state: TokenState) => TokenState;
|
|
209
|
-
refreshed: (state: TokenState, token: Token) => TokenState;
|
|
210
|
-
ensureFresh: (state: TokenState, at: number) => readonly [TokenState, readonly Cmd[]];
|
|
211
|
-
handlers: (ports: TokenRefreshPorts) => Interpret<TokenRefreshMsg, RefreshTokenCmd, unknown>;
|
|
212
|
-
};
|
|
213
|
-
/** The shape `createTokenRefresh` returns — useful for typing a held knob. */
|
|
214
|
-
type TokenRefresh = ReturnType<typeof createTokenRefresh>;
|
|
215
|
-
|
|
216
|
-
export { type RefreshTokenCmd, type Token, type TokenRefresh, type TokenRefreshConfig, type TokenRefreshFailedMsg, type TokenRefreshMsg, type TokenRefreshPorts, type TokenRefreshedMsg, type TokenState, createTokenRefresh, initTokenRefresh, refreshTokenCmd, tokenRefreshFailedMsg, tokenRefreshedMsg };
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export { createTokenRefresh, initTokenRefresh, refreshTokenCmd, tokenRefreshFailedMsg, tokenRefreshedMsg } from '../chunk-CLM6ERNO.js';
|
|
2
|
-
import '../chunk-JELSZN25.js';
|
|
3
|
-
import '../chunk-ZSUUOEPL.js';
|
|
4
|
-
import '../chunk-OOYD44JI.js';
|
|
5
|
-
//# sourceMappingURL=index.js.map
|
|
6
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import { C as Cmd, S as Sub, M as Machine } from '../core-Co0LWkIA.js';
|
|
2
|
-
import 'zod';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @demlik/tea/with-deadline — auto-fail a wrapped machine at T+N, re-arm on
|
|
6
|
-
* progress. A **pure function over machine data**: `withDeadline(base, config)`
|
|
7
|
-
* takes any `Machine<S, M, C, U, Ctx>` and returns a NEW `Machine` over the
|
|
8
|
-
* composed Model `{ base, $deadline }`. You `run()` / `replay()` the result
|
|
9
|
-
* exactly like any other machine — there is no new runtime, no privileged
|
|
10
|
-
* interception path.
|
|
11
|
-
*
|
|
12
|
-
* ## What it does
|
|
13
|
-
*
|
|
14
|
-
* The wrapper watches the base Msg stream. While the deadline is `armed`, a
|
|
15
|
-
* RELATIVE timeout Sub counts down `config.ms`. Every base Msg the
|
|
16
|
-
* `config.progress` predicate accepts (default: every base Msg) is treated as
|
|
17
|
-
* activity: the wrapper bumps a numeric `seq`, which CHANGES the timer Sub's id,
|
|
18
|
-
* so the substrate's reconcile pass retires the old countdown and starts a fresh
|
|
19
|
-
* one — "re-arm on progress". If `config.ms` elapses with NO accepted progress,
|
|
20
|
-
* the timeout Sub dispatches `$deadline:exceeded`; the merged `update` folds it
|
|
21
|
-
* by flipping `phase` to `exceeded`, and from then on `subscriptions` returns no
|
|
22
|
-
* timer (the machine has auto-failed). The expiry is a slice transition visible
|
|
23
|
-
* in the Msg log — the auto-fail is never an off-ledger side effect.
|
|
24
|
-
*
|
|
25
|
-
* This is an OBSERVE-ONLY wrapper in the same sense as `withTelemetry`: it never
|
|
26
|
-
* intercepts a base Cmd and never gates a base Msg. `state.base` after wrapping
|
|
27
|
-
* is BYTE-IDENTICAL to running the base alone, so the shared
|
|
28
|
-
* `assertWrapperFaithful` gate passes with the deadline bolted on.
|
|
29
|
-
*
|
|
30
|
-
* ## The 5 rules it satisfies (from the wrapper-tier contract)
|
|
31
|
-
*
|
|
32
|
-
* 1. **Named, serializable slice.** Wrapper state lives at `model.$deadline`,
|
|
33
|
-
* a plain `{ phase, seq }` — JSON-serializable, never a closure. There is
|
|
34
|
-
* NO absolute timestamp in the slice: the clock is never read in `update`.
|
|
35
|
-
* 2. **Retag-and-re-emit, never swallow.** The merged `update` runs the base
|
|
36
|
-
* reducer, passes its Cmds through UNCHANGED, and APPENDS its own
|
|
37
|
-
* `$deadline:rearm` / `$deadline:expire` decision Cmd. No base Cmd ever
|
|
38
|
-
* vanishes; nothing is gated.
|
|
39
|
-
* 3. **Every decision is a Msg/Cmd.** Re-arm is a `$deadline:rearm` Cmd; the
|
|
40
|
-
* auto-fail expiry is the `$deadline:exceeded` Msg the Sub delivers, folded
|
|
41
|
-
* into the slice and echoed as a `$deadline:expire` Cmd. "Why did this
|
|
42
|
-
* fire" is answerable from reducer + log alone.
|
|
43
|
-
* 4. **Subs merge by id.** `subscriptions = [...base, ...deadlineSubs]`; the
|
|
44
|
-
* timeout id is `$deadline:timeout:{seq}`, so a progress bump (seq+1)
|
|
45
|
-
* yields a NEW id — the substrate retires the old timer and arms a fresh
|
|
46
|
-
* one. When `exceeded`, no deadline sub is returned.
|
|
47
|
-
* 5. **Clock out of update.** The countdown is a relative-timeout Sub; the
|
|
48
|
-
* clock is read at subscribe time inside the Sub (`setTimeout`), NEVER in a
|
|
49
|
-
* verb. The slice carries `seq`, not a deadline timestamp.
|
|
50
|
-
*
|
|
51
|
-
* ## Typical wiring
|
|
52
|
-
*
|
|
53
|
-
* const guarded = withDeadline(baseMachine, {
|
|
54
|
-
* ms: 900_000, // auto-fail after 15 minutes of inactivity
|
|
55
|
-
* progress: (msg) => msg.type !== "heartbeat", // heartbeats don't re-arm
|
|
56
|
-
* });
|
|
57
|
-
* const runtime = run(guarded, { ctx: baseCtx });
|
|
58
|
-
*/
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* The wrapper's Model slice. `phase` is the lifecycle (`armed` while the
|
|
62
|
-
* countdown runs, `exceeded` once the deadline fired); `seq` is the monotonic
|
|
63
|
-
* re-arm counter that keys the timer Sub's id so each accepted progress Msg
|
|
64
|
-
* retires the old timer and starts a fresh one.
|
|
65
|
-
*
|
|
66
|
-
* PURE and SERIALIZABLE: there is deliberately NO absolute timestamp here. A
|
|
67
|
-
* deadline timestamp would force the merged `update` to read the wall clock to
|
|
68
|
-
* compute it, which the conformance gate (property 2 — two replays under
|
|
69
|
-
* distinct ambient clocks) is built to catch. Instead, the timer arms a fresh
|
|
70
|
-
* full `ms` countdown per generation; no remaining-delay computation and no
|
|
71
|
-
* clock read occur in the slice or `update` — the only clock is `setTimeout`
|
|
72
|
-
* inside the Sub.
|
|
73
|
-
*/
|
|
74
|
-
interface DeadlineSlice {
|
|
75
|
-
/** `armed` while the countdown is live; `exceeded` once the deadline fired. */
|
|
76
|
-
readonly phase: "armed" | "exceeded";
|
|
77
|
-
/**
|
|
78
|
-
* Monotonic re-arm counter. Starts at 0; each accepted progress Msg (while
|
|
79
|
-
* armed) bumps it by one. Folds into the timer Sub's id, so a bump = a new id
|
|
80
|
-
* = the substrate retires the old timer and arms a fresh `ms` countdown.
|
|
81
|
-
*/
|
|
82
|
-
readonly seq: number;
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* The composed Model. The base machine's state is nested under `base`; the
|
|
86
|
-
* wrapper's state lives in the NAMED `$deadline` slice — never hidden in a
|
|
87
|
-
* closure. Both fields are plain data, so the whole composed Model round-trips
|
|
88
|
-
* through `JSON.parse(JSON.stringify(...))` iff the base state does.
|
|
89
|
-
*/
|
|
90
|
-
interface DeadlineModel<S> {
|
|
91
|
-
readonly base: S;
|
|
92
|
-
readonly $deadline: DeadlineSlice;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* The relative-timeout Sub the wrapper arms while `phase === "armed"`. `delayMs`
|
|
96
|
-
* is the window `config.ms`; the id is `$deadline:timeout:{seq}`, so each
|
|
97
|
-
* progress bump produces a distinct id and the reconcile pass churns the timer.
|
|
98
|
-
* Same `delayMs`-on-the-Sub shape `fromTimeout` consumes.
|
|
99
|
-
*/
|
|
100
|
-
type DeadlineTimeoutSub = Sub<"$deadline:timeout"> & {
|
|
101
|
-
readonly delayMs: number;
|
|
102
|
-
};
|
|
103
|
-
/**
|
|
104
|
-
* The Msg the timeout Sub dispatches when `config.ms` elapses with no accepted
|
|
105
|
-
* progress. `seq` echoes the re-arm generation the timer was armed against, so a
|
|
106
|
-
* stale timer's Msg (one whose id was already retired) is identifiable; the
|
|
107
|
-
* merged `update` only honors it when it matches the current slice `seq`.
|
|
108
|
-
*/
|
|
109
|
-
interface DeadlineExceededMsg {
|
|
110
|
-
readonly type: "$deadline:exceeded";
|
|
111
|
-
/** The re-arm generation this timer was armed against. */
|
|
112
|
-
readonly seq: number;
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Construct the deadline-exceeded Msg. Exported so the subscribe cell and tests
|
|
116
|
-
* share one constructor rather than two literals that can drift.
|
|
117
|
-
*/
|
|
118
|
-
declare function deadlineExceededMsg(seq: number): DeadlineExceededMsg;
|
|
119
|
-
/**
|
|
120
|
-
* The fire-and-forget decision Cmd the merged `update` appends on every
|
|
121
|
-
* transition, so the wrapper's choice is visible in the replayed Cmd log
|
|
122
|
-
* (rule 3) — `rearm` when an accepted progress Msg bumped `seq`, `expire` when
|
|
123
|
-
* the deadline-exceeded Msg flipped the phase, `idle` otherwise (a non-progress
|
|
124
|
-
* Msg, or a Msg after the machine already auto-failed). Plain data; its
|
|
125
|
-
* interpret handler is a no-op (the decision is the Cmd's presence in the log,
|
|
126
|
-
* not a side effect).
|
|
127
|
-
*/
|
|
128
|
-
type DeadlineDecisionCmd = Cmd<"$deadline:decision"> & {
|
|
129
|
-
readonly decision: "rearm" | "expire" | "idle";
|
|
130
|
-
/** The slice `seq` AFTER this transition (the re-arm generation now armed). */
|
|
131
|
-
readonly seq: number;
|
|
132
|
-
};
|
|
133
|
-
/**
|
|
134
|
-
* A predicate over a Msg that decides whether it re-arms the deadline.
|
|
135
|
-
*
|
|
136
|
-
* The argument is `Readonly<M>` and the result is `boolean`: this is the
|
|
137
|
-
* STRONGEST purity TS can express here. `Readonly<M>` removes the most common
|
|
138
|
-
* impurity at compile time — the predicate cannot reassign the Msg's own
|
|
139
|
-
* fields — and `boolean` pins the return so a side-effecting `(msg) => { … }`
|
|
140
|
-
* with an implicit `undefined`/`void` return is rejected.
|
|
141
|
-
*
|
|
142
|
-
* What the type system CANNOT encode (TS has no effect tracking): observational
|
|
143
|
-
* purity. A body that reads `Date.now()`, calls `Math.random()`, performs IO,
|
|
144
|
-
* or closes over and mutates external state still type-checks. Those remain a
|
|
145
|
-
* CONVENTION enforced by review, not the compiler — the predicate runs inside
|
|
146
|
-
* the pure merged `update` (invariant 2), so it must be a pure function of the
|
|
147
|
-
* Msg alone: no clock, no RNG, no IO, no captured mutable state.
|
|
148
|
-
*/
|
|
149
|
-
type ProgressPredicate<M extends {
|
|
150
|
-
type: string;
|
|
151
|
-
}> = (msg: Readonly<M>) => boolean;
|
|
152
|
-
/**
|
|
153
|
-
* The deadline knob. `ms` is the inactivity window; `progress` is an OPTIONAL
|
|
154
|
-
* predicate picking which base Msgs count as activity (default: EVERY base Msg
|
|
155
|
-
* re-arms). The predicate runs INSIDE the pure merged `update`, so it must be a
|
|
156
|
-
* pure function of the Msg — see {@link ProgressPredicate} for what the type
|
|
157
|
-
* enforces vs. what stays a convention.
|
|
158
|
-
*/
|
|
159
|
-
interface DeadlineConfig<M extends {
|
|
160
|
-
type: string;
|
|
161
|
-
}> {
|
|
162
|
-
/** The inactivity window in milliseconds. Auto-fail after `ms` with no progress. */
|
|
163
|
-
readonly ms: number;
|
|
164
|
-
/**
|
|
165
|
-
* Predicate picking which base Msgs re-arm the timer. Default: every base Msg
|
|
166
|
-
* counts as progress. Pure — a function of the Msg alone (see
|
|
167
|
-
* {@link ProgressPredicate}).
|
|
168
|
-
*/
|
|
169
|
-
readonly progress?: ProgressPredicate<M>;
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Wrap `base` with an inactivity deadline. Returns a NEW `Machine` over the
|
|
173
|
-
* composed Model `{ base, $deadline }`, with the base's Msgs/Cmds/Subs extended
|
|
174
|
-
* by the wrapper's own (`$deadline:exceeded` Msg, `$deadline:decision` Cmd,
|
|
175
|
-
* `$deadline:timeout` Sub).
|
|
176
|
-
*
|
|
177
|
-
* The composed machine:
|
|
178
|
-
* - `init` rehydrates the base (honoring the `[loaded, []]` contract) and
|
|
179
|
-
* seeds `$deadline: { phase: "armed", seq: 0 }`. Base init Cmds pass
|
|
180
|
-
* through unchanged.
|
|
181
|
-
* - `update` (Reducer form) runs the base reducer for base Msgs — base Cmds
|
|
182
|
-
* pass through UNCHANGED — and on an accepted progress Msg bumps `seq`
|
|
183
|
-
* (re-arm). The `$deadline:exceeded` Msg cell flips `phase` to `exceeded`.
|
|
184
|
-
* Every transition appends a `$deadline:decision` marker Cmd.
|
|
185
|
-
* - `subscriptions` is the base's, plus a `$deadline:timeout` Sub keyed on
|
|
186
|
-
* `seq` while `phase === "armed"`.
|
|
187
|
-
* - `subscribe` is the base's, plus the `$deadline:timeout` cell.
|
|
188
|
-
* - `interpret` is the base's, plus a no-op `$deadline:decision` handler.
|
|
189
|
-
*
|
|
190
|
-
* @param base any `Machine<S, M, C, U, Ctx>`.
|
|
191
|
-
* @param config the deadline knob (`ms` window + optional `progress` predicate).
|
|
192
|
-
*/
|
|
193
|
-
declare function withDeadline<S, M extends {
|
|
194
|
-
type: string;
|
|
195
|
-
}, C extends Cmd, U extends Sub, Ctx>(base: Machine<S, M, C, U, Ctx>, config: DeadlineConfig<M>): Machine<DeadlineModel<S>, M | DeadlineExceededMsg, C | DeadlineDecisionCmd, U | DeadlineTimeoutSub, Ctx>;
|
|
196
|
-
|
|
197
|
-
export { type DeadlineConfig, type DeadlineDecisionCmd, type DeadlineExceededMsg, type DeadlineModel, type DeadlineSlice, type DeadlineTimeoutSub, type ProgressPredicate, deadlineExceededMsg, withDeadline };
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { fromTimeout } from '../chunk-2YFLOCWX.js';
|
|
2
|
-
import '../chunk-ZSUUOEPL.js';
|
|
3
|
-
import { msgKeysOf, applyCell, subId } from '../chunk-OOYD44JI.js';
|
|
4
|
-
|
|
5
|
-
// src/with-deadline/index.ts
|
|
6
|
-
function deadlineExceededMsg(seq) {
|
|
7
|
-
return { type: "$deadline:exceeded", seq };
|
|
8
|
-
}
|
|
9
|
-
function withDeadline(base, config) {
|
|
10
|
-
const windowMs = config.ms;
|
|
11
|
-
const isProgress = config.progress;
|
|
12
|
-
const update = {};
|
|
13
|
-
const baseMsgKeys = msgKeysOf(base);
|
|
14
|
-
for (const key of baseMsgKeys) {
|
|
15
|
-
if (key.startsWith("$deadline:")) {
|
|
16
|
-
throw new Error(
|
|
17
|
-
`withDeadline: the base machine declares a reserved "${key}" update cell \u2014 the wrapper owns the "$deadline:" Msg namespace. Rename the base Msg.`
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
for (const key of baseMsgKeys) {
|
|
22
|
-
update[key] = (state, msg) => {
|
|
23
|
-
const [nextBase, baseCmds] = applyCell(
|
|
24
|
-
base,
|
|
25
|
-
state.base,
|
|
26
|
-
msg
|
|
27
|
-
);
|
|
28
|
-
const armed = state.$deadline.phase === "armed";
|
|
29
|
-
const counts = armed && (isProgress === void 0 || isProgress(msg));
|
|
30
|
-
const $deadline = counts ? { phase: "armed", seq: state.$deadline.seq + 1 } : state.$deadline;
|
|
31
|
-
const next = { base: nextBase, $deadline };
|
|
32
|
-
const decision = {
|
|
33
|
-
type: "$deadline:decision",
|
|
34
|
-
decision: counts ? "rearm" : "idle",
|
|
35
|
-
seq: $deadline.seq
|
|
36
|
-
};
|
|
37
|
-
return [next, [...baseCmds, decision]];
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
update["$deadline:exceeded"] = (state, msg) => {
|
|
41
|
-
const m = msg;
|
|
42
|
-
const fires = state.$deadline.phase === "armed" && m.seq === state.$deadline.seq;
|
|
43
|
-
const $deadline = fires ? { phase: "exceeded", seq: state.$deadline.seq } : state.$deadline;
|
|
44
|
-
const next = { base: state.base, $deadline };
|
|
45
|
-
const decision = {
|
|
46
|
-
type: "$deadline:decision",
|
|
47
|
-
decision: fires ? "expire" : "idle",
|
|
48
|
-
seq: $deadline.seq
|
|
49
|
-
};
|
|
50
|
-
return [next, [decision]];
|
|
51
|
-
};
|
|
52
|
-
const baseInterpret = base.interpret ?? {};
|
|
53
|
-
if (Object.hasOwn(baseInterpret, "$deadline:decision")) {
|
|
54
|
-
throw new Error(
|
|
55
|
-
'withDeadline: the base machine declares a reserved "$deadline:decision" interpret handler \u2014 the wrapper owns the "$deadline:" Cmd namespace. Rename the base handler.'
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
const interpret = {
|
|
59
|
-
...baseInterpret,
|
|
60
|
-
"$deadline:decision": async () => {
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
const baseSubscriptions = base.subscriptions;
|
|
64
|
-
const subscriptions = (state) => {
|
|
65
|
-
const baseSubs = baseSubscriptions ? baseSubscriptions(state.base) : [];
|
|
66
|
-
if (state.$deadline.phase !== "armed") return baseSubs;
|
|
67
|
-
const timeout = {
|
|
68
|
-
id: subId(`$deadline:timeout:${state.$deadline.seq}`),
|
|
69
|
-
type: "$deadline:timeout",
|
|
70
|
-
delayMs: windowMs
|
|
71
|
-
};
|
|
72
|
-
return [...baseSubs, timeout];
|
|
73
|
-
};
|
|
74
|
-
const baseSubscribe = base.subscribe ?? {};
|
|
75
|
-
if (Object.hasOwn(baseSubscribe, "$deadline:timeout")) {
|
|
76
|
-
throw new Error(
|
|
77
|
-
'withDeadline: the base machine declares a reserved "$deadline:timeout" subscribe handler \u2014 the wrapper owns the "$deadline:" Sub namespace. Rename the base handler.'
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
const timeoutCell = fromTimeout(
|
|
81
|
-
(sub) => {
|
|
82
|
-
const seq = Number(sub.id.slice(sub.id.lastIndexOf(":") + 1));
|
|
83
|
-
return deadlineExceededMsg(seq);
|
|
84
|
-
}
|
|
85
|
-
);
|
|
86
|
-
const subscribe = {
|
|
87
|
-
...baseSubscribe,
|
|
88
|
-
"$deadline:timeout": timeoutCell
|
|
89
|
-
};
|
|
90
|
-
return {
|
|
91
|
-
init: (loaded, ctx) => {
|
|
92
|
-
if (loaded !== null) {
|
|
93
|
-
return [loaded, []];
|
|
94
|
-
}
|
|
95
|
-
const [base0, cmds] = base.init(null, ctx);
|
|
96
|
-
const model = {
|
|
97
|
-
base: base0,
|
|
98
|
-
$deadline: { phase: "armed", seq: 0 }
|
|
99
|
-
};
|
|
100
|
-
return [model, cmds];
|
|
101
|
-
},
|
|
102
|
-
update,
|
|
103
|
-
subscriptions,
|
|
104
|
-
subscribe,
|
|
105
|
-
interpret
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export { deadlineExceededMsg, withDeadline };
|
|
110
|
-
//# sourceMappingURL=index.js.map
|
|
111
|
-
//# sourceMappingURL=index.js.map
|