@demlik/tea 0.13.0 → 0.15.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-RH5EFRVJ.js → chunk-22POWGFA.js} +31 -5
- package/dist/chunk-22POWGFA.js.map +1 -0
- package/dist/{chunk-DMYGQB4O.js → chunk-3B5X7SBB.js} +23 -6
- package/dist/chunk-3B5X7SBB.js.map +1 -0
- package/dist/chunk-66PY5WYF.js +1816 -0
- package/dist/chunk-66PY5WYF.js.map +1 -0
- 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-AYS5N6WY.js +505 -0
- package/dist/chunk-AYS5N6WY.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-O4MVQTEJ.js → chunk-L3TND7LA.js} +20 -16
- package/dist/chunk-L3TND7LA.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-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-YUXP55T2.js → chunk-Q5CQTBFA.js} +57 -7
- package/dist/chunk-Q5CQTBFA.js.map +1 -0
- package/dist/{batch-window/index.js → chunk-QPEVCJ5Q.js} +4 -8
- package/dist/chunk-QPEVCJ5Q.js.map +1 -0
- package/dist/chunk-TCLBCERH.js +1480 -0
- package/dist/chunk-TCLBCERH.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-MUUROGIH.js → chunk-V46HSVCK.js} +62 -12
- package/dist/chunk-V46HSVCK.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-ZVJZ72HY.js → chunk-VTQI2NHP.js} +25 -11
- package/dist/chunk-VTQI2NHP.js.map +1 -0
- package/dist/{core-Co0LWkIA.d.ts → core-DnzqWy6u.d.ts} +72 -23
- package/dist/devtools/index.d.ts +2 -2
- package/dist/devtools/index.js +207 -2
- package/dist/devtools/index.js.map +1 -1
- package/dist/do/index.d.ts +43 -29
- package/dist/do/index.js +36 -25
- package/dist/do/index.js.map +1 -1
- package/dist/{durable-effects-C6uwzjb5.d.ts → durable-effects-CWzA-o2B.d.ts} +2 -2
- package/dist/extension/index.d.ts +300 -3
- package/dist/extension/index.js +596 -5
- package/dist/extension/index.js.map +1 -1
- package/dist/flow/index.d.ts +1284 -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/index-Bc40JWVl.d.ts +131 -0
- package/dist/{batch-window/index.d.ts → index-C2DwkjlP.d.ts} +7 -12
- package/dist/index-CA_7I5g9.d.ts +806 -0
- package/dist/index-CSyMYDAB.d.ts +69 -0
- package/dist/{fan-out/index.d.ts → index-CuNO9m8i.d.ts} +7 -9
- package/dist/{debounce/index.d.ts → index-DHSUmQTR.d.ts} +7 -7
- package/dist/{recorder/index.d.ts → index-DrIRb_Ch.d.ts} +4 -7
- package/dist/index-HSYgG2Yt.d.ts +380 -0
- package/dist/{monitored-run/index.d.ts → index-KXqTRJyb.d.ts} +37 -13
- package/dist/{snapshot/index.d.ts → index-ZCMhnVKN.d.ts} +15 -78
- package/dist/index.d.ts +771 -6
- package/dist/index.js +1 -2
- package/dist/jev/index.d.ts +646 -0
- package/dist/jev/index.js +485 -0
- package/dist/jev/index.js.map +1 -0
- package/dist/machine-DGlPWCWI.d.ts +1781 -0
- package/dist/machine-viz/index.d.ts +1 -1
- package/dist/machine-viz/index.js +12 -5
- package/dist/machine-viz/index.js.map +1 -1
- package/dist/mem/index.d.ts +18 -3
- package/dist/mem/index.js +22 -2
- package/dist/mem/index.js.map +1 -1
- package/dist/node/index.d.ts +104 -6
- package/dist/node/index.js +132 -9
- package/dist/node/index.js.map +1 -1
- package/dist/{paginator → paginate}/index.d.ts +140 -6
- package/dist/paginate/index.js +7 -0
- package/dist/parity/index.d.ts +4 -10
- package/dist/parity/index.js +4 -7
- package/dist/parity/index.js.map +1 -1
- package/dist/pbt/index.d.ts +247 -5
- package/dist/pbt/index.js +124 -5
- package/dist/pbt/index.js.map +1 -1
- package/dist/{trace-replay → persistence}/index.d.ts +7 -5
- package/dist/persistence/index.js +6 -0
- package/dist/{protocol-B5YmJr0d.d.ts → protocol-D8VbH-VH.d.ts} +10 -1
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +1 -2
- package/dist/react/index.js.map +1 -1
- package/dist/resilience/index.d.ts +744 -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-CMF13BBh.d.ts +998 -0
- package/dist/testing/index.d.ts +147 -3
- package/dist/testing/index.js +95 -3
- package/dist/testing/index.js.map +1 -1
- package/dist/{throttled-input → timing}/index.d.ts +143 -12
- package/dist/{throttled-input → timing}/index.js +57 -12
- package/dist/timing/index.js.map +1 -0
- package/dist/{types-XS_miRnB.d.ts → types-BseNPIhr.d.ts} +1 -1
- package/dist/work-queue/index.d.ts +130 -54
- package/dist/work-queue/index.js +3 -2
- package/dist/work-queue/index.js.map +1 -1
- package/package.json +45 -218
- package/dist/authed-call/index.d.ts +0 -120
- package/dist/authed-call/index.js +0 -134
- package/dist/authed-call/index.js.map +0 -1
- package/dist/await-terminal/index.d.ts +0 -101
- package/dist/await-terminal/index.js +0 -76
- package/dist/await-terminal/index.js.map +0 -1
- package/dist/batch-window/index.js.map +0 -1
- package/dist/cache/index.d.ts +0 -152
- package/dist/cache/index.js +0 -8
- package/dist/chart/index.d.ts +0 -218
- package/dist/chart/index.js +0 -16
- package/dist/chart/index.js.map +0 -1
- package/dist/chart/inspect/index.d.ts +0 -86
- package/dist/chart/inspect/index.js +0 -5
- package/dist/chart/inspect/react.d.ts +0 -113
- package/dist/chart/inspect/react.js +0 -11
- package/dist/chart/inspect/react.js.map +0 -1
- package/dist/chart/inspect/styles.css +0 -286
- package/dist/chart/lane/index.d.ts +0 -362
- package/dist/chart/lane/index.js +0 -9
- package/dist/chart/lane/index.js.map +0 -1
- package/dist/chart/lane/react.d.ts +0 -84
- package/dist/chart/lane/react.js +0 -559
- package/dist/chart/lane/react.js.map +0 -1
- package/dist/chart/lane/server.d.ts +0 -148
- package/dist/chart/lane/server.js +0 -209
- package/dist/chart/lane/server.js.map +0 -1
- package/dist/chart/lane/styles.css +0 -498
- package/dist/chart/lane/viewer/assets/abnfDiagram-N423BO3Z-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/architectureDiagram-T3A2C74G-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/blockDiagram-VBNYF7ZC-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/c4Diagram-5PPSVZJV-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/chunk-2GRJ4B5K-HdDf8SI3.js +0 -1
- package/dist/chart/lane/viewer/assets/chunk-5RXB4S5H-CcNtpUd7.js +0 -231
- package/dist/chart/lane/viewer/assets/chunk-5VM5RSS4-BP4fRS_5.js +0 -15
- package/dist/chart/lane/viewer/assets/chunk-KBJHAD2P-DZOw7xU6.js +0 -1
- package/dist/chart/lane/viewer/assets/chunk-NSK5VX7P-CBCyTZMs.js +0 -128
- package/dist/chart/lane/viewer/assets/classDiagram-JCYQIIEL-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/classDiagram-v2-OCEON4UE-D4uAiFr8.js +0 -206
- package/dist/chart/lane/viewer/assets/cose-bilkent-JH36ORCC-DOwCrGXH.js +0 -1
- package/dist/chart/lane/viewer/assets/cynefinDiagram-MW4NZA55-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/dagre-K_PewWfS.js +0 -1
- package/dist/chart/lane/viewer/assets/dagre-VZM6K2ZE-831qZcA8.js +0 -4
- package/dist/chart/lane/viewer/assets/diagram-7IWD3JNH-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/diagram-B4RE2ZJO-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/diagram-LBJQPF4R-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/diagram-Q27KOJAE-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/diagram-UB23O5K3-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/ebnfDiagram-BXEA7PRR-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/erDiagram-JOGREHBK-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/flowDiagram-UKHOOZJN-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/ganttDiagram-PKOTCBZU-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/gitGraphDiagram-DS77QQ5N-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/index-9SkH5NA3.css +0 -1
- package/dist/chart/lane/viewer/assets/index-Bgt4sXpW.js +0 -195
- package/dist/chart/lane/viewer/assets/infoDiagram-6WML65LV-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/ishikawaDiagram-WSZJBQD7-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/journeyDiagram-NVQOT4AX-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/kanban-definition-27J2QSJJ-G7PaPzy-.js +0 -89
- package/dist/chart/lane/viewer/assets/katex-DOwCrGXH.js +0 -1
- package/dist/chart/lane/viewer/assets/mindmap-definition-FAOFIHXS-CGj9nrVk.js +0 -96
- package/dist/chart/lane/viewer/assets/path-fybaL0A-.js +0 -1
- package/dist/chart/lane/viewer/assets/pegDiagram-VL7TDLO6-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/pieDiagram-7S7Q4E2Y-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/quadrantDiagram-CIZ2JOQS-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/railroadDiagram-AXF67PYL-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/requirementDiagram-LRYGKXZP-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/sankeyDiagram-W5VNT64P-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/sequenceDiagram-SI44F4Z6-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/stateDiagram-OKZ733FA-B_88AzBS.js +0 -1
- package/dist/chart/lane/viewer/assets/stateDiagram-v2-UEYNNEHI-CR5gcgq6.js +0 -1
- package/dist/chart/lane/viewer/assets/swimlanes-SLNWSIFB-B4xK-rwg.js +0 -1
- package/dist/chart/lane/viewer/assets/swimlanesDiagram-ULZ7WXOC-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/timeline-definition-Z64GVDOM-CCv52MfY.js +0 -120
- package/dist/chart/lane/viewer/assets/vennDiagram-T6HMQDX7-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/wardleyDiagram-T6FBY63Y-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/assets/xychartDiagram-ELKLHX3M-C729LI31.js +0 -1
- package/dist/chart/lane/viewer/index.html +0 -15
- package/dist/chart/report/index.d.ts +0 -117
- package/dist/chart/report/index.js +0 -32
- package/dist/chart/report/index.js.map +0 -1
- package/dist/chunk-2YFLOCWX.js +0 -15
- package/dist/chunk-2YFLOCWX.js.map +0 -1
- package/dist/chunk-3I52QZZ5.js +0 -519
- package/dist/chunk-3I52QZZ5.js.map +0 -1
- package/dist/chunk-3ZAFFRRB.js +0 -457
- package/dist/chunk-3ZAFFRRB.js.map +0 -1
- package/dist/chunk-4EQZ76JC.js +0 -33
- package/dist/chunk-4EQZ76JC.js.map +0 -1
- package/dist/chunk-4KLG43GY.js +0 -223
- package/dist/chunk-4KLG43GY.js.map +0 -1
- package/dist/chunk-7FRZ2CT2.js +0 -424
- package/dist/chunk-7FRZ2CT2.js.map +0 -1
- package/dist/chunk-AZZLE7XR.js +0 -62
- package/dist/chunk-AZZLE7XR.js.map +0 -1
- package/dist/chunk-BYQUGDD3.js +0 -16
- package/dist/chunk-BYQUGDD3.js.map +0 -1
- package/dist/chunk-CIQG5L42.js +0 -685
- package/dist/chunk-CIQG5L42.js.map +0 -1
- package/dist/chunk-CLM6ERNO.js +0 -61
- package/dist/chunk-CLM6ERNO.js.map +0 -1
- package/dist/chunk-COS5MSTO.js +0 -88
- package/dist/chunk-COS5MSTO.js.map +0 -1
- package/dist/chunk-CRPZJVD2.js +0 -71
- package/dist/chunk-CRPZJVD2.js.map +0 -1
- package/dist/chunk-D62FDQKE.js +0 -53
- package/dist/chunk-D62FDQKE.js.map +0 -1
- package/dist/chunk-D736QUGF.js.map +0 -1
- package/dist/chunk-DGE4PV4A.js +0 -26
- package/dist/chunk-DGE4PV4A.js.map +0 -1
- package/dist/chunk-DMYGQB4O.js.map +0 -1
- package/dist/chunk-EWJP3YYP.js.map +0 -1
- package/dist/chunk-FV3Z5MBE.js.map +0 -1
- package/dist/chunk-HCEVHFJ7.js +0 -54
- package/dist/chunk-HCEVHFJ7.js.map +0 -1
- package/dist/chunk-J6527VRQ.js.map +0 -1
- package/dist/chunk-JELSZN25.js +0 -47
- package/dist/chunk-JELSZN25.js.map +0 -1
- package/dist/chunk-K575PT4S.js.map +0 -1
- package/dist/chunk-L57ZOT5K.js +0 -184
- package/dist/chunk-L57ZOT5K.js.map +0 -1
- package/dist/chunk-MU6MCIAC.js +0 -15
- package/dist/chunk-MU6MCIAC.js.map +0 -1
- package/dist/chunk-MUUROGIH.js.map +0 -1
- package/dist/chunk-NR7BU22N.js +0 -758
- package/dist/chunk-NR7BU22N.js.map +0 -1
- package/dist/chunk-O4MVQTEJ.js.map +0 -1
- package/dist/chunk-OOYD44JI.js +0 -317
- package/dist/chunk-OOYD44JI.js.map +0 -1
- package/dist/chunk-Q2UM7BXU.js.map +0 -1
- package/dist/chunk-RH5EFRVJ.js.map +0 -1
- package/dist/chunk-S2EGRPCM.js +0 -47
- package/dist/chunk-S2EGRPCM.js.map +0 -1
- package/dist/chunk-SINXE47Y.js +0 -55
- package/dist/chunk-SINXE47Y.js.map +0 -1
- package/dist/chunk-UF4MZSLT.js +0 -53
- package/dist/chunk-UF4MZSLT.js.map +0 -1
- package/dist/chunk-UOC2PL46.js +0 -13
- package/dist/chunk-UOC2PL46.js.map +0 -1
- package/dist/chunk-VYFAZN3F.js +0 -372
- package/dist/chunk-VYFAZN3F.js.map +0 -1
- package/dist/chunk-WRAA7GVZ.js +0 -209
- package/dist/chunk-WRAA7GVZ.js.map +0 -1
- package/dist/chunk-XGELA764.js +0 -163
- package/dist/chunk-XGELA764.js.map +0 -1
- package/dist/chunk-YUXP55T2.js.map +0 -1
- package/dist/chunk-YWIKDKHY.js +0 -307
- package/dist/chunk-YWIKDKHY.js.map +0 -1
- package/dist/chunk-ZJ5AOYBH.js +0 -8
- package/dist/chunk-ZJ5AOYBH.js.map +0 -1
- package/dist/chunk-ZSUUOEPL.js +0 -731
- package/dist/chunk-ZSUUOEPL.js.map +0 -1
- package/dist/chunk-ZVJZ72HY.js.map +0 -1
- package/dist/circuit-breaker/index.d.ts +0 -197
- package/dist/circuit-breaker/index.js +0 -3
- package/dist/circuit-breaker/index.js.map +0 -1
- package/dist/deadline/index.d.ts +0 -199
- package/dist/deadline/index.js +0 -6
- package/dist/deadline/index.js.map +0 -1
- package/dist/debounce/index.js +0 -3
- package/dist/debounce/index.js.map +0 -1
- package/dist/extension/react.d.ts +0 -121
- package/dist/extension/react.js +0 -75
- package/dist/extension/react.js.map +0 -1
- package/dist/extension/subs/index.d.ts +0 -45
- package/dist/extension/subs/index.js +0 -80
- package/dist/extension/subs/index.js.map +0 -1
- package/dist/extension/test-utils.d.ts +0 -128
- package/dist/extension/test-utils.js +0 -277
- package/dist/extension/test-utils.js.map +0 -1
- package/dist/fan-out/index.js +0 -5
- package/dist/fan-out/index.js.map +0 -1
- package/dist/fold-BJPdjc9w.d.ts +0 -435
- package/dist/graph-B3L5e0N1.d.ts +0 -923
- package/dist/idempotency/adapter.d.ts +0 -62
- package/dist/idempotency/adapter.js +0 -4
- package/dist/idempotency/adapter.js.map +0 -1
- package/dist/idempotent-intake/index.d.ts +0 -188
- package/dist/idempotent-intake/index.js +0 -7
- package/dist/idempotent-intake/index.js.map +0 -1
- package/dist/journal/index.d.ts +0 -373
- package/dist/journal/index.js +0 -3
- package/dist/journal/index.js.map +0 -1
- package/dist/llm-call/index.d.ts +0 -311
- package/dist/llm-call/index.js +0 -16
- package/dist/llm-call/index.js.map +0 -1
- package/dist/machine-BtFWQmmq.d.ts +0 -804
- package/dist/monitored-run/index.js +0 -10
- package/dist/monitored-run/index.js.map +0 -1
- package/dist/paginated-walk/index.d.ts +0 -235
- package/dist/paginated-walk/index.js +0 -16
- package/dist/paginated-walk/index.js.map +0 -1
- package/dist/paginator/index.js +0 -3
- package/dist/paginator/index.js.map +0 -1
- package/dist/pbt/arbitraries/index.d.ts +0 -136
- package/dist/pbt/arbitraries/index.js +0 -3
- package/dist/pbt/arbitraries/index.js.map +0 -1
- package/dist/pbt/runners/index.d.ts +0 -118
- package/dist/pbt/runners/index.js +0 -5
- package/dist/pbt/runners/index.js.map +0 -1
- package/dist/poller/index.d.ts +0 -352
- package/dist/poller/index.js +0 -115
- package/dist/poller/index.js.map +0 -1
- package/dist/prediction/index.d.ts +0 -131
- package/dist/prediction/index.js +0 -4
- package/dist/prediction/index.js.map +0 -1
- package/dist/pure/index.d.ts +0 -3
- package/dist/pure/index.js +0 -4
- package/dist/pure/index.js.map +0 -1
- package/dist/rate-limit/index.d.ts +0 -115
- package/dist/rate-limit/index.js +0 -3
- package/dist/rate-limit/index.js.map +0 -1
- package/dist/reconciler/index.d.ts +0 -193
- package/dist/reconciler/index.js +0 -164
- package/dist/reconciler/index.js.map +0 -1
- package/dist/recorder/index.js +0 -3
- package/dist/recorder/index.js.map +0 -1
- package/dist/reducer-4GNR6b8B.d.ts +0 -447
- package/dist/resilient-call/index.d.ts +0 -320
- package/dist/resilient-call/index.js +0 -14
- package/dist/resilient-call/index.js.map +0 -1
- package/dist/retry-to-success/index.d.ts +0 -109
- package/dist/retry-to-success/index.js +0 -37
- package/dist/retry-to-success/index.js.map +0 -1
- package/dist/run-pAcmBpah.d.ts +0 -713
- package/dist/runtime-types-CNLmhWif.d.ts +0 -517
- package/dist/saga/index.d.ts +0 -241
- package/dist/saga/index.js +0 -150
- package/dist/saga/index.js.map +0 -1
- package/dist/samples-B3My5oh2.d.ts +0 -59
- package/dist/snapshot/index.js +0 -5
- package/dist/snapshot/index.js.map +0 -1
- package/dist/subs/index.d.ts +0 -472
- package/dist/subs/index.js +0 -7
- package/dist/subs/index.js.map +0 -1
- package/dist/throttle/index.d.ts +0 -134
- package/dist/throttle/index.js +0 -3
- package/dist/throttle/index.js.map +0 -1
- package/dist/throttled-input/index.js.map +0 -1
- package/dist/token-refresh/index.d.ts +0 -216
- package/dist/token-refresh/index.js +0 -6
- package/dist/token-refresh/index.js.map +0 -1
- package/dist/trace-replay/index.js +0 -6
- package/dist/trace-replay/index.js.map +0 -1
- package/dist/with-deadline/index.d.ts +0 -197
- package/dist/with-deadline/index.js +0 -111
- package/dist/with-deadline/index.js.map +0 -1
- package/dist/with-resilience/index.d.ts +0 -225
- package/dist/with-resilience/index.js +0 -240
- package/dist/with-resilience/index.js.map +0 -1
- package/dist/with-telemetry/index.d.ts +0 -150
- package/dist/with-telemetry/index.js +0 -70
- package/dist/with-telemetry/index.js.map +0 -1
- package/dist/work-queue/adapter.d.ts +0 -84
- package/dist/work-queue/adapter.js +0 -4
- package/dist/work-queue/adapter.js.map +0 -1
- package/dist/work-queue/ops.d.ts +0 -71
- package/dist/work-queue/ops.js +0 -3
- package/dist/work-queue/ops.js.map +0 -1
- package/dist/workflow/index.d.ts +0 -485
- package/dist/workflow/index.js +0 -244
- package/dist/workflow/index.js.map +0 -1
- /package/dist/{cache → paginate}/index.js.map +0 -0
- /package/dist/{chart/inspect → persistence}/index.js.map +0 -0
package/dist/pbt/index.d.ts
CHANGED
|
@@ -1,9 +1,251 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { C as Cmd, c as Reducer, T as Transitions, U as UpdateForm } from '../core-Co0LWkIA.js';
|
|
4
|
-
import 'fast-check';
|
|
1
|
+
import * as fc from 'fast-check';
|
|
2
|
+
import { C as Cmd, S as Sub, M as Machine, d as Reducer, T as Transitions, U as UpdateForm } from '../core-DnzqWy6u.js';
|
|
5
3
|
import 'zod';
|
|
6
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Build a Ctx value whose every property access throws. Use as the `ctx`
|
|
7
|
+
* argument to PBT runners when the reducer under test is pure (does not
|
|
8
|
+
* read from ctx). Accidental ctx access during property generation
|
|
9
|
+
* surfaces as a labelled error instead of a silent `undefined` or
|
|
10
|
+
* downstream type-error.
|
|
11
|
+
*
|
|
12
|
+
* Returns a typed `Ctx` (via `as unknown as Ctx`) — the proxy satisfies the
|
|
13
|
+
* type-shape requirement at the call site; the runtime contract is
|
|
14
|
+
* "throw on first read." The `as unknown` cast is the one boundary cast
|
|
15
|
+
* this helper requires; the proxy is structurally a `Ctx` for every
|
|
16
|
+
* property accessor.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* import { stubCtxThrowingProxy } from "../index";
|
|
20
|
+
* const ctx = stubCtxThrowingProxy<MyCtx>();
|
|
21
|
+
* propertyTerminates(machine, ctx, ...);
|
|
22
|
+
* // If anything reads ctx.someField during the run, an Error throws:
|
|
23
|
+
* // "@demlik/tea/pbt: ctx access denied (PBT operates on the pure
|
|
24
|
+
* // reducer; ctx field 'someField' was read)"
|
|
25
|
+
*/
|
|
26
|
+
declare function stubCtxThrowingProxy<Ctx>(): Ctx;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Strict per-variant Msg arbitrary table. Mapped type: every key in
|
|
30
|
+
* `M["type"]` MUST have an arbitrary entry whose `T` is the narrowed
|
|
31
|
+
* variant. Adding a new Msg variant without an entry is a compile error
|
|
32
|
+
* (same load-bearing discipline as `Reducer<S, M, C>` in the substrate).
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* type Msg = { type: "start" } | { type: "tick"; now: number };
|
|
36
|
+
* const table: MsgArbitraryTable<Msg> = {
|
|
37
|
+
* start: arbConstantMsg("start"),
|
|
38
|
+
* tick: arbRecordMsg("tick", { now: fc.integer({ min: 0 }) }),
|
|
39
|
+
* };
|
|
40
|
+
*/
|
|
41
|
+
type MsgArbitraryTable<M extends {
|
|
42
|
+
type: string;
|
|
43
|
+
}> = {
|
|
44
|
+
[K in M["type"]]: fc.Arbitrary<Extract<M, {
|
|
45
|
+
type: K;
|
|
46
|
+
}>>;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Build a single `fc.Arbitrary<M>` from a `MsgArbitraryTable<M>`. Picks one
|
|
50
|
+
* variant per generation via `fc.oneof`; optional per-variant `weights`
|
|
51
|
+
* bias the distribution (default uniform).
|
|
52
|
+
*
|
|
53
|
+
* @param table Per-variant arbitrary table (strict — every variant required).
|
|
54
|
+
* @param opts Optional bias: `weights` is a `Partial<Record<M["type"], number>>`.
|
|
55
|
+
* Variants without an explicit weight default to 1.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* const msgArb = arbMsg<Msg>({
|
|
59
|
+
* start: arbConstantMsg("start"),
|
|
60
|
+
* tick: arbRecordMsg("tick", { now: fc.integer() }),
|
|
61
|
+
* stop: arbConstantMsg("stop"),
|
|
62
|
+
* }, { weights: { tick: 5, start: 1, stop: 1 } });
|
|
63
|
+
*/
|
|
64
|
+
declare function arbMsg<M extends {
|
|
65
|
+
type: string;
|
|
66
|
+
}>(table: MsgArbitraryTable<M>, opts?: {
|
|
67
|
+
weights?: Partial<Record<M["type"], number>>;
|
|
68
|
+
}): fc.Arbitrary<M>;
|
|
69
|
+
/**
|
|
70
|
+
* Build a payload-free Msg variant arbitrary. Sugar for
|
|
71
|
+
* `fc.constant({ type })` that narrows the result to `{ type: T }` literal.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* arbConstantMsg("stop") // fc.Arbitrary<{ type: "stop" }>
|
|
75
|
+
*/
|
|
76
|
+
declare function arbConstantMsg<T extends string>(type: T): fc.Arbitrary<{
|
|
77
|
+
type: T;
|
|
78
|
+
}>;
|
|
79
|
+
/**
|
|
80
|
+
* Build a record-shaped Msg variant arbitrary. Sugar for
|
|
81
|
+
* `fc.record({ type: fc.constant(type), ...fields })` that stamps the
|
|
82
|
+
* discriminator literal and combines with the per-field arbitraries.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* arbRecordMsg("tick", { now: fc.integer({ min: 0 }) })
|
|
86
|
+
* // fc.Arbitrary<{ type: "tick"; now: number }>
|
|
87
|
+
*/
|
|
88
|
+
declare function arbRecordMsg<T extends string, R>(type: T, fields: {
|
|
89
|
+
[K in keyof R]: fc.Arbitrary<R[K]>;
|
|
90
|
+
}): fc.Arbitrary<{
|
|
91
|
+
type: T;
|
|
92
|
+
} & R>;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Build an arbitrary of Msg sequences over a per-Msg arbitrary. Optionally
|
|
96
|
+
* bounded in length and / or prefixed with a fixed sequence.
|
|
97
|
+
*
|
|
98
|
+
* - `minLength` (default 0) and `maxLength` (default 30) bound the random
|
|
99
|
+
* array length. `prefix` is prepended AFTER the random tail is built; the
|
|
100
|
+
* final length is `prefix.length + tail.length`.
|
|
101
|
+
* - `prefix` is the load-bearing escape hatch for "the first msg is the
|
|
102
|
+
* one that exercises the cell I care about" (e.g. Test A's
|
|
103
|
+
* `[{ type: "ws:client:hello" }]` prefix to land in the
|
|
104
|
+
* `auditing.ws:client:hello` cell on the first transition).
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* arbMsgSequence(msgArb, { minLength: 1, maxLength: 30 });
|
|
108
|
+
* arbMsgSequence(msgArb, { prefix: [{ type: "ws:client:hello" }], maxLength: 20 });
|
|
109
|
+
*/
|
|
110
|
+
declare function arbMsgSequence<M extends {
|
|
111
|
+
type: string;
|
|
112
|
+
}>(msgArb: fc.Arbitrary<M>, opts?: {
|
|
113
|
+
readonly minLength?: number;
|
|
114
|
+
readonly maxLength?: number;
|
|
115
|
+
readonly prefix?: readonly NoInfer<M>[];
|
|
116
|
+
}): fc.Arbitrary<readonly M[]>;
|
|
117
|
+
/**
|
|
118
|
+
* State-aware Msg sequence arbitrary — generates only msgs whose
|
|
119
|
+
* precondition holds in the current state. Backed by `fc.commands`
|
|
120
|
+
* internally. Planned for a later phase.
|
|
121
|
+
*
|
|
122
|
+
* **NOT IMPLEMENTED IN v1.** The export exists today so the surface is
|
|
123
|
+
* forward-compatible; this ships in a later phase alongside
|
|
124
|
+
* shrinkers. Calling it throws.
|
|
125
|
+
*/
|
|
126
|
+
declare function arbGuidedSequence<S, M extends {
|
|
127
|
+
type: string;
|
|
128
|
+
}, C extends Cmd, U extends Sub, Ctx>(_machine: Machine<S, M, C, U, Ctx>, _ctx: Ctx, _cells: {
|
|
129
|
+
[K in M["type"]]?: (state: S) => fc.Arbitrary<Extract<M, {
|
|
130
|
+
type: K;
|
|
131
|
+
}>> | null;
|
|
132
|
+
}, _opts?: {
|
|
133
|
+
maxLength?: number;
|
|
134
|
+
}): fc.Arbitrary<readonly M[]>;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* One unit in a fold trace — the four pieces of data a property
|
|
138
|
+
* invariant typically asserts on. `prev` is the state before the msg
|
|
139
|
+
* applied; `next` is the state after; `cmds` is the cmds emitted by this
|
|
140
|
+
* single step (NOT the running total).
|
|
141
|
+
*/
|
|
142
|
+
interface Step<S, M, C> {
|
|
143
|
+
readonly prev: S;
|
|
144
|
+
readonly msg: M;
|
|
145
|
+
readonly next: S;
|
|
146
|
+
readonly cmds: readonly C[];
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Fold a Msg sequence through a machine's pure reducer, returning the
|
|
150
|
+
* per-step trace, every state in order, and the final state. Initial
|
|
151
|
+
* state comes from `replay(machine, { msgs: [], ctx, loaded })` — i.e.
|
|
152
|
+
* `machine.init(loaded ?? null, ctx)` faithfully. Init's emitted cmds
|
|
153
|
+
* are NOT included in any `Step` (they're the boot moment, not a Msg).
|
|
154
|
+
*
|
|
155
|
+
* @param machine The machine under test.
|
|
156
|
+
* @param ctx The Ctx — typically `stubCtxThrowingProxy<Ctx>()` when
|
|
157
|
+
* init is pure. Pass a real ctx if init reads from it.
|
|
158
|
+
* @param loaded Optional pre-init snapshot (the `loaded` arg to
|
|
159
|
+
* `machine.init`). Defaults to `null` (fresh boot).
|
|
160
|
+
* @param msgs The Msg sequence to fold.
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* const { states, steps, finalState } = foldEvents(machine, ctx, null, [
|
|
164
|
+
* { type: "start" }, { type: "tick" }, { type: "stop" },
|
|
165
|
+
* ]);
|
|
166
|
+
* // steps[1] = { prev: { type: "counting", n: 0 }, msg: { type: "tick" }, ... }
|
|
167
|
+
*/
|
|
168
|
+
declare function foldEvents<S, M extends {
|
|
169
|
+
type: string;
|
|
170
|
+
}, C extends Cmd, U extends Sub, Ctx>(machine: Machine<S, M, C, U, Ctx>, ctx: NoInfer<Ctx>, loaded: NoInfer<S> | null, msgs: readonly NoInfer<M>[]): {
|
|
171
|
+
readonly states: readonly S[];
|
|
172
|
+
readonly steps: readonly Step<S, M, C>[];
|
|
173
|
+
readonly finalState: S;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
/** Common options shared by every property runner. */
|
|
177
|
+
interface PropertyOpts<S> {
|
|
178
|
+
/** Pre-init snapshot — passed to `machine.init(loaded, ctx)`. Default `null`. */
|
|
179
|
+
readonly loaded?: S | null;
|
|
180
|
+
/** Number of generated sequences to test. Forwarded to `fc.assert`. */
|
|
181
|
+
readonly numRuns?: number;
|
|
182
|
+
/** Optional fast-check seed for reproducibility. */
|
|
183
|
+
readonly seed?: number;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Assert every generated Msg sequence ends in a terminal state. `terminal`
|
|
187
|
+
* is the predicate that names the acceptable final states (often
|
|
188
|
+
* `(s) => s.type === "done" || s.type === "idle"`).
|
|
189
|
+
*
|
|
190
|
+
* The "every sequence" property catches stuck states (machine gets to a
|
|
191
|
+
* non-terminal state and no further msg can escape) AND silent loops
|
|
192
|
+
* (every msg variant is a noop from a given state).
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* propertyTerminates(
|
|
196
|
+
* auditBackgroundMachine,
|
|
197
|
+
* stubCtxThrowingProxy<BackgroundCtx>(),
|
|
198
|
+
* arbMsgSequence(msgArb, { minLength: 1, maxLength: 30 }),
|
|
199
|
+
* (s) => s.type === "done" || s.type === "idle",
|
|
200
|
+
* { loaded: auditingState, numRuns: 500 },
|
|
201
|
+
* );
|
|
202
|
+
*/
|
|
203
|
+
declare function propertyTerminates<S, M extends {
|
|
204
|
+
type: string;
|
|
205
|
+
}, C extends Cmd, U extends Sub, Ctx>(machine: Machine<S, M, C, U, Ctx>, ctx: NoInfer<Ctx>, seqArb: fc.Arbitrary<readonly NoInfer<M>[]>, terminal: (state: NoInfer<S>) => boolean, opts?: NoInfer<PropertyOpts<S>>): void;
|
|
206
|
+
/**
|
|
207
|
+
* Assert a predicate holds on EVERY transition step in a generated
|
|
208
|
+
* sequence. The predicate sees `{ prev, msg, next, cmds }` per step;
|
|
209
|
+
* return true to accept, false (or throw) to fail.
|
|
210
|
+
*
|
|
211
|
+
* Use to pin a "when X happens in state Y, cmd Z must be emitted" rule.
|
|
212
|
+
* The shrinker minimizes the offending sequence to the smallest Msg list
|
|
213
|
+
* that still violates the predicate.
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* // Pin the resume-handshake fix: `ws:client:hello` in auditing must
|
|
217
|
+
* // emit `send_ws { client:ready }`.
|
|
218
|
+
* propertyInvariant(
|
|
219
|
+
* auditBackgroundMachine, ctx,
|
|
220
|
+
* arbMsgSequence(msgArb, { prefix: [{ type: "ws:client:hello" }] }),
|
|
221
|
+
* ({ prev, msg, cmds }) =>
|
|
222
|
+
* !(prev.type === "auditing" && msg.type === "ws:client:hello") ||
|
|
223
|
+
* cmds.some((c) => c.type === "send_ws" && c.msg.type === "client:ready"),
|
|
224
|
+
* { loaded: auditingState, numRuns: 200 },
|
|
225
|
+
* );
|
|
226
|
+
*/
|
|
227
|
+
declare function propertyInvariant<S, M extends {
|
|
228
|
+
type: string;
|
|
229
|
+
}, C extends Cmd, U extends Sub, Ctx>(machine: Machine<S, M, C, U, Ctx>, ctx: NoInfer<Ctx>, seqArb: fc.Arbitrary<readonly NoInfer<M>[]>, invariant: (step: Step<NoInfer<S>, NoInfer<M>, NoInfer<C>>) => boolean, opts?: NoInfer<PropertyOpts<S>>): void;
|
|
230
|
+
/**
|
|
231
|
+
* Assert a predicate over the full trace plus the final state. Use when
|
|
232
|
+
* the property is "some Msg appeared in the trace before reaching the
|
|
233
|
+
* final state" or "no two consecutive steps had the same state.type" —
|
|
234
|
+
* predicates that need the full sequence, not a single step.
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* propertyTrace(
|
|
238
|
+
* machine, ctx, seqArb,
|
|
239
|
+
* (steps, final) =>
|
|
240
|
+
* final.type !== "done" ||
|
|
241
|
+
* steps.some((step) => step.msg.type === "ws:audit:done"),
|
|
242
|
+
* { loaded: auditingState, numRuns: 500 },
|
|
243
|
+
* );
|
|
244
|
+
*/
|
|
245
|
+
declare function propertyTrace<S, M extends {
|
|
246
|
+
type: string;
|
|
247
|
+
}, C extends Cmd, U extends Sub, Ctx>(machine: Machine<S, M, C, U, Ctx>, ctx: NoInfer<Ctx>, seqArb: fc.Arbitrary<readonly NoInfer<M>[]>, predicate: (steps: readonly Step<NoInfer<S>, NoInfer<M>, NoInfer<C>>[], finalState: NoInfer<S>) => boolean, opts?: NoInfer<PropertyOpts<S>>): void;
|
|
248
|
+
|
|
7
249
|
/**
|
|
8
250
|
* Extract the Msg discriminant set at runtime from a machine. Useful for
|
|
9
251
|
* asserting that a user-supplied `MsgArbitraryTable<M>` covers every variant
|
|
@@ -33,4 +275,4 @@ declare function msgTypeKeys<S, M extends {
|
|
|
33
275
|
__form?: UpdateForm;
|
|
34
276
|
}): readonly string[];
|
|
35
277
|
|
|
36
|
-
export { msgTypeKeys };
|
|
278
|
+
export { type MsgArbitraryTable, type Step, arbConstantMsg, arbGuidedSequence, arbMsg, arbMsgSequence, arbRecordMsg, foldEvents, msgTypeKeys, propertyInvariant, propertyTerminates, propertyTrace, stubCtxThrowingProxy };
|
package/dist/pbt/index.js
CHANGED
|
@@ -1,13 +1,132 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { replay, applyCell, msgKeysOf } from '../chunk-66PY5WYF.js';
|
|
2
|
+
import * as fc from 'fast-check';
|
|
3
|
+
|
|
4
|
+
// src/pbt/arbitraries/ctx.ts
|
|
5
|
+
function stubCtxThrowingProxy() {
|
|
6
|
+
const handler = {
|
|
7
|
+
get(_target, prop) {
|
|
8
|
+
if (typeof prop === "symbol") return void 0;
|
|
9
|
+
if (prop === "toJSON" || prop === "toString" || prop === "valueOf" || prop === "then") {
|
|
10
|
+
return void 0;
|
|
11
|
+
}
|
|
12
|
+
throw new Error(
|
|
13
|
+
`@demlik/tea/pbt: ctx access denied (PBT operates on the pure reducer; ctx field '${prop}' was read). Pass a real ctx value if the reducer's init reads from ctx.`
|
|
14
|
+
);
|
|
15
|
+
},
|
|
16
|
+
has() {
|
|
17
|
+
return false;
|
|
18
|
+
},
|
|
19
|
+
ownKeys() {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
return new Proxy({}, handler);
|
|
24
|
+
}
|
|
25
|
+
function arbMsg(table, opts) {
|
|
26
|
+
const weights = opts?.weights;
|
|
27
|
+
const entries = Object.entries(table);
|
|
28
|
+
if (entries.length === 0) {
|
|
29
|
+
throw new Error("@demlik/tea/pbt: arbMsg table is empty");
|
|
30
|
+
}
|
|
31
|
+
const weighted = entries.map(([key, arb]) => ({
|
|
32
|
+
arbitrary: arb,
|
|
33
|
+
weight: weights?.[key] ?? 1
|
|
34
|
+
}));
|
|
35
|
+
return fc.oneof(...weighted);
|
|
36
|
+
}
|
|
37
|
+
function arbConstantMsg(type) {
|
|
38
|
+
return fc.constant({ type });
|
|
39
|
+
}
|
|
40
|
+
function arbRecordMsg(type, fields) {
|
|
41
|
+
const recordArbitraries = {
|
|
42
|
+
type: fc.constant(type),
|
|
43
|
+
...fields
|
|
44
|
+
};
|
|
45
|
+
return fc.record(recordArbitraries);
|
|
46
|
+
}
|
|
47
|
+
function arbMsgSequence(msgArb, opts) {
|
|
48
|
+
const minLength = opts?.minLength ?? 0;
|
|
49
|
+
const maxLength = opts?.maxLength ?? 30;
|
|
50
|
+
const prefix = opts?.prefix ?? [];
|
|
51
|
+
const tail = fc.array(msgArb, { minLength, maxLength });
|
|
52
|
+
if (prefix.length === 0) return tail;
|
|
53
|
+
return tail.map((arr) => [...prefix, ...arr]);
|
|
54
|
+
}
|
|
55
|
+
function arbGuidedSequence(_machine, _ctx, _cells, _opts) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
"@demlik/tea/pbt: arbGuidedSequence is not implemented in v1. Use arbMsgSequence with an unguided arbMsg table for now; states that don't accept a given msg should noop in the reducer (mapped-type discipline)."
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// src/pbt/runners/replay-fold.ts
|
|
62
|
+
function foldEvents(machine, ctx, loaded, msgs) {
|
|
63
|
+
const { state: initialState } = replay(machine, {
|
|
64
|
+
msgs: [],
|
|
65
|
+
ctx,
|
|
66
|
+
loaded: loaded ?? null
|
|
67
|
+
});
|
|
68
|
+
const states = [initialState];
|
|
69
|
+
const steps = [];
|
|
70
|
+
let current = initialState;
|
|
71
|
+
for (const msg of msgs) {
|
|
72
|
+
const [next, emitted] = applyCell(machine, current, msg);
|
|
73
|
+
steps.push({ prev: current, msg, next, cmds: [...emitted] });
|
|
74
|
+
states.push(next);
|
|
75
|
+
current = next;
|
|
76
|
+
}
|
|
77
|
+
return { states, steps, finalState: current };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// src/pbt/runners/property.ts
|
|
81
|
+
function resolveFcParams(opts) {
|
|
82
|
+
return {
|
|
83
|
+
numRuns: opts?.numRuns ?? 200,
|
|
84
|
+
...opts?.seed !== void 0 ? { seed: opts.seed } : {}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function runProperty(machine, ctx, seqArb, opts, check) {
|
|
88
|
+
fc.assert(
|
|
89
|
+
fc.property(seqArb, (msgs) => {
|
|
90
|
+
check(foldEvents(machine, ctx, opts?.loaded ?? null, msgs));
|
|
91
|
+
}),
|
|
92
|
+
resolveFcParams(opts)
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
function propertyTerminates(machine, ctx, seqArb, terminal, opts) {
|
|
96
|
+
runProperty(machine, ctx, seqArb, opts, ({ finalState }) => {
|
|
97
|
+
if (!terminal(finalState)) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
`propertyTerminates: final state did not match terminal predicate. Final: ${JSON.stringify(finalState)}`
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
function propertyInvariant(machine, ctx, seqArb, invariant, opts) {
|
|
105
|
+
runProperty(machine, ctx, seqArb, opts, ({ steps }) => {
|
|
106
|
+
for (const step of steps) {
|
|
107
|
+
if (!invariant(step)) {
|
|
108
|
+
throw new Error(
|
|
109
|
+
`propertyInvariant: failed at step msg=${JSON.stringify(step.msg)} prev=${JSON.stringify(step.prev)} next=${JSON.stringify(step.next)} cmds=${JSON.stringify(step.cmds)}`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function propertyTrace(machine, ctx, seqArb, predicate, opts) {
|
|
116
|
+
runProperty(machine, ctx, seqArb, opts, ({ steps, finalState }) => {
|
|
117
|
+
if (!predicate(steps, finalState)) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`propertyTrace: predicate failed on trace length=${steps.length}, final=${JSON.stringify(finalState)}`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
5
124
|
|
|
6
125
|
// src/pbt/util/msg-keys.ts
|
|
7
126
|
function msgTypeKeys(machine) {
|
|
8
127
|
return msgKeysOf(machine);
|
|
9
128
|
}
|
|
10
129
|
|
|
11
|
-
export { msgTypeKeys };
|
|
130
|
+
export { arbConstantMsg, arbGuidedSequence, arbMsg, arbMsgSequence, arbRecordMsg, foldEvents, msgTypeKeys, propertyInvariant, propertyTerminates, propertyTrace, stubCtxThrowingProxy };
|
|
12
131
|
//# sourceMappingURL=index.js.map
|
|
13
132
|
//# sourceMappingURL=index.js.map
|
package/dist/pbt/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/pbt/util/msg-keys.ts"],"names":[],"mappings":";;;;;;AA8CO,SAAS,YAId,OAAA,EAKoB;AACpB,EAAA,OAAO,UAAU,OAAO,CAAA;AAC1B","file":"index.js","sourcesContent":["// ---------------------------------------------------------------------------\n// msgTypeKeys — read the Msg discriminant set at runtime from a machine's\n// Reducer record or Transitions table.\n//\n// TS Msg unions only exist at the type level; the discriminant strings are\n// erased at runtime. The reducer record / transitions table is the load-\n// bearing artifact that DOES carry the discriminants at runtime — its keys\n// (for Reducer) or any one cell's inner keys (for Transitions) are exactly\n// the set we need to build an `arbMsg` table without hand-listing them.\n//\n// Standalone helper: hand it a machine and it returns the Msg variants the\n// reducer/transitions record carries at runtime. `arbMsg` does NOT call it —\n// `MsgArbitraryTable<M>` enforces table coverage at compile time (adding a\n// variant without an arbitrary fails to compile, not at runtime). This helper\n// is for callers that want the discriminant set explicitly at runtime — e.g.\n// a test asserting a table covers every variant.\n// ---------------------------------------------------------------------------\n\nimport {\n type Cmd,\n msgKeysOf,\n type Reducer,\n type Transitions,\n type UpdateForm,\n} from \"../../index\";\n\n/**\n * Extract the Msg discriminant set at runtime from a machine. Useful for\n * asserting that a user-supplied `MsgArbitraryTable<M>` covers every variant\n * the reducer can handle.\n *\n * Takes the MACHINE (not the bare `update` record) so the reducer-vs-\n * transitions branch honors the authoritative `__form` tag via `msgKeysOf` —\n * the same classification production `run` uses (#275).\n *\n * - **Reducer form** — keys of the top-level record ARE the Msg variants.\n * - **Transitions form** — keys of any single state's inner record. Every\n * state's inner record must cover every Msg variant (mapped-type\n * discipline), so reading the first state's keys is equivalent to reading\n * the union.\n *\n * @example\n * import { auditBackgroundMachine } from \"./reducer\";\n * msgTypeKeys(auditBackgroundMachine);\n * // → [\"start_audit\", \"stop_audit\", \"window_created\", ...]\n */\nexport function msgTypeKeys<\n S,\n M extends { type: string },\n C extends Cmd,\n>(machine: {\n update:\n | Reducer<S, M, C>\n | ([S] extends [{ type: string }] ? Transitions<S, M, C> : never);\n __form?: UpdateForm;\n}): readonly string[] {\n return msgKeysOf(machine);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/pbt/arbitraries/ctx.ts","../../src/pbt/arbitraries/msg.ts","../../src/pbt/arbitraries/sequence.ts","../../src/pbt/runners/replay-fold.ts","../../src/pbt/runners/property.ts","../../src/pbt/util/msg-keys.ts"],"names":["fc2","fc3"],"mappings":"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","file":"index.js","sourcesContent":["// ---------------------------------------------------------------------------\n// `stubCtxThrowingProxy<Ctx>()` — a Proxy that satisfies the Ctx type-shape\n// at compile time but throws on every property access at runtime.\n//\n// Why this exists: PBT runs the pure reducer surface ONLY — `replay` never\n// invokes `interpret` and never starts a Sub, so Ctx should never be\n// dereferenced during property generation. But the substrate's `replay`\n// signature requires a `ctx: Ctx` value at compile time (it forwards ctx\n// into `init`, which on some machines IS pure but on others reads ctx). A\n// hand-rolled `{} as Ctx` would silently pass through any accidental ctx\n// access — exactly the silent footgun this proxy catches.\n//\n// Open question 2 (design doc): we ship this as the default. Tests that\n// genuinely need a working ctx (because their `init` reads from it) can\n// pass a real ctx value instead — the proxy is opt-in, not load-bearing.\n//\n// Strengthens invariant 6 (no silent failures — accidental ctx reads\n// produce a useful error, not a `undefined.foo` confusion later).\n// ---------------------------------------------------------------------------\n\n/**\n * Build a Ctx value whose every property access throws. Use as the `ctx`\n * argument to PBT runners when the reducer under test is pure (does not\n * read from ctx). Accidental ctx access during property generation\n * surfaces as a labelled error instead of a silent `undefined` or\n * downstream type-error.\n *\n * Returns a typed `Ctx` (via `as unknown as Ctx`) — the proxy satisfies the\n * type-shape requirement at the call site; the runtime contract is\n * \"throw on first read.\" The `as unknown` cast is the one boundary cast\n * this helper requires; the proxy is structurally a `Ctx` for every\n * property accessor.\n *\n * @example\n * import { stubCtxThrowingProxy } from \"../index\";\n * const ctx = stubCtxThrowingProxy<MyCtx>();\n * propertyTerminates(machine, ctx, ...);\n * // If anything reads ctx.someField during the run, an Error throws:\n * // \"@demlik/tea/pbt: ctx access denied (PBT operates on the pure\n * // reducer; ctx field 'someField' was read)\"\n */\nexport function stubCtxThrowingProxy<Ctx>(): Ctx {\n const handler: ProxyHandler<object> = {\n get(_target, prop: string | symbol): unknown {\n // Allow vitest / fast-check internals to introspect via Symbol-keyed\n // checks (e.g. Symbol.toStringTag, Symbol.iterator). Returning\n // undefined on symbol keys keeps property-tree walks cheap; the\n // throw fires on real domain field reads.\n if (typeof prop === \"symbol\") return undefined;\n // Some shrinkers / pretty-printers in fast-check probe a small set\n // of conventional field names (`toJSON`, `toString`, `valueOf`,\n // `then` — the last for thenable-check). Return undefined for those\n // so the proxy doesn't fail a probe before the property body runs.\n if (\n prop === \"toJSON\" ||\n prop === \"toString\" ||\n prop === \"valueOf\" ||\n prop === \"then\"\n ) {\n return undefined;\n }\n throw new Error(\n `@demlik/tea/pbt: ctx access denied (PBT operates on the pure reducer; ` +\n `ctx field '${prop}' was read). Pass a real ctx value if the reducer's ` +\n `init reads from ctx.`,\n );\n },\n has(): boolean {\n return false;\n },\n ownKeys(): ArrayLike<string | symbol> {\n return [];\n },\n };\n return new Proxy({}, handler) as unknown as Ctx;\n}\n","// ---------------------------------------------------------------------------\n// Msg arbitrary builders.\n//\n// `MsgArbitraryTable<M>` is a strict mapped type — every Msg variant must\n// have an arbitrary entry, keyed by `M[\"type\"]`, narrowing the arbitrary's\n// `T` to `Extract<M, { type: K }>`. This mirrors the load-bearing discipline\n// of `Reducer<S, M, C>` and `Transitions<S, M, C>` in the substrate: adding\n// a Msg variant without an arbitrary fails to compile, not at runtime.\n//\n// `arbMsg(table, opts?)` collapses the table into a single `fc.Arbitrary<M>`\n// via `fc.oneof`. Optional per-variant weighting for sequence-skew tests.\n//\n// `arbConstantMsg(type)` / `arbRecordMsg(type, fields)` are sugar over\n// `fc.constant({ type })` / `fc.record({ type: fc.constant(type), ...fields })`.\n// They exist because every Msg variant arbitrary either (a) carries no\n// payload — `arbConstantMsg(\"stop\")` — or (b) carries a record of fields —\n// `arbRecordMsg(\"tick\", { now: fc.integer() })`. Naming the two shapes\n// prevents callers from hand-rolling `fc.record({ type: fc.constant(\"...\") })`\n// inconsistently across test files.\n//\n// Open question 1 from the design doc (strict vs Partial table): strict by\n// default. The mapped type catches drift at compile time; `arbMsgPartial`\n// sugar is a future addition iff friction becomes real.\n// ---------------------------------------------------------------------------\n\nimport * as fc from \"fast-check\";\n\n/**\n * Strict per-variant Msg arbitrary table. Mapped type: every key in\n * `M[\"type\"]` MUST have an arbitrary entry whose `T` is the narrowed\n * variant. Adding a new Msg variant without an entry is a compile error\n * (same load-bearing discipline as `Reducer<S, M, C>` in the substrate).\n *\n * @example\n * type Msg = { type: \"start\" } | { type: \"tick\"; now: number };\n * const table: MsgArbitraryTable<Msg> = {\n * start: arbConstantMsg(\"start\"),\n * tick: arbRecordMsg(\"tick\", { now: fc.integer({ min: 0 }) }),\n * };\n */\nexport type MsgArbitraryTable<M extends { type: string }> = {\n [K in M[\"type\"]]: fc.Arbitrary<Extract<M, { type: K }>>;\n};\n\n/**\n * Build a single `fc.Arbitrary<M>` from a `MsgArbitraryTable<M>`. Picks one\n * variant per generation via `fc.oneof`; optional per-variant `weights`\n * bias the distribution (default uniform).\n *\n * @param table Per-variant arbitrary table (strict — every variant required).\n * @param opts Optional bias: `weights` is a `Partial<Record<M[\"type\"], number>>`.\n * Variants without an explicit weight default to 1.\n *\n * @example\n * const msgArb = arbMsg<Msg>({\n * start: arbConstantMsg(\"start\"),\n * tick: arbRecordMsg(\"tick\", { now: fc.integer() }),\n * stop: arbConstantMsg(\"stop\"),\n * }, { weights: { tick: 5, start: 1, stop: 1 } });\n */\nexport function arbMsg<M extends { type: string }>(\n table: MsgArbitraryTable<M>,\n opts?: { weights?: Partial<Record<M[\"type\"], number>> },\n): fc.Arbitrary<M> {\n const weights = opts?.weights;\n const entries = Object.entries(table) as [M[\"type\"], fc.Arbitrary<M>][];\n if (entries.length === 0) {\n throw new Error(\"@demlik/tea/pbt: arbMsg table is empty\");\n }\n const weighted = entries.map(([key, arb]) => ({\n arbitrary: arb,\n weight: weights?.[key] ?? 1,\n }));\n return fc.oneof(...weighted);\n}\n\n/**\n * Build a payload-free Msg variant arbitrary. Sugar for\n * `fc.constant({ type })` that narrows the result to `{ type: T }` literal.\n *\n * @example\n * arbConstantMsg(\"stop\") // fc.Arbitrary<{ type: \"stop\" }>\n */\nexport function arbConstantMsg<T extends string>(\n type: T,\n): fc.Arbitrary<{ type: T }> {\n return fc.constant({ type });\n}\n\n/**\n * Build a record-shaped Msg variant arbitrary. Sugar for\n * `fc.record({ type: fc.constant(type), ...fields })` that stamps the\n * discriminator literal and combines with the per-field arbitraries.\n *\n * @example\n * arbRecordMsg(\"tick\", { now: fc.integer({ min: 0 }) })\n * // fc.Arbitrary<{ type: \"tick\"; now: number }>\n */\nexport function arbRecordMsg<T extends string, R>(\n type: T,\n fields: { [K in keyof R]: fc.Arbitrary<R[K]> },\n): fc.Arbitrary<{ type: T } & R> {\n // `fc.record` builds an arbitrary of the merged-shape record. The\n // `type: fc.constant(type)` field stamps the literal discriminator;\n // the spread of `fields` provides every payload field's arbitrary.\n //\n // The intermediate `as Record<string, fc.Arbitrary<unknown>>` is the\n // single load-bearing cast — fc.record's parameter type is invariant in\n // its inferred field shape, and the merged literal-and-generic spread\n // doesn't unify with the strict `{ [K in keyof R]: Arbitrary<R[K]> }`\n // shape TS computes for us. The outer cast to `fc.Arbitrary<{ type: T }\n // & R>` restates the result shape we know to be correct at this\n // boundary. Mirrors the same discipline `fc.record` callers use\n // throughout the prior-art branch.\n const recordArbitraries: Record<string, fc.Arbitrary<unknown>> = {\n type: fc.constant(type),\n ...(fields as Record<string, fc.Arbitrary<unknown>>),\n };\n return fc.record(recordArbitraries) as unknown as fc.Arbitrary<\n { type: T } & R\n >;\n}\n","// ---------------------------------------------------------------------------\n// Msg-sequence arbitraries.\n//\n// `arbMsgSequence(msgArb, opts)` produces `fc.Arbitrary<readonly M[]>` —\n// fast-check's default-shrinker handles the array; the per-element shrinker\n// inside `msgArb` shrinks each variant. Optional `prefix` is prepended\n// verbatim (used by Test A: \"the bug-triggering Msg leads the sequence\").\n//\n// `arbGuidedSequence` is the state-aware sequence builder. In v1 it throws\n// — Phase 6 of the design doc lands the `fc.commands`-backed implementation.\n// The export exists today so the surface is forward-compatible: consumers\n// that need state-aware generation get a useful error pointing at the\n// design doc instead of \"is not a function.\"\n// ---------------------------------------------------------------------------\n\nimport * as fc from \"fast-check\";\nimport type { Cmd, Machine, Sub } from \"../../index\";\n\n/**\n * Build an arbitrary of Msg sequences over a per-Msg arbitrary. Optionally\n * bounded in length and / or prefixed with a fixed sequence.\n *\n * - `minLength` (default 0) and `maxLength` (default 30) bound the random\n * array length. `prefix` is prepended AFTER the random tail is built; the\n * final length is `prefix.length + tail.length`.\n * - `prefix` is the load-bearing escape hatch for \"the first msg is the\n * one that exercises the cell I care about\" (e.g. Test A's\n * `[{ type: \"ws:client:hello\" }]` prefix to land in the\n * `auditing.ws:client:hello` cell on the first transition).\n *\n * @example\n * arbMsgSequence(msgArb, { minLength: 1, maxLength: 30 });\n * arbMsgSequence(msgArb, { prefix: [{ type: \"ws:client:hello\" }], maxLength: 20 });\n */\nexport function arbMsgSequence<M extends { type: string }>(\n msgArb: fc.Arbitrary<M>,\n opts?: {\n readonly minLength?: number;\n readonly maxLength?: number;\n readonly prefix?: readonly NoInfer<M>[];\n },\n): fc.Arbitrary<readonly M[]> {\n const minLength = opts?.minLength ?? 0;\n const maxLength = opts?.maxLength ?? 30;\n const prefix = opts?.prefix ?? [];\n const tail = fc.array(msgArb, { minLength, maxLength });\n if (prefix.length === 0) return tail;\n return tail.map((arr) => [...prefix, ...arr]);\n}\n\n/**\n * State-aware Msg sequence arbitrary — generates only msgs whose\n * precondition holds in the current state. Backed by `fc.commands`\n * internally. Planned for a later phase.\n *\n * **NOT IMPLEMENTED IN v1.** The export exists today so the surface is\n * forward-compatible; this ships in a later phase alongside\n * shrinkers. Calling it throws.\n */\nexport function arbGuidedSequence<\n S,\n M extends { type: string },\n C extends Cmd,\n U extends Sub,\n Ctx,\n>(\n _machine: Machine<S, M, C, U, Ctx>,\n _ctx: Ctx,\n _cells: {\n [K in M[\"type\"]]?: (\n state: S,\n ) => fc.Arbitrary<Extract<M, { type: K }>> | null;\n },\n _opts?: { maxLength?: number },\n): fc.Arbitrary<readonly M[]> {\n throw new Error(\n \"@demlik/tea/pbt: arbGuidedSequence is not implemented in v1. \" +\n \"Use arbMsgSequence with \" +\n \"an unguided arbMsg table for now; states that don't accept a given \" +\n \"msg should noop in the reducer (mapped-type discipline).\",\n );\n}\n","// ---------------------------------------------------------------------------\n// `foldEvents` — pure deterministic fold over a Msg sequence.\n//\n// PBT needs the per-step (prev/msg/next/cmds) structure to assert\n// step-shaped invariants. The substrate's `replay(machine, opts)` returns\n// only final state + cumulative cmds — insufficient. We use `replay` for\n// the boot step (calls `machine.init(loaded, ctx)` faithfully) then walk\n// msgs ourselves through `applyCell`, the substrate's own cell dispatch.\n//\n// Why walk cells directly instead of looping `replay` once per msg with\n// `loaded: prevState`? Because `init(loaded)` runs every call, and on\n// machines with non-trivial init transforms (e.g. the audit machine's\n// `auditing → attach_debugger` resume cell) that would either (a) re-fire\n// the transform on every step, or (b) require fragile cmd-subtraction to\n// isolate this step's cmds. Calling the cells directly keeps the fold pure\n// and the cmds per-step exactly.\n//\n// Dispatches through `applyCell` — the single primitive `run`/`replay` use —\n// so form classification agrees with production by construction (#275).\n//\n// `foldEvents` does NOT call `interpret`, does NOT touch a Store, does NOT\n// start Subs. The reducer surface is the contract.\n// ---------------------------------------------------------------------------\n\nimport {\n applyCell,\n type Cmd,\n type Machine,\n replay,\n type Sub,\n} from \"../../index\";\n\n/**\n * One unit in a fold trace — the four pieces of data a property\n * invariant typically asserts on. `prev` is the state before the msg\n * applied; `next` is the state after; `cmds` is the cmds emitted by this\n * single step (NOT the running total).\n */\nexport interface Step<S, M, C> {\n readonly prev: S;\n readonly msg: M;\n readonly next: S;\n readonly cmds: readonly C[];\n}\n\n/**\n * Fold a Msg sequence through a machine's pure reducer, returning the\n * per-step trace, every state in order, and the final state. Initial\n * state comes from `replay(machine, { msgs: [], ctx, loaded })` — i.e.\n * `machine.init(loaded ?? null, ctx)` faithfully. Init's emitted cmds\n * are NOT included in any `Step` (they're the boot moment, not a Msg).\n *\n * @param machine The machine under test.\n * @param ctx The Ctx — typically `stubCtxThrowingProxy<Ctx>()` when\n * init is pure. Pass a real ctx if init reads from it.\n * @param loaded Optional pre-init snapshot (the `loaded` arg to\n * `machine.init`). Defaults to `null` (fresh boot).\n * @param msgs The Msg sequence to fold.\n *\n * @example\n * const { states, steps, finalState } = foldEvents(machine, ctx, null, [\n * { type: \"start\" }, { type: \"tick\" }, { type: \"stop\" },\n * ]);\n * // steps[1] = { prev: { type: \"counting\", n: 0 }, msg: { type: \"tick\" }, ... }\n */\nexport function foldEvents<\n S,\n M extends { type: string },\n C extends Cmd,\n U extends Sub,\n Ctx,\n>(\n machine: Machine<S, M, C, U, Ctx>,\n ctx: NoInfer<Ctx>,\n loaded: NoInfer<S> | null,\n msgs: readonly NoInfer<M>[],\n): {\n readonly states: readonly S[];\n readonly steps: readonly Step<S, M, C>[];\n readonly finalState: S;\n} {\n // Boot through `replay` so `init` runs faithfully and we honor the\n // substrate's loaded-snapshot contract (init may transform the loaded\n // value before the first Msg lands — e.g. the audit machine flips\n // `debuggerAttached: false` on resume).\n const { state: initialState } = replay(machine, {\n msgs: [],\n ctx,\n loaded: loaded ?? null,\n });\n\n // Per-msg dispatch goes through `applyCell` — the same primitive `run` and\n // `replay` use — so this runner classifies the update form identically to\n // production (`formOf` honors the `__form` tag; #275).\n const states: S[] = [initialState];\n const steps: Step<S, M, C>[] = [];\n let current = initialState;\n\n for (const msg of msgs) {\n const [next, emitted] = applyCell<S, M, C>(machine, current, msg);\n steps.push({ prev: current, msg, next, cmds: [...emitted] });\n states.push(next);\n current = next;\n }\n\n return { states, steps, finalState: current };\n}\n","// ---------------------------------------------------------------------------\n// Property runners — three thin wrappers over `fc.assert(fc.property(...))`\n// that fold a generated Msg sequence through the machine via `foldEvents`\n// and pipe the result into a TEA-shaped predicate.\n//\n// - `propertyTerminates` — every sequence ends in a terminal state.\n// - `propertyInvariant` — predicate holds on every (prev, msg, next, cmds) step.\n// - `propertyTrace` — predicate holds on the full (trace, final) shape.\n//\n// Each runner accepts `numRuns` (passed through to fast-check), an optional\n// `loaded` snapshot (forwarded to `foldEvents`), and the Msg-sequence\n// arbitrary. They return `void`; failures throw via fast-check's standard\n// shrinking output.\n//\n// Default shrinker is fast-check's built-in (open question 4): drop-msg /\n// prefix shrinkers can be layered later but are opt-in, not default. The\n// built-in shrinker handles array-shape shrinking + per-element variant\n// shrinking automatically.\n// ---------------------------------------------------------------------------\n\nimport * as fc from \"fast-check\";\nimport type { Cmd, Machine, Sub } from \"../../index\";\nimport { foldEvents, type Step } from \"./replay-fold\";\n\n/** Common options shared by every property runner. */\ninterface PropertyOpts<S> {\n /** Pre-init snapshot — passed to `machine.init(loaded, ctx)`. Default `null`. */\n readonly loaded?: S | null;\n /** Number of generated sequences to test. Forwarded to `fc.assert`. */\n readonly numRuns?: number;\n /** Optional fast-check seed for reproducibility. */\n readonly seed?: number;\n}\n\n/** The `foldEvents` result a runner's `check` inspects. */\ntype FoldResult<S, M, C> = {\n readonly states: readonly S[];\n readonly steps: readonly Step<S, M, C>[];\n readonly finalState: S;\n};\n\n/**\n * Build the fast-check parameters shared by every runner: the 200-default\n * `numRuns` plus an optional `seed`. Single source of truth so a change to\n * the default lands in one place.\n */\nfunction resolveFcParams<M>(\n opts: PropertyOpts<unknown> | undefined,\n): fc.Parameters<[readonly M[]]> {\n return {\n numRuns: opts?.numRuns ?? 200,\n ...(opts?.seed !== undefined ? { seed: opts.seed } : {}),\n };\n}\n\n/**\n * The fold+assert core every runner shares: assert `check` over each\n * generated Msg sequence, folded once through the machine via `foldEvents`.\n * `check` throws on failure so the error message carries the offending\n * shape into fast-check's shrunk counter-example.\n */\nfunction runProperty<\n S,\n M extends { type: string },\n C extends Cmd,\n U extends Sub,\n Ctx,\n>(\n machine: Machine<S, M, C, U, Ctx>,\n ctx: Ctx,\n seqArb: fc.Arbitrary<readonly M[]>,\n opts: PropertyOpts<S> | undefined,\n check: (result: FoldResult<S, M, C>) => void,\n): void {\n fc.assert(\n fc.property(seqArb, (msgs) => {\n check(foldEvents(machine, ctx, opts?.loaded ?? null, msgs));\n }),\n resolveFcParams<M>(opts),\n );\n}\n\n/**\n * Assert every generated Msg sequence ends in a terminal state. `terminal`\n * is the predicate that names the acceptable final states (often\n * `(s) => s.type === \"done\" || s.type === \"idle\"`).\n *\n * The \"every sequence\" property catches stuck states (machine gets to a\n * non-terminal state and no further msg can escape) AND silent loops\n * (every msg variant is a noop from a given state).\n *\n * @example\n * propertyTerminates(\n * auditBackgroundMachine,\n * stubCtxThrowingProxy<BackgroundCtx>(),\n * arbMsgSequence(msgArb, { minLength: 1, maxLength: 30 }),\n * (s) => s.type === \"done\" || s.type === \"idle\",\n * { loaded: auditingState, numRuns: 500 },\n * );\n */\nexport function propertyTerminates<\n S,\n M extends { type: string },\n C extends Cmd,\n U extends Sub,\n Ctx,\n>(\n machine: Machine<S, M, C, U, Ctx>,\n ctx: NoInfer<Ctx>,\n seqArb: fc.Arbitrary<readonly NoInfer<M>[]>,\n terminal: (state: NoInfer<S>) => boolean,\n opts?: NoInfer<PropertyOpts<S>>,\n): void {\n runProperty(machine, ctx, seqArb, opts, ({ finalState }) => {\n if (!terminal(finalState)) {\n // Throwing here (vs returning false) lets the error message carry\n // the offending final state — fast-check pretty-prints it inside\n // the shrunk counter-example.\n throw new Error(\n `propertyTerminates: final state did not match terminal predicate. ` +\n `Final: ${JSON.stringify(finalState)}`,\n );\n }\n });\n}\n\n/**\n * Assert a predicate holds on EVERY transition step in a generated\n * sequence. The predicate sees `{ prev, msg, next, cmds }` per step;\n * return true to accept, false (or throw) to fail.\n *\n * Use to pin a \"when X happens in state Y, cmd Z must be emitted\" rule.\n * The shrinker minimizes the offending sequence to the smallest Msg list\n * that still violates the predicate.\n *\n * @example\n * // Pin the resume-handshake fix: `ws:client:hello` in auditing must\n * // emit `send_ws { client:ready }`.\n * propertyInvariant(\n * auditBackgroundMachine, ctx,\n * arbMsgSequence(msgArb, { prefix: [{ type: \"ws:client:hello\" }] }),\n * ({ prev, msg, cmds }) =>\n * !(prev.type === \"auditing\" && msg.type === \"ws:client:hello\") ||\n * cmds.some((c) => c.type === \"send_ws\" && c.msg.type === \"client:ready\"),\n * { loaded: auditingState, numRuns: 200 },\n * );\n */\nexport function propertyInvariant<\n S,\n M extends { type: string },\n C extends Cmd,\n U extends Sub,\n Ctx,\n>(\n machine: Machine<S, M, C, U, Ctx>,\n ctx: NoInfer<Ctx>,\n seqArb: fc.Arbitrary<readonly NoInfer<M>[]>,\n invariant: (step: Step<NoInfer<S>, NoInfer<M>, NoInfer<C>>) => boolean,\n opts?: NoInfer<PropertyOpts<S>>,\n): void {\n runProperty(machine, ctx, seqArb, opts, ({ steps }) => {\n for (const step of steps) {\n if (!invariant(step)) {\n throw new Error(\n `propertyInvariant: failed at step msg=${JSON.stringify(step.msg)} ` +\n `prev=${JSON.stringify(step.prev)} next=${JSON.stringify(step.next)} ` +\n `cmds=${JSON.stringify(step.cmds)}`,\n );\n }\n }\n });\n}\n\n/**\n * Assert a predicate over the full trace plus the final state. Use when\n * the property is \"some Msg appeared in the trace before reaching the\n * final state\" or \"no two consecutive steps had the same state.type\" —\n * predicates that need the full sequence, not a single step.\n *\n * @example\n * propertyTrace(\n * machine, ctx, seqArb,\n * (steps, final) =>\n * final.type !== \"done\" ||\n * steps.some((step) => step.msg.type === \"ws:audit:done\"),\n * { loaded: auditingState, numRuns: 500 },\n * );\n */\nexport function propertyTrace<\n S,\n M extends { type: string },\n C extends Cmd,\n U extends Sub,\n Ctx,\n>(\n machine: Machine<S, M, C, U, Ctx>,\n ctx: NoInfer<Ctx>,\n seqArb: fc.Arbitrary<readonly NoInfer<M>[]>,\n predicate: (\n steps: readonly Step<NoInfer<S>, NoInfer<M>, NoInfer<C>>[],\n finalState: NoInfer<S>,\n ) => boolean,\n opts?: NoInfer<PropertyOpts<S>>,\n): void {\n runProperty(machine, ctx, seqArb, opts, ({ steps, finalState }) => {\n if (!predicate(steps, finalState)) {\n throw new Error(\n `propertyTrace: predicate failed on trace length=${steps.length}, ` +\n `final=${JSON.stringify(finalState)}`,\n );\n }\n });\n}\n","// ---------------------------------------------------------------------------\n// msgTypeKeys — read the Msg discriminant set at runtime from a machine's\n// Reducer record or Transitions table.\n//\n// TS Msg unions only exist at the type level; the discriminant strings are\n// erased at runtime. The reducer record / transitions table is the load-\n// bearing artifact that DOES carry the discriminants at runtime — its keys\n// (for Reducer) or any one cell's inner keys (for Transitions) are exactly\n// the set we need to build an `arbMsg` table without hand-listing them.\n//\n// Standalone helper: hand it a machine and it returns the Msg variants the\n// reducer/transitions record carries at runtime. `arbMsg` does NOT call it —\n// `MsgArbitraryTable<M>` enforces table coverage at compile time (adding a\n// variant without an arbitrary fails to compile, not at runtime). This helper\n// is for callers that want the discriminant set explicitly at runtime — e.g.\n// a test asserting a table covers every variant.\n// ---------------------------------------------------------------------------\n\nimport {\n type Cmd,\n msgKeysOf,\n type Reducer,\n type Transitions,\n type UpdateForm,\n} from \"../../index\";\n\n/**\n * Extract the Msg discriminant set at runtime from a machine. Useful for\n * asserting that a user-supplied `MsgArbitraryTable<M>` covers every variant\n * the reducer can handle.\n *\n * Takes the MACHINE (not the bare `update` record) so the reducer-vs-\n * transitions branch honors the authoritative `__form` tag via `msgKeysOf` —\n * the same classification production `run` uses (#275).\n *\n * - **Reducer form** — keys of the top-level record ARE the Msg variants.\n * - **Transitions form** — keys of any single state's inner record. Every\n * state's inner record must cover every Msg variant (mapped-type\n * discipline), so reading the first state's keys is equivalent to reading\n * the union.\n *\n * @example\n * import { auditBackgroundMachine } from \"./reducer\";\n * msgTypeKeys(auditBackgroundMachine);\n * // → [\"start_audit\", \"stop_audit\", \"window_created\", ...]\n */\nexport function msgTypeKeys<\n S,\n M extends { type: string },\n C extends Cmd,\n>(machine: {\n update:\n | Reducer<S, M, C>\n | ([S] extends [{ type: string }] ? Transitions<S, M, C> : never);\n __form?: UpdateForm;\n}): readonly string[] {\n return msgKeysOf(machine);\n}\n"]}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import '../
|
|
1
|
+
import { T as Trace } from '../index-DrIRb_Ch.js';
|
|
2
|
+
export { B as BreadcrumbsOptions, a as Recorder, R as RecorderOptions, b as TraceAttachment, c as TraceBreadcrumb, d as breadcrumbsFromTrace, p as parseJSONL, r as recorder, t as traceAttachment } from '../index-DrIRb_Ch.js';
|
|
3
|
+
export { h as SnapshotConfig, d as SnapshotFailedMsg, i as SnapshotKnob, g as SnapshotLoadCmd, f as SnapshotLoadFailedMsg, e as SnapshotLoadedMsg, j as SnapshotPorts, c as SnapshotSavedMsg, a as SnapshotState, b as SnapshotStore, S as SnapshotWriteCmd, k as createSnapshot, s as snapshotFailed, l as snapshotLoad, m as snapshotLoadFailed, n as snapshotLoaded, o as snapshotSaved, p as snapshotWriteDef } from '../index-ZCMhnVKN.js';
|
|
4
|
+
import { C as Cmd, S as Sub, M as Machine } from '../core-DnzqWy6u.js';
|
|
5
|
+
import '../runtime-types-CMF13BBh.js';
|
|
5
6
|
import 'better-result';
|
|
7
|
+
import 'zod';
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* The outcome of {@link replayTrace}.
|
|
@@ -65,4 +67,4 @@ declare function replayTrace<S, M extends {
|
|
|
65
67
|
*/
|
|
66
68
|
declare function deepEqual(a: unknown, b: unknown): boolean;
|
|
67
69
|
|
|
68
|
-
export { type ReplayResult, deepEqual, replayTrace };
|
|
70
|
+
export { type ReplayResult, Trace, deepEqual, replayTrace };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { breadcrumbsFromTrace, deepEqual, parseJSONL, recorder, replayTrace, traceAttachment } from '../chunk-V46HSVCK.js';
|
|
2
|
+
export { createSnapshot, snapshotFailed, snapshotLoad, snapshotLoadFailed, snapshotLoaded, snapshotSaved, snapshotWriteDef } from '../chunk-L3TND7LA.js';
|
|
3
|
+
import '../chunk-HWVW4AXC.js';
|
|
4
|
+
import '../chunk-66PY5WYF.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -23,6 +23,13 @@ declare const MsgType: {
|
|
|
23
23
|
* by the agent reducer — see `AgentBootPort` in `../agent`.
|
|
24
24
|
*/
|
|
25
25
|
readonly AgentBoot: "agent_boot";
|
|
26
|
+
/**
|
|
27
|
+
* Stop the run from outside and settle it `cancelled` — what an `AbortSignal`
|
|
28
|
+
* handed to `driveToDone` / a defined agent's `run` dispatches on abort. A
|
|
29
|
+
* transition, never a throw: the outcome lands in the Model, so a reload reads
|
|
30
|
+
* a run that ended rather than one to resume.
|
|
31
|
+
*/
|
|
32
|
+
readonly AgentCancel: "agent_cancel";
|
|
26
33
|
/**
|
|
27
34
|
* The "summarize the oldest N turns" effect Cmd the agent emits when its
|
|
28
35
|
* `CompactionPolicy` asks to compact before a brain call. A DEDICATED
|
|
@@ -41,5 +48,7 @@ declare const MsgType: {
|
|
|
41
48
|
/** The 401 the consumer dispatches when a guarded call comes back unauthorized. */
|
|
42
49
|
readonly Unauthorized: "unauthorized";
|
|
43
50
|
};
|
|
51
|
+
/** The union of every discriminant string in the protocol. */
|
|
52
|
+
type MsgTypeValue = (typeof MsgType)[keyof typeof MsgType];
|
|
44
53
|
|
|
45
|
-
export { MsgType as M };
|
|
54
|
+
export { MsgType as M, type MsgTypeValue as a };
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as Store, R as Runtime } from '../runtime-types-
|
|
2
|
-
import { C as Cmd, S as Sub, M as Machine, R as RequiredCtx } from '../core-
|
|
1
|
+
import { S as Store, R as Runtime } from '../runtime-types-CMF13BBh.js';
|
|
2
|
+
import { C as Cmd, S as Sub, M as Machine, R as RequiredCtx } from '../core-DnzqWy6u.js';
|
|
3
3
|
import 'better-result';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
package/dist/react/index.js
CHANGED
package/dist/react/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/react/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/react/index.ts"],"names":[],"mappings":";;;AA6EO,SAAS,UAAA,CAOd,SAEA,IAAA,EACgC;AAMhC,EAAA,MAAM,MAAM,IAAA,CAAK,GAAA;AACjB,EAAA,MAAM,QAAQ,IAAA,CAAK,KAAA;AAMnB,EAAA,MAAM,OAAA,GAAU,OAAA;AAAA,IACd,MAAM,GAAA,CAAI,OAAA,EAAS,EAAE,GAAA,EAAK,OAAO,CAAA;AAAA,IACjC,CAAC,OAAA,EAAS,GAAA,EAAK,KAAK;AAAA,GACtB;AAeA,EAAA,MAAM,QAAA,GAAW,OAA6B,IAAI,CAAA;AAClD,EAAA,MAAM,GAAG,UAAU,CAAA,GAAI,WAAW,CAAC,IAAA,KAAiB,IAAA,GAAO,CAAA,EAAG,CAAC,CAAA;AAa/D,EAAA,MAAM,gBAAA,GAAmB,OAAA;AAAA,IACvB,MAAM,OAAA,CAAQ,IAAA,CAAK,IAAA,EAAM,GAAG,EAAE,CAAC,CAAA;AAAA,IAC/B,CAAC,SAAS,GAAG;AAAA,GACf;AAMA,EAAA,MAAM,WAAA,GAAc,MAClB,QAAA,CAAS,OAAA,KAAY,OAAO,QAAA,CAAS,OAAA,CAAQ,UAAS,GAAI,gBAAA;AAE5D,EAAA,MAAM,KAAA,GAAQ,oBAAA;AAAA,IACZ,OAAA,CAAQ,SAAA;AAAA,IACR,WAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,IAAA,GAAO,IAAA;AAMX,IAAA,OAAA,CAAQ,KAAA,CAAM,IAAA;AAAA,MACZ,CAAC,CAAA,KAAM;AACL,QAAA,IAAI,IAAA,EAAM;AACR,UAAA,QAAA,CAAS,OAAA,GAAU,CAAA;AACnB,UAAA,UAAA,EAAW;AAAA,QACb;AAAA,MACF,CAAA;AAAA,MACA,MAAM;AAAA,MAAC;AAAA,KACT;AACA,IAAA,OAAO,MAAM;AACX,MAAA,IAAA,GAAO,KAAA;AACP,MAAA,QAAA,CAAS,OAAA,GAAU,IAAA;AAInB,MAAA,OAAA,CAAQ,IAAA,EAAK,CAAE,KAAA,CAAM,MAAM;AAAA,MAAC,CAAC,CAAA;AAAA,IAC/B,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAEZ,EAAA,OAAO,CAAC,KAAA,EAAO,OAAA,CAAQ,QAAQ,CAAA;AACjC;AAeO,SAAS,WACd,OAAA,EACgC;AAChC,EAAA,MAAM,KAAA,GAAQ,oBAAA;AAAA,IACZ,OAAA,CAAQ,SAAA;AAAA,IACR,OAAA,CAAQ,QAAA;AAAA,IACR,OAAA,CAAQ;AAAA,GACV;AACA,EAAA,OAAO,CAAC,KAAA,EAAO,OAAA,CAAQ,QAAQ,CAAA;AACjC","file":"index.js","sourcesContent":["/**\n * @packageDocumentation\n * @demlik/tea/react — React host adapter for `@demlik/tea`.\n *\n * The thinnest possible adapter that makes a tea machine consumable from a\n * React component. Three rules (PRD §\"React adapter\"):\n *\n * 1. The runtime is the source of truth, NOT React state. We subscribe via\n * `useSyncExternalStore(runtime.subscribe, runtime.getState,\n * runtime.getState)`. React renders are driven by runtime state changes;\n * React never owns the state.\n * 2. The runtime is memoized per component-mount, not per render. The deps\n * array is `[machine, opts.ctx, opts.store]` — IDENTITY, not value. See\n * `README.md` for the ctx-identity footgun + fix.\n * 3. Concurrent React is the design target. `useSyncExternalStore` is the\n * React-blessed primitive for tearing-free external state.\n *\n * Client-only in v1 — components that call `useMachine` MUST be `\"use client\"`.\n * Server Components consume data via Relay/RSC as today; tea machines own\n * client-side stateful flows. No RSC streaming, no server-side state\n * hydration. Crossing this boundary is a v2 concern.\n */\n\n\"use client\";\n\nimport {\n useEffect,\n useMemo,\n useReducer,\n useRef,\n useSyncExternalStore,\n} from \"react\";\nimport {\n type BootingRuntime,\n type Cmd,\n type Machine,\n type RequiredCtx,\n type Runtime,\n run,\n type Store,\n type Sub,\n} from \"../index\";\n\n/**\n * Options passed to `useMachine`. The shape is intentionally minimal — `ctx`\n * is required (every machine has one), `store` is optional (omit it for\n * volatile-state machines).\n *\n * **Identity matters.** The runtime is memoized on `[machine, opts.ctx,\n * opts.store]`. A new `ctx` reference rebuilds the runtime. Always `useMemo`\n * (or otherwise stabilize) the ctx at the call site. See README.\n *\n * Forgetting to is no longer silent: the replaced runtime's `stop()` reports\n * `RuntimeDiscardedError` under `phase: \"discard\"` when Cmds were still in\n * flight, which the substrate's default sink warns about (issue #365).\n */\nexport interface UseMachineOpts<S, Ctx> {\n ctx: Ctx;\n store?: Store<S>;\n}\n\n/**\n * Build and own a `Runtime<S, M>` for the lifetime of the component mount.\n *\n * - Builds via `useMemo(() => run(machine, opts), [machine, opts.ctx,\n * opts.store])` — runtime is recreated when ANY of the three identities\n * change.\n * - Subscribes via `useSyncExternalStore(runtime.subscribe, runtime.getState,\n * runtime.getState)` — tearing-free under React 18 concurrent rendering.\n * - On unmount (or any dep change), `useEffect` cleanup calls\n * `runtime.stop()` — drains the queue, runs every active sub cleanup,\n * flushes state, and — if Cmds were still in flight — reports\n * `RuntimeDiscardedError` (`phase: \"discard\"`) rather than dropping them\n * silently.\n *\n * Returns `[state, dispatch]` shaped like `useReducer`.\n */\nexport function useMachine<\n S,\n M extends { type: string },\n C extends Cmd,\n U extends Sub,\n Ctx,\n>(\n machine: Machine<S, M, C, U, Ctx>,\n // The ctx `run` demands: the machine's own plus every typed Cmd's `R`.\n opts: UseMachineOpts<S, Ctx & RequiredCtx<C>>,\n): [S, (msg: M) => Promise<void>] {\n // Deps are literal: machine identity, ctx identity, store identity. NOT\n // `[opts]` (would rebuild every render — callers pass fresh objects).\n // We pass explicit fields to `run()` so the closure captures only the\n // deps in the array — keeps biome's `useExhaustiveDependencies` happy\n // without lying about what the memo actually depends on.\n const ctx = opts.ctx;\n const store = opts.store;\n // `run()` returns a `BootingRuntime<S, M>` SYNCHRONOUSLY (issue #45) — exactly\n // what `useMemo` needs. We never `await` here: awaiting would force an async\n // memo, a null first-commit state, and a resolved-flag dance. Instead we hold\n // the booting handle and capture the booted `Runtime` (the only thing with a\n // total `getState`) once `ready` resolves.\n const booting = useMemo<BootingRuntime<S, M>>(\n () => run(machine, { ctx, store }),\n [machine, ctx, store],\n );\n\n // Captures the booted `Runtime` once `ready` resolves. Until then it is\n // `null` and `getSnapshot` serves `preliminaryState`. Reset whenever the\n // booting handle identity changes (a new machine/ctx/store mount).\n //\n // The boot race the paired `bootedTick` bump exists for: the substrate's\n // boot fanout fires BEFORE `ready` resolves (fireListeners runs inside the\n // boot step; `ready` chains off the boot promise), so at notification time\n // this ref is still null and `getSnapshot` returns the same\n // `preliminaryState` reference — React sees an unchanged snapshot and\n // skips the re-render. Nothing re-notifies after the ref is set, so a\n // store-backed mount would stay stuck on the preliminary state until the\n // next unrelated transition. Bumping a reducer when we capture the booted\n // runtime forces the render that swaps preliminary → real state.\n const readyRef = useRef<Runtime<S, M> | null>(null);\n const [, markBooted] = useReducer((tick: number) => tick + 1, 0);\n\n // Preliminary state computed sync from `machine.init(null, ctx)`. This is\n // the snapshot React sees BEFORE the runtime finishes booting (matters\n // only when `opts.store` is present — without a store, the substrate\n // already sets state synchronously inside `run()`, so the boot fanout that\n // captures `readyRef` lands on the same microtask as the first commit).\n //\n // We deliberately recompute on each render but cache by `[machine,\n // opts.ctx]` — `init` is pure by convention, so cost is negligible. The\n // cached snapshot is also identity-stable across rerenders when the deps\n // don't change, which `useSyncExternalStore` rewards (no spurious\n // re-renders).\n const preliminaryState = useMemo<S>(\n () => machine.init(null, ctx)[0],\n [machine, ctx],\n );\n\n // `getSnapshot` reads the booted runtime if `ready` has resolved (the ref is\n // populated), else falls back to the preliminary state. No try/catch dance\n // anymore — pre-boot there is simply no booted `Runtime` to read from, so\n // the fallback is structural, not exception-driven.\n const getSnapshot = (): S =>\n readyRef.current !== null ? readyRef.current.getState() : preliminaryState;\n\n const state = useSyncExternalStore(\n booting.subscribe,\n getSnapshot,\n getSnapshot,\n );\n\n useEffect(() => {\n let live = true;\n // Capture the booted runtime when `ready` resolves, then force the\n // render that swaps preliminary → real state (see the boot-race note on\n // `readyRef` — the boot fanout fires too early to do it for us). Boot\n // rejections are swallowed: a failed boot surfaces on every `dispatch`,\n // which is where the consumer handles it.\n booting.ready.then(\n (r) => {\n if (live) {\n readyRef.current = r;\n markBooted();\n }\n },\n () => {},\n );\n return () => {\n live = false;\n readyRef.current = null;\n // Fire-and-forget — `stop()` is async but `useEffect` cleanup is sync.\n // The runtime swallows in-flight rejections internally, so this never\n // rejects in practice; we still attach `.catch` for safety.\n booting.stop().catch(() => {});\n };\n }, [booting]);\n\n return [state, booting.dispatch];\n}\n\n/**\n * Lower-level escape hatch: consume an externally-built `Runtime<S, M>`.\n *\n * Use this when the runtime is owned by something OTHER than the component —\n * a parent component, a test harness, a singleton. **The component does NOT\n * call `runtime.stop()` on unmount** — the caller owns the lifecycle.\n *\n * Primary use case in this repo: component tests. Build a runtime with\n * `@demlik/tea/mem` and pre-seed it via `replay`, then mount the component with\n * `useRuntime(testRuntime)` to render in any phase.\n *\n * Returns `[state, dispatch]` — same shape as `useMachine`.\n */\nexport function useRuntime<S, M extends { type: string }>(\n runtime: Runtime<S, M>,\n): [S, (msg: M) => Promise<void>] {\n const state = useSyncExternalStore(\n runtime.subscribe,\n runtime.getState,\n runtime.getState,\n );\n return [state, runtime.dispatch];\n}\n"]}
|