@demlik/tea 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -9
- package/dist/agent/index.d.ts +638 -45
- package/dist/agent/index.js +9 -19
- package/dist/{chunk-25LBDCBC.js → chunk-6IQPODUF.js} +2 -2
- package/dist/{chunk-25LBDCBC.js.map → chunk-6IQPODUF.js.map} +1 -1
- package/dist/chunk-AQ6ZIMEA.js +421 -0
- package/dist/chunk-AQ6ZIMEA.js.map +1 -0
- package/dist/{chunk-MUUROGIH.js → chunk-BLJ2JQSH.js} +62 -12
- package/dist/chunk-BLJ2JQSH.js.map +1 -0
- package/dist/{chunk-7SVIRMC6.js → chunk-F2US5BW6.js} +25 -5
- package/dist/chunk-F2US5BW6.js.map +1 -0
- package/dist/{batch-window/index.js → chunk-F7FMAWLA.js} +4 -8
- package/dist/chunk-F7FMAWLA.js.map +1 -0
- package/dist/{chunk-7V4EVLZA.js → chunk-HUKZQX6U.js} +20 -16
- package/dist/chunk-HUKZQX6U.js.map +1 -0
- package/dist/{chunk-EWJP3YYP.js → chunk-HWVW4AXC.js} +3 -3
- package/dist/chunk-HWVW4AXC.js.map +1 -0
- package/dist/{chunk-WLGO64WC.js → chunk-HYDWG35Q.js} +23 -6
- package/dist/chunk-HYDWG35Q.js.map +1 -0
- package/dist/{chunk-I5OV65MS.js → chunk-I5MQMJDW.js} +57 -7
- package/dist/chunk-I5MQMJDW.js.map +1 -0
- package/dist/{chunk-J6527VRQ.js → chunk-LFZUK6J2.js} +3 -3
- package/dist/chunk-LFZUK6J2.js.map +1 -0
- package/dist/{chunk-ZVJZ72HY.js → chunk-LYLTKJWM.js} +25 -11
- package/dist/chunk-LYLTKJWM.js.map +1 -0
- package/dist/{chunk-D736QUGF.js → chunk-MYXFNWAJ.js} +4 -5
- package/dist/chunk-MYXFNWAJ.js.map +1 -0
- package/dist/{chunk-K575PT4S.js → chunk-PR6TB3BL.js} +15 -4
- package/dist/chunk-PR6TB3BL.js.map +1 -0
- package/dist/chunk-RQULHGYH.js +1804 -0
- package/dist/chunk-RQULHGYH.js.map +1 -0
- package/dist/{chunk-FV3Z5MBE.js → chunk-TXN2KFHF.js} +14 -4
- package/dist/chunk-TXN2KFHF.js.map +1 -0
- package/dist/{chunk-Q2UM7BXU.js → chunk-VBDU4JL6.js} +2 -2
- package/dist/chunk-VBDU4JL6.js.map +1 -0
- package/dist/chunk-Z2L3LSNV.js +1470 -0
- package/dist/chunk-Z2L3LSNV.js.map +1 -0
- package/dist/core-CTzMJ82M.d.ts +562 -0
- package/dist/devtools/index.d.ts +2 -2
- package/dist/devtools/index.js +207 -2
- package/dist/devtools/index.js.map +1 -1
- package/dist/do/index.d.ts +48 -31
- package/dist/do/index.js +36 -25
- package/dist/do/index.js.map +1 -1
- package/dist/{durable-effects-D8SqU_if.d.ts → durable-effects-B0-qGQDy.d.ts} +2 -2
- package/dist/extension/index.d.ts +301 -3
- package/dist/extension/index.js +596 -5
- package/dist/extension/index.js.map +1 -1
- package/dist/flow/index.d.ts +1295 -0
- package/dist/flow/index.js +732 -0
- package/dist/flow/index.js.map +1 -0
- package/dist/idempotency/index.d.ts +90 -116
- package/dist/idempotency/index.js +4 -1
- package/dist/{batch-window/index.d.ts → index-4vZzljCD.d.ts} +7 -11
- package/dist/{fan-out/index.d.ts → index-6A7dB8f6.d.ts} +7 -8
- package/dist/index-B5BZ-_cT.d.ts +616 -0
- package/dist/index-Bc40JWVl.d.ts +131 -0
- package/dist/{debounce/index.d.ts → index-DHSUmQTR.d.ts} +7 -7
- package/dist/index-DJWIER_3.d.ts +69 -0
- package/dist/{snapshot/index.d.ts → index-DMCeMPMJ.d.ts} +15 -77
- package/dist/{monitored-run/index.d.ts → index-NjrT3fL2.d.ts} +37 -12
- package/dist/{recorder/index.d.ts → index-TvRb1KVf.d.ts} +4 -6
- package/dist/{deadline/index.d.ts → index-q0hXFeZ0.d.ts} +155 -8
- package/dist/index.d.ts +719 -6
- package/dist/index.js +1 -2
- package/dist/jev/index.d.ts +634 -0
- package/dist/jev/index.js +433 -0
- package/dist/jev/index.js.map +1 -0
- package/dist/machine-CdIcN2Xm.d.ts +1773 -0
- package/dist/machine-viz/index.d.ts +2 -1
- package/dist/machine-viz/index.js +12 -5
- package/dist/machine-viz/index.js.map +1 -1
- package/dist/mem/index.d.ts +19 -3
- package/dist/mem/index.js +22 -2
- package/dist/mem/index.js.map +1 -1
- package/dist/node/index.d.ts +130 -4
- package/dist/node/index.js +222 -10
- package/dist/node/index.js.map +1 -1
- package/dist/{paginator → paginate}/index.d.ts +151 -6
- package/dist/paginate/index.js +7 -0
- package/dist/parity/index.d.ts +5 -10
- package/dist/parity/index.js +4 -7
- package/dist/parity/index.js.map +1 -1
- package/dist/pbt/index.d.ts +248 -5
- package/dist/pbt/index.js +124 -5
- package/dist/pbt/index.js.map +1 -1
- package/dist/{trace-replay → persistence}/index.d.ts +7 -4
- package/dist/persistence/index.js +6 -0
- package/dist/react/index.d.ts +4 -3
- package/dist/react/index.js +1 -2
- package/dist/react/index.js.map +1 -1
- package/dist/resilience/index.d.ts +743 -0
- package/dist/resilience/index.js +657 -0
- package/dist/resilience/index.js.map +1 -0
- package/dist/retry-backoff/index.d.ts +3 -2
- package/dist/retry-backoff/index.js +1 -1
- package/dist/runtime-types-LWDoi943.d.ts +998 -0
- package/dist/testing/index.d.ts +3 -2
- package/dist/testing/index.js +1 -2
- package/dist/testing/index.js.map +1 -1
- package/dist/{throttled-input → timing}/index.d.ts +144 -12
- package/dist/{throttled-input → timing}/index.js +57 -12
- package/dist/timing/index.js.map +1 -0
- package/dist/{types-D7u9DkH7.d.ts → types-DP3f5NIl.d.ts} +1 -1
- package/dist/work-queue/index.d.ts +131 -54
- package/dist/work-queue/index.js +3 -2
- package/dist/work-queue/index.js.map +1 -1
- package/package.json +50 -216
- package/dist/authed-call/index.d.ts +0 -119
- package/dist/authed-call/index.js +0 -134
- package/dist/authed-call/index.js.map +0 -1
- package/dist/await-terminal/index.d.ts +0 -100
- package/dist/await-terminal/index.js +0 -76
- package/dist/await-terminal/index.js.map +0 -1
- package/dist/batch-window/index.js.map +0 -1
- package/dist/cache/index.d.ts +0 -151
- package/dist/cache/index.js +0 -8
- package/dist/chart/index.d.ts +0 -217
- package/dist/chart/index.js +0 -16
- package/dist/chart/index.js.map +0 -1
- package/dist/chart/inspect/index.d.ts +0 -85
- package/dist/chart/inspect/index.js +0 -5
- package/dist/chart/inspect/react.d.ts +0 -112
- package/dist/chart/inspect/react.js +0 -11
- package/dist/chart/inspect/react.js.map +0 -1
- package/dist/chart/inspect/styles.css +0 -286
- package/dist/chart/lane/index.d.ts +0 -361
- package/dist/chart/lane/index.js +0 -9
- package/dist/chart/lane/index.js.map +0 -1
- package/dist/chart/lane/react.d.ts +0 -83
- package/dist/chart/lane/react.js +0 -559
- package/dist/chart/lane/react.js.map +0 -1
- package/dist/chart/lane/server.d.ts +0 -148
- package/dist/chart/lane/server.js +0 -209
- package/dist/chart/lane/server.js.map +0 -1
- package/dist/chart/lane/styles.css +0 -498
- package/dist/chart/lane/viewer/assets/abnfDiagram-N423BO3Z-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/architectureDiagram-T3A2C74G-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/blockDiagram-VBNYF7ZC-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/c4Diagram-5PPSVZJV-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/chunk-2GRJ4B5K-HdDf8SI3.js +0 -1
- package/dist/chart/lane/viewer/assets/chunk-5RXB4S5H-CcNtpUd7.js +0 -231
- package/dist/chart/lane/viewer/assets/chunk-5VM5RSS4-BP4fRS_5.js +0 -15
- package/dist/chart/lane/viewer/assets/chunk-KBJHAD2P-DZOw7xU6.js +0 -1
- package/dist/chart/lane/viewer/assets/chunk-NSK5VX7P-CBCyTZMs.js +0 -128
- package/dist/chart/lane/viewer/assets/classDiagram-JCYQIIEL-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/classDiagram-v2-OCEON4UE-D4uAiFr8.js +0 -206
- package/dist/chart/lane/viewer/assets/cose-bilkent-JH36ORCC-DOwCrGXH.js +0 -1
- package/dist/chart/lane/viewer/assets/cynefinDiagram-MW4NZA55-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/dagre-K_PewWfS.js +0 -1
- package/dist/chart/lane/viewer/assets/dagre-VZM6K2ZE-831qZcA8.js +0 -4
- package/dist/chart/lane/viewer/assets/diagram-7IWD3JNH-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/diagram-B4RE2ZJO-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/diagram-LBJQPF4R-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/diagram-Q27KOJAE-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/diagram-UB23O5K3-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/ebnfDiagram-BXEA7PRR-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/erDiagram-JOGREHBK-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/flowDiagram-UKHOOZJN-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/ganttDiagram-PKOTCBZU-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/gitGraphDiagram-DS77QQ5N-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/index-9SkH5NA3.css +0 -1
- package/dist/chart/lane/viewer/assets/index-Bgt4sXpW.js +0 -195
- package/dist/chart/lane/viewer/assets/infoDiagram-6WML65LV-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/ishikawaDiagram-WSZJBQD7-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/journeyDiagram-NVQOT4AX-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/kanban-definition-27J2QSJJ-G7PaPzy-.js +0 -89
- package/dist/chart/lane/viewer/assets/katex-DOwCrGXH.js +0 -1
- package/dist/chart/lane/viewer/assets/mindmap-definition-FAOFIHXS-CGj9nrVk.js +0 -96
- package/dist/chart/lane/viewer/assets/path-fybaL0A-.js +0 -1
- package/dist/chart/lane/viewer/assets/pegDiagram-VL7TDLO6-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/pieDiagram-7S7Q4E2Y-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/quadrantDiagram-CIZ2JOQS-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/railroadDiagram-AXF67PYL-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/requirementDiagram-LRYGKXZP-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/sankeyDiagram-W5VNT64P-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/sequenceDiagram-SI44F4Z6-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/stateDiagram-OKZ733FA-B_88AzBS.js +0 -1
- package/dist/chart/lane/viewer/assets/stateDiagram-v2-UEYNNEHI-CR5gcgq6.js +0 -1
- package/dist/chart/lane/viewer/assets/swimlanes-SLNWSIFB-B4xK-rwg.js +0 -1
- package/dist/chart/lane/viewer/assets/swimlanesDiagram-ULZ7WXOC-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/timeline-definition-Z64GVDOM-CCv52MfY.js +0 -120
- package/dist/chart/lane/viewer/assets/vennDiagram-T6HMQDX7-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/wardleyDiagram-T6FBY63Y-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/xychartDiagram-ELKLHX3M-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/index.html +0 -15
- package/dist/chart/report/index.d.ts +0 -116
- package/dist/chart/report/index.js +0 -32
- package/dist/chart/report/index.js.map +0 -1
- package/dist/chunk-2YFLOCWX.js +0 -15
- package/dist/chunk-2YFLOCWX.js.map +0 -1
- package/dist/chunk-3JU6657S.js +0 -372
- package/dist/chunk-3JU6657S.js.map +0 -1
- package/dist/chunk-4KTWLPL5.js +0 -33
- package/dist/chunk-4KTWLPL5.js.map +0 -1
- package/dist/chunk-5EHLEUTL.js +0 -686
- package/dist/chunk-5EHLEUTL.js.map +0 -1
- package/dist/chunk-5KJKJOFC.js +0 -758
- package/dist/chunk-5KJKJOFC.js.map +0 -1
- package/dist/chunk-7SVIRMC6.js.map +0 -1
- package/dist/chunk-7V4EVLZA.js.map +0 -1
- package/dist/chunk-A56OR5RF.js +0 -184
- package/dist/chunk-A56OR5RF.js.map +0 -1
- package/dist/chunk-AZZLE7XR.js +0 -62
- package/dist/chunk-AZZLE7XR.js.map +0 -1
- package/dist/chunk-B5VXOFMZ.js +0 -266
- package/dist/chunk-B5VXOFMZ.js.map +0 -1
- package/dist/chunk-BYQUGDD3.js +0 -16
- package/dist/chunk-BYQUGDD3.js.map +0 -1
- package/dist/chunk-D736QUGF.js.map +0 -1
- package/dist/chunk-E6GEDSF4.js +0 -307
- package/dist/chunk-E6GEDSF4.js.map +0 -1
- package/dist/chunk-EUF7XOEE.js +0 -223
- package/dist/chunk-EUF7XOEE.js.map +0 -1
- package/dist/chunk-EWJP3YYP.js.map +0 -1
- package/dist/chunk-FV3Z5MBE.js.map +0 -1
- package/dist/chunk-HCEVHFJ7.js +0 -54
- package/dist/chunk-HCEVHFJ7.js.map +0 -1
- package/dist/chunk-I5OV65MS.js.map +0 -1
- package/dist/chunk-J6527VRQ.js.map +0 -1
- package/dist/chunk-JELSZN25.js +0 -47
- package/dist/chunk-JELSZN25.js.map +0 -1
- package/dist/chunk-JER5O7PQ.js +0 -416
- package/dist/chunk-JER5O7PQ.js.map +0 -1
- package/dist/chunk-JGVL3WPL.js +0 -26
- package/dist/chunk-JGVL3WPL.js.map +0 -1
- package/dist/chunk-JP5D6GSL.js +0 -71
- package/dist/chunk-JP5D6GSL.js.map +0 -1
- package/dist/chunk-K575PT4S.js.map +0 -1
- package/dist/chunk-MU6MCIAC.js +0 -15
- package/dist/chunk-MU6MCIAC.js.map +0 -1
- package/dist/chunk-MUUROGIH.js.map +0 -1
- package/dist/chunk-ND3DH6KM.js +0 -88
- package/dist/chunk-ND3DH6KM.js.map +0 -1
- package/dist/chunk-Q2UM7BXU.js.map +0 -1
- package/dist/chunk-S2EGRPCM.js +0 -47
- package/dist/chunk-S2EGRPCM.js.map +0 -1
- package/dist/chunk-SINXE47Y.js +0 -55
- package/dist/chunk-SINXE47Y.js.map +0 -1
- package/dist/chunk-SUST46KO.js +0 -53
- package/dist/chunk-SUST46KO.js.map +0 -1
- package/dist/chunk-TP5UPGLY.js +0 -61
- package/dist/chunk-TP5UPGLY.js.map +0 -1
- package/dist/chunk-UF4MZSLT.js +0 -53
- package/dist/chunk-UF4MZSLT.js.map +0 -1
- package/dist/chunk-UOC2PL46.js +0 -13
- package/dist/chunk-UOC2PL46.js.map +0 -1
- package/dist/chunk-WLGO64WC.js.map +0 -1
- package/dist/chunk-WRAA7GVZ.js +0 -209
- package/dist/chunk-WRAA7GVZ.js.map +0 -1
- package/dist/chunk-ZCL7SCBK.js +0 -685
- package/dist/chunk-ZCL7SCBK.js.map +0 -1
- package/dist/chunk-ZD6PNZBK.js +0 -457
- package/dist/chunk-ZD6PNZBK.js.map +0 -1
- package/dist/chunk-ZF6WDK2D.js +0 -519
- package/dist/chunk-ZF6WDK2D.js.map +0 -1
- package/dist/chunk-ZJ5AOYBH.js +0 -8
- package/dist/chunk-ZJ5AOYBH.js.map +0 -1
- package/dist/chunk-ZVJZ72HY.js.map +0 -1
- package/dist/circuit-breaker/index.d.ts +0 -197
- package/dist/circuit-breaker/index.js +0 -3
- package/dist/circuit-breaker/index.js.map +0 -1
- package/dist/core-Bjc0bS8j.d.ts +0 -326
- package/dist/deadline/index.js +0 -6
- package/dist/deadline/index.js.map +0 -1
- package/dist/debounce/index.js +0 -3
- package/dist/debounce/index.js.map +0 -1
- package/dist/extension/react.d.ts +0 -121
- package/dist/extension/react.js +0 -75
- package/dist/extension/react.js.map +0 -1
- package/dist/extension/subs/index.d.ts +0 -44
- package/dist/extension/subs/index.js +0 -80
- package/dist/extension/subs/index.js.map +0 -1
- package/dist/extension/test-utils.d.ts +0 -128
- package/dist/extension/test-utils.js +0 -277
- package/dist/extension/test-utils.js.map +0 -1
- package/dist/fan-out/index.js +0 -5
- package/dist/fan-out/index.js.map +0 -1
- package/dist/fold-Blbhru48.d.ts +0 -435
- package/dist/graph-CcjWZVrd.d.ts +0 -923
- package/dist/idempotency/adapter.d.ts +0 -62
- package/dist/idempotency/adapter.js +0 -4
- package/dist/idempotency/adapter.js.map +0 -1
- package/dist/idempotent-intake/index.d.ts +0 -187
- package/dist/idempotent-intake/index.js +0 -7
- package/dist/idempotent-intake/index.js.map +0 -1
- package/dist/llm-call/index.d.ts +0 -310
- package/dist/llm-call/index.js +0 -16
- package/dist/llm-call/index.js.map +0 -1
- package/dist/machine-0OmPvsy_.d.ts +0 -804
- package/dist/monitored-run/index.js +0 -10
- package/dist/monitored-run/index.js.map +0 -1
- package/dist/paginated-walk/index.d.ts +0 -234
- package/dist/paginated-walk/index.js +0 -16
- package/dist/paginated-walk/index.js.map +0 -1
- package/dist/paginator/index.js +0 -3
- package/dist/paginator/index.js.map +0 -1
- package/dist/pbt/arbitraries/index.d.ts +0 -135
- package/dist/pbt/arbitraries/index.js +0 -3
- package/dist/pbt/arbitraries/index.js.map +0 -1
- package/dist/pbt/runners/index.d.ts +0 -117
- package/dist/pbt/runners/index.js +0 -5
- package/dist/pbt/runners/index.js.map +0 -1
- package/dist/poller/index.d.ts +0 -351
- package/dist/poller/index.js +0 -115
- package/dist/poller/index.js.map +0 -1
- package/dist/prediction/index.d.ts +0 -130
- package/dist/prediction/index.js +0 -4
- package/dist/prediction/index.js.map +0 -1
- package/dist/protocol-B5YmJr0d.d.ts +0 -45
- package/dist/pure/index.d.ts +0 -2
- package/dist/pure/index.js +0 -4
- package/dist/pure/index.js.map +0 -1
- package/dist/rate-limit/index.d.ts +0 -115
- package/dist/rate-limit/index.js +0 -3
- package/dist/rate-limit/index.js.map +0 -1
- package/dist/reconciler/index.d.ts +0 -192
- package/dist/reconciler/index.js +0 -164
- package/dist/reconciler/index.js.map +0 -1
- package/dist/recorder/index.js +0 -3
- package/dist/recorder/index.js.map +0 -1
- package/dist/reducer-BqyoVyBG.d.ts +0 -447
- package/dist/resilient-call/index.d.ts +0 -319
- package/dist/resilient-call/index.js +0 -14
- package/dist/resilient-call/index.js.map +0 -1
- package/dist/retry-to-success/index.d.ts +0 -109
- package/dist/retry-to-success/index.js +0 -37
- package/dist/retry-to-success/index.js.map +0 -1
- package/dist/run-BVeqJDBF.d.ts +0 -713
- package/dist/runtime-types-Bxc637bp.d.ts +0 -502
- package/dist/saga/index.d.ts +0 -240
- package/dist/saga/index.js +0 -150
- package/dist/saga/index.js.map +0 -1
- package/dist/samples-DCt6nF8H.d.ts +0 -59
- package/dist/snapshot/index.js +0 -5
- package/dist/snapshot/index.js.map +0 -1
- package/dist/subs/index.d.ts +0 -471
- package/dist/subs/index.js +0 -7
- package/dist/subs/index.js.map +0 -1
- package/dist/throttle/index.d.ts +0 -134
- package/dist/throttle/index.js +0 -3
- package/dist/throttle/index.js.map +0 -1
- package/dist/throttled-input/index.js.map +0 -1
- package/dist/token-refresh/index.d.ts +0 -215
- package/dist/token-refresh/index.js +0 -6
- package/dist/token-refresh/index.js.map +0 -1
- package/dist/trace-replay/index.js +0 -6
- package/dist/trace-replay/index.js.map +0 -1
- package/dist/with-deadline/index.d.ts +0 -196
- package/dist/with-deadline/index.js +0 -111
- package/dist/with-deadline/index.js.map +0 -1
- package/dist/with-resilience/index.d.ts +0 -224
- package/dist/with-resilience/index.js +0 -240
- package/dist/with-resilience/index.js.map +0 -1
- package/dist/with-telemetry/index.d.ts +0 -149
- package/dist/with-telemetry/index.js +0 -70
- package/dist/with-telemetry/index.js.map +0 -1
- package/dist/work-queue/adapter.d.ts +0 -83
- package/dist/work-queue/adapter.js +0 -4
- package/dist/work-queue/adapter.js.map +0 -1
- package/dist/work-queue/ops.d.ts +0 -70
- package/dist/work-queue/ops.js +0 -3
- package/dist/work-queue/ops.js.map +0 -1
- package/dist/workflow/index.d.ts +0 -484
- package/dist/workflow/index.js +0 -244
- package/dist/workflow/index.js.map +0 -1
- /package/dist/{cache → paginate}/index.js.map +0 -0
- /package/dist/{chart/inspect → persistence}/index.js.map +0 -0
|
@@ -0,0 +1,1804 @@
|
|
|
1
|
+
import { Result } from 'better-result';
|
|
2
|
+
|
|
3
|
+
// src/observability.ts
|
|
4
|
+
function historyTracker(runtime, size) {
|
|
5
|
+
const buffer = [];
|
|
6
|
+
let stopped = false;
|
|
7
|
+
const push = (entry) => {
|
|
8
|
+
buffer.push(entry);
|
|
9
|
+
if (buffer.length > size) buffer.shift();
|
|
10
|
+
};
|
|
11
|
+
const unobserve = size <= 0 ? () => {
|
|
12
|
+
} : runtime.observe((msg, state) => {
|
|
13
|
+
push({ msg, state });
|
|
14
|
+
});
|
|
15
|
+
const unboot = size <= 0 ? () => {
|
|
16
|
+
} : runtime.onBoot((state) => {
|
|
17
|
+
push({ msg: null, state });
|
|
18
|
+
});
|
|
19
|
+
return {
|
|
20
|
+
snapshot() {
|
|
21
|
+
return buffer.slice();
|
|
22
|
+
},
|
|
23
|
+
stop() {
|
|
24
|
+
if (stopped) return;
|
|
25
|
+
stopped = true;
|
|
26
|
+
unobserve();
|
|
27
|
+
unboot();
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// src/provide/index.ts
|
|
33
|
+
var providedBrand = /* @__PURE__ */ Symbol("demlik-tea.provided");
|
|
34
|
+
var ProvideFailedError = class extends Error {
|
|
35
|
+
_tag = "provide_failed";
|
|
36
|
+
/** The provider key whose `acquire` failed. */
|
|
37
|
+
provider;
|
|
38
|
+
constructor(provider, cause) {
|
|
39
|
+
super(
|
|
40
|
+
`@demlik/tea: provider ${JSON.stringify(provider)} failed to acquire`,
|
|
41
|
+
{ cause }
|
|
42
|
+
);
|
|
43
|
+
this.name = "ProvideFailedError";
|
|
44
|
+
this.provider = provider;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
var UnknownProviderError = class extends Error {
|
|
48
|
+
_tag = "unknown_provider";
|
|
49
|
+
/** The missing key. */
|
|
50
|
+
provider;
|
|
51
|
+
/** The provider that asked for it. */
|
|
52
|
+
requiredBy;
|
|
53
|
+
constructor(provider, requiredBy) {
|
|
54
|
+
super(
|
|
55
|
+
`@demlik/tea: provider ${JSON.stringify(requiredBy)} depends on ${JSON.stringify(provider)}, which the provider map has no entry for`
|
|
56
|
+
);
|
|
57
|
+
this.name = "UnknownProviderError";
|
|
58
|
+
this.provider = provider;
|
|
59
|
+
this.requiredBy = requiredBy;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var ProviderCycleError = class extends Error {
|
|
63
|
+
_tag = "provider_cycle";
|
|
64
|
+
/** The cycle, in the order it was walked, closing on its own first key. */
|
|
65
|
+
cycle;
|
|
66
|
+
constructor(cycle) {
|
|
67
|
+
super(`@demlik/tea: provider dependency cycle \u2014 ${cycle.join(" \u2192 ")}`);
|
|
68
|
+
this.name = "ProviderCycleError";
|
|
69
|
+
this.cycle = cycle;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
function dep() {
|
|
73
|
+
return (name) => ({ name });
|
|
74
|
+
}
|
|
75
|
+
function layer(first, second, third) {
|
|
76
|
+
if (typeof first === "function") {
|
|
77
|
+
return {
|
|
78
|
+
deps: [],
|
|
79
|
+
acquire: first,
|
|
80
|
+
release: second
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
// Tokens collapse to their names here: `deps` is a name list at runtime
|
|
85
|
+
// whichever overload wrote it, so the walk in `provide` stays one path and
|
|
86
|
+
// a graph assembled from tokens journals nothing extra.
|
|
87
|
+
deps: first.map(
|
|
88
|
+
(entry) => typeof entry === "string" ? entry : entry.name
|
|
89
|
+
),
|
|
90
|
+
acquire: second,
|
|
91
|
+
release: third
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function value(v) {
|
|
95
|
+
return { deps: [], acquire: () => v };
|
|
96
|
+
}
|
|
97
|
+
function provide(map) {
|
|
98
|
+
const keys = Object.keys(map);
|
|
99
|
+
const nodes = map;
|
|
100
|
+
return {
|
|
101
|
+
[providedBrand]: true,
|
|
102
|
+
async open(onReleaseError = defaultOnReleaseError) {
|
|
103
|
+
const built = /* @__PURE__ */ new Map();
|
|
104
|
+
const acquired = [];
|
|
105
|
+
const path = [];
|
|
106
|
+
async function build(key, requiredBy) {
|
|
107
|
+
if (built.has(key)) return built.get(key);
|
|
108
|
+
const provider = nodes[key];
|
|
109
|
+
if (provider === void 0) {
|
|
110
|
+
throw new UnknownProviderError(key, requiredBy);
|
|
111
|
+
}
|
|
112
|
+
if (path.includes(key)) {
|
|
113
|
+
throw new ProviderCycleError([...path.slice(path.indexOf(key)), key]);
|
|
114
|
+
}
|
|
115
|
+
path.push(key);
|
|
116
|
+
const deps = {};
|
|
117
|
+
for (const dep2 of provider.deps) {
|
|
118
|
+
deps[dep2] = await build(dep2, key);
|
|
119
|
+
}
|
|
120
|
+
let acquiredValue;
|
|
121
|
+
try {
|
|
122
|
+
acquiredValue = await provider.acquire(deps);
|
|
123
|
+
} catch (error) {
|
|
124
|
+
throw new ProvideFailedError(key, error);
|
|
125
|
+
}
|
|
126
|
+
path.pop();
|
|
127
|
+
built.set(key, acquiredValue);
|
|
128
|
+
acquired.push({ key, provider });
|
|
129
|
+
return acquiredValue;
|
|
130
|
+
}
|
|
131
|
+
let released = false;
|
|
132
|
+
async function releaseAll() {
|
|
133
|
+
if (released) return;
|
|
134
|
+
released = true;
|
|
135
|
+
for (let i = acquired.length - 1; i >= 0; i--) {
|
|
136
|
+
const entry = acquired[i];
|
|
137
|
+
if (entry === void 0) continue;
|
|
138
|
+
const { key, provider } = entry;
|
|
139
|
+
const release = provider.release;
|
|
140
|
+
if (release === void 0) continue;
|
|
141
|
+
try {
|
|
142
|
+
await release(built.get(key));
|
|
143
|
+
} catch (error) {
|
|
144
|
+
onReleaseError(error, key);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
for (const key of keys) await build(key, key);
|
|
150
|
+
} catch (error) {
|
|
151
|
+
await releaseAll();
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
const ctx = Object.fromEntries(
|
|
155
|
+
keys.map((key) => [key, built.get(key)])
|
|
156
|
+
);
|
|
157
|
+
return { ctx, release: releaseAll };
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function isProvided(candidate) {
|
|
162
|
+
return typeof candidate === "object" && candidate !== null && candidate[providedBrand] === true;
|
|
163
|
+
}
|
|
164
|
+
function defaultOnReleaseError(error, provider) {
|
|
165
|
+
console.warn(
|
|
166
|
+
`@demlik/tea: release of provider ${JSON.stringify(provider)} threw`,
|
|
167
|
+
error
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// src/pure/core.ts
|
|
172
|
+
var __DEV__ = (() => {
|
|
173
|
+
try {
|
|
174
|
+
const meta = import.meta;
|
|
175
|
+
if (meta.env?.DEV !== void 0) {
|
|
176
|
+
return meta.env.DEV;
|
|
177
|
+
}
|
|
178
|
+
} catch {
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
return typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
|
|
182
|
+
} catch {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
})();
|
|
186
|
+
function deepFreeze(obj, seen) {
|
|
187
|
+
if (obj === null || typeof obj !== "object") return obj;
|
|
188
|
+
const proto = Object.getPrototypeOf(obj);
|
|
189
|
+
if (proto !== Object.prototype && proto !== Array.prototype && proto !== null)
|
|
190
|
+
return obj;
|
|
191
|
+
const visited = seen ?? /* @__PURE__ */ new WeakSet();
|
|
192
|
+
if (visited.has(obj)) return obj;
|
|
193
|
+
visited.add(obj);
|
|
194
|
+
Object.freeze(obj);
|
|
195
|
+
for (const v of Object.values(obj))
|
|
196
|
+
deepFreeze(v, visited);
|
|
197
|
+
return obj;
|
|
198
|
+
}
|
|
199
|
+
function hasFunctionValues(obj) {
|
|
200
|
+
if (obj === null || typeof obj !== "object") return null;
|
|
201
|
+
for (const [key, value2] of Object.entries(obj)) {
|
|
202
|
+
if (typeof value2 === "function") return key;
|
|
203
|
+
}
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
function assertPureResult(result, msgType) {
|
|
207
|
+
if (result && typeof result.then === "function") {
|
|
208
|
+
throw new Error(
|
|
209
|
+
`@demlik/tea: update cell "${msgType}" returned a Promise. update must be synchronous. Move async work to interpret.`
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
if (!Array.isArray(result) || result.length < 2 || !Array.isArray(result[1])) {
|
|
213
|
+
throw new Error(
|
|
214
|
+
`@demlik/tea: update cell "${msgType}" returned a non-tuple. Expected [State, Cmd[]], got ${typeof result}.`
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
const cmds = result[1];
|
|
218
|
+
for (const cmd of cmds) {
|
|
219
|
+
const fnField = hasFunctionValues(cmd);
|
|
220
|
+
if (fnField !== null) {
|
|
221
|
+
throw new Error(
|
|
222
|
+
`@demlik/tea: Cmd "${cmd.type}" has function field "${fnField}". Cmds must be plain data, not closures.`
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function without(rec, key) {
|
|
228
|
+
const { [key]: _dropped, ...rest } = rec;
|
|
229
|
+
return rest;
|
|
230
|
+
}
|
|
231
|
+
function malformedResult(issues) {
|
|
232
|
+
return {
|
|
233
|
+
_tag: "malformed_result",
|
|
234
|
+
issues: issues.map((issue) => ({
|
|
235
|
+
path: issue.path.map(String).join("."),
|
|
236
|
+
message: issue.message
|
|
237
|
+
}))
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
var cmdEdge = /* @__PURE__ */ Symbol("tea.cmdEdge");
|
|
241
|
+
function cmdEdgeOver(defs, clock) {
|
|
242
|
+
const byType = /* @__PURE__ */ new Map();
|
|
243
|
+
for (const def of defs) byType.set(def.cmdType, def);
|
|
244
|
+
return (cmd, follow) => {
|
|
245
|
+
const def = byType.get(cmd.type);
|
|
246
|
+
if (def === void 0 || !isSettledShape(follow)) return follow;
|
|
247
|
+
const at = follow.at ?? clock();
|
|
248
|
+
if (follow.type === def.okType) {
|
|
249
|
+
const parsed = def.schema.ok.safeParse(follow.value);
|
|
250
|
+
if (!parsed.success) {
|
|
251
|
+
return {
|
|
252
|
+
type: def.errType,
|
|
253
|
+
cmd: follow.cmd,
|
|
254
|
+
error: malformedResult(parsed.error.issues),
|
|
255
|
+
at
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
return { ...follow, value: parsed.data, at };
|
|
259
|
+
}
|
|
260
|
+
if (follow.type === def.errType) return { ...follow, at };
|
|
261
|
+
return follow;
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function cmdEdgeOf(ctx) {
|
|
265
|
+
const edge = typeof ctx === "object" && ctx !== null ? ctx[cmdEdge] : void 0;
|
|
266
|
+
return edge ?? ((_, follow) => follow);
|
|
267
|
+
}
|
|
268
|
+
var detachWork = /* @__PURE__ */ Symbol("tea.detachWork");
|
|
269
|
+
function detachWorkOf(ctx) {
|
|
270
|
+
const detach = typeof ctx === "object" && ctx !== null ? ctx[detachWork] : void 0;
|
|
271
|
+
return detach ?? (() => void 0);
|
|
272
|
+
}
|
|
273
|
+
function isSettledShape(follow) {
|
|
274
|
+
return typeof follow === "object" && follow !== null && typeof follow.type === "string";
|
|
275
|
+
}
|
|
276
|
+
function defineCmd(name, spec) {
|
|
277
|
+
const okType = `${name}_ok`;
|
|
278
|
+
const errType = `${name}_err`;
|
|
279
|
+
const build = (input) => ({ ...input, type: name });
|
|
280
|
+
return Object.assign(build, {
|
|
281
|
+
cmdType: name,
|
|
282
|
+
okType,
|
|
283
|
+
errType,
|
|
284
|
+
ok: (cmd, value2, at) => stamp({ type: okType, cmd, value: value2 }, at),
|
|
285
|
+
err: (cmd, error, at) => stamp({ type: errType, cmd, error }, at),
|
|
286
|
+
schema: { input: spec.input, ok: spec.ok },
|
|
287
|
+
errTags: spec.err
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
function stamp(msg, at) {
|
|
291
|
+
return at === void 0 ? msg : { ...msg, at };
|
|
292
|
+
}
|
|
293
|
+
function detectUpdateForm(update) {
|
|
294
|
+
const firstKey = Object.keys(update)[0];
|
|
295
|
+
if (firstKey === void 0) return "reducer";
|
|
296
|
+
const firstValue = update[firstKey];
|
|
297
|
+
return typeof firstValue === "function" ? "reducer" : "transitions";
|
|
298
|
+
}
|
|
299
|
+
function formOf(machine) {
|
|
300
|
+
return machine.__form ?? detectUpdateForm(machine.update);
|
|
301
|
+
}
|
|
302
|
+
var NoCellError = class extends Error {
|
|
303
|
+
constructor(msgType, stateName, acceptedTypes2) {
|
|
304
|
+
super(
|
|
305
|
+
// The pre-#14 text is kept VERBATIM as a prefix: a caller matching on it
|
|
306
|
+
// keeps matching, and the new clause only ever appends.
|
|
307
|
+
`@demlik/tea: no update cell for msg.type "${msgType}" in state "${stateName}" \u2014 the machine's update does not handle this Msg (an unknown wire msg.type, or a missing cell reached by bypassing the mapped types).` + (acceptedTypes2.length === 0 ? ` This state accepts no Msg at all.` : ` This state accepts: ${acceptedTypes2.map((t) => `"${t}"`).join(", ")}.`)
|
|
308
|
+
);
|
|
309
|
+
this.msgType = msgType;
|
|
310
|
+
this.stateName = stateName;
|
|
311
|
+
this.acceptedTypes = acceptedTypes2;
|
|
312
|
+
}
|
|
313
|
+
msgType;
|
|
314
|
+
stateName;
|
|
315
|
+
acceptedTypes;
|
|
316
|
+
name = "NoCellError";
|
|
317
|
+
_tag = "NoCellError";
|
|
318
|
+
};
|
|
319
|
+
function stateNameOf(state) {
|
|
320
|
+
if (state === void 0 || state === null) return "(no state)";
|
|
321
|
+
if (typeof state === "object" && "type" in state) {
|
|
322
|
+
const t = state.type;
|
|
323
|
+
if (typeof t === "string") return t;
|
|
324
|
+
}
|
|
325
|
+
return "(untagged state)";
|
|
326
|
+
}
|
|
327
|
+
function acceptedTypes(machine, state) {
|
|
328
|
+
if (state === void 0 || state === null) return [];
|
|
329
|
+
if (formOf(machine) === "reducer") {
|
|
330
|
+
return cellKeysOf(machine.update);
|
|
331
|
+
}
|
|
332
|
+
const table = machine.update;
|
|
333
|
+
const row = table[state.type];
|
|
334
|
+
return row === void 0 || row === null ? [] : cellKeysOf(row);
|
|
335
|
+
}
|
|
336
|
+
function cellKeysOf(row) {
|
|
337
|
+
return Object.keys(row).filter(
|
|
338
|
+
(key) => typeof row[key] === "function"
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
function lookupCell(machine, state, msg) {
|
|
342
|
+
if (state === void 0 || state === null) {
|
|
343
|
+
return {
|
|
344
|
+
cell: void 0,
|
|
345
|
+
stateName: stateNameOf(state),
|
|
346
|
+
acceptedTypes: acceptedTypes(machine, state)
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
if (formOf(machine) === "reducer") {
|
|
350
|
+
const record = machine.update;
|
|
351
|
+
const cell2 = record[msg.type];
|
|
352
|
+
const stateName2 = stateNameOf(state);
|
|
353
|
+
return typeof cell2 === "function" ? { cell: cell2, stateName: stateName2 } : {
|
|
354
|
+
cell: void 0,
|
|
355
|
+
stateName: stateName2,
|
|
356
|
+
acceptedTypes: acceptedTypes(machine, state)
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
const table = machine.update;
|
|
360
|
+
const stateKey = state.type;
|
|
361
|
+
const cell = table[stateKey]?.[msg.type];
|
|
362
|
+
const stateName = String(stateKey);
|
|
363
|
+
return typeof cell === "function" ? { cell, stateName } : {
|
|
364
|
+
cell: void 0,
|
|
365
|
+
stateName,
|
|
366
|
+
acceptedTypes: acceptedTypes(machine, state)
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
function applyCell(machine, state, msg) {
|
|
370
|
+
const found = lookupCell(machine, state, msg);
|
|
371
|
+
if (found.cell === void 0) {
|
|
372
|
+
throw new NoCellError(msg.type, found.stateName, found.acceptedTypes);
|
|
373
|
+
}
|
|
374
|
+
return found.cell(state, msg);
|
|
375
|
+
}
|
|
376
|
+
function applyCellChecked(machine, state, msg) {
|
|
377
|
+
if (__DEV__) deepFreeze(state);
|
|
378
|
+
const result = applyCell(machine, state, msg);
|
|
379
|
+
if (__DEV__) assertPureResult(result, msg.type);
|
|
380
|
+
return result;
|
|
381
|
+
}
|
|
382
|
+
function msgKeysOf(machine) {
|
|
383
|
+
const keys = Object.keys(machine.update);
|
|
384
|
+
if (keys.length === 0) return [];
|
|
385
|
+
if (formOf(machine) === "reducer") return keys;
|
|
386
|
+
const table = machine.update;
|
|
387
|
+
const seen = /* @__PURE__ */ new Set();
|
|
388
|
+
const union = [];
|
|
389
|
+
for (const stateKey of keys) {
|
|
390
|
+
const row = table[stateKey];
|
|
391
|
+
if (row === null || row === void 0) continue;
|
|
392
|
+
for (const msgKey of Object.keys(row)) {
|
|
393
|
+
if (seen.has(msgKey)) continue;
|
|
394
|
+
seen.add(msgKey);
|
|
395
|
+
union.push(msgKey);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return union;
|
|
399
|
+
}
|
|
400
|
+
function describeMachine(machine) {
|
|
401
|
+
const msgs = msgKeysOf(machine);
|
|
402
|
+
if (formOf(machine) === "reducer") return { form: "reducer", msgs };
|
|
403
|
+
const table = machine.update;
|
|
404
|
+
const states = Object.keys(table);
|
|
405
|
+
const accepts = {};
|
|
406
|
+
for (const stateKey of states) {
|
|
407
|
+
const row = table[stateKey];
|
|
408
|
+
accepts[stateKey] = row === null || row === void 0 ? [] : Object.keys(row);
|
|
409
|
+
}
|
|
410
|
+
return { form: "transitions", msgs, states, accepts };
|
|
411
|
+
}
|
|
412
|
+
function acceptsOf(machine, stateType) {
|
|
413
|
+
const shape = describeMachine(machine);
|
|
414
|
+
if (shape.form === "reducer") return shape.msgs;
|
|
415
|
+
return shape.accepts[stateType] ?? [];
|
|
416
|
+
}
|
|
417
|
+
var Cmd = {
|
|
418
|
+
/**
|
|
419
|
+
* Declare a typed Cmd constructor (ADR 0014). Returns the builder —
|
|
420
|
+
* `fetch({ url })` yields `{ type: "fetch", url }` — carrying the minted Msg
|
|
421
|
+
* builders `fetch.ok(cmd, value)` / `fetch.err(cmd, error)` and the
|
|
422
|
+
* declaration the runtime edge parses against. `Settled<typeof fetch>` is
|
|
423
|
+
* the two-arm Msg union it settles with; `defineMachine({ cmds: [fetch] })`
|
|
424
|
+
* folds that union into the machine's `M`.
|
|
425
|
+
*
|
|
426
|
+
* const fetch = Cmd.define("fetch", {
|
|
427
|
+
* input: z.object({ url: z.string() }),
|
|
428
|
+
* ok: z.object({ status: z.number(), body: z.string() }),
|
|
429
|
+
* err: ["not_found", "timeout"],
|
|
430
|
+
* requirements: Cmd.requirements<{ http: Http }>(),
|
|
431
|
+
* });
|
|
432
|
+
*
|
|
433
|
+
* `err` is the `_tag` list the handler may settle with; the runtime adds
|
|
434
|
+
* `malformed_result` for an `_ok` value the `ok` schema rejects. `requirements`
|
|
435
|
+
* names the `Ctx` slice the handler reads — `run` refuses a ctx without it.
|
|
436
|
+
*
|
|
437
|
+
* A Cmd must not wait; see `DepKeyedSub` for anything that watches.
|
|
438
|
+
*/
|
|
439
|
+
define: defineCmd,
|
|
440
|
+
/**
|
|
441
|
+
* Name a Cmd's `R` — the `Ctx` slice its handler reads. A phantom: nothing
|
|
442
|
+
* is built, nothing is checked at runtime; the type is what `run` reads.
|
|
443
|
+
*/
|
|
444
|
+
requirements: () => ({}),
|
|
445
|
+
/**
|
|
446
|
+
* The empty Cmd array. Typed `readonly never[]` so it's assignable to any
|
|
447
|
+
* `readonly C[]` for any `C extends Cmd`. Use in `init` returns and
|
|
448
|
+
* Transitions cells that emit zero effects:
|
|
449
|
+
*
|
|
450
|
+
* init: (loaded) => [loaded ?? initial, Cmd.none],
|
|
451
|
+
* tick: (state) => [state, Cmd.none],
|
|
452
|
+
*
|
|
453
|
+
* Elm's `Cmd.none` analogue. Cultural signal alongside the runtime help:
|
|
454
|
+
* `[state, Cmd.none]` reads as intent ("this transition emits nothing"),
|
|
455
|
+
* `[state, []]` reads as "empty array of what".
|
|
456
|
+
*
|
|
457
|
+
* Frozen at runtime so a downstream consumer can't `.push()` into the
|
|
458
|
+
* shared reference.
|
|
459
|
+
*/
|
|
460
|
+
none: Object.freeze([]),
|
|
461
|
+
/**
|
|
462
|
+
* Flat concat of cmd arrays. Use when a cell composes effects from
|
|
463
|
+
* multiple conditional sources:
|
|
464
|
+
*
|
|
465
|
+
* return [next, Cmd.batch(
|
|
466
|
+
* Cmd.whenDefined(state.queueItemId, (id) => ({ type: "complete", id })),
|
|
467
|
+
* Cmd.when(state.windowId !== undefined, { type: "close_window", windowId }),
|
|
468
|
+
* [{ type: "detach_debugger", tabId: state.tabId }],
|
|
469
|
+
* )];
|
|
470
|
+
*
|
|
471
|
+
* `<const C>` keeps inline cmd literals' discriminants narrow (same
|
|
472
|
+
* rationale as `when` / `whenDefined` above).
|
|
473
|
+
*/
|
|
474
|
+
batch: (...arrs) => {
|
|
475
|
+
const out = [];
|
|
476
|
+
for (const arr of arrs) out.push(...arr);
|
|
477
|
+
return out;
|
|
478
|
+
},
|
|
479
|
+
/**
|
|
480
|
+
* Emit `cmd` wrapped in a single-element array iff `cond` is true.
|
|
481
|
+
* Otherwise return the empty array. Spreads cleanly into the cmds array
|
|
482
|
+
* returned by a Transitions cell.
|
|
483
|
+
*
|
|
484
|
+
* `const C` (TypeScript 5.0+) keeps the inferred `type:` discriminator
|
|
485
|
+
* literal narrow when called with an object literal — so `Cmd.when(b,
|
|
486
|
+
* { type: "x", ... })` infers as `{ type: "x", ... }`, not `{ type:
|
|
487
|
+
* string, ... }`, and stays assignable to a discriminated-union arm
|
|
488
|
+
* without `as const` at the call site.
|
|
489
|
+
*/
|
|
490
|
+
when: (cond, cmd) => cond ? [cmd] : [],
|
|
491
|
+
/**
|
|
492
|
+
* If `value` is defined, call `build(value)` and emit the resulting cmd
|
|
493
|
+
* wrapped in a single-element array. If `value` is `undefined`, return
|
|
494
|
+
* the empty array. `value` is narrowed to `T` inside `build`.
|
|
495
|
+
*
|
|
496
|
+
* `const C` on the return type keeps the callback's object-literal
|
|
497
|
+
* `type:` field narrow (see `when` above for the full rationale).
|
|
498
|
+
*/
|
|
499
|
+
whenDefined: (value2, build) => value2 !== void 0 ? [build(value2)] : []
|
|
500
|
+
};
|
|
501
|
+
function subId(s) {
|
|
502
|
+
return s;
|
|
503
|
+
}
|
|
504
|
+
function depsInactive(deps) {
|
|
505
|
+
return deps === null || deps === void 0;
|
|
506
|
+
}
|
|
507
|
+
function structuralHash(deps) {
|
|
508
|
+
return stableStringify(deps);
|
|
509
|
+
}
|
|
510
|
+
function stableStringify(value2) {
|
|
511
|
+
if (value2 === null) return "null";
|
|
512
|
+
const t = typeof value2;
|
|
513
|
+
if (t === "string") return JSON.stringify(value2);
|
|
514
|
+
if (t === "number" || t === "boolean") return String(value2);
|
|
515
|
+
if (t === "undefined") return "undefined";
|
|
516
|
+
if (t === "function") {
|
|
517
|
+
throw new Error(
|
|
518
|
+
"@demlik/tea: structuralHash received a function in `deps`. A dep-keyed Sub's `deps` must be a plain state slice (string / number / boolean / null / array / object), not a closure \u2014 see invariant 1."
|
|
519
|
+
);
|
|
520
|
+
}
|
|
521
|
+
if (Array.isArray(value2)) {
|
|
522
|
+
return `[${value2.map(stableStringify).join(",")}]`;
|
|
523
|
+
}
|
|
524
|
+
if (t === "object") {
|
|
525
|
+
const proto = Object.getPrototypeOf(value2);
|
|
526
|
+
if (proto !== Object.prototype && proto !== null) {
|
|
527
|
+
const ctor = value2.constructor;
|
|
528
|
+
const label = ctor?.name ?? "object";
|
|
529
|
+
throw new Error(
|
|
530
|
+
`@demlik/tea: structuralHash received a non-plain object (${label}) in \`deps\`. A \`Date\`, \`Map\`, \`Set\`, \`Error\` or class instance carries no own enumerable properties, so every one of them would hash to the same id as \`{}\` \u2014 a silent collision, not a wrong-looking key. Project it to plain data first (e.g. \`startedAt.toISOString()\`, \`[...set].sort()\`) \u2014 see invariant 1.`
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
const obj = value2;
|
|
534
|
+
const keys = Object.keys(obj).sort();
|
|
535
|
+
return `{${keys.map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`).join(",")}}`;
|
|
536
|
+
}
|
|
537
|
+
throw new Error(
|
|
538
|
+
`@demlik/tea: structuralHash received an unsupported \`deps\` value of type "${t}". Use plain JSON-compatible data for a dep-keyed Sub's \`deps\`.`
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
function foldUpdates(machine, initialState, msgs) {
|
|
542
|
+
let state = initialState;
|
|
543
|
+
const cmds = [];
|
|
544
|
+
for (const msg of msgs) {
|
|
545
|
+
const [next, emitted] = applyCellChecked(machine, state, msg);
|
|
546
|
+
state = next;
|
|
547
|
+
cmds.push(...emitted);
|
|
548
|
+
}
|
|
549
|
+
return { state, cmds };
|
|
550
|
+
}
|
|
551
|
+
function foldMsgs(machine, base, msgs) {
|
|
552
|
+
return foldUpdates(machine, base, msgs).state;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// src/internal/prediction/index.ts
|
|
556
|
+
var tagSeq = (seq, value2) => ({ seq, value: value2 });
|
|
557
|
+
var ack = (lastAppliedSeq) => ({ lastAppliedSeq });
|
|
558
|
+
var NO_ACK = -1;
|
|
559
|
+
var initAck = () => ack(NO_ACK);
|
|
560
|
+
var partitionByAck = (buffer, ackOrSeq) => {
|
|
561
|
+
const lastAppliedSeq = typeof ackOrSeq === "number" ? ackOrSeq : ackOrSeq.lastAppliedSeq;
|
|
562
|
+
const acked = [];
|
|
563
|
+
const pending = [];
|
|
564
|
+
for (const item of buffer) {
|
|
565
|
+
if (item.seq <= lastAppliedSeq) {
|
|
566
|
+
acked.push(item);
|
|
567
|
+
} else {
|
|
568
|
+
pending.push(item);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
return { acked, pending };
|
|
572
|
+
};
|
|
573
|
+
var nextSeq = (buffer) => buffer.reduce((max, item) => item.seq > max ? item.seq : max, -1) + 1;
|
|
574
|
+
function reconcile(machine, authoritativeState, lastAppliedSeq, pending) {
|
|
575
|
+
const { pending: unacked } = partitionByAck(pending, lastAppliedSeq);
|
|
576
|
+
return foldMsgs(
|
|
577
|
+
machine,
|
|
578
|
+
authoritativeState,
|
|
579
|
+
unacked.map((tagged) => tagged.value)
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
function absurd(x) {
|
|
583
|
+
throw new Error(`unreachable: ${JSON.stringify(x)}`);
|
|
584
|
+
}
|
|
585
|
+
var noop = (state, _msg) => [state, []];
|
|
586
|
+
var definedPortNames = /* @__PURE__ */ new Set();
|
|
587
|
+
var PortNameCollisionError = class extends Error {
|
|
588
|
+
name = "PortNameCollisionError";
|
|
589
|
+
_tag = "PortNameCollisionError";
|
|
590
|
+
constructor(portName) {
|
|
591
|
+
super(
|
|
592
|
+
`definePort: a port named "${portName}" was already defined. Each definePort call must use a unique name. If two modules need the same port, export it from one module and import it.`
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
};
|
|
596
|
+
var SubIdCollisionError = class extends Error {
|
|
597
|
+
name = "SubIdCollisionError";
|
|
598
|
+
_tag = "SubIdCollisionError";
|
|
599
|
+
constructor(id, declaredType, conflictingType) {
|
|
600
|
+
super(
|
|
601
|
+
`@demlik/tea: Sub.id collision: id="${id}" declared as type="${declaredType}" and type="${conflictingType}"`
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
function __resetPortRegistry() {
|
|
606
|
+
definedPortNames.clear();
|
|
607
|
+
}
|
|
608
|
+
var QuiescenceTimeoutError = class extends Error {
|
|
609
|
+
constructor(iterations) {
|
|
610
|
+
super(
|
|
611
|
+
`@demlik/tea: idle() did not reach quiescence after ${iterations} iterations \u2014 the dispatch tail kept advancing. The machine is likely livelocking (an interpret handler enqueues a follow-up Msg that enqueues another, without end). Bound the follow-up chain in the reducer, or stop the runtime.`
|
|
612
|
+
);
|
|
613
|
+
this.iterations = iterations;
|
|
614
|
+
}
|
|
615
|
+
iterations;
|
|
616
|
+
name = "QuiescenceTimeoutError";
|
|
617
|
+
_tag = "QuiescenceTimeoutError";
|
|
618
|
+
};
|
|
619
|
+
var DriveFailedError = class extends Error {
|
|
620
|
+
constructor(state) {
|
|
621
|
+
super(
|
|
622
|
+
`@demlik/tea: driveToDone ended on a failed State \u2014 the run reached a terminal State the \`failed\` predicate marks as a failure. Read \`error.state\` for the final Model.`
|
|
623
|
+
);
|
|
624
|
+
this.state = state;
|
|
625
|
+
}
|
|
626
|
+
state;
|
|
627
|
+
name = "DriveFailedError";
|
|
628
|
+
_tag = "DriveFailedError";
|
|
629
|
+
};
|
|
630
|
+
var DriveStalledError = class extends Error {
|
|
631
|
+
constructor(state) {
|
|
632
|
+
super(
|
|
633
|
+
`@demlik/tea: driveToDone stalled \u2014 the start chain quiesced on a State that is neither terminal nor failed, with no live Sub and no Cmd in flight to move it further. Read \`error.state\` for the State it parked on; if a later transition was expected, the machine needs a Sub (or a Cmd) that delivers it.`
|
|
634
|
+
);
|
|
635
|
+
this.state = state;
|
|
636
|
+
}
|
|
637
|
+
state;
|
|
638
|
+
name = "DriveStalledError";
|
|
639
|
+
_tag = "DriveStalledError";
|
|
640
|
+
};
|
|
641
|
+
var RuntimeDiscardNotice = class extends Error {
|
|
642
|
+
};
|
|
643
|
+
var RuntimeDiscardedError = class extends RuntimeDiscardNotice {
|
|
644
|
+
constructor(pendingCmds) {
|
|
645
|
+
super(
|
|
646
|
+
`@demlik/tea: runtime stopped with ${pendingCmds} Cmd(s) in flight \u2014 their results will reach no listener. In React this is usually a ctx-identity change rebuilding useMachine's runtime mid-flight: stabilize the ctx (useMemo / useState) so the runtime outlives the Cmds it started. An intentional teardown (unmount, navigation) can silence this with a run({ onError }) sink that ignores phase: "discard".`
|
|
647
|
+
);
|
|
648
|
+
this.pendingCmds = pendingCmds;
|
|
649
|
+
}
|
|
650
|
+
pendingCmds;
|
|
651
|
+
name = "RuntimeDiscardedError";
|
|
652
|
+
_tag = "RuntimeDiscardedError";
|
|
653
|
+
};
|
|
654
|
+
var IdentityDropNotice = class extends RuntimeDiscardNotice {
|
|
655
|
+
constructor(msgType) {
|
|
656
|
+
super(
|
|
657
|
+
`@demlik/tea: Msg "${msgType}" was addressed to a different instance than this state owns and was dropped before \`update\` ran \u2014 the machine's \`identity\` filter working as declared. If this Msg was meant for THIS instance, its \`ofMsg\` projection disagrees with \`ofState\`; if the instance is being reused across runs, route the message to the run that owns it.`
|
|
658
|
+
);
|
|
659
|
+
this.msgType = msgType;
|
|
660
|
+
}
|
|
661
|
+
msgType;
|
|
662
|
+
name = "IdentityDropNotice";
|
|
663
|
+
_tag = "IdentityDropNotice";
|
|
664
|
+
};
|
|
665
|
+
var DisposeTimeoutNotice = class extends RuntimeDiscardNotice {
|
|
666
|
+
constructor(pendingDisposals, timeoutMs) {
|
|
667
|
+
super(
|
|
668
|
+
`@demlik/tea: stop() gave up waiting for ${pendingDisposals} async teardown(s) after ${timeoutMs}ms \u2014 the resources they release may still be open. Make \`release\` / the Sub cleanup settle (bound its own IO), or raise run({ disposeTimeoutMs }).`
|
|
669
|
+
);
|
|
670
|
+
this.pendingDisposals = pendingDisposals;
|
|
671
|
+
this.timeoutMs = timeoutMs;
|
|
672
|
+
}
|
|
673
|
+
pendingDisposals;
|
|
674
|
+
timeoutMs;
|
|
675
|
+
name = "DisposeTimeoutNotice";
|
|
676
|
+
_tag = "DisposeTimeoutNotice";
|
|
677
|
+
};
|
|
678
|
+
var DispatchDiscardedError = class extends RuntimeDiscardNotice {
|
|
679
|
+
constructor(msgType) {
|
|
680
|
+
super(
|
|
681
|
+
`@demlik/tea: Msg "${msgType}" arrived while the runtime was stopping and was discarded \u2014 stop() refuses new work so the drain terminates. It is the result of a Cmd that outlived its runtime; keep the runtime alive until the Cmd settles (in React: stabilize useMachine's ctx) if the transition matters.`
|
|
682
|
+
);
|
|
683
|
+
this.msgType = msgType;
|
|
684
|
+
}
|
|
685
|
+
msgType;
|
|
686
|
+
name = "DispatchDiscardedError";
|
|
687
|
+
_tag = "DispatchDiscardedError";
|
|
688
|
+
};
|
|
689
|
+
function definePort(name) {
|
|
690
|
+
let isHmr = false;
|
|
691
|
+
try {
|
|
692
|
+
const meta = import.meta;
|
|
693
|
+
isHmr = meta?.hot !== void 0 && meta?.hot !== null;
|
|
694
|
+
} catch {
|
|
695
|
+
isHmr = false;
|
|
696
|
+
}
|
|
697
|
+
if (!isHmr && definedPortNames.has(name)) {
|
|
698
|
+
throw new PortNameCollisionError(name);
|
|
699
|
+
}
|
|
700
|
+
definedPortNames.add(name);
|
|
701
|
+
return { __brand: "port", name };
|
|
702
|
+
}
|
|
703
|
+
function isFencedStore(store) {
|
|
704
|
+
return "fenced" in store && store.fenced === true;
|
|
705
|
+
}
|
|
706
|
+
var StoreConflictError = class extends Error {
|
|
707
|
+
constructor(expectedVersion, actualVersion) {
|
|
708
|
+
super(
|
|
709
|
+
`@demlik/tea: store conflict \u2014 expected version ${expectedVersion}, found ${actualVersion}. Another process has written this state; this run is no longer the single writer and has stopped.`
|
|
710
|
+
);
|
|
711
|
+
this.expectedVersion = expectedVersion;
|
|
712
|
+
this.actualVersion = actualVersion;
|
|
713
|
+
}
|
|
714
|
+
expectedVersion;
|
|
715
|
+
actualVersion;
|
|
716
|
+
name = "StoreConflictError";
|
|
717
|
+
_tag = "store_conflict";
|
|
718
|
+
};
|
|
719
|
+
function schemaMigrate(schema, upcast = (raw) => raw) {
|
|
720
|
+
return (raw) => {
|
|
721
|
+
let migrated;
|
|
722
|
+
try {
|
|
723
|
+
migrated = upcast(raw);
|
|
724
|
+
} catch {
|
|
725
|
+
return null;
|
|
726
|
+
}
|
|
727
|
+
const parsed = schema.safeParse(migrated);
|
|
728
|
+
return parsed.success ? parsed.data : null;
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
function defineMachine(m) {
|
|
732
|
+
if (m.__form === void 0) {
|
|
733
|
+
Object.defineProperty(m, "__form", {
|
|
734
|
+
value: detectUpdateForm(m.update),
|
|
735
|
+
enumerable: false,
|
|
736
|
+
writable: false,
|
|
737
|
+
configurable: true
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
return m;
|
|
741
|
+
}
|
|
742
|
+
function asReducer(reducer) {
|
|
743
|
+
return reducer;
|
|
744
|
+
}
|
|
745
|
+
function replay(machine, opts) {
|
|
746
|
+
const loaded = opts.loaded ?? null;
|
|
747
|
+
const [initialState, initCmds] = machine.init(loaded, opts.ctx);
|
|
748
|
+
if (loaded !== null && initCmds.length > 0) {
|
|
749
|
+
throw new Error(
|
|
750
|
+
"TEA contract violation: machine.init must return [state, []] (no Cmds) when `loaded` is non-null. Init's rehydrate branch is a pure state passthrough \u2014 the migration/parse boundary, not the boot-effect hook.\n\nRoutes for boot effects:\n - Stateless infrastructure (e.g. chrome.alarms ensure) \u2192 host module top level, outside TEA.\n - State-conditional resume (e.g. re-attach a session) \u2192 a `boot` Msg dispatched once from the host after `run(...)` returns, handled in update.\n\nSee .patterns/tea/tea-invariants.md (Invariant 2)."
|
|
751
|
+
);
|
|
752
|
+
}
|
|
753
|
+
const { state, cmds: foldedCmds } = foldUpdates(
|
|
754
|
+
machine,
|
|
755
|
+
initialState,
|
|
756
|
+
opts.msgs
|
|
757
|
+
);
|
|
758
|
+
const cmds = [...initCmds, ...foldedCmds];
|
|
759
|
+
const subs = machine.subscriptions ? [...machine.subscriptions(state)] : [];
|
|
760
|
+
const depSubs = [];
|
|
761
|
+
if (machine.subs) {
|
|
762
|
+
for (const [index, entry] of machine.subs.entries()) {
|
|
763
|
+
const deps = entry.deps(state);
|
|
764
|
+
if (!depsInactive(deps))
|
|
765
|
+
depSubs.push({ index, id: structuralHash(deps) });
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
return { state, cmds, subs, depSubs };
|
|
769
|
+
}
|
|
770
|
+
function wrapDetached(handler) {
|
|
771
|
+
return (cmd, ctx, dispatch) => {
|
|
772
|
+
if (dispatch === void 0) {
|
|
773
|
+
throw new Error(
|
|
774
|
+
"@demlik/tea: a wrapDetached handler was invoked without the injected dispatch. The kernel always supplies it; call the handler through the runtime, not directly."
|
|
775
|
+
);
|
|
776
|
+
}
|
|
777
|
+
return handler(cmd, ctx, dispatch);
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
function tryApplyCell(machine, state, msg) {
|
|
781
|
+
const found = lookupCell(machine, state, msg);
|
|
782
|
+
if (found.cell === void 0) {
|
|
783
|
+
return Result.err(
|
|
784
|
+
new NoCellError(msg.type, found.stateName, found.acceptedTypes)
|
|
785
|
+
);
|
|
786
|
+
}
|
|
787
|
+
return Result.ok(found.cell(state, msg));
|
|
788
|
+
}
|
|
789
|
+
function tryFoldMsgs(machine, base, msgs) {
|
|
790
|
+
let state = base;
|
|
791
|
+
for (const [index, msg] of msgs.entries()) {
|
|
792
|
+
if (__DEV__) deepFreeze(state);
|
|
793
|
+
const stepped = tryApplyCell(machine, state, msg);
|
|
794
|
+
if (Result.isError(stepped)) {
|
|
795
|
+
return Result.err({ index, msg, error: stepped.error });
|
|
796
|
+
}
|
|
797
|
+
if (__DEV__) assertPureResult(stepped.value, msg.type);
|
|
798
|
+
state = stepped.value[0];
|
|
799
|
+
}
|
|
800
|
+
return Result.ok(state);
|
|
801
|
+
}
|
|
802
|
+
function settle(def, work) {
|
|
803
|
+
const builders = def;
|
|
804
|
+
return async (cmd, ctx) => {
|
|
805
|
+
const result = await work(cmd, ctx);
|
|
806
|
+
return result.match({
|
|
807
|
+
ok: (value2) => builders.ok(cmd, value2),
|
|
808
|
+
err: (error) => builders.err(cmd, error)
|
|
809
|
+
});
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
function tryInterpret(work, onOk, onErr) {
|
|
813
|
+
return async (cmd, ctx) => {
|
|
814
|
+
const result = await Result.tryPromise({
|
|
815
|
+
try: () => work(cmd, ctx),
|
|
816
|
+
catch: (error) => error
|
|
817
|
+
});
|
|
818
|
+
return result.match({
|
|
819
|
+
ok: (value2) => onOk(value2, cmd),
|
|
820
|
+
err: (error) => onErr(error, cmd)
|
|
821
|
+
});
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// src/run.ts
|
|
826
|
+
function defaultOnError(error, _context) {
|
|
827
|
+
if (error instanceof RuntimeDiscardNotice) {
|
|
828
|
+
console.warn(error);
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
831
|
+
setTimeout(() => {
|
|
832
|
+
throw error;
|
|
833
|
+
}, 0);
|
|
834
|
+
}
|
|
835
|
+
function normalizeSupervision(supervision) {
|
|
836
|
+
if (supervision === void 0) return { strategy: "stop" };
|
|
837
|
+
if (typeof supervision === "string") return { strategy: supervision };
|
|
838
|
+
return supervision;
|
|
839
|
+
}
|
|
840
|
+
var liveWork = /* @__PURE__ */ Symbol("demlik-tea.liveWork");
|
|
841
|
+
function run(machine, opts) {
|
|
842
|
+
const { store } = opts;
|
|
843
|
+
const fenced = store !== void 0 && isFencedStore(store) ? store : null;
|
|
844
|
+
let fencedVersion = 0;
|
|
845
|
+
async function readFenced(from) {
|
|
846
|
+
const read = await from.loadFenced();
|
|
847
|
+
fencedVersion = read.version;
|
|
848
|
+
return read.raw;
|
|
849
|
+
}
|
|
850
|
+
async function persist(next) {
|
|
851
|
+
if (fenced) {
|
|
852
|
+
fencedVersion = await fenced.saveFenced(next, fencedVersion);
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
if (store) await store.save(next);
|
|
856
|
+
}
|
|
857
|
+
const provided = isProvided(
|
|
858
|
+
opts.ctx
|
|
859
|
+
) ? opts.ctx : null;
|
|
860
|
+
let ctx = provided ? {} : opts.ctx ?? {};
|
|
861
|
+
let releaseProvided = null;
|
|
862
|
+
const clock = opts.clock ?? Date.now;
|
|
863
|
+
const idleCap = opts.__idleCap ?? 1e5;
|
|
864
|
+
const disposeTimeoutMs = opts.disposeTimeoutMs ?? 5e3;
|
|
865
|
+
const projectEvents = opts.events ?? (() => []);
|
|
866
|
+
const isTerminal = opts.terminal ?? (() => false);
|
|
867
|
+
const onError = opts.onError ?? defaultOnError;
|
|
868
|
+
const reportError = (error, context) => {
|
|
869
|
+
try {
|
|
870
|
+
onError(error, context);
|
|
871
|
+
} catch (sinkError) {
|
|
872
|
+
defaultOnError(sinkError);
|
|
873
|
+
}
|
|
874
|
+
};
|
|
875
|
+
function fanout(items, phase, fn) {
|
|
876
|
+
for (const item of items) {
|
|
877
|
+
try {
|
|
878
|
+
fn(item);
|
|
879
|
+
} catch (err) {
|
|
880
|
+
reportError(err, { phase });
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
const supervision = normalizeSupervision(opts.supervision);
|
|
885
|
+
let state;
|
|
886
|
+
let bootError = null;
|
|
887
|
+
let gate = "open";
|
|
888
|
+
let inFlightCmds = 0;
|
|
889
|
+
const subRegistry = /* @__PURE__ */ new Map();
|
|
890
|
+
const depSubRegistry = /* @__PURE__ */ new Map();
|
|
891
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
892
|
+
const observers = /* @__PURE__ */ new Set();
|
|
893
|
+
const bootHandlers = /* @__PURE__ */ new Set();
|
|
894
|
+
let booted = false;
|
|
895
|
+
const eventHandlers = /* @__PURE__ */ new Map();
|
|
896
|
+
const doneWaiters = /* @__PURE__ */ new Set();
|
|
897
|
+
const portRegistry = /* @__PURE__ */ new Map();
|
|
898
|
+
function portEmit(port, value2) {
|
|
899
|
+
const subscribers = portRegistry.get(port);
|
|
900
|
+
if (!subscribers || subscribers.size === 0) return;
|
|
901
|
+
fanout(subscribers, "port-emit", (listener) => listener(value2));
|
|
902
|
+
}
|
|
903
|
+
const settleAtEdge = cmdEdgeOver(machine.cmds ?? [], clock);
|
|
904
|
+
let augmentedCtx = buildAugmentedCtx();
|
|
905
|
+
function buildAugmentedCtx() {
|
|
906
|
+
return Object.assign({}, ctx, {
|
|
907
|
+
emit: portEmit,
|
|
908
|
+
[cmdEdge]: settleAtEdge,
|
|
909
|
+
[detachWork]: detachInFlight
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
let tail = Promise.resolve();
|
|
913
|
+
function stopSubs(ids) {
|
|
914
|
+
for (const id of ids) {
|
|
915
|
+
const cleanup = subRegistry.get(id);
|
|
916
|
+
if (cleanup === void 0) continue;
|
|
917
|
+
try {
|
|
918
|
+
trackDisposal(cleanup());
|
|
919
|
+
} catch (err) {
|
|
920
|
+
reportError(err, { phase: "sub-cleanup" });
|
|
921
|
+
}
|
|
922
|
+
subRegistry.delete(id);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
const pendingDisposals = /* @__PURE__ */ new Set();
|
|
926
|
+
function trackDisposal(result) {
|
|
927
|
+
if (!(result instanceof Promise)) return;
|
|
928
|
+
const settling = result.catch((err) => {
|
|
929
|
+
reportError(err, { phase: "sub-cleanup" });
|
|
930
|
+
}).finally(() => {
|
|
931
|
+
pendingDisposals.delete(settling);
|
|
932
|
+
});
|
|
933
|
+
pendingDisposals.add(settling);
|
|
934
|
+
}
|
|
935
|
+
async function drainDisposals() {
|
|
936
|
+
if (pendingDisposals.size === 0) return;
|
|
937
|
+
const outstanding = [...pendingDisposals];
|
|
938
|
+
let timer;
|
|
939
|
+
try {
|
|
940
|
+
const outcome = await Promise.race([
|
|
941
|
+
Promise.all(outstanding).then(() => "settled"),
|
|
942
|
+
new Promise((resolve) => {
|
|
943
|
+
timer = setTimeout(() => resolve("timeout"), disposeTimeoutMs);
|
|
944
|
+
})
|
|
945
|
+
]);
|
|
946
|
+
if (outcome === "timeout") {
|
|
947
|
+
reportError(
|
|
948
|
+
new DisposeTimeoutNotice(outstanding.length, disposeTimeoutMs),
|
|
949
|
+
{ phase: "discard" }
|
|
950
|
+
);
|
|
951
|
+
}
|
|
952
|
+
} finally {
|
|
953
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
function disposeDepSubs(indices) {
|
|
957
|
+
for (const index of indices) {
|
|
958
|
+
const running = depSubRegistry.get(index);
|
|
959
|
+
if (running === void 0) continue;
|
|
960
|
+
try {
|
|
961
|
+
trackDisposal(running.dispose());
|
|
962
|
+
} catch (err) {
|
|
963
|
+
reportError(err, { phase: "sub-cleanup" });
|
|
964
|
+
}
|
|
965
|
+
depSubRegistry.delete(index);
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
function reconcileDepSubs() {
|
|
969
|
+
let firstError = null;
|
|
970
|
+
const subs = machine.subs;
|
|
971
|
+
if (!subs) return firstError;
|
|
972
|
+
for (const [i, entry] of subs.entries()) {
|
|
973
|
+
let deps;
|
|
974
|
+
let id;
|
|
975
|
+
try {
|
|
976
|
+
deps = entry.deps(state);
|
|
977
|
+
if (depsInactive(deps)) {
|
|
978
|
+
disposeDepSubs([i]);
|
|
979
|
+
continue;
|
|
980
|
+
}
|
|
981
|
+
id = structuralHash(deps);
|
|
982
|
+
} catch (err) {
|
|
983
|
+
if (firstError === null) firstError = err;
|
|
984
|
+
continue;
|
|
985
|
+
}
|
|
986
|
+
const running = depSubRegistry.get(i);
|
|
987
|
+
if (running !== void 0 && running.runningId === id) {
|
|
988
|
+
continue;
|
|
989
|
+
}
|
|
990
|
+
disposeDepSubs([i]);
|
|
991
|
+
try {
|
|
992
|
+
const dispose = entry.source(state, dispatchUnawaited, ctx);
|
|
993
|
+
depSubRegistry.set(i, { runningId: id, dispose });
|
|
994
|
+
} catch (err) {
|
|
995
|
+
if (firstError === null) firstError = err;
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
return firstError;
|
|
999
|
+
}
|
|
1000
|
+
function reconcileSubs() {
|
|
1001
|
+
const depError = reconcileDepSubs();
|
|
1002
|
+
if (!machine.subscriptions) {
|
|
1003
|
+
if (depError !== null) throw depError;
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
1006
|
+
const desired = machine.subscriptions(state);
|
|
1007
|
+
const desiredIds = /* @__PURE__ */ new Set();
|
|
1008
|
+
const desiredTypeById = /* @__PURE__ */ new Map();
|
|
1009
|
+
for (const sub of desired) {
|
|
1010
|
+
const existing = desiredTypeById.get(sub.id);
|
|
1011
|
+
if (existing !== void 0 && existing !== sub.type) {
|
|
1012
|
+
throw new SubIdCollisionError(sub.id, existing, sub.type);
|
|
1013
|
+
}
|
|
1014
|
+
desiredTypeById.set(sub.id, sub.type);
|
|
1015
|
+
}
|
|
1016
|
+
for (const sub of desired) desiredIds.add(sub.id);
|
|
1017
|
+
stopSubs([...subRegistry.keys()].filter((id) => !desiredIds.has(id)));
|
|
1018
|
+
let firstStartError = depError;
|
|
1019
|
+
for (const sub of desired) {
|
|
1020
|
+
if (subRegistry.has(sub.id)) continue;
|
|
1021
|
+
const handler = machine.subscribe?.[sub.type];
|
|
1022
|
+
if (!handler) {
|
|
1023
|
+
continue;
|
|
1024
|
+
}
|
|
1025
|
+
try {
|
|
1026
|
+
const cleanup = handler(
|
|
1027
|
+
sub,
|
|
1028
|
+
ctx,
|
|
1029
|
+
dispatchUnawaited
|
|
1030
|
+
);
|
|
1031
|
+
subRegistry.set(sub.id, cleanup);
|
|
1032
|
+
} catch (err) {
|
|
1033
|
+
if (firstStartError === null) firstStartError = err;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
if (firstStartError !== null) throw firstStartError;
|
|
1037
|
+
}
|
|
1038
|
+
const interpretMap = machine.interpret ?? {};
|
|
1039
|
+
const dispatchUnawaited = (msg) => {
|
|
1040
|
+
enqueueDispatch(msg).catch(reportUndelivered);
|
|
1041
|
+
};
|
|
1042
|
+
function reportUndelivered(error) {
|
|
1043
|
+
reportError(error, {
|
|
1044
|
+
phase: error instanceof DispatchDiscardedError ? "discard" : "follow-up"
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
function trackInFlight(work) {
|
|
1048
|
+
inFlightCmds++;
|
|
1049
|
+
return Promise.resolve(work).finally(() => {
|
|
1050
|
+
inFlightCmds--;
|
|
1051
|
+
});
|
|
1052
|
+
}
|
|
1053
|
+
function detachInFlight(work) {
|
|
1054
|
+
const tracked = trackInFlight(work);
|
|
1055
|
+
tracked.catch(reportUndelivered);
|
|
1056
|
+
tail = tail.then(async () => {
|
|
1057
|
+
await tracked;
|
|
1058
|
+
}).catch(() => {
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
1061
|
+
async function runInterpret(cmds) {
|
|
1062
|
+
for (const cmd of cmds) {
|
|
1063
|
+
const handler = interpretMap[cmd.type];
|
|
1064
|
+
if (!handler) continue;
|
|
1065
|
+
const returned = await trackInFlight(
|
|
1066
|
+
handler(
|
|
1067
|
+
cmd,
|
|
1068
|
+
// The handler's cell demands `Ctx & RequirementsOf<its Cmd>`; the runtime
|
|
1069
|
+
// holds `Ctx & RequiredCtx<C>` — the intersection over EVERY Cmd, so
|
|
1070
|
+
// a superset of any one cell's slice. The widening is sound by
|
|
1071
|
+
// construction; `tsc` cannot see through the generic `C` to prove it.
|
|
1072
|
+
augmentedCtx,
|
|
1073
|
+
dispatchUnawaited
|
|
1074
|
+
)
|
|
1075
|
+
);
|
|
1076
|
+
const follow = settleAtEdge(cmd, returned);
|
|
1077
|
+
if (follow !== void 0 && follow !== null) {
|
|
1078
|
+
enqueueDispatch(follow).catch(reportUndelivered);
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
function fireListeners() {
|
|
1083
|
+
fanout(listeners, "listener", (listener) => listener());
|
|
1084
|
+
}
|
|
1085
|
+
function fireObservers(msg) {
|
|
1086
|
+
if (observers.size === 0 || state === void 0) return;
|
|
1087
|
+
const snapshot = state;
|
|
1088
|
+
fanout(observers, "observer", (observer) => observer(msg, snapshot));
|
|
1089
|
+
}
|
|
1090
|
+
function fireEvents(msg) {
|
|
1091
|
+
if (eventHandlers.size === 0 || state === void 0) return;
|
|
1092
|
+
let events;
|
|
1093
|
+
try {
|
|
1094
|
+
events = projectEvents(msg, state);
|
|
1095
|
+
} catch (err) {
|
|
1096
|
+
reportError(err, { phase: "event" });
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
1099
|
+
for (const event of events) {
|
|
1100
|
+
const bucket = eventHandlers.get(event.type);
|
|
1101
|
+
if (bucket === void 0) continue;
|
|
1102
|
+
fanout(bucket, "event", (handler) => handler(event));
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
function fireBoot() {
|
|
1106
|
+
booted = true;
|
|
1107
|
+
if (bootHandlers.size === 0 || state === void 0) return;
|
|
1108
|
+
const snapshot = state;
|
|
1109
|
+
fanout(bootHandlers, "boot", (handler) => handler(snapshot));
|
|
1110
|
+
}
|
|
1111
|
+
function settleDoneWaiters() {
|
|
1112
|
+
if (doneWaiters.size === 0 || state === void 0) return;
|
|
1113
|
+
if (!isTerminal(state)) return;
|
|
1114
|
+
const snapshot = state;
|
|
1115
|
+
const parked = [...doneWaiters];
|
|
1116
|
+
doneWaiters.clear();
|
|
1117
|
+
for (const resolve of parked) resolve(snapshot);
|
|
1118
|
+
}
|
|
1119
|
+
async function commit(next, msg, cmds) {
|
|
1120
|
+
state = next;
|
|
1121
|
+
await persist(next);
|
|
1122
|
+
reconcileSubs();
|
|
1123
|
+
await runInterpret(cmds);
|
|
1124
|
+
fireListeners();
|
|
1125
|
+
fireObservers(msg);
|
|
1126
|
+
fireEvents(msg);
|
|
1127
|
+
settleDoneWaiters();
|
|
1128
|
+
}
|
|
1129
|
+
function isMisaddressed(msg, current) {
|
|
1130
|
+
if (machine.identity === void 0) return false;
|
|
1131
|
+
const addressed = machine.identity.ofMsg(msg);
|
|
1132
|
+
if (addressed === void 0) return false;
|
|
1133
|
+
const own = machine.identity.ofState(current);
|
|
1134
|
+
if (own === void 0) return false;
|
|
1135
|
+
return structuralHash(addressed) !== structuralHash(own);
|
|
1136
|
+
}
|
|
1137
|
+
async function stepDispatch(msg) {
|
|
1138
|
+
if (state === void 0) {
|
|
1139
|
+
throw new Error("@demlik/tea: runtime not booted");
|
|
1140
|
+
}
|
|
1141
|
+
let next;
|
|
1142
|
+
let cmds;
|
|
1143
|
+
try {
|
|
1144
|
+
if (isMisaddressed(msg, state)) {
|
|
1145
|
+
reportError(new IdentityDropNotice(msg.type), {
|
|
1146
|
+
phase: "identity-drop"
|
|
1147
|
+
});
|
|
1148
|
+
return;
|
|
1149
|
+
}
|
|
1150
|
+
[next, cmds] = applyCellChecked(machine, state, msg);
|
|
1151
|
+
} catch (reduceError) {
|
|
1152
|
+
reportError(reduceError, { phase: "reduce" });
|
|
1153
|
+
switch (supervision.strategy) {
|
|
1154
|
+
case "restart": {
|
|
1155
|
+
await commit(supervision.rehydrate(state, msg, reduceError), msg, []);
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
case "escalate":
|
|
1159
|
+
throw reduceError;
|
|
1160
|
+
default:
|
|
1161
|
+
gate = "closed";
|
|
1162
|
+
throw reduceError;
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
await commit(next, msg, cmds);
|
|
1166
|
+
}
|
|
1167
|
+
let pendingInitCmds = [];
|
|
1168
|
+
if (!store && !provided) {
|
|
1169
|
+
const [initialState, initCmds] = machine.init(null, ctx);
|
|
1170
|
+
state = initialState;
|
|
1171
|
+
pendingInitCmds = initCmds;
|
|
1172
|
+
}
|
|
1173
|
+
async function stepBootEffects() {
|
|
1174
|
+
if (provided) {
|
|
1175
|
+
let scope;
|
|
1176
|
+
try {
|
|
1177
|
+
scope = await provided.open((error, provider) => {
|
|
1178
|
+
reportError(error, { phase: "provide", provider });
|
|
1179
|
+
});
|
|
1180
|
+
} catch (error) {
|
|
1181
|
+
reportError(error, { phase: "provide" });
|
|
1182
|
+
throw error;
|
|
1183
|
+
}
|
|
1184
|
+
ctx = scope.ctx;
|
|
1185
|
+
releaseProvided = scope.release;
|
|
1186
|
+
augmentedCtx = buildAugmentedCtx();
|
|
1187
|
+
if (!store) {
|
|
1188
|
+
const [initialState, initCmds] = machine.init(null, ctx);
|
|
1189
|
+
state = initialState;
|
|
1190
|
+
pendingInitCmds = initCmds;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
try {
|
|
1194
|
+
await bootAfterProvide();
|
|
1195
|
+
} catch (error) {
|
|
1196
|
+
if (releaseProvided) await releaseProvided();
|
|
1197
|
+
throw error;
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
async function bootAfterProvide() {
|
|
1201
|
+
if (store) {
|
|
1202
|
+
const raw = fenced ? await readFenced(fenced) : await store.load();
|
|
1203
|
+
const parsed = store.migrate(raw);
|
|
1204
|
+
const [initialState, initCmds] = machine.init(parsed, ctx);
|
|
1205
|
+
state = initialState;
|
|
1206
|
+
pendingInitCmds = initCmds;
|
|
1207
|
+
await persist(state);
|
|
1208
|
+
}
|
|
1209
|
+
reconcileSubs();
|
|
1210
|
+
await runInterpret(pendingInitCmds);
|
|
1211
|
+
fireListeners();
|
|
1212
|
+
fireBoot();
|
|
1213
|
+
settleDoneWaiters();
|
|
1214
|
+
}
|
|
1215
|
+
function enqueueDispatch(msg) {
|
|
1216
|
+
if (gate !== "open") {
|
|
1217
|
+
return Promise.reject(
|
|
1218
|
+
gate === "draining" ? new DispatchDiscardedError(msg.type) : new Error("@demlik/tea: runtime stopped")
|
|
1219
|
+
);
|
|
1220
|
+
}
|
|
1221
|
+
const next = tail.then(() => {
|
|
1222
|
+
if (bootError !== null) throw bootError;
|
|
1223
|
+
return stepDispatch(msg);
|
|
1224
|
+
});
|
|
1225
|
+
tail = next.catch(() => {
|
|
1226
|
+
});
|
|
1227
|
+
return next;
|
|
1228
|
+
}
|
|
1229
|
+
async function drainToQuiescence() {
|
|
1230
|
+
for (let i = 0; i < idleCap; i++) {
|
|
1231
|
+
const observed = tail;
|
|
1232
|
+
await observed;
|
|
1233
|
+
if (tail === observed) return;
|
|
1234
|
+
}
|
|
1235
|
+
throw new QuiescenceTimeoutError(idleCap);
|
|
1236
|
+
}
|
|
1237
|
+
async function dispatchToQuiescence(msg, opts2) {
|
|
1238
|
+
await enqueueDispatch(msg);
|
|
1239
|
+
if (opts2?.settle === "once") return;
|
|
1240
|
+
await drainToQuiescence();
|
|
1241
|
+
}
|
|
1242
|
+
const bootPromise = stepBootEffects();
|
|
1243
|
+
tail = bootPromise.catch((err) => {
|
|
1244
|
+
bootError = err;
|
|
1245
|
+
});
|
|
1246
|
+
const readyPromise = bootPromise.then(
|
|
1247
|
+
() => runtime
|
|
1248
|
+
);
|
|
1249
|
+
const runtime = {
|
|
1250
|
+
[liveWork]: () => ({
|
|
1251
|
+
subs: subRegistry.size + depSubRegistry.size,
|
|
1252
|
+
cmds: inFlightCmds
|
|
1253
|
+
}),
|
|
1254
|
+
dispatch: dispatchToQuiescence,
|
|
1255
|
+
dispatchOnce: enqueueDispatch,
|
|
1256
|
+
getState() {
|
|
1257
|
+
return state;
|
|
1258
|
+
},
|
|
1259
|
+
subscribe(listener) {
|
|
1260
|
+
listeners.add(listener);
|
|
1261
|
+
return () => {
|
|
1262
|
+
listeners.delete(listener);
|
|
1263
|
+
};
|
|
1264
|
+
},
|
|
1265
|
+
observe(observer) {
|
|
1266
|
+
observers.add(observer);
|
|
1267
|
+
return () => {
|
|
1268
|
+
observers.delete(observer);
|
|
1269
|
+
};
|
|
1270
|
+
},
|
|
1271
|
+
onBoot(handler) {
|
|
1272
|
+
if (booted && state !== void 0) {
|
|
1273
|
+
const snapshot = state;
|
|
1274
|
+
fanout([handler], "boot", (h) => h(snapshot));
|
|
1275
|
+
return () => {
|
|
1276
|
+
};
|
|
1277
|
+
}
|
|
1278
|
+
bootHandlers.add(handler);
|
|
1279
|
+
return () => {
|
|
1280
|
+
bootHandlers.delete(handler);
|
|
1281
|
+
};
|
|
1282
|
+
},
|
|
1283
|
+
on(type, handler) {
|
|
1284
|
+
let bucket = eventHandlers.get(type);
|
|
1285
|
+
if (bucket === void 0) {
|
|
1286
|
+
bucket = /* @__PURE__ */ new Set();
|
|
1287
|
+
eventHandlers.set(type, bucket);
|
|
1288
|
+
}
|
|
1289
|
+
const erased = handler;
|
|
1290
|
+
bucket.add(erased);
|
|
1291
|
+
return () => {
|
|
1292
|
+
const set = eventHandlers.get(type);
|
|
1293
|
+
if (set === void 0) return;
|
|
1294
|
+
set.delete(erased);
|
|
1295
|
+
if (set.size === 0) eventHandlers.delete(type);
|
|
1296
|
+
};
|
|
1297
|
+
},
|
|
1298
|
+
subscribePort(port, listener) {
|
|
1299
|
+
const key = port;
|
|
1300
|
+
let bucket = portRegistry.get(key);
|
|
1301
|
+
if (!bucket) {
|
|
1302
|
+
bucket = /* @__PURE__ */ new Set();
|
|
1303
|
+
portRegistry.set(key, bucket);
|
|
1304
|
+
}
|
|
1305
|
+
const erased = listener;
|
|
1306
|
+
bucket.add(erased);
|
|
1307
|
+
return () => {
|
|
1308
|
+
const set = portRegistry.get(key);
|
|
1309
|
+
if (!set) return;
|
|
1310
|
+
set.delete(erased);
|
|
1311
|
+
if (set.size === 0) portRegistry.delete(key);
|
|
1312
|
+
};
|
|
1313
|
+
},
|
|
1314
|
+
emitPort(port, value2) {
|
|
1315
|
+
portEmit(port, value2);
|
|
1316
|
+
},
|
|
1317
|
+
ready: readyPromise,
|
|
1318
|
+
idle() {
|
|
1319
|
+
return drainToQuiescence();
|
|
1320
|
+
},
|
|
1321
|
+
result() {
|
|
1322
|
+
const current = state;
|
|
1323
|
+
return isTerminal(current) ? current : void 0;
|
|
1324
|
+
},
|
|
1325
|
+
done() {
|
|
1326
|
+
const current = state;
|
|
1327
|
+
if (isTerminal(current)) return Promise.resolve(current);
|
|
1328
|
+
return new Promise((resolve) => {
|
|
1329
|
+
doneWaiters.add(resolve);
|
|
1330
|
+
});
|
|
1331
|
+
},
|
|
1332
|
+
async stop() {
|
|
1333
|
+
if (gate === "open") gate = "draining";
|
|
1334
|
+
if (inFlightCmds > 0) {
|
|
1335
|
+
reportError(new RuntimeDiscardedError(inFlightCmds), {
|
|
1336
|
+
phase: "discard"
|
|
1337
|
+
});
|
|
1338
|
+
}
|
|
1339
|
+
await tail;
|
|
1340
|
+
gate = "closed";
|
|
1341
|
+
stopSubs([...subRegistry.keys()]);
|
|
1342
|
+
disposeDepSubs([...depSubRegistry.keys()]);
|
|
1343
|
+
await drainDisposals();
|
|
1344
|
+
if (store && state !== void 0 && bootError === null) {
|
|
1345
|
+
try {
|
|
1346
|
+
await persist(state);
|
|
1347
|
+
} catch (error) {
|
|
1348
|
+
reportError(error, { phase: "stop-save" });
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
if (releaseProvided) await releaseProvided();
|
|
1352
|
+
}
|
|
1353
|
+
};
|
|
1354
|
+
return runtime;
|
|
1355
|
+
}
|
|
1356
|
+
function isStalled(runtime) {
|
|
1357
|
+
const probe = runtime[liveWork];
|
|
1358
|
+
if (probe === void 0) return false;
|
|
1359
|
+
const live = probe();
|
|
1360
|
+
return live.subs === 0 && live.cmds === 0;
|
|
1361
|
+
}
|
|
1362
|
+
async function driveToDone(handle, start, isTerminal, opts = {}) {
|
|
1363
|
+
const failed = opts.failed ?? (() => false);
|
|
1364
|
+
const settles = (state) => isTerminal(state) || failed(state);
|
|
1365
|
+
let detach;
|
|
1366
|
+
let unlisten;
|
|
1367
|
+
try {
|
|
1368
|
+
const runtime = await handle.ready;
|
|
1369
|
+
const booted = runtime.getState();
|
|
1370
|
+
const outcome = (state) => {
|
|
1371
|
+
if (failed(state)) throw new DriveFailedError(state);
|
|
1372
|
+
return state;
|
|
1373
|
+
};
|
|
1374
|
+
if (settles(booted)) return outcome(booted);
|
|
1375
|
+
const terminal = new Promise((resolve) => {
|
|
1376
|
+
detach = runtime.observe((_msg, state) => {
|
|
1377
|
+
if (settles(state)) resolve(state);
|
|
1378
|
+
});
|
|
1379
|
+
});
|
|
1380
|
+
let cancelFailed;
|
|
1381
|
+
if (opts.signal !== void 0) {
|
|
1382
|
+
const { signal, cancel } = opts;
|
|
1383
|
+
let onCancelError;
|
|
1384
|
+
cancelFailed = new Promise((_resolve, reject) => {
|
|
1385
|
+
onCancelError = reject;
|
|
1386
|
+
});
|
|
1387
|
+
const onAbort = () => {
|
|
1388
|
+
try {
|
|
1389
|
+
runtime.dispatchOnce(cancel(runtime.getState())).catch(onCancelError);
|
|
1390
|
+
} catch (error) {
|
|
1391
|
+
onCancelError(error);
|
|
1392
|
+
}
|
|
1393
|
+
};
|
|
1394
|
+
if (signal.aborted) {
|
|
1395
|
+
onAbort();
|
|
1396
|
+
return outcome(await Promise.race([terminal, cancelFailed]));
|
|
1397
|
+
}
|
|
1398
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
1399
|
+
unlisten = () => signal.removeEventListener("abort", onAbort);
|
|
1400
|
+
}
|
|
1401
|
+
const msg = typeof start === "function" ? start(booted) : start;
|
|
1402
|
+
const started = runtime.dispatch(msg).then(() => {
|
|
1403
|
+
const parked = runtime.getState();
|
|
1404
|
+
if (!settles(parked) && isStalled(runtime)) {
|
|
1405
|
+
throw new DriveStalledError(parked);
|
|
1406
|
+
}
|
|
1407
|
+
return terminal;
|
|
1408
|
+
});
|
|
1409
|
+
const racers = [terminal, started];
|
|
1410
|
+
if (cancelFailed !== void 0) racers.push(cancelFailed);
|
|
1411
|
+
return outcome(await Promise.race(racers));
|
|
1412
|
+
} finally {
|
|
1413
|
+
detach?.();
|
|
1414
|
+
unlisten?.();
|
|
1415
|
+
await handle.stop();
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
// src/subs/types.ts
|
|
1420
|
+
function dispatchIfPresent(dispatch, msg) {
|
|
1421
|
+
if (msg !== null) dispatch(msg);
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
// src/subs/define-listener.ts
|
|
1425
|
+
function defineListener(target) {
|
|
1426
|
+
return (msgFn) => {
|
|
1427
|
+
return (sub, ctx, dispatch) => {
|
|
1428
|
+
const listener = (...args) => {
|
|
1429
|
+
dispatchIfPresent(dispatch, msgFn(sub, ...args));
|
|
1430
|
+
};
|
|
1431
|
+
target.add(listener, sub, ctx);
|
|
1432
|
+
return () => {
|
|
1433
|
+
target.remove(listener, sub, ctx);
|
|
1434
|
+
};
|
|
1435
|
+
};
|
|
1436
|
+
};
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
// src/subs/from-broadcast-channel.ts
|
|
1440
|
+
function fromBroadcastChannel(msgFn) {
|
|
1441
|
+
return (sub, _ctx, dispatch) => {
|
|
1442
|
+
const channel = new BroadcastChannel(sub.channelName);
|
|
1443
|
+
const listener = (event) => {
|
|
1444
|
+
dispatchIfPresent(dispatch, msgFn(event, sub));
|
|
1445
|
+
};
|
|
1446
|
+
channel.addEventListener("message", listener);
|
|
1447
|
+
return () => {
|
|
1448
|
+
channel.removeEventListener("message", listener);
|
|
1449
|
+
channel.close();
|
|
1450
|
+
};
|
|
1451
|
+
};
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
// src/subs/from-event-source.ts
|
|
1455
|
+
function fromEventSource(opts) {
|
|
1456
|
+
return (sub, _ctx, dispatch) => {
|
|
1457
|
+
const source = new EventSource(sub.url);
|
|
1458
|
+
const messageListener = (event) => {
|
|
1459
|
+
dispatchIfPresent(dispatch, opts.onMessage(event.data, sub));
|
|
1460
|
+
};
|
|
1461
|
+
source.addEventListener("message", messageListener);
|
|
1462
|
+
const onError = opts.onError;
|
|
1463
|
+
const errorListener = onError ? (event) => {
|
|
1464
|
+
dispatchIfPresent(dispatch, onError(event, sub));
|
|
1465
|
+
} : void 0;
|
|
1466
|
+
if (errorListener) source.addEventListener("error", errorListener);
|
|
1467
|
+
const onOpen = opts.onOpen;
|
|
1468
|
+
const openListener = onOpen ? () => {
|
|
1469
|
+
dispatchIfPresent(dispatch, onOpen(sub));
|
|
1470
|
+
} : void 0;
|
|
1471
|
+
if (openListener) source.addEventListener("open", openListener);
|
|
1472
|
+
return () => {
|
|
1473
|
+
source.removeEventListener("message", messageListener);
|
|
1474
|
+
if (errorListener) source.removeEventListener("error", errorListener);
|
|
1475
|
+
if (openListener) source.removeEventListener("open", openListener);
|
|
1476
|
+
source.close();
|
|
1477
|
+
};
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
// src/subs/from-event-target.ts
|
|
1482
|
+
function fromEventTarget(getTarget, eventName, msgFn) {
|
|
1483
|
+
return (sub, _ctx, dispatch) => {
|
|
1484
|
+
const target = getTarget();
|
|
1485
|
+
const listener = (event) => {
|
|
1486
|
+
dispatchIfPresent(dispatch, msgFn(event, sub));
|
|
1487
|
+
};
|
|
1488
|
+
target.addEventListener(eventName, listener);
|
|
1489
|
+
return () => {
|
|
1490
|
+
target.removeEventListener(eventName, listener);
|
|
1491
|
+
};
|
|
1492
|
+
};
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
// src/subs/from-interval.ts
|
|
1496
|
+
function fromInterval(msgFn) {
|
|
1497
|
+
return (sub, _ctx, dispatch) => {
|
|
1498
|
+
const handle = setInterval(() => {
|
|
1499
|
+
dispatch(msgFn(sub));
|
|
1500
|
+
}, sub.intervalMs);
|
|
1501
|
+
return () => {
|
|
1502
|
+
clearInterval(handle);
|
|
1503
|
+
};
|
|
1504
|
+
};
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
// src/subs/from-port.ts
|
|
1508
|
+
function fromPort(selectRuntime, port, msgFn) {
|
|
1509
|
+
return (sub, ctx, dispatch) => {
|
|
1510
|
+
const runtime = selectRuntime(ctx);
|
|
1511
|
+
return runtime.subscribePort(port, (value2) => {
|
|
1512
|
+
dispatchIfPresent(dispatch, msgFn(value2, sub));
|
|
1513
|
+
});
|
|
1514
|
+
};
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
// src/subs/from-reconnecting-web-socket.ts
|
|
1518
|
+
var defaultConnect = (url) => new WebSocket(url);
|
|
1519
|
+
var defaultSchedule = (fn, ms) => {
|
|
1520
|
+
const handle = setTimeout(fn, ms);
|
|
1521
|
+
return () => clearTimeout(handle);
|
|
1522
|
+
};
|
|
1523
|
+
function fromReconnectingWebSocket(opts) {
|
|
1524
|
+
const backoffBaseMs = opts.backoffBaseMs ?? 250;
|
|
1525
|
+
const backoffMaxMs = opts.backoffMaxMs ?? 5e3;
|
|
1526
|
+
const connect = opts.connect ?? defaultConnect;
|
|
1527
|
+
const schedule = opts.schedule ?? defaultSchedule;
|
|
1528
|
+
const { onMessage, onOpen, onError, onClose, onReconnect } = opts;
|
|
1529
|
+
return (sub, _ctx, dispatch) => {
|
|
1530
|
+
let ws = null;
|
|
1531
|
+
let attempt = 0;
|
|
1532
|
+
let opened = false;
|
|
1533
|
+
let closedByCaller = false;
|
|
1534
|
+
let cancelReconnect = null;
|
|
1535
|
+
const emit = (msg) => dispatchIfPresent(dispatch, msg);
|
|
1536
|
+
const handleClose = (code, reason) => {
|
|
1537
|
+
ws = null;
|
|
1538
|
+
if (onClose) emit(onClose(code, reason, sub));
|
|
1539
|
+
if (closedByCaller) return;
|
|
1540
|
+
const delay = Math.min(backoffBaseMs * 2 ** attempt, backoffMaxMs);
|
|
1541
|
+
attempt += 1;
|
|
1542
|
+
cancelReconnect = schedule(() => {
|
|
1543
|
+
cancelReconnect = null;
|
|
1544
|
+
if (!closedByCaller) open();
|
|
1545
|
+
}, delay);
|
|
1546
|
+
};
|
|
1547
|
+
function open() {
|
|
1548
|
+
const socket = connect(sub.wsUrl);
|
|
1549
|
+
ws = socket;
|
|
1550
|
+
socket.onopen = () => {
|
|
1551
|
+
const reconnected = opened;
|
|
1552
|
+
const reconnectCount = attempt;
|
|
1553
|
+
attempt = 0;
|
|
1554
|
+
opened = true;
|
|
1555
|
+
if (onOpen) emit(onOpen(sub));
|
|
1556
|
+
if (reconnected && onReconnect) emit(onReconnect(reconnectCount, sub));
|
|
1557
|
+
};
|
|
1558
|
+
socket.onmessage = (event) => {
|
|
1559
|
+
emit(onMessage(event.data, sub));
|
|
1560
|
+
};
|
|
1561
|
+
socket.onerror = onError ? (event) => emit(onError(event, sub)) : () => {
|
|
1562
|
+
};
|
|
1563
|
+
socket.onclose = (event) => {
|
|
1564
|
+
handleClose(event.code, event.reason);
|
|
1565
|
+
};
|
|
1566
|
+
}
|
|
1567
|
+
open();
|
|
1568
|
+
return () => {
|
|
1569
|
+
closedByCaller = true;
|
|
1570
|
+
if (cancelReconnect !== null) {
|
|
1571
|
+
cancelReconnect();
|
|
1572
|
+
cancelReconnect = null;
|
|
1573
|
+
}
|
|
1574
|
+
const socket = ws;
|
|
1575
|
+
ws = null;
|
|
1576
|
+
if (socket !== null) {
|
|
1577
|
+
socket.onopen = null;
|
|
1578
|
+
socket.onmessage = null;
|
|
1579
|
+
socket.onerror = null;
|
|
1580
|
+
socket.onclose = null;
|
|
1581
|
+
socket.close(1e3);
|
|
1582
|
+
}
|
|
1583
|
+
};
|
|
1584
|
+
};
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
// src/subs/from-timeout.ts
|
|
1588
|
+
function fromTimeout(msgFn) {
|
|
1589
|
+
return (sub, _ctx, dispatch) => {
|
|
1590
|
+
const handle = setTimeout(() => {
|
|
1591
|
+
dispatch(msgFn(sub));
|
|
1592
|
+
}, sub.delayMs);
|
|
1593
|
+
return () => {
|
|
1594
|
+
clearTimeout(handle);
|
|
1595
|
+
};
|
|
1596
|
+
};
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
// src/subs/from-web-socket.ts
|
|
1600
|
+
function fromWebSocket(opts) {
|
|
1601
|
+
return (sub, _ctx, dispatch) => {
|
|
1602
|
+
const ws = new WebSocket(sub.wsUrl);
|
|
1603
|
+
ws.onmessage = (event) => {
|
|
1604
|
+
dispatchIfPresent(dispatch, opts.onMessage(event.data, sub));
|
|
1605
|
+
};
|
|
1606
|
+
const onOpen = opts.onOpen;
|
|
1607
|
+
if (onOpen) {
|
|
1608
|
+
ws.onopen = () => {
|
|
1609
|
+
dispatchIfPresent(dispatch, onOpen(sub));
|
|
1610
|
+
};
|
|
1611
|
+
}
|
|
1612
|
+
const onError = opts.onError;
|
|
1613
|
+
if (onError) {
|
|
1614
|
+
ws.onerror = (event) => {
|
|
1615
|
+
dispatchIfPresent(dispatch, onError(event, sub));
|
|
1616
|
+
};
|
|
1617
|
+
}
|
|
1618
|
+
const onClose = opts.onClose;
|
|
1619
|
+
if (onClose) {
|
|
1620
|
+
ws.onclose = (event) => {
|
|
1621
|
+
dispatchIfPresent(dispatch, onClose(event.code, event.reason, sub));
|
|
1622
|
+
};
|
|
1623
|
+
}
|
|
1624
|
+
return () => {
|
|
1625
|
+
ws.onmessage = null;
|
|
1626
|
+
ws.onopen = null;
|
|
1627
|
+
ws.onerror = null;
|
|
1628
|
+
ws.onclose = null;
|
|
1629
|
+
ws.close(1e3);
|
|
1630
|
+
};
|
|
1631
|
+
};
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
// src/subs/managed-resource.ts
|
|
1635
|
+
function defineManagedResource(opts) {
|
|
1636
|
+
const held = /* @__PURE__ */ new Map();
|
|
1637
|
+
const keyString = (k) => structuralHash(k);
|
|
1638
|
+
const subIdFor = (key) => subId(`managed:${opts.name}:${keyString(key)}`);
|
|
1639
|
+
const subBuilder = (key) => ({
|
|
1640
|
+
id: subIdFor(key),
|
|
1641
|
+
type: "managed_resource",
|
|
1642
|
+
key
|
|
1643
|
+
});
|
|
1644
|
+
const subscribeHandler = (sub, ctx, _dispatch) => {
|
|
1645
|
+
const handle = opts.acquire(sub.key, ctx);
|
|
1646
|
+
const k = keyString(sub.key);
|
|
1647
|
+
held.set(k, handle);
|
|
1648
|
+
return () => {
|
|
1649
|
+
held.delete(k);
|
|
1650
|
+
return opts.release(handle);
|
|
1651
|
+
};
|
|
1652
|
+
};
|
|
1653
|
+
return {
|
|
1654
|
+
sub: subBuilder,
|
|
1655
|
+
// Pair the battery with a state-gate. `TKey` / `Handle` / `Ctx` are in
|
|
1656
|
+
// scope here, so `subFor` builds the fully-typed sub and `subscribe`
|
|
1657
|
+
// forwards straight to the battery's own typed `subscribe`. The entry
|
|
1658
|
+
// erases ONLY `Handle` for the combinator (`TKey` and `Ctx` stay), so the
|
|
1659
|
+
// substrate's narrowed `ManagedResourceSub<TKey>` flows in with no cast.
|
|
1660
|
+
gated: (when) => ({
|
|
1661
|
+
name: opts.name,
|
|
1662
|
+
owns: (sub) => sub.id === subIdFor(sub.key),
|
|
1663
|
+
subFor: (state) => {
|
|
1664
|
+
const key = when(state);
|
|
1665
|
+
return key === null ? null : subBuilder(key);
|
|
1666
|
+
},
|
|
1667
|
+
subscribe: subscribeHandler
|
|
1668
|
+
}),
|
|
1669
|
+
// Dep-keyed entry. `when` is the gate (the deps = the KEY); the source runs
|
|
1670
|
+
// the SAME `acquire` → hold → `release`-on-dispose lifecycle the `subscribe`
|
|
1671
|
+
// cell does, now driven by the kernel's dep-keyed reconcile. The Msg type is
|
|
1672
|
+
// `never` (a managed resource dispatches nothing); the ignored `_dispatch`
|
|
1673
|
+
// matches the source signature.
|
|
1674
|
+
depKeyed: (when) => ({
|
|
1675
|
+
deps: when,
|
|
1676
|
+
source: (state, _dispatch, ctx) => {
|
|
1677
|
+
const key = when(state);
|
|
1678
|
+
if (key === null) return () => {
|
|
1679
|
+
};
|
|
1680
|
+
return subscribeHandler(subBuilder(key), ctx);
|
|
1681
|
+
}
|
|
1682
|
+
}),
|
|
1683
|
+
subscribe: subscribeHandler,
|
|
1684
|
+
get: (key) => held.get(keyString(key)),
|
|
1685
|
+
subIdFor
|
|
1686
|
+
};
|
|
1687
|
+
}
|
|
1688
|
+
function combineManagedResources(entries) {
|
|
1689
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1690
|
+
for (const entry of entries) {
|
|
1691
|
+
if (seen.has(entry.name)) {
|
|
1692
|
+
throw new Error(
|
|
1693
|
+
`[combineManagedResources] duplicate managed-resource name "${entry.name}" \u2014 names must be unique (the Sub id encodes the name; two batteries sharing it collide)`
|
|
1694
|
+
);
|
|
1695
|
+
}
|
|
1696
|
+
seen.add(entry.name);
|
|
1697
|
+
}
|
|
1698
|
+
return {
|
|
1699
|
+
subs: (state) => {
|
|
1700
|
+
const live = [];
|
|
1701
|
+
for (const entry of entries) {
|
|
1702
|
+
const sub = entry.subFor(state);
|
|
1703
|
+
if (sub !== null) live.push(sub);
|
|
1704
|
+
}
|
|
1705
|
+
return live;
|
|
1706
|
+
},
|
|
1707
|
+
subscribe: (sub, ctx, dispatch) => {
|
|
1708
|
+
const owner = entries.find((entry) => entry.owns(sub));
|
|
1709
|
+
if (owner === void 0) {
|
|
1710
|
+
throw new Error(
|
|
1711
|
+
`[combineManagedResources] no battery for sub id ${sub.id}`
|
|
1712
|
+
);
|
|
1713
|
+
}
|
|
1714
|
+
return owner.subscribe(sub, ctx, dispatch);
|
|
1715
|
+
}
|
|
1716
|
+
};
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
// src/subs/transport.ts
|
|
1720
|
+
function fromTransport(opts) {
|
|
1721
|
+
const live = /* @__PURE__ */ new Map();
|
|
1722
|
+
const keyString = (k) => structuralHash(k);
|
|
1723
|
+
const subIdFor = (key) => subId(`${opts.name}:${keyString(key)}`);
|
|
1724
|
+
const sub = (key) => ({
|
|
1725
|
+
id: subIdFor(key),
|
|
1726
|
+
type: "transport",
|
|
1727
|
+
key
|
|
1728
|
+
});
|
|
1729
|
+
const subscribe = (s, ctx, dispatch) => {
|
|
1730
|
+
const t = opts.openTransport(s.key, ctx);
|
|
1731
|
+
const k = keyString(s.key);
|
|
1732
|
+
let offMessage;
|
|
1733
|
+
let offClose;
|
|
1734
|
+
try {
|
|
1735
|
+
offMessage = t.onMessage((raw) => {
|
|
1736
|
+
const parsed = opts.parseInbound(raw, s.key);
|
|
1737
|
+
if (parsed === null) return;
|
|
1738
|
+
const msg = opts.onInbound(parsed, s.key);
|
|
1739
|
+
if (msg === null) return;
|
|
1740
|
+
dispatch(msg);
|
|
1741
|
+
});
|
|
1742
|
+
offClose = t.onClose(() => {
|
|
1743
|
+
dispatch(opts.lostMsg(s.key));
|
|
1744
|
+
});
|
|
1745
|
+
} catch (err) {
|
|
1746
|
+
offMessage?.();
|
|
1747
|
+
offClose?.();
|
|
1748
|
+
try {
|
|
1749
|
+
t.close();
|
|
1750
|
+
} catch (closeErr) {
|
|
1751
|
+
console.warn(
|
|
1752
|
+
`[fromTransport:${opts.name}] close during failed wiring failed`,
|
|
1753
|
+
closeErr
|
|
1754
|
+
);
|
|
1755
|
+
}
|
|
1756
|
+
throw err;
|
|
1757
|
+
}
|
|
1758
|
+
live.set(k, t);
|
|
1759
|
+
return () => {
|
|
1760
|
+
offMessage?.();
|
|
1761
|
+
offClose?.();
|
|
1762
|
+
live.delete(k);
|
|
1763
|
+
try {
|
|
1764
|
+
t.close();
|
|
1765
|
+
} catch (err) {
|
|
1766
|
+
console.warn(`[fromTransport:${opts.name}] close failed`, err);
|
|
1767
|
+
}
|
|
1768
|
+
};
|
|
1769
|
+
};
|
|
1770
|
+
return {
|
|
1771
|
+
sub,
|
|
1772
|
+
subscribe,
|
|
1773
|
+
send: (key, outbound) => {
|
|
1774
|
+
const t = live.get(keyString(key));
|
|
1775
|
+
if (t === void 0) {
|
|
1776
|
+
console.warn(
|
|
1777
|
+
`[fromTransport:${opts.name}] send dropped \u2014 no live transport for key`,
|
|
1778
|
+
keyString(key)
|
|
1779
|
+
);
|
|
1780
|
+
return;
|
|
1781
|
+
}
|
|
1782
|
+
t.send(opts.serializeOutbound(outbound));
|
|
1783
|
+
},
|
|
1784
|
+
subIdFor,
|
|
1785
|
+
// Dep-keyed entry: `when` is the gate (the deps slice → the seam key);
|
|
1786
|
+
// `source` re-runs `when(state)` to recover the typed key and opens the seam
|
|
1787
|
+
// via the battery's own `subscribe`. The kernel only calls `source` when
|
|
1788
|
+
// `deps(state)` was non-null, so `when` is non-null here; the key type never
|
|
1789
|
+
// escapes the entry (cast-free existential).
|
|
1790
|
+
depKeyed: (when) => ({
|
|
1791
|
+
deps: when,
|
|
1792
|
+
source: (state, dispatch, ctx) => {
|
|
1793
|
+
const key = when(state);
|
|
1794
|
+
if (key === null) return () => {
|
|
1795
|
+
};
|
|
1796
|
+
return subscribe(sub(key), ctx, dispatch);
|
|
1797
|
+
}
|
|
1798
|
+
})
|
|
1799
|
+
};
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
export { Cmd, DispatchDiscardedError, DisposeTimeoutNotice, DriveFailedError, DriveStalledError, IdentityDropNotice, NO_ACK, NoCellError, PortNameCollisionError, ProvideFailedError, ProviderCycleError, QuiescenceTimeoutError, RuntimeDiscardNotice, RuntimeDiscardedError, StoreConflictError, SubIdCollisionError, UnknownProviderError, __resetPortRegistry, absurd, acceptedTypes, acceptsOf, ack, applyCell, applyCellChecked, asReducer, cmdEdgeOf, combineManagedResources, defineListener, defineMachine, defineManagedResource, definePort, dep, describeMachine, detachWorkOf, detectUpdateForm, dispatchIfPresent, driveToDone, foldMsgs, foldUpdates, formOf, fromBroadcastChannel, fromEventSource, fromEventTarget, fromInterval, fromPort, fromReconnectingWebSocket, fromTimeout, fromTransport, fromWebSocket, historyTracker, initAck, isFencedStore, isProvided, layer, malformedResult, msgKeysOf, nextSeq, noop, partitionByAck, provide, reconcile, replay, run, schemaMigrate, settle, structuralHash, subId, tagSeq, tryApplyCell, tryFoldMsgs, tryInterpret, value, without, wrapDetached };
|
|
1803
|
+
//# sourceMappingURL=chunk-RQULHGYH.js.map
|
|
1804
|
+
//# sourceMappingURL=chunk-RQULHGYH.js.map
|