@demlik/tea 0.20.0 → 0.22.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.
Files changed (130) hide show
  1. package/README.md +11 -2
  2. package/dist/agent/index.d.ts +36 -23
  3. package/dist/agent/index.js +12 -10
  4. package/dist/{chunk-UHAQ4PI6.js → chunk-2A5XTKQQ.js} +205 -59
  5. package/dist/chunk-2A5XTKQQ.js.map +1 -0
  6. package/dist/{chunk-JAKM53JF.js → chunk-7K7SEYCH.js} +16 -15
  7. package/dist/chunk-7K7SEYCH.js.map +1 -0
  8. package/dist/{chunk-RKVUVALV.js → chunk-A3QPMX5M.js} +31 -9
  9. package/dist/chunk-A3QPMX5M.js.map +1 -0
  10. package/dist/{chunk-DVNXEB7V.js → chunk-BVFS3ICC.js} +3 -3
  11. package/dist/chunk-BVFS3ICC.js.map +1 -0
  12. package/dist/{chunk-FTCYY2DO.js → chunk-CPE5ZQXQ.js} +3 -3
  13. package/dist/{chunk-FTCYY2DO.js.map → chunk-CPE5ZQXQ.js.map} +1 -1
  14. package/dist/chunk-DEAPNMKO.js +11 -0
  15. package/dist/chunk-DEAPNMKO.js.map +1 -0
  16. package/dist/{chunk-XWIE5V7R.js → chunk-ETRNSJCR.js} +4 -4
  17. package/dist/{chunk-XWIE5V7R.js.map → chunk-ETRNSJCR.js.map} +1 -1
  18. package/dist/chunk-FXWDDNGD.js +98 -0
  19. package/dist/chunk-FXWDDNGD.js.map +1 -0
  20. package/dist/chunk-GFGOQIEC.js +10 -0
  21. package/dist/chunk-GFGOQIEC.js.map +1 -0
  22. package/dist/{chunk-2R62Q5UK.js → chunk-IAHEYPYJ.js} +3 -3
  23. package/dist/{chunk-2R62Q5UK.js.map → chunk-IAHEYPYJ.js.map} +1 -1
  24. package/dist/{chunk-NGYFBD5G.js → chunk-J5JNLXO7.js} +3 -3
  25. package/dist/{chunk-NGYFBD5G.js.map → chunk-J5JNLXO7.js.map} +1 -1
  26. package/dist/{chunk-72CN3VPY.js → chunk-NFOGYDRS.js} +5 -5
  27. package/dist/{chunk-72CN3VPY.js.map → chunk-NFOGYDRS.js.map} +1 -1
  28. package/dist/{chunk-A73IJ27X.js → chunk-R2YNDRGL.js} +3 -3
  29. package/dist/{chunk-A73IJ27X.js.map → chunk-R2YNDRGL.js.map} +1 -1
  30. package/dist/{chunk-5HVKDHY6.js → chunk-R5NXOPL2.js} +3 -3
  31. package/dist/{chunk-5HVKDHY6.js.map → chunk-R5NXOPL2.js.map} +1 -1
  32. package/dist/chunk-RMBZ7YH7.js +52 -0
  33. package/dist/chunk-RMBZ7YH7.js.map +1 -0
  34. package/dist/{chunk-AIXC33SE.js → chunk-SHXUSTHM.js} +62 -15
  35. package/dist/chunk-SHXUSTHM.js.map +1 -0
  36. package/dist/{chunk-TAKPC6SD.js → chunk-UGTC33VH.js} +4 -4
  37. package/dist/{chunk-TAKPC6SD.js.map → chunk-UGTC33VH.js.map} +1 -1
  38. package/dist/{chunk-EA47MI5Q.js → chunk-VH5MYJ2K.js} +4 -4
  39. package/dist/{chunk-EA47MI5Q.js.map → chunk-VH5MYJ2K.js.map} +1 -1
  40. package/dist/{chunk-2774I242.js → chunk-WZEDIUWR.js} +21 -20
  41. package/dist/chunk-WZEDIUWR.js.map +1 -0
  42. package/dist/{chunk-TGJLXZAU.js → chunk-ZRRET3RP.js} +11 -11
  43. package/dist/chunk-ZRRET3RP.js.map +1 -0
  44. package/dist/{core-CtvAyPpH.d.ts → core-DNDAEhO2.d.ts} +9 -12
  45. package/dist/devtools/index.d.ts +4 -4
  46. package/dist/do/index.d.ts +103 -38
  47. package/dist/do/index.js +40 -21
  48. package/dist/do/index.js.map +1 -1
  49. package/dist/{drive-loop-Dw1sGSsW.d.ts → drive-loop-DlOEv49c.d.ts} +2 -2
  50. package/dist/{durable-effects-Ump5lSdO.d.ts → durable-effects-wLWEdy9H.d.ts} +1 -1
  51. package/dist/effect/index.d.ts +121 -28
  52. package/dist/effect/index.js +45 -31
  53. package/dist/effect/index.js.map +1 -1
  54. package/dist/extension/index.d.ts +3 -3
  55. package/dist/extension/index.js +2 -2
  56. package/dist/extension/index.js.map +1 -1
  57. package/dist/flow/index.d.ts +17 -13
  58. package/dist/flow/index.js +15 -12
  59. package/dist/flow/index.js.map +1 -1
  60. package/dist/idempotency/index.d.ts +3 -3
  61. package/dist/idempotency/index.js +3 -3
  62. package/dist/{index-CrcoVfd_.d.ts → index-9P1PaXIV.d.ts} +2 -2
  63. package/dist/{index-D3NY3VCN.d.ts → index-BBLI2WWN.d.ts} +1 -1
  64. package/dist/{index-Dl71V7kt.d.ts → index-C1WhBZ6a.d.ts} +4 -5
  65. package/dist/{index-CKtEKGyp.d.ts → index-C92SgNWz.d.ts} +3 -3
  66. package/dist/{index-CZZ3HI-Z.d.ts → index-CAsUE_d1.d.ts} +4 -4
  67. package/dist/{index-EIgfl83J.d.ts → index-CO34esWT.d.ts} +2 -2
  68. package/dist/{index-Bk2hBUdK.d.ts → index-COeX9Bmz.d.ts} +11 -9
  69. package/dist/{index-CVU7SK3a.d.ts → index-Cg0QXnzf.d.ts} +2 -2
  70. package/dist/index.d.ts +9 -9
  71. package/dist/index.js +2 -2
  72. package/dist/jev/index.d.ts +15 -15
  73. package/dist/jev/index.js +5 -5
  74. package/dist/jev/index.js.map +1 -1
  75. package/dist/laws-DTtCDDlU.d.ts +135 -0
  76. package/dist/loop-DReKGV1X.d.ts +70 -0
  77. package/dist/{machine-Dtre2TmN.d.ts → machine-C0WhOAyB.d.ts} +7 -7
  78. package/dist/machine-viz/index.d.ts +1 -1
  79. package/dist/machine-viz/index.js +2 -2
  80. package/dist/mem/index.d.ts +4 -3
  81. package/dist/mem/index.js +2 -2
  82. package/dist/mem/index.js.map +1 -1
  83. package/dist/node/index.d.ts +57 -9
  84. package/dist/node/index.js +175 -68
  85. package/dist/node/index.js.map +1 -1
  86. package/dist/otel/index.d.ts +28 -12
  87. package/dist/otel/index.js +25 -21
  88. package/dist/otel/index.js.map +1 -1
  89. package/dist/paginate/index.d.ts +4 -4
  90. package/dist/paginate/index.js +5 -5
  91. package/dist/parity/index.d.ts +11 -15
  92. package/dist/parity/index.js +4 -9
  93. package/dist/parity/index.js.map +1 -1
  94. package/dist/pbt/index.d.ts +279 -67
  95. package/dist/pbt/index.js +299 -58
  96. package/dist/pbt/index.js.map +1 -1
  97. package/dist/persistence/index.d.ts +10 -12
  98. package/dist/persistence/index.js +4 -4
  99. package/dist/promise/index.d.ts +118 -21
  100. package/dist/promise/index.js +6 -4
  101. package/dist/react/index.d.ts +34 -21
  102. package/dist/react/index.js +271 -42
  103. package/dist/react/index.js.map +1 -1
  104. package/dist/resilience/index.d.ts +6 -6
  105. package/dist/resilience/index.js +5 -5
  106. package/dist/{run-fiBe7pOG.d.ts → run-Cnw4qXj2.d.ts} +105 -23
  107. package/dist/{runtime-types-DEluQgGO.d.ts → runtime-types-CP-ykwgf.d.ts} +157 -29
  108. package/dist/testing/effect/index.d.ts +162 -9
  109. package/dist/testing/effect/index.js +110 -10
  110. package/dist/testing/effect/index.js.map +1 -1
  111. package/dist/testing/index.d.ts +6 -8
  112. package/dist/testing/index.js +4 -24
  113. package/dist/testing/index.js.map +1 -1
  114. package/dist/testing/promise/index.d.ts +4 -4
  115. package/dist/testing/promise/index.js +5 -5
  116. package/dist/timing/index.d.ts +4 -4
  117. package/dist/timing/index.js +4 -4
  118. package/dist/{types-CXNzlbAg.d.ts → types-S53WDy_h.d.ts} +1 -1
  119. package/dist/work-queue/index.d.ts +4 -4
  120. package/dist/work-queue/index.js +2 -2
  121. package/package.json +19 -17
  122. package/dist/chunk-2774I242.js.map +0 -1
  123. package/dist/chunk-AIXC33SE.js.map +0 -1
  124. package/dist/chunk-DVNXEB7V.js.map +0 -1
  125. package/dist/chunk-HX3C6LDK.js +0 -34
  126. package/dist/chunk-HX3C6LDK.js.map +0 -1
  127. package/dist/chunk-JAKM53JF.js.map +0 -1
  128. package/dist/chunk-RKVUVALV.js.map +0 -1
  129. package/dist/chunk-TGJLXZAU.js.map +0 -1
  130. package/dist/chunk-UHAQ4PI6.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/internal/engine/builtins.ts","../src/internal/engine/loop.ts","../src/internal/engine/tell.ts"],"names":[],"mappings":";;;;;AAmDO,SAAS,WAAA,CACd,UACA,OAAA,EACuB;AACvB,EAAA,MAAM,MAAA,GACJ,QAAA,KAAa,MAAA,GACR,EAAE,QAAA,EAAU,MAAA,EAAO,GACpB,OAAO,QAAA,KAAa,QAAA,GACjB,EAAE,QAAA,EAAU,UAAS,GACtB,QAAA;AACR,EAAA,OAAO,CAAC,IAAA,MAAU;AAAA,IAChB,MAAA,EAAQ,CAAC,IAAA,KAAS,CAAC,OAAO,GAAA,KAAQ;AAChC,MAAA,IAAI;AACF,QAAA,OAAO,IAAA,CAAK,OAAO,GAAG,CAAA;AAAA,MACxB,SAAS,WAAA,EAAa;AACpB,QAAA,IAAI,UAAU,OAAA,EAAS,WAAA,EAAa,KAAA,EAAO,GAAG,GAAG,MAAM,WAAA;AACvD,QAAA,IAAA,CAAK,MAAA,CAAO,aAAa,QAAQ,CAAA;AACjC,QAAA,QAAQ,OAAO,QAAA;AAAU,UACvB,KAAK,SAAA;AAEH,YAAA,OAAO,CAAC,OAAO,SAAA,CAAU,KAAA,EAAO,KAAK,WAAW,CAAA,EAAG,EAAE,CAAA;AAAA,UACvD,KAAK,UAAA;AACH,YAAA,MAAM,WAAA;AAAA,UACR;AACE,YAAA,IAAA,CAAK,KAAK,WAAW,CAAA;AACrB,YAAA,MAAM,WAAA;AAAA;AACV,MACF;AAAA,IACF;AAAA,GACF,CAAA;AACF;AAWA,SAAS,SAAA,CACP,OAAA,EACA,KAAA,EACA,KAAA,EACA,GAAA,EACS;AACT,EAAA,OACE,iBAAiB,WAAA,IACjB,UAAA,CAAW,SAAS,KAAA,EAAO,GAAG,EAAE,IAAA,KAAS,MAAA;AAE7C;AAaO,SAAS,eACd,QAAA,EACuB;AACvB,EAAA,OAAO,CAAC,IAAA,KAAS;AACf,IAAA,IAAI,QAAA,KAAa,MAAA,EAAW,OAAO,EAAC;AACpC,IAAA,MAAM,YAAA,GAAe,CAAC,GAAA,EAAQ,KAAA,KAAsB;AAClD,MAAA,MAAM,SAAA,GAAY,QAAA,CAAS,KAAA,CAAM,GAAG,CAAA;AACpC,MAAA,IAAI,SAAA,KAAc,QAAW,OAAO,KAAA;AACpC,MAAA,MAAM,GAAA,GAAM,QAAA,CAAS,OAAA,CAAQ,KAAK,CAAA;AAClC,MAAA,IAAI,GAAA,KAAQ,QAAW,OAAO,KAAA;AAC9B,MAAA,OAAO,cAAA,CAAe,SAAS,CAAA,KAAM,cAAA,CAAe,GAAG,CAAA;AAAA,IACzD,CAAA;AACA,IAAA,OAAO;AAAA,MACL,MAAA,EAAQ,CAAC,IAAA,KAAS,CAAC,OAAO,GAAA,KAAQ;AAChC,QAAA,IAAI,CAAC,aAAa,GAAA,EAAK,KAAK,GAAG,OAAO,IAAA,CAAK,OAAO,GAAG,CAAA;AACrD,QAAA,IAAA,CAAK,OAAO,IAAI,kBAAA,CAAmB,GAAA,CAAI,IAAI,GAAG,eAAe,CAAA;AAC7D,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,KACF;AAAA,EACF,CAAA;AACF;AAQO,SAAS,SAAA,GAId;AACA,EAAA,OAAO,OAAO;AAAA,IACZ,MAAA,EAAQ,CAAC,IAAA,KAAS,CAAC,OAAO,GAAA,KAAQ,WAAA,CAAY,KAAA,EAAO,GAAA,EAAK,IAAI;AAAA,GAChE,CAAA;AACF;AAoBO,SAAS,cAAA,CACd,MACA,KAAA,EACuB;AACvB,EAAA,OAAO,CAAC,IAAA,KAAS;AACf,IAAA,MAAM,EAAE,MAAA,EAAQ,aAAA,EAAe,OAAM,GAAI,eAAA,CAAgB,MAAM,KAAK,CAAA;AACpE,IAAA,MAAM,OAAA,GAAU,IAAI,GAAA,CAAI,IAAA,CAAK,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,CAAC,CAAA;AAClD,IAAA,OAAO;AAAA,MACL,SAAA,EAAW,CAAC,IAAA,KAAS,OAAO,KAAK,QAAA,KAAa;AAC5C,QAAA,MAAM,OAAQ,GAAA,CAAyB,IAAA;AACvC,QAAA,MAAM,UAAU,OAAA,CAAQ,GAAA,CAAI,IAAI,CAAA,GAC5B,CAAC,GAAA,KAAW;AACV,UAAA,IAAI;AACF,YAAA,KAAA,CAAM,KAAyB,GAAG,CAAA;AAAA,UACpC,SAAS,GAAA,EAAK;AACZ,YAAA,IAAA,CAAK,MAAA,CAAO,KAAK,WAAW,CAAA;AAC5B,YAAA;AAAA,UACF;AACA,UAAA,QAAA,CAAS,GAAG,CAAA;AAAA,QACd,CAAA,GACA,QAAA;AACJ,QAAA,IAAI;AACF,UAAA,OAAO,OAAO,GAAA,EAAyB,MAAM,IAAA,CAAK,GAAA,EAAK,OAAO,CAAC,CAAA;AAAA,QACjE,SAAS,GAAA,EAAK;AACZ,UAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,IAAI,GAAG,MAAM,GAAA;AAC9B,UAAA,IAAA,CAAK,MAAA,CAAO,KAAK,WAAW,CAAA;AAC5B,UAAA,OAAO,MAAA;AAAA,QACT;AAAA,MACF,CAAA;AAAA,MACA,GAAA,EAAK,EAAE,EAAA,EAAI,OAAA,CAAQ,EAAA,EAAI,GAAA,EAAK,OAAA,CAAQ,GAAA,EAAK,CAAC,OAAO,GAAG,MAAA;AAAO,KAC7D;AAAA,EACF,CAAA;AACF;AAWO,SAAS,OAAA,GAA0C;AACxD,EAAA,OAAO,OAAO;AAAA,IACZ,KAAA,EAAO,CAAC,KAAA,KAA8B;AACpC,MAAA,IAAI,CAAC,aAAA,CAAc,KAAK,CAAA,EAAG,OAAO,KAAA;AAClC,MAAA,IAAI,OAAA,GAAU,CAAA;AACd,MAAA,OAAO;AAAA,QACL,MAAM,IAAA,GAAO;AACX,UAAA,MAAM,IAAA,GAAO,MAAM,KAAA,CAAM,UAAA,EAAW;AACpC,UAAA,OAAA,GAAU,IAAA,CAAK,OAAA;AACf,UAAA,OAAO,IAAA,CAAK,GAAA;AAAA,QACd,CAAA;AAAA,QACA,MAAM,KAAK,KAAA,EAAO;AAChB,UAAA,OAAA,GAAU,MAAM,KAAA,CAAM,UAAA,CAAW,KAAA,EAAO,OAAO,CAAA;AAAA,QACjD,CAAA;AAAA,QACA,OAAA,EAAS,CAAC,GAAA,KAAQ,KAAA,CAAM,QAAQ,GAAG;AAAA,OACrC;AAAA,IACF;AAAA,GACF,CAAA;AACF;AAYO,SAAS,0BAAA,CACd,OACA,OAAA,EACM;AACN,EAAA,IAAI,YAAY,MAAA,IAAa,KAAA,KAAU,UAAa,CAAC,aAAA,CAAc,KAAK,CAAA,EAAG;AACzE,IAAA;AAAA,EACF;AACA,EAAA,MAAM,IAAI,KAAA;AAAA,IACR;AAAA,GACF;AACF;AASO,SAAS,KAAA,GAAwC;AACtD,EAAA,OAAO,CAAC,IAAA,KAAS;AACf,IAAA,MAAM,QAAA,uBAAe,GAAA,EAAkD;AACvE,IAAA,SAAS,IAAA,CAAQ,MAAe,KAAA,EAAgB;AAC9C,MAAA,MAAM,WAAA,GAAc,QAAA,CAAS,GAAA,CAAI,IAAqB,CAAA;AACtD,MAAA,IAAI,CAAC,WAAA,IAAe,WAAA,CAAY,IAAA,KAAS,CAAA,EAAG;AAC5C,MAAA,IAAA,CAAK,OAAO,WAAA,EAAa,WAAA,EAAa,CAAC,QAAA,KAAa,QAAA,CAAS,KAAK,CAAC,CAAA;AAAA,IACrE;AACA,IAAA,OAAO;AAAA,MACL,GAAA,EAAK,EAAE,IAAA,EAAK;AAAA,MACZ,MAAA,EAAQ;AAAA,QACN,aAAA,CACE,MACA,QAAA,EACY;AACZ,UAAA,MAAM,GAAA,GAAM,IAAA;AACZ,UAAA,MAAM,SAAS,QAAA,CAAS,GAAA,CAAI,GAAG,CAAA,wBAAS,GAAA,EAAI;AAC5C,UAAA,QAAA,CAAS,GAAA,CAAI,KAAK,MAAM,CAAA;AACxB,UAAA,MAAM,MAAA,GAAS,QAAA;AACf,UAAA,MAAA,CAAO,IAAI,MAAM,CAAA;AACjB,UAAA,OAAO,MAAM;AACX,YAAA,MAAA,CAAO,OAAO,MAAM,CAAA;AACpB,YAAA,IAAI,OAAO,IAAA,KAAS,CAAA,IAAK,QAAA,CAAS,GAAA,CAAI,GAAG,CAAA,KAAM,MAAA;AAC7C,cAAA,QAAA,CAAS,OAAO,GAAG,CAAA;AAAA,UACvB,CAAA;AAAA,QACF,CAAA;AAAA,QACA,QAAA,EAAU;AAAA;AACZ,KACF;AAAA,EACF,CAAA;AACF;AAWO,SAAS,WAAA,GAA8C;AAC5D,EAAA,OAAO,CAAC,IAAA,KAAS;AACf,IAAA,MAAM,SAAA,uBAAgB,GAAA,EAAgB;AACtC,IAAA,MAAM,SAAA,uBAAgB,GAAA,EAAgC;AACtD,IAAA,MAAM,YAAA,uBAAmB,GAAA,EAAwB;AACjD,IAAA,IAAI,MAAA,GAAS,KAAA;AACb,IAAA,OAAO;AAAA,MACL,SAAA,GAAY;AACV,QAAA,IAAA,CAAK,OAAO,SAAA,EAAW,UAAA,EAAY,CAAC,QAAA,KAAa,UAAU,CAAA;AAAA,MAC7D,CAAA;AAAA,MACA,MAAA,CAAO,KAAK,KAAA,EAAO;AACjB,QAAA,IAAI,QAAQ,MAAA,EAAW;AACrB,UAAA,MAAA,GAAS,IAAA;AACT,UAAA,IAAA,CAAK,OAAO,YAAA,EAAc,MAAA,EAAQ,CAAC,OAAA,KAAY,OAAA,CAAQ,KAAK,CAAC,CAAA;AAC7D,UAAA;AAAA,QACF;AACA,QAAA,IAAA,CAAK,MAAA,CAAO,WAAW,UAAA,EAAY,CAAC,aAAa,QAAA,CAAS,GAAA,EAAK,KAAK,CAAC,CAAA;AAAA,MACvE,CAAA;AAAA,MACA,MAAA,EAAQ;AAAA,QACN,SAAA,EAAW,YAAY,SAAS,CAAA;AAAA,QAChC,OAAA,EAAS,YAAY,SAAS,CAAA;AAAA,QAC9B,OAAO,OAAA,EAAyC;AAC9C,UAAA,MAAM,KAAA,GAAQ,KAAK,KAAA,EAAM;AACzB,UAAA,IAAI,MAAA,IAAU,UAAU,MAAA,EAAW;AACjC,YAAA,IAAA,CAAK,MAAA,CAAO,CAAC,OAAO,CAAA,EAAG,QAAQ,CAAC,CAAA,KAAM,CAAA,CAAE,KAAK,CAAC,CAAA;AAC9C,YAAA,OAAO,MAAM;AAAA,YAAC,CAAA;AAAA,UAChB;AACA,UAAA,OAAO,WAAA,CAAY,YAAY,CAAA,CAAE,OAAO,CAAA;AAAA,QAC1C;AAAA;AACF,KACF;AAAA,EACF,CAAA;AACF;AAEA,SAAS,YAAe,GAAA,EAAsC;AAC5D,EAAA,OAAO,CAAC,IAAA,KAAS;AACf,IAAA,GAAA,CAAI,IAAI,IAAI,CAAA;AACZ,IAAA,OAAO,MAAM;AACX,MAAA,GAAA,CAAI,OAAO,IAAI,CAAA;AAAA,IACjB,CAAA;AAAA,EACF,CAAA;AACF;AAQO,SAAS,eACd,OAAA,EACuB;AACvB,EAAA,OAAO,CAAC,IAAA,KAAS;AACf,IAAA,MAAM,QAAA,uBAAe,GAAA,EAAqC;AAC1D,IAAA,OAAO;AAAA,MACL,MAAA,CAAO,KAAK,KAAA,EAAO;AACjB,QAAA,IAAI,GAAA,KAAQ,MAAA,IAAa,OAAA,KAAY,MAAA,IAAa,SAAS,IAAA,KAAS,CAAA;AAClE,UAAA;AACF,QAAA,IAAI,MAAA;AACJ,QAAA,IAAI;AACF,UAAA,MAAA,GAAS,OAAA,CAAQ,KAAK,KAAK,CAAA;AAAA,QAC7B,SAAS,GAAA,EAAK;AACZ,UAAA,IAAA,CAAK,MAAA,CAAO,KAAK,OAAO,CAAA;AACxB,UAAA;AAAA,QACF;AACA,QAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,UAAA,MAAM,MAAA,GAAS,QAAA,CAAS,GAAA,CAAI,KAAA,CAAM,IAAI,CAAA;AACtC,UAAA,IAAI,WAAW,MAAA,EAAW;AAC1B,UAAA,IAAA,CAAK,OAAO,MAAA,EAAQ,OAAA,EAAS,CAAC,OAAA,KAAY,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,QAC1D;AAAA,MACF,CAAA;AAAA,MACA,MAAA,EAAQ;AAAA,QACN,EAAA,CAAG,MAAc,OAAA,EAAyC;AACxD,UAAA,MAAM,SAAS,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA,wBAAS,GAAA,EAAI;AAC7C,UAAA,QAAA,CAAS,GAAA,CAAI,MAAM,MAAM,CAAA;AACzB,UAAA,MAAA,CAAO,IAAI,OAAO,CAAA;AAClB,UAAA,OAAO,MAAM;AACX,YAAA,MAAA,CAAO,OAAO,OAAO,CAAA;AACrB,YAAA,IAAI,OAAO,IAAA,KAAS,CAAA,IAAK,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA,KAAM,MAAA;AAC9C,cAAA,QAAA,CAAS,OAAO,IAAI,CAAA;AAAA,UACxB,CAAA;AAAA,QACF;AAAA;AACF,KACF;AAAA,EACF,CAAA;AACF;AAiBO,SAAS,YACd,UAAA,EACuB;AACvB,EAAA,MAAM,KAAA,GAAQ,eAAe,MAAM,KAAA,CAAA;AACnC,EAAA,OAAO,CAAC,IAAA,KAAS;AACf,IAAA,MAAM,OAAA,uBAAc,GAAA,EAGjB;AAEH,IAAA,IAAI,OAAA;AAEJ,IAAA,IAAI,SAAA;AACJ,IAAA,OAAO;AAAA,MACL,UAAU,KAAA,EAAO;AACf,QAAA,OAAA,KAAY,EAAE,MAAA,EAAQ,IAAI,cAAA,CAAe,KAAK,CAAA,EAAE;AAAA,MAClD,CAAA;AAAA,MACA,OAAO,KAAA,EAAO;AACZ,QAAA,OAAA,KAAY,EAAE,QAAQ,KAAA,EAAM;AAAA,MAC9B,CAAA;AAAA,MACA,OAAA,GAAU;AACR,QAAA,IAAI,YAAY,MAAA,EAAW;AAC3B,QAAA,SAAA,GAAY,OAAA;AACZ,QAAA,MAAM,KAAA,GAAQ,KAAK,KAAA,EAAM;AACzB,QAAA,MAAM,QAAA,GAAW,MAAM,KAAK,CAAA;AAG5B,QAAA,IAAI,QAAA,IAAY,IAAA,CAAK,UAAA,EAAW,CAAE,SAAS,OAAA,EAAS;AACpD,QAAA,MAAM,MAAA,GAAS,CAAC,GAAG,OAAO,CAAA;AAC1B,QAAA,OAAA,CAAQ,KAAA,EAAM;AACd,QAAA,KAAA,MAAW,UAAU,MAAA,EAAQ;AAC3B,UAAA,IAAI,QAAA,EAAU,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA;AAAA,eAC7B,MAAA,CAAO,MAAA,CAAO,SAAA,CAAU,MAAM,CAAA;AAAA,QACrC;AAAA,MACF,CAAA;AAAA,MACA,MAAA,CAAO,MAAM,KAAA,EAAO;AAClB,QAAA,IACE,IAAA,CAAK,UAAA,EAAW,CAAE,IAAA,KAAS,OAAA,IAC3B,QAAQ,IAAA,KAAS,CAAA,IACjB,CAAC,KAAA,CAAM,KAAK,CAAA;AAEZ,UAAA;AACF,QAAA,MAAM,MAAA,GAAS,CAAC,GAAG,OAAO,CAAA;AAC1B,QAAA,OAAA,CAAQ,KAAA,EAAM;AACd,QAAA,KAAA,MAAW,MAAA,IAAU,MAAA,EAAQ,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA;AAAA,MACnD,CAAA;AAAA,MACA,UAAA,CAAW,OAAO,KAAA,EAAO;AACvB,QAAA,IAAI,QAAQ,IAAA,KAAS,CAAA,IAAK,CAAC,KAAA,CAAM,KAAK,CAAA,EAAG;AACzC,QAAA,MAAM,MAAA,GAAS,CAAC,GAAG,OAAO,CAAA;AAC1B,QAAA,OAAA,CAAQ,KAAA,EAAM;AACd,QAAA,KAAA,MAAW,MAAA,IAAU,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,KAAK,CAAA;AAAA,MAClD,CAAA;AAAA,MACA,MAAA,EAAQ;AAAA,QACN,MAAA,GAAwB;AACtB,UAAA,MAAM,OAAA,GAAU,KAAK,KAAA,EAAM;AAC3B,UAAA,OAAO,IAAA,CAAK,YAAW,CAAE,IAAA,KAAS,WAAW,KAAA,CAAM,OAAO,IACtD,OAAA,GACA,MAAA;AAAA,QACN,CAAA;AAAA,QACA,IAAA,GAAmB;AACjB,UAAA,MAAM,OAAA,GAAU,KAAK,KAAA,EAAM;AAC3B,UAAA,IAAI,KAAA,CAAM,OAAO,CAAA,EAAG;AAClB,YAAA,MAAM,KAAA,GAAQ,KAAK,UAAA,EAAW;AAC9B,YAAA,IAAI,MAAM,IAAA,KAAS,OAAA,EAAS,OAAO,OAAA,CAAQ,QAAQ,OAAO,CAAA;AAC1D,YAAA,IAAI,MAAM,IAAA,KAAS,QAAA,SAAiB,OAAA,CAAQ,MAAA,CAAO,MAAM,KAAK,CAAA;AAAA,UAChE,CAAA,MAAA,IAAW,cAAc,MAAA,EAAW;AAClC,YAAA,OAAO,OAAA,CAAQ,MAAA,CAAO,SAAA,CAAU,MAAM,CAAA;AAAA,UACxC;AACA,UAAA,OAAO,IAAI,OAAA,CAAW,CAAC,OAAA,EAAS,MAAA,KAAW;AACzC,YAAA,OAAA,CAAQ,GAAA,CAAI,EAAE,OAAA,EAAS,MAAA,EAAQ,CAAA;AAAA,UACjC,CAAC,CAAA;AAAA,QACH;AAAA;AACF,KACF;AAAA,EACF,CAAA;AACF;AASO,SAAS,SAAA,CACd,MACA,KAAA,EACuB;AACvB,EAAA,OAAO,CAAC,IAAA,KAA8C;AACpD,IAAA,IAAI,IAAA,KAAS,MAAA,EAAW,OAAO,EAAC;AAChC,IAAA,IAAI,GAAA,GAAM,CAAA;AACV,IAAA,OAAO;AAAA,MACL,OAAO,GAAA,EAAK;AACV,QAAA,IAAI,QAAQ,MAAA,EAAW;AACvB,QAAA,GAAA,IAAO,CAAA;AACP,QAAA,MAAM,KAAA,GAAwB,EAAE,GAAA,EAAK,OAAA,EAAS,IAAI,IAAA,EAAM,EAAA,EAAI,OAAM,EAAE;AACpE,QAAA,IAAI;AACF,UAAA,OAAA,CAAQ,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAC,CAAA,CAAE,KAAA;AAAA,YAAM,CAAC,GAAA,KAClC,IAAA,CAAK,MAAA,CAAO,KAAK,UAAU;AAAA,WAC7B;AAAA,QACF,SAAS,GAAA,EAAK;AACZ,UAAA,IAAA,CAAK,MAAA,CAAO,KAAK,UAAU,CAAA;AAAA,QAC7B;AAAA,MACF;AAAA,KACF;AAAA,EACF,CAAA;AACF;AA4BO,SAAS,iBAAA,CAMd,SAIA,IAAA,EACsC;AACtC,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,IAAS,IAAA,CAAK,GAAA;AACjC,EAAA,OAAO;AAAA,IACL,WAAA,CAAY,IAAA,CAAK,WAAA,EAAa,OAAO,CAAA;AAAA,IACrC,cAAA,CAAe,QAAQ,QAAQ,CAAA;AAAA,IAC/B,SAAA,EAAU;AAAA,IACV,cAAA,CAAe,OAAA,CAAQ,IAAA,IAAQ,IAAI,KAAK,CAAA;AAAA,IACxC,OAAA,EAAQ;AAAA,IACR,KAAA,EAAM;AAAA,IACN,WAAA,EAAY;AAAA,IACZ,cAAA,CAAe,KAAK,MAAM,CAAA;AAAA,IAC1B,WAAA,CAAY,KAAK,QAAQ,CAAA;AAAA,IACzB,SAAA,CAAU,IAAA,CAAK,SAAA,EAAW,KAAK;AAAA,GACjC;AACF;;;AChXO,IAAM,QAAA,0BAAiC,qBAAqB;AAmB5D,IAAM,IAAA,0BAA6B,iBAAiB;AA0DpD,SAAS,cAAA,CACd,OACA,QAAA,EACM;AACN,EAAA,IAAI,iBAAiB,oBAAA,EAAsB;AACzC,IAAA,OAAA,CAAQ,KAAK,KAAK,CAAA;AAClB,IAAA;AAAA,EACF;AACA,EAAA,UAAA,CAAW,MAAM;AACf,IAAA,MAAM,KAAA;AAAA,EACR,GAAG,CAAC,CAAA;AACN;AAQO,IAAM,mBAAA,GAAN,cAAkC,KAAA,CAAM;AAAA,EAC7C,YAAqB,OAAA,EAAiB;AACpC,IAAA,KAAA,CAAM,8BAA8B,CAAA;AADjB,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA,EAErB;AAAA,EAFqB,OAAA;AAGvB;AAGA,IAAM,aAAN,MAAiB;AAAA,EAGf,YAAqB,IAAA,EAAc;AAAd,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAAA,EAAe;AAAA,EAAf,IAAA;AAAA,EAFrB,UAAmB,MAAM;AAAA,EAAC,CAAA;AAAA,EAC1B,MAAA,GAAS,KAAA;AAEX,CAAA;AAOA,IAAM,UAAN,MAAc;AAAA,EACK,MAAA,uBAAa,GAAA,EAAoB;AAAA,EAElD,OAAO,IAAA,EAAoB;AACzB,IAAA,IAAA,CAAK,MAAA,CAAO,IAAI,IAAA,EAAA,CAAO,IAAA,CAAK,OAAO,GAAA,CAAI,IAAI,CAAA,IAAK,CAAA,IAAK,CAAC,CAAA;AAAA,EACxD;AAAA,EAEA,YAAY,IAAA,EAAoB;AAC9B,IAAA,MAAM,QAAQ,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,IAAI,KAAK,CAAA,IAAK,CAAA;AAC5C,IAAA,IAAI,OAAO,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,MAAM,IAAI,CAAA;AAAA,SACnC,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,IAAI,CAAA;AAAA,EAC9B;AAAA;AAAA,EAGA,QAAA,GAA6C;AAC3C,IAAA,OAAO,MAAA,CAAO,WAAA,CAAY,IAAA,CAAK,MAAM,CAAA;AAAA,EACvC;AACF,CAAA;AASO,SAAS,UACd,MAAA,EACkB;AAClB,EAAA,MAAM,EAAE,OAAA,EAAS,gBAAA,EAAiB,GAAI,MAAA;AACtC,EAAA,MAAM,OAAA,GAAmB,OAAO,OAAA,IAAW,cAAA;AAI3C,EAAA,SAAS,MAAA,CAAO,OAAgB,KAAA,EAAgC;AAC9D,IAAA,MAAM,OAAA,GAA+B,EAAE,KAAA,EAAM;AAC7C,IAAA,IAAI;AACF,MAAA,OAAA,CAAQ,OAAO,OAAO,CAAA;AAAA,IACxB,SAAS,SAAA,EAAW;AAClB,MAAA,cAAA,CAAe,SAAkB,CAAA;AAAA,IACnC;AAAA,EACF;AAIA,EAAA,SAAS,MAAA,CACP,KAAA,EACA,KAAA,EACA,EAAA,EACM;AACN,IAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,MAAA,IAAI;AACF,QAAA,EAAA,CAAG,IAAI,CAAA;AAAA,MACT,SAAS,GAAA,EAAK;AACZ,QAAA,MAAA,CAAO,KAAK,KAAK,CAAA;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AAIA,EAAA,IAAI,KAAA;AAGJ,EAAA,IAAI,SAAA;AACJ,EAAA,IAAI,UAAA,GAAyB,EAAE,IAAA,EAAM,SAAA,EAAU;AAC/C,EAAA,IAAI,SAAA,GAAqB,IAAA;AAuBzB,EAAA,IAAI,IAAA,GAAqD,MAAA;AAKzD,EAAA,MAAM,QAAA,uBAAe,GAAA,EAA8C;AAEnE,EAAA,MAAM,QAAA,GAA4B;AAAA,IAChC,MAAA;AAAA,IACA,MAAA;AAAA,IACA,KAAK,KAAA,EAAO;AAGV,MAAA,MAAM,WAAW,IAAA,KAAS,MAAA;AAC1B,MAAA,IAAI,IAAA,KAAS,aAAa,IAAA,GAAO,QAAA;AACjC,MAAA,KAAA,MAAW,GAAA,IAAO,UAAA,EAAY,GAAA,CAAI,MAAA,GAAS,KAAK,CAAA;AAIhD,MAAA,IAAI,CAAC,UAAU,MAAA,CAAO,aAAA,CAAc,EAAE,IAAA,EAAM,MAAA,EAAQ,OAAO,CAAA;AAAA,IAC7D,CAAA;AAAA,IACA,OAAO,MAAM,KAAA;AAAA,IACb,UAAA,EAAY,MACV,MAAA,CAAO,KAAA,KAAU,SAAY,EAAE,IAAA,EAAM,SAAQ,GAAI;AAAA,GACrD;AACA,EAAA,MAAM,UAAA,GAAa,OAAO,UAAA,CAAW,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,QAAQ,CAAC,CAAA;AAEjE,EAAA,SAAS,gBAAA,GAAyB;AAChC,IAAA,MAAA,CAAO,YAAY,KAAA,EAAO,CAAC,GAAA,KAAQ,GAAA,CAAI,WAAW,CAAA;AAAA,EACpD;AAIA,EAAA,MAAM,SAAwB,UAAA,CAAW,WAAA;AAAA,IACvC,CAAC,MAAM,GAAA,KAAS,GAAA,CAAI,SAAS,GAAA,CAAI,MAAA,CAAO,IAAI,CAAA,GAAI,IAAA;AAAA,IAChD,MAAA,CAAO;AAAA,GACT;AACA,EAAA,MAAM,SAAA,GAAiC,UAAA,CAAW,WAAA,CAEhD,CAAC,IAAA,EAAM,GAAA,KAAS,GAAA,CAAI,SAAA,GAAY,GAAA,CAAI,SAAA,CAAU,IAAI,CAAA,GAAI,MAAO,WAAW,CAAA;AAC1E,EAAA,MAAM,KAAA,GACJ,MAAA,CAAO,KAAA,KAAU,MAAA,GACb,SACA,UAAA,CAAW,WAAA;AAAA,IACT,CAAC,OAAO,GAAA,KAAS,GAAA,CAAI,QAAQ,GAAA,CAAI,KAAA,CAAM,KAAK,CAAA,GAAI,KAAA;AAAA,IAChD,MAAA,CAAO;AAAA,GACT;AACN,EAAA,MAAM,qBAAqB,UAAA,CAAW,OAAA;AAAA,IAAQ,CAAC,QAC7C,GAAA,CAAI,SAAA,GAAY,CAAC,GAAA,CAAI,SAAS,IAAI;AAAC,GACrC;AACA,EAAA,MAAM,kBAAkB,UAAA,CAAW,OAAA;AAAA,IAAQ,CAAC,QAC1C,GAAA,CAAI,MAAA,GAAS,CAAC,GAAA,CAAI,MAAM,IAAI;AAAC,GAC/B;AAMA,EAAA,MAAM,aAAsB,MAAA,CAAO,MAAA;AAAA,IACjC,EAAC;AAAA,IACD,MAAA,CAAO,GAAA;AAAA,IACP,GAAG,WAAW,GAAA,CAAI,CAAC,QAAQ,GAAA,CAAI,GAAA,IAAO,EAAE,CAAA;AAAA,IACxC,EAAE,CAAC,UAAU,GAAG,cAAA;AAAe,GACjC;AAGA,EAAA,IAAI,IAAA,GAAsB,QAAQ,OAAA,EAAQ;AAG1C,EAAA,MAAM,IAAA,GAAO,IAAI,OAAA,EAAQ;AAIzB,EAAA,MAAM,WAAA,uBAAkB,GAAA,EAAwB;AAIhD,EAAA,SAAS,SAAS,GAAA,EAA6B;AAC7C,IAAA,KAAA,MAAW,MAAM,GAAA,EAAK;AACpB,MAAA,MAAM,OAAA,GAAU,WAAA,CAAY,GAAA,CAAI,EAAE,CAAA;AAClC,MAAA,IAAI,YAAY,MAAA,EAAW;AAC3B,MAAA,IAAI;AACF,QAAA,aAAA,CAAc,OAAA,CAAQ,SAAS,CAAA;AAAA,MACjC,SAAS,GAAA,EAAK;AACZ,QAAA,MAAA,CAAO,KAAK,aAAa,CAAA;AAAA,MAC3B;AACA,MAAA,WAAA,CAAY,OAAO,EAAE,CAAA;AAAA,IACvB;AAAA,EACF;AASA,EAAA,MAAM,gBAAA,uBAAuB,GAAA,EAAmB;AAEhD,EAAA,SAAS,cAAc,MAAA,EAAoC;AACzD,IAAA,IAAI,EAAE,kBAAkB,OAAA,CAAA,EAAU;AAClC,IAAA,MAAM,QAAA,GAA0B,MAAA,CAC7B,KAAA,CAAM,CAAC,GAAA,KAAQ;AACd,MAAA,MAAA,CAAO,KAAK,aAAa,CAAA;AAAA,IAC3B,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,MAAA,gBAAA,CAAiB,OAAO,QAAQ,CAAA;AAAA,IAClC,CAAC,CAAA;AACH,IAAA,gBAAA,CAAiB,IAAI,QAAQ,CAAA;AAAA,EAC/B;AAQA,EAAA,eAAe,YACb,IAAA,EACgC;AAChC,IAAA,IAAI,KAAA;AACJ,IAAA,IAAI;AACF,MAAA,OAAO,MAAM,QAAQ,IAAA,CAAK;AAAA,QACxB,IAAA,CAAK,IAAA,CAAK,MAAM,SAAkB,CAAA;AAAA,QAClC,IAAI,OAAA,CAAmB,CAAC,OAAA,KAAY;AAClC,UAAA,KAAA,GAAQ,UAAA,CAAW,MAAM,OAAA,CAAQ,SAAS,GAAG,gBAAgB,CAAA;AAAA,QAC/D,CAAC;AAAA,OACF,CAAA;AAAA,IACH,CAAA,SAAE;AACA,MAAA,IAAI,KAAA,KAAU,MAAA,EAAW,YAAA,CAAa,KAAK,CAAA;AAAA,IAC7C;AAAA,EACF;AASA,EAAA,eAAe,SAAA,GAA2B;AACxC,IAAA,IAAK,MAAM,WAAA,CAAY,IAAI,CAAA,KAAO,SAAA,EAAW;AAC3C,MAAA,IAAA,GAAO,QAAA;AACP,MAAA;AAAA,IACF;AACA,IAAA,MAAA;AAAA,MACE,IAAI,kBAAA;AAAA,QACF,CAAC,GAAG,QAAQ,CAAA,CAAE,OAAA,CAAQ,CAAC,EAAE,OAAA,EAAQ,KAAM,OAAA,IAAW,EAAE,CAAA;AAAA,QACpD,QAAA,CAAS,IAAA;AAAA,QACT,gBAAA;AAAA,QACA,KAAK,QAAA;AAAS,OAChB;AAAA,MACA;AAAA,KACF;AACA,IAAA,IAAA,GAAO,WAAA;AAAA,EACT;AAMA,EAAA,eAAe,cAAA,GAAgC;AAC7C,IAAA,IAAI,gBAAA,CAAiB,SAAS,CAAA,EAAG;AACjC,IAAA,MAAM,WAAA,GAAc,CAAC,GAAG,gBAAgB,CAAA;AACxC,IAAA,IAAK,MAAM,WAAA,CAAY,OAAA,CAAQ,IAAI,WAAW,CAAC,MAAO,SAAA,EAAW;AAC/D,MAAA,MAAA;AAAA,QACE,IAAI,oBAAA,CAAqB,WAAA,CAAY,MAAA,EAAQ,gBAAgB,CAAA;AAAA,QAC7D;AAAA,OACF;AAAA,IACF;AAAA,EACF;AAaA,EAAA,SAAS,aAAA,GAAsB;AAC7B,IAAA,IAAI,UAAA,GAAsB,IAAA;AAC1B,IAAA,MAAM,QAAA,GAAW,CAAC,GAAA,KAAuB;AACvC,MAAA,IAAI,UAAA,KAAe,MAAM,UAAA,GAAa,GAAA;AAAA,IACxC,CAAA;AACA,IAAA,MAAM,OAAA,uBAAc,GAAA,EAAiB;AAErC,IAAA,MAAM,WAAA,uBAAkB,GAAA,EAAY;AACpC,IAAA,KAAA,MAAW,KAAA,IAAS,OAAO,IAAA,EAAM;AAC/B,MAAA,IAAI;AACF,QAAA,MAAM,GAAA,GAAM,UAAA,CAAW,KAAA,EAAO,KAAU,CAAA;AACxC,QAAA,IAAI,QAAQ,IAAA,EAAM,OAAA,CAAQ,GAAA,CAAI,GAAA,CAAI,IAAI,GAAG,CAAA;AAAA,MAC3C,SAAS,GAAA,EAAK;AACZ,QAAA,QAAA,CAAS,GAAG,CAAA;AACZ,QAAA,WAAA,CAAY,GAAA,CAAI,MAAM,IAAI,CAAA;AAAA,MAC5B;AAAA,IACF;AAEA,IAAA,QAAA;AAAA,MACE,CAAC,GAAG,WAAW,CAAA,CAAE,OAAA;AAAA,QAAQ,CAAC,CAAC,EAAA,EAAI,OAAO,CAAA,KACpC,QAAQ,GAAA,CAAI,EAAE,CAAA,IAAK,WAAA,CAAY,IAAI,OAAA,CAAQ,IAAI,IAAI,EAAC,GAAI,CAAC,EAAE;AAAA;AAC7D,KACF;AAIA,IAAA,MAAM,QAAA,GAAW,IAAA,KAAS,MAAA,GAAS,OAAA,uBAAc,GAAA,EAAiB;AAClE,IAAA,KAAA,MAAW,CAAC,EAAA,EAAI,GAAG,CAAA,IAAK,QAAA,EAAU;AAChC,MAAA,IAAI,WAAA,CAAY,GAAA,CAAI,EAAE,CAAA,EAAG;AACzB,MAAA,MAAM,MAAA,GAAS,MAAA,CAAO,SAAA,CAAU,GAAA,CAAI,IAAI,CAAA;AACxC,MAAA,IAAI,WAAW,MAAA,EAAW;AACxB,QAAA,QAAA;AAAA,UACE,IAAI,KAAA;AAAA,YACF,CAAA,+CAAA,EAAkD,IAAI,IAAI,CAAA,oCAAA;AAAA;AAE5D,SACF;AACA,QAAA;AAAA,MACF;AACA,MAAA,MAAM,OAAA,GAAU,IAAI,UAAA,CAAW,GAAA,CAAI,IAAI,CAAA;AACvC,MAAA,IAAI;AAIF,QAAA,OAAA,CAAQ,OAAA,GAAU,MAAA;AAAA,UAAO,GAAA;AAAA,UAAK,MAAA,CAAO,GAAA;AAAA,UAAK,iBAAA;AAAA,UAAmB,CAAC,KAAA,KAC5D,SAAA,CAAU,EAAA,EAAI,SAAS,KAAK;AAAA,SAC9B;AAAA,MACF,SAAS,GAAA,EAAK;AAGZ,QAAA,QAAA,CAAS,GAAG,CAAA;AACZ,QAAA,SAAA,CAAU,EAAA,EAAI,SAAS,GAAG,CAAA;AAC1B,QAAA;AAAA,MACF;AACA,MAAA,IAAI,CAAC,QAAQ,MAAA,EAAQ;AACnB,QAAA,WAAA,CAAY,GAAA,CAAI,IAAI,OAAO,CAAA;AAC3B,QAAA;AAAA,MACF;AAGA,MAAA,IAAI;AACF,QAAA,aAAA,CAAc,OAAA,CAAQ,SAAS,CAAA;AAAA,MACjC,SAAS,GAAA,EAAK;AACZ,QAAA,MAAA,CAAO,KAAK,aAAa,CAAA;AAAA,MAC3B;AAAA,IACF;AACA,IAAA,IAAI,UAAA,KAAe,MAAM,MAAM,UAAA;AAAA,EACjC;AAWA,EAAA,SAAS,SAAA,CAAU,EAAA,EAAY,OAAA,EAAqB,KAAA,EAAsB;AACxE,IAAA,IAAI,QAAQ,MAAA,EAAQ;AACpB,IAAA,OAAA,CAAQ,MAAA,GAAS,IAAA;AACjB,IAAA,IAAI,YAAY,GAAA,CAAI,EAAE,MAAM,OAAA,EAAS,WAAA,CAAY,OAAO,EAAE,CAAA;AAC1D,IAAA,MAAA,CAAO,OAAO,KAAK,CAAA;AACnB,IAAA,IAAI,SAAS,MAAA,EAAQ;AACrB,IAAA,IAAA,GAAO,UAAA;AACP,IAAA,KAAA,MAAW,GAAA,IAAO,UAAA,EAAY,GAAA,CAAI,SAAA,GAAY,KAAK,CAAA;AACnD,IAAA,MAAA,CAAO,aAAA,CAAc,EAAE,IAAA,EAAM,KAAA,EAAO,OAAO,CAAA;AAAA,EAC7C;AAQA,EAAA,SAAS,kBAAkB,GAAA,EAAc;AACvC,IAAA,eAAA,CAAgB,GAAA,EAAK,MAAM,CAAA,CAAE,KAAA,CAAM,iBAAiB,CAAA;AAAA,EACtD;AAIA,EAAA,SAAS,kBAAkB,KAAA,EAAsB;AAC/C,IAAA,MAAA;AAAA,MACE,KAAA;AAAA,MACA,KAAA,YAAiB,yBAAyB,SAAA,GAAY;AAAA,KACxD;AAAA,EACF;AASA,EAAA,SAAS,aAAA,CACP,MACA,OAAA,EACY;AACZ,IAAA,MAAM,KAAA,GAAQ,EAAE,OAAA,EAAQ;AACxB,IAAA,QAAA,CAAS,IAAI,KAAK,CAAA;AAClB,IAAA,OAAO,OAAA,CAAQ,OAAA,CAAQ,IAAI,CAAA,CAAE,QAAQ,MAAM;AACzC,MAAA,QAAA,CAAS,OAAO,KAAK,CAAA;AAAA,IACvB,CAAC,CAAA;AAAA,EACH;AAWA,EAAA,SAAS,eAAe,IAAA,EAA8B;AACpD,IAAA,MAAM,OAAA,GAAU,cAAc,IAAI,CAAA;AAClC,IAAA,OAAA,CAAQ,MAAM,iBAAiB,CAAA;AAC/B,IAAA,IAAA,GAAO,IAAA,CACJ,KAAK,YAAY;AAChB,MAAA,MAAM,OAAA;AAAA,IACR,CAAC,CAAA,CACA,KAAA,CAAM,MAAM;AAAA,IAAC,CAAC,CAAA;AAAA,EACnB;AAKA,EAAA,SAAS,WAAA,CAAY,KAAQ,QAAA,EAA8C;AACzE,IAAA,MAAM,EAAE,MAAK,GAAI,GAAA;AACjB,IAAA,MAAM,OAAA,GAAU,MAAA,CAAO,UAAA,CAAW,IAAI,CAAA;AACtC,IAAA,IAAI,OAAA,KAAY,MAAA,EAAW,OAAO,OAAA,CAAQ,QAAQ,MAAS,CAAA;AAC3D,IAAA,OAAO,cAAc,OAAA,CAAQ,GAAA,EAAc,UAAA,EAAY,QAAQ,GAAG,IAAI,CAAA;AAAA,EACxE;AAiBA,EAAA,eAAe,QAAQ,IAAA,EAAmC;AACxD,IAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,MAAA,IAAI,SAAS,WAAA,EAAa;AAC1B,MAAA,MAAM,QAAA,GAAW,MAAM,SAAA,CAAU,GAAA,EAAK,iBAAiB,CAAA;AACvD,MAAA,KAAA,MAAW,MAAA,IAAU,SAAA,CAAa,QAAQ,CAAA,oBAAqB,MAAM,CAAA;AAAA,IACvE;AAAA,EACF;AAuBA,EAAA,eAAe,MAAA,CACb,IAAA,EACA,GAAA,EACA,IAAA,EACe;AACf,IAAA,KAAA,GAAQ,IAAA;AACR,IAAA,UAAA,GAAa,EAAE,MAAM,SAAA,EAAU;AAC/B,IAAA,IAAI,KAAA,IAAS,SAAS,WAAA,EAAa;AACjC,MAAA,IAAI;AACF,QAAA,MAAM,KAAA,CAAM,KAAK,IAAI,CAAA;AACrB,QAAA,UAAA,GAAa,EAAE,MAAM,OAAA,EAAQ;AAAA,MAC/B,SAAS,KAAA,EAAO;AACd,QAAA,UAAA,GAAa,EAAE,IAAA,EAAM,QAAA,EAAU,KAAA,EAAM;AACrC,QAAA,KAAA,MAAW,GAAA,IAAO,UAAA,EAAY,GAAA,CAAI,UAAA,GAAa,MAAM,KAAK,CAAA;AAC1D,QAAA,MAAM,KAAA;AAAA,MACR;AAAA,IACF;AACA,IAAA,aAAA,EAAc;AACd,IAAA,SAAA,GAAY,IAAA;AACZ,IAAA,KAAA,MAAW,QAAA,IAAY,oBAAoB,QAAA,EAAS;AACpD,IAAA,IAAI;AACF,MAAA,MAAM,QAAQ,IAAI,CAAA;AAAA,IACpB,CAAA,SAAE;AACA,MAAA,KAAA,MAAW,QAAA,IAAY,eAAA,EAAiB,QAAA,CAAS,GAAA,EAAK,IAAI,CAAA;AAAA,IAC5D;AAAA,EACF;AAIA,EAAA,eAAe,aAAa,GAAA,EAAuB;AACjD,IAAA,IAAI,UAAU,MAAA,EAAW;AACvB,MAAA,MAAM,IAAI,MAAM,iCAAiC,CAAA;AAAA,IACnD;AACA,IAAA,MAAM,UAAA,GAAa,MAAA,CAAO,KAAA,EAAO,GAAG,CAAA;AACpC,IAAA,IAAI,eAAe,IAAA,EAAM;AACzB,IAAA,MAAM,OAAO,UAAA,CAAW,CAAC,GAAG,GAAA,EAAK,UAAA,CAAW,CAAC,CAAC,CAAA;AAAA,EAChD;AAQA,EAAA,MAAM,SAAA,GACJ,UAAU,MAAA,GAAY,MAAA,CAAO,KAAK,IAAA,EAAM,MAAA,CAAO,GAAG,CAAA,GAAI,IAAA;AACxD,EAAA,IAAI,SAAA,KAAc,IAAA,EAAM,KAAA,GAAQ,SAAA,CAAU,CAAC,CAAA;AAE3C,EAAA,eAAe,IAAA,GAAsB;AAInC,IAAA,MAAM,CAAC,OAAA,EAAS,IAAI,CAAA,GAClB,SAAA,IAAa,MAAA,CAAO,IAAA,CAAK,MAAM,OAAA,CAAQ,KAAiB,CAAA,EAAG,MAAA,CAAO,GAAG,CAAA;AACvE,IAAA,MAAM,MAAA,CAAO,OAAA,EAAS,MAAA,EAAW,IAAI,CAAA;AAAA,EACvC;AAeA,EAAA,SAAS,eAAA,CACP,GAAA,EACA,MAAA,GAA4B,QAAA,EACb;AACf,IAAA,IAAI,SAAS,MAAA,EAAQ;AACnB,MAAA,OAAO,OAAA,CAAQ,MAAA;AAAA,QACb,IAAA,KAAS,UAAA,IAAe,IAAA,KAAS,WAAA,IAAe,WAAW,MAAA,GACvD,IAAI,sBAAA,CAAuB,GAAA,CAAI,IAAI,CAAA,GACnC,IAAI,mBAAA,CAAoB,IAAI,IAAI;AAAA,OACtC;AAAA,IACF;AACA,IAAA,OAAO,WAAA,CAAY,GAAA,EAAK,MAAA,EAAQ,YAAY,CAAA;AAAA,EAC9C;AAUA,EAAA,SAAS,WAAA,CACP,GAAA,EACA,MAAA,EACA,IAAA,EACe;AACf,IAAA,IAAA,CAAK,MAAA,CAAO,IAAI,IAAI,CAAA;AACpB,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,MAAM;AAC3B,MAAA,IAAA,CAAK,WAAA,CAAY,IAAI,IAAI,CAAA;AACzB,MAAA,IAAI,SAAS,WAAA,EAAa;AACxB,QAAA,IAAI,WAAW,QAAA,EAAU,MAAM,IAAI,sBAAA,CAAuB,IAAI,IAAI,CAAA;AAClE,QAAA;AAAA,MACF;AACA,MAAA,IAAI,SAAA,KAAc,MAAM,MAAM,SAAA;AAC9B,MAAA,OAAO,KAAK,GAAG,CAAA;AAAA,IACjB,CAAC,CAAA;AAGD,IAAA,IAAA,GAAO,IAAA,CAAK,MAAM,MAAM;AAAA,IAAC,CAAC,CAAA;AAC1B,IAAA,OAAO,IAAA;AAAA,EACT;AAWA,EAAA,SAAS,OAAA,CAAQ,KAAQ,KAAA,EAA0C;AACjE,IAAA,IAAI,IAAA,KAAS,QAAQ,OAAO,SAAA;AAC5B,IAAA,IAAI,CAAC,KAAA,CAAM,KAAU,CAAA,EAAG,OAAO,SAAA;AAC/B,IAAA,WAAA;AAAA,MAAY,GAAA;AAAA,MAAK,MAAA;AAAA,MAAQ,CAAC,MAAA,KACxB,KAAA,CAAM,KAAU,CAAA,GAAI,YAAA,CAAa,MAAM,CAAA,GAAI;AAAA,KAC7C,CAAE,MAAM,iBAAiB,CAAA;AACzB,IAAA,OAAO,QAAA;AAAA,EACT;AASA,EAAA,eAAe,iBAAA,GAAmC;AAChD,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,OAAA,EAAS,CAAA,EAAA,EAAK;AAChC,MAAA,MAAM,QAAA,GAAW,IAAA;AACjB,MAAA,MAAM,QAAA;AACN,MAAA,IAAI,SAAS,QAAA,EAAU;AAAA,IACzB;AACA,IAAA,MAAM,IAAI,uBAAuB,OAAO,CAAA;AAAA,EAC1C;AAOA,EAAA,eAAe,oBAAA,CACb,KACA,IAAA,EACe;AACf,IAAA,MAAM,gBAAgB,GAAG,CAAA;AACzB,IAAA,IAAI,IAAA,EAAM,WAAW,MAAA,EAAQ;AAC7B,IAAA,MAAM,iBAAA,EAAkB;AAAA,EAC1B;AAMA,EAAA,MAAM,cAAc,IAAA,EAAK;AACzB,EAAA,IAAA,GAAO,WAAA,CAAY,KAAA,CAAM,CAAC,GAAA,KAAQ;AAChC,IAAA,SAAA,GAAY,GAAA;AAAA,EACd,CAAC,CAAA;AAED,EAAA,eAAe,QAAA,GAA0B;AAGvC,IAAA,IAAI,IAAA,KAAS,QAAQ,IAAA,GAAO,UAAA;AAI5B,IAAA,IAAI,QAAA,CAAS,OAAO,CAAA,EAAG;AACrB,MAAA,MAAA,CAAO,IAAI,qBAAA,CAAsB,QAAA,CAAS,IAAI,GAAG,SAAS,CAAA;AAAA,IAC5D;AAKA,IAAA,MAAM,SAAA,EAAU;AAChB,IAAA,gBAAA,EAAiB;AACjB,IAAA,QAAA,CAAS,CAAC,GAAG,WAAA,CAAY,IAAA,EAAM,CAAC,CAAA;AAGhC,IAAA,MAAM,cAAA,EAAe;AAIrB,IAAA,IAAI,KAAA,IAAS,KAAA,KAAU,MAAA,IAAa,SAAA,KAAc,IAAA,EAAM;AACtD,MAAA,IAAI;AACF,QAAA,MAAM,KAAA,CAAM,KAAK,KAAK,CAAA;AAAA,MACxB,SAAS,KAAA,EAAO;AACd,QAAA,MAAA,CAAO,OAAO,WAAW,CAAA;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAOA,EAAA,IAAI,OAAA;AAEJ,EAAA,MAAM,IAAA,GAAyB;AAAA,IAC7B,CAAC,QAAQ,GAAG,OAAO,EAAE,MAAM,WAAA,CAAY,IAAA,EAAM,IAAA,EAAM,QAAA,CAAS,IAAA,EAAK,CAAA;AAAA,IACjE,CAAC,IAAI,GAAG,OAAA;AAAA,IACR,CAAC,cAAc,GAAG,MAAM,SAAA;AAAA,IACxB,QAAA,EAAU,oBAAA;AAAA,IACV,YAAA,EAAc,CAAC,GAAA,KAAQ,eAAA,CAAgB,GAAG,CAAA;AAAA,IAC1C,QAAA,GAAc;AAIZ,MAAA,OAAO,KAAA;AAAA,IACT,CAAA;AAAA;AAAA;AAAA,IAGA,KAAA,EAAO,WAAA,CAAY,IAAA,CAAK,MAAM,MAAM,CAAA;AAAA,IACpC,IAAA,EAAM,iBAAA;AAAA,IACN,IAAA,GAAsB;AACpB,MAAA,OAAA,KAAY,QAAA,EAAS;AACrB,MAAA,OAAO,OAAA;AAAA,IACT;AAAA,GACF;AACA,EAAA,MAAM,SAA2B,MAAA,CAAO,MAAA;AAAA,IACtC,IAAA;AAAA,IACA,GAAG,WAAW,GAAA,CAAI,CAAC,QAAQ,GAAA,CAAI,MAAA,IAAU,EAAE;AAAA,GAC7C;AACA,EAAA,OAAO,MAAA;AACT;;;AC3+BO,SAAS,OAAA,CACd,OAAA,EACA,OAAA,EACA,GAAA,EACY;AACZ,EAAA,MAAM,QAAA,GAAY,QAAoC,IAAI,CAAA;AAC1D,EAAA,IAAI,aAAa,MAAA,EAAW;AAC1B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AACA,EAAA,OAAO,QAAA;AAAA,IAAS,GAAA;AAAA,IAAK,CAAC,UACpB,aAAA,CAAc,OAAA,EAAS,KAAK,CAAA,CAAE,QAAA,CAAS,IAAI,IAAI;AAAA,GACjD;AACF","file":"chunk-2A5XTKQQ.js","sourcesContent":["/**\n * tea's built-ins, each one an {@link Extension} of the core loop (`./loop`,\n * #280). None is a public plugin API (#268): each engine's `run` builds them\n * from its options through {@link builtinExtensions}, which fixes their order.\n */\n\nimport type { AnyCmdDef, Identity, Port } from \"../../pure/core\";\nimport {\n checkedStep,\n cmdContractOver,\n cmdEdge,\n lookupCell,\n NoCellError,\n Outcome,\n structuralHash,\n} from \"../../pure/core\";\nimport type {\n OnError,\n Store,\n Supervision,\n TelemetryEvent,\n TelemetrySink,\n} from \"../../runtime-types\";\nimport {\n IdentityDropNotice,\n isFencedStore,\n SubFailedError,\n} from \"../../runtime-types\";\nimport type { Extension, ExtensionFactory, LoopServices } from \"./loop\";\n\ntype AnyExtension<S, M, C> = ExtensionFactory<S, M, C>;\n\n// === update middleware ===\n\n/**\n * Supervision: a throw from the fold (the reducer, or any update middleware\n * inside this one) is reported under `\"reduce\"` for every strategy, then\n * `restart` commits the host's rehydrated State with no Cmds, `escalate`\n * rethrows with the runtime still live, and `stop` (the default) halts the run\n * and rethrows, so THIS dispatch rejects too and `done()` answers with the throw\n * (see {@link terminality}). The halt starts the same stop a Sub failure starts:\n * the Msgs already in line fold, then the Subs close, the final save runs and,\n * on the Effect engine, the run's Scope closes (ADR 0033).\n *\n * A Msg the current State has no cell for is not a reducer throw — no machine\n * code ran, the caller dispatched something this State does not accept (#310).\n * Its `NoCellError` rejects only that dispatch and keeps the run alive under\n * every strategy: it is not reported under `\"reduce\"`, `restart` does not\n * rehydrate, and `stop` does not halt. The refusal stays loud; it just is not\n * the program's failure.\n */\nexport function supervision<S, M extends { type: string }, C>(\n declared: Supervision<S, M> | undefined,\n machine: CellTable,\n): AnyExtension<S, M, C> {\n const policy =\n declared === undefined\n ? ({ strategy: \"stop\" } as const)\n : typeof declared === \"string\"\n ? ({ strategy: declared } as const)\n : declared;\n return (loop) => ({\n update: (next) => (state, msg) => {\n try {\n return next(state, msg);\n } catch (reduceError) {\n if (isRefusal(machine, reduceError, state, msg)) throw reduceError;\n loop.report(reduceError, \"reduce\");\n switch (policy.strategy) {\n case \"restart\":\n // A throw inside `rehydrate` is NOT caught — it reaches the caller.\n return [policy.rehydrate(state, msg, reduceError), []];\n case \"escalate\":\n throw reduceError;\n default:\n loop.halt(reduceError);\n throw reduceError;\n }\n }\n },\n });\n}\n\n/** The part of a machine that says which cell a `(state, msg)` pair selects. */\ntype CellTable = Parameters<typeof lookupCell>[0];\n\n/**\n * A `NoCellError` is a refusal only when the machine really has no cell for\n * this `(state, msg)`: then nothing ran, and the error is the lookup's own. A\n * `NoCellError` raised INSIDE a cell that does exist (a reducer stepping a\n * child machine by hand) is that reducer failing, and stays supervised.\n */\nfunction isRefusal<S, M extends { type: string }>(\n machine: CellTable,\n error: unknown,\n state: S,\n msg: M,\n): boolean {\n return (\n error instanceof NoCellError &&\n lookupCell(machine, state, msg).cell === undefined\n );\n}\n\n/**\n * The instance-identity filter: drop a Msg addressed to a DIFFERENT instance\n * than the one this State owns, before the reducer sees it. A Msg with no\n * identity, or a State that has none yet, always proceeds. The drop is no\n * transition, and it RESOLVES the dispatch — a mis-addressed Msg is not the\n * caller's error — so it is reported as an `IdentityDropNotice` (warn by\n * default) or the caller could not tell \"applied\" from \"discarded\".\n *\n * Sits INSIDE {@link supervision}, so a throwing `ofMsg` / `ofState` is reported\n * and supervised exactly like a reducer throw (spike #264 run 3).\n */\nexport function identityFilter<S, M extends { type: string }, C>(\n identity: Identity<S, M> | undefined,\n): AnyExtension<S, M, C> {\n return (loop) => {\n if (identity === undefined) return {};\n const misaddressed = (msg: M, state: S): boolean => {\n const addressed = identity.ofMsg(msg);\n if (addressed === undefined) return false;\n const own = identity.ofState(state);\n if (own === undefined) return false;\n return structuralHash(addressed) !== structuralHash(own);\n };\n return {\n update: (next) => (state, msg) => {\n if (!misaddressed(msg, state)) return next(state, msg);\n loop.report(new IdentityDropNotice(msg.type), \"identity-drop\");\n return null;\n },\n };\n };\n}\n\n/**\n * The dev pre/post pair around the reducer (`checkedStep`): freeze the input\n * State so an in-place mutation trips, and check the returned `[state, cmds]`\n * shape. Both compile out of production. Innermost, so it sees exactly what the\n * reducer saw.\n */\nexport function devChecks<S, M extends { type: string }, C>(): AnyExtension<\n S,\n M,\n C\n> {\n return () => ({\n update: (next) => (state, msg) => checkedStep(state, msg, next),\n });\n}\n\n// === interpret middleware ===\n\n/**\n * The `Cmd.define` edge (ADR 0021): a defined Cmd's handler return is minted\n * into its `_ok` / `_err` Msg, its `ok` value parsed against the def's schema\n * and stamped with `at` from `clock`. A defined Cmd's handler failing outside\n * its declared channel goes to the sink under `\"interpret\"`; a hand-written\n * Cmd's handler throw keeps rejecting the dispatch.\n *\n * A defined Cmd's handler that DISPATCHES its own `_ok` / `_err`, built by hand\n * rather than minted by this edge, breaks the same contract as one that\n * returns it: the Msg is dropped and the `OutcomeContractError` goes to the\n * sink under `\"interpret\"`. Its other Msgs are delivered as before.\n *\n * The same edge rides on ctx under `cmdEdge`, beside the `ok` / `err` builders,\n * so a handler that runs a base handler inside its own settles the base's\n * outcome through this one edge (#66).\n */\nexport function cmdDefinitions<S, M extends { type: string }, C>(\n defs: readonly AnyCmdDef[],\n clock: () => number,\n): AnyExtension<S, M, C> {\n return (loop) => {\n const { settle, checkDispatch: check } = cmdContractOver(defs, clock);\n const defined = new Set(defs.map((d) => d.cmdType));\n return {\n interpret: (next) => async (cmd, dispatch) => {\n const type = (cmd as { type: string }).type;\n const checked = defined.has(type)\n ? (msg: M) => {\n try {\n check(cmd as { type: string }, msg);\n } catch (err) {\n loop.report(err, \"interpret\");\n return;\n }\n dispatch(msg);\n }\n : dispatch;\n try {\n return settle(cmd as { type: string }, await next(cmd, checked));\n } catch (err) {\n if (!defined.has(type)) throw err;\n loop.report(err, \"interpret\");\n return undefined;\n }\n },\n ctx: { ok: Outcome.ok, err: Outcome.err, [cmdEdge]: settle },\n };\n };\n}\n\n// === store wrapper ===\n\n/**\n * Fencing is a property of the store the caller handed `run`, never a flag\n * (#143). A fenced store is read with its version at boot and every save is a\n * compare-and-swap against the last version this run saw, so a second writer\n * that took over is refused with `StoreConflictError` at this run's next save —\n * before that transition's Cmds run. A plain store passes through unchanged.\n */\nexport function fencing<S, M, C>(): AnyExtension<S, M, C> {\n return () => ({\n store: (store: Store<S>): Store<S> => {\n if (!isFencedStore(store)) return store;\n let version = 0;\n return {\n async load() {\n const read = await store.loadFenced();\n version = read.version;\n return read.raw;\n },\n async save(state) {\n version = await store.saveFenced(state, version);\n },\n migrate: (raw) => store.migrate(raw),\n };\n },\n });\n}\n\n/**\n * Refuse a run on a store that is fenced at runtime when the caller passed no\n * `onError` (ADR 0031, amended by #810). The type already refuses it; this is\n * the same rule for a store typed plain `Store<S>` and for a JavaScript caller.\n *\n * Each engine's `run` calls it on the caller's own `onError`, before the loop\n * starts, so nothing is loaded or saved. It is not an extension: the Effect\n * engine always hands the loop a wrapped sink, so the loop never sees the\n * caller's option.\n */\nexport function refuseFencedRunWithoutSink<S>(\n store: Store<S> | undefined,\n onError: OnError | undefined,\n): void {\n if (onError !== undefined || store === undefined || !isFencedStore(store)) {\n return;\n }\n throw new Error(\n \"@demlik/tea: a run on a fenced store needs an `onError`. Without one, a lost fence ends the process and every run in it. Pass `onError` to `run`.\",\n );\n}\n\n// === ctx + handle: ports ===\n\n/**\n * Ports (`definePort`): `ctx.emit(port, value)` from a handler and\n * `emitPort` / `subscribePort` on the handle. Fanout is synchronous and\n * throw-isolated under `\"port-emit\"`; no subscribers is a no-op.\n */\nexport function ports<S, M, C>(): AnyExtension<S, M, C> {\n return (loop) => {\n const registry = new Map<Port<unknown>, Set<(value: unknown) => void>>();\n function emit<T>(port: Port<T>, value: T): void {\n const subscribers = registry.get(port as Port<unknown>);\n if (!subscribers || subscribers.size === 0) return;\n loop.fanout(subscribers, \"port-emit\", (listener) => listener(value));\n }\n return {\n ctx: { emit },\n handle: {\n subscribePort<T>(\n port: Port<T>,\n listener: (value: T) => void,\n ): () => void {\n const key = port as Port<unknown>;\n const bucket = registry.get(key) ?? new Set();\n registry.set(key, bucket);\n const erased = listener as (value: unknown) => void;\n bucket.add(erased);\n return () => {\n bucket.delete(erased);\n if (bucket.size === 0 && registry.get(key) === bucket)\n registry.delete(key);\n };\n },\n emitPort: emit,\n },\n };\n };\n}\n\n// === commit observers ===\n\n/**\n * `subscribe` (zero-arg change notifiers, told after the save and before the\n * Cmds, #695), then, after the Cmds, `observe` (every applied transition's\n * `(msg, state)`) or, at boot, `onBoot` (the initial State, once; a handler\n * registered after boot fires at once). Each fanout is throw-isolated under its\n * own phase.\n */\nexport function observation<S, M, C>(): AnyExtension<S, M, C> {\n return (loop) => {\n const listeners = new Set<() => void>();\n const observers = new Set<(msg: M, state: S) => void>();\n const bootHandlers = new Set<(state: S) => void>();\n let booted = false;\n return {\n installed() {\n loop.fanout(listeners, \"listener\", (listener) => listener());\n },\n commit(msg, state) {\n if (msg === undefined) {\n booted = true;\n loop.fanout(bootHandlers, \"boot\", (handler) => handler(state));\n return;\n }\n loop.fanout(observers, \"observer\", (observer) => observer(msg, state));\n },\n handle: {\n subscribe: subscribeTo(listeners),\n observe: subscribeTo(observers),\n onBoot(handler: (state: S) => void): () => void {\n const state = loop.state();\n if (booted && state !== undefined) {\n loop.fanout([handler], \"boot\", (h) => h(state));\n return () => {};\n }\n return subscribeTo(bootHandlers)(handler);\n },\n },\n };\n };\n}\n\nfunction subscribeTo<T>(set: Set<T>): (item: T) => () => void {\n return (item) => {\n set.add(item);\n return () => {\n set.delete(item);\n };\n };\n}\n\n/**\n * The semantic event channel: `project` maps each APPLIED transition to zero or\n * more public events, and `on(type, handler)` receives only its own type. The\n * machine's private Msg names never reach `on`. A throw in the projector or a\n * handler is isolated under `\"event\"`. Boot projects nothing.\n */\nexport function semanticEvents<S, M, C, E extends { type: string }>(\n project: ((msg: M, state: S) => readonly E[]) | undefined,\n): AnyExtension<S, M, C> {\n return (loop) => {\n const handlers = new Map<string, Set<(event: E) => void>>();\n return {\n commit(msg, state) {\n if (msg === undefined || project === undefined || handlers.size === 0)\n return;\n let events: readonly E[];\n try {\n events = project(msg, state);\n } catch (err) {\n loop.report(err, \"event\");\n return;\n }\n for (const event of events) {\n const bucket = handlers.get(event.type);\n if (bucket === undefined) continue;\n loop.fanout(bucket, \"event\", (handler) => handler(event));\n }\n },\n handle: {\n on(type: string, handler: (event: E) => void): () => void {\n const bucket = handlers.get(type) ?? new Set();\n handlers.set(type, bucket);\n bucket.add(handler);\n return () => {\n bucket.delete(handler);\n if (bucket.size === 0 && handlers.get(type) === bucket)\n handlers.delete(type);\n };\n },\n },\n };\n };\n}\n\n/**\n * Run terminality: only saved State can be reported terminal. `done()` resolves\n * on a terminal commit (boot included — a rehydrated run can land terminal),\n * or rejects when that State's save fails. Storeless State is eligible as soon\n * as it is set. No predicate → never terminal.\n *\n * When tea closes a run because of a failure, `done()` fails with it: a Sub\n * failure as `SubFailedError`, and a reducer throw that halts the run as what was\n * thrown. The first failure is the one that counts. It answers only once no Msg\n * can fold any more, because a Msg already in line can still reach a terminal\n * State. A State terminal by then keeps its answer: its own save decides. So a\n * waiter, a later caller and `result()` read one outcome.\n *\n * A `stop()` with no failure leaves `done()` as it was.\n */\nexport function terminality<S, M, C>(\n isTerminal: ((state: S) => boolean) | undefined,\n): AnyExtension<S, M, C> {\n const holds = isTerminal ?? (() => false);\n return (loop) => {\n const waiters = new Set<{\n resolve(state: S): void;\n reject(error: unknown): void;\n }>();\n // Boxed: a reducer can throw anything, `undefined` included.\n let failure: { readonly answer: unknown } | undefined;\n // Set once the queue is finished with: the failure is now `done()`'s answer.\n let stoppedBy: { readonly answer: unknown } | undefined;\n return {\n subFailed(error) {\n failure ??= { answer: new SubFailedError(error) };\n },\n halted(error) {\n failure ??= { answer: error };\n },\n drained() {\n if (failure === undefined) return;\n stoppedBy = failure;\n const state = loop.state() as S;\n const terminal = holds(state);\n // A terminal State still waiting on its save keeps its waiters. A saved\n // one can have them too: a runner that throws skips its step's commit.\n if (terminal && loop.saveStatus().type !== \"saved\") return;\n const parked = [...waiters];\n waiters.clear();\n for (const waiter of parked) {\n if (terminal) waiter.resolve(state);\n else waiter.reject(stoppedBy.answer);\n }\n },\n commit(_msg, state) {\n if (\n loop.saveStatus().type !== \"saved\" ||\n waiters.size === 0 ||\n !holds(state)\n )\n return;\n const parked = [...waiters];\n waiters.clear();\n for (const waiter of parked) waiter.resolve(state);\n },\n saveFailed(state, error) {\n if (waiters.size === 0 || !holds(state)) return;\n const parked = [...waiters];\n waiters.clear();\n for (const waiter of parked) waiter.reject(error);\n },\n handle: {\n result(): S | undefined {\n const current = loop.state() as S;\n return loop.saveStatus().type === \"saved\" && holds(current)\n ? current\n : undefined;\n },\n done(): Promise<S> {\n const current = loop.state() as S;\n if (holds(current)) {\n const saved = loop.saveStatus();\n if (saved.type === \"saved\") return Promise.resolve(current);\n if (saved.type === \"failed\") return Promise.reject(saved.error);\n } else if (stoppedBy !== undefined) {\n return Promise.reject(stoppedBy.answer);\n }\n return new Promise<S>((resolve, reject) => {\n waiters.add({ resolve, reject });\n });\n },\n },\n };\n };\n}\n\n/**\n * Telemetry (#268: `withTelemetry` moved inside tea). Every applied transition\n * hands the sink `{ seq, msgType, at }` — `seq` counts this run's applied\n * transitions from 1, `at` reads `clock`. Fire-and-forget: the loop never waits\n * on the sink, and a sink that throws or rejects reaches `onError` under\n * `\"observer\"` without touching the run.\n */\nexport function telemetry<S, M extends { type: string }, C>(\n sink: TelemetrySink | undefined,\n clock: () => number,\n): AnyExtension<S, M, C> {\n return (loop: LoopServices<S>): Extension<S, M, C> => {\n if (sink === undefined) return {};\n let seq = 0;\n return {\n commit(msg) {\n if (msg === undefined) return;\n seq += 1;\n const event: TelemetryEvent = { seq, msgType: msg.type, at: clock() };\n try {\n Promise.resolve(sink(event)).catch((err: unknown) =>\n loop.report(err, \"observer\"),\n );\n } catch (err) {\n loop.report(err, \"observer\");\n }\n },\n };\n };\n}\n\n// === assembly: the one order both engines run the built-ins in ===\n\n/** The `run` options the built-ins read. Every engine's `run` accepts them. */\nexport interface BuiltinOptions<\n S,\n M extends { type: string },\n E extends { type: string },\n> {\n readonly clock?: () => number;\n readonly events?: (msg: M, state: S) => readonly E[];\n readonly supervision?: Supervision<S, M>;\n readonly terminal?: (state: S) => boolean;\n readonly telemetry?: TelemetrySink;\n}\n\n/**\n * The built-ins, in the one order that gives them their meaning. Every engine\n * builds its loop from this list, so a machine means the same thing on each.\n *\n * Update middleware nests first-outermost: supervision wraps the identity\n * filter (a throwing `ofMsg` is supervised like a reducer throw — spike #264\n * run 3), which wraps the dev checks around the reducer itself. A Msg with no\n * cell rejects through supervision unsupervised (#310). Change listeners hear\n * before the Cmds. Commit callbacks run after them, in order: `observe` /\n * `onBoot`, then semantic events, then `done()` waiters, then telemetry.\n */\nexport function builtinExtensions<\n S,\n M extends { type: string },\n C,\n E extends { type: string },\n>(\n machine: CellTable & {\n readonly identity?: Identity<S, M>;\n readonly cmds?: readonly AnyCmdDef[];\n },\n opts: BuiltinOptions<S, M, E>,\n): readonly ExtensionFactory<S, M, C>[] {\n const clock = opts.clock ?? Date.now;\n return [\n supervision(opts.supervision, machine),\n identityFilter(machine.identity),\n devChecks(),\n cmdDefinitions(machine.cmds ?? [], clock),\n fencing(),\n ports(),\n observation(),\n semanticEvents(opts.events),\n terminality(opts.terminal),\n telemetry(opts.telemetry, clock),\n ];\n}\n","/**\n * The core loop both engines run (#280, spike #264). It does five things and\n * nothing else: it keeps one serial tail, folds a Msg into a transition, saves\n * before any effect, reconciles the running Subs, and runs the transition's\n * Cmds, dispatching what they return. It has no special case for any built-in.\n *\n * One loop, not one per engine (#283). The loop calls a handler and a runner\n * through erased signatures and awaits a Promise either way, so an engine's\n * own types never pass through it. The Effect engine turns each handler and\n * runner into a fiber at its own edge, run with the services the caller\n * provided, so Effect services (`R`) reach every handler without the loop\n * carrying a type slot for them — the gap spike #260's generic loop left open.\n * Sharing the loop is also what makes the two engines' traces identical: the\n * fold, the save order and the built-ins are the same code.\n *\n * Everything else `run` offers is an {@link Extension} built on ten points:\n *\n * 1. `update` — middleware over the fold. Returning `null` means \"no\n * transition\": no save, no effects, no commit.\n * 2. `interpret` — middleware over one Cmd's handler call; it maps what the\n * handler returned to the Msgs to dispatch, if any.\n * 3. `store` — a wrapper over the store the caller handed `run`.\n * 4. `installed` — called once a transition's State is past its save and its\n * Subs are reconciled, before its first Cmd's handler starts.\n * This is Elm's `view`: it never waits on a Cmd (#695).\n * 5. `commit` — called after a transition's effects, with the Msg and the\n * committed State, even when a Cmd handler threw. Boot\n * passes `undefined` for the Msg.\n * 6. `saveFailed` — called when a transition's save rejects, before that\n * rejection reaches the dispatch caller.\n * 7. `subFailed` — called when a Sub's failure stops the run, before the\n * engine is told to stop it.\n * 8. `halted` — called when an extension halts the run with an error.\n * 9. `drained` — called once no Msg can fold any more, so the State is the\n * run's last: `stop()` has finished with the queue, the\n * host's or the one a failure started.\n * 10. `ctx` — keys added to the ctx every Cmd handler receives, so a\n * handler that runs another handler inside its own can reach\n * the same machinery the loop applies to it.\n *\n * An extension may also add methods to the run handle (`handle`). Array order\n * is nesting order: the first extension's middleware is the outermost, and\n * `installed` and commit callbacks run first to last. `builtinExtensions`\n * (`./builtins`) fixes that order for every engine; it is not a user-facing\n * plugin API (#268).\n *\n * `stop()` is the core's own lifecycle, because the gate it drives is what every\n * dispatch passes through: open → draining → closed, or → abandoned when\n * `stop()` gives up on the queue (ADR 0025), never backwards.\n */\n\nimport type { Dispose, Sub, SubEntry } from \"../../pure/core\";\nimport { desiredSub, detachWork, followUps } from \"../../pure/core\";\nimport type {\n DispatchSettle,\n OnError,\n RuntimeErrorContext,\n RuntimeErrorPhase,\n Store,\n} from \"../../runtime-types\";\nimport {\n DispatchDiscardedError,\n DisposeTimeoutNotice,\n DrainTimeoutNotice,\n QuiescenceTimeoutError,\n RuntimeDiscardedError,\n RuntimeDiscardNotice,\n} from \"../../runtime-types\";\nimport { type InstalledStateRead, installedState } from \"./installed-state\";\nimport { restore } from \"./restore\";\n\n// === The extension points ===\n\n/** A fold's result: the next State and the Cmds it emits. */\nexport type Transition<S, C> = readonly [S, readonly C[]];\n\n/** One fold step. `null` means the Msg produced no transition. */\nexport type Step<S, M, C> = (state: S, msg: M) => Transition<S, C> | null;\n\n/**\n * One Cmd's handler call; resolves to the Msg to dispatch, a list of them in\n * order, or nothing. `dispatch` is what the handler is handed for Msgs it fires\n * itself, so an extension can check them on the way out.\n */\nexport type InterpretStep<C, M> = (\n cmd: C,\n dispatch: (msg: M) => void,\n) => Promise<unknown>;\n\n/** Whether the current State has crossed this transition's save boundary. */\ntype SaveStatus =\n | { readonly type: \"pending\" }\n | { readonly type: \"saved\" }\n | { readonly type: \"failed\"; readonly error: unknown };\n\n/** What the loop lends an extension. */\nexport interface LoopServices<S> {\n /** Route a failure with no caller to the `onError` sink. */\n report(error: unknown, phase: RuntimeErrorPhase): void;\n /** Call `fn` for each item, routing every throw to the sink under `phase`. */\n fanout<T>(\n items: Iterable<T>,\n phase: RuntimeErrorPhase,\n fn: (item: T) => void,\n ): void;\n /**\n * Close the gate for good because of `error`, and have the engine stop the\n * run: every later dispatch is refused, the Msgs already in line still fold,\n * and then the Subs close and the final save runs (ADR 0033).\n */\n halt(error: unknown): void;\n /** The current State, or `undefined` before boot has produced one. */\n state(): S | undefined;\n /** The current State's save status; storeless State is saved immediately. */\n saveStatus(): SaveStatus;\n}\n\n/** One built-in, as the loop sees it. Every member is optional. */\nexport interface Extension<S, M, C> {\n readonly update?: (next: Step<S, M, C>) => Step<S, M, C>;\n readonly interpret?: (next: InterpretStep<C, M>) => InterpretStep<C, M>;\n readonly store?: (store: Store<S>) => Store<S>;\n readonly installed?: () => void;\n readonly commit?: (msg: M | undefined, state: S) => void;\n readonly saveFailed?: (state: S, error: unknown) => void;\n readonly subFailed?: (error: unknown) => void;\n readonly halted?: (error: unknown) => void;\n readonly drained?: () => void;\n readonly ctx?: object;\n readonly handle?: object;\n}\n\n/** An extension is built once per run, from the loop's services. */\nexport type ExtensionFactory<S, M, C> = (\n loop: LoopServices<S>,\n) => Extension<S, M, C>;\n\n/** A Cmd handler as the loop calls it. */\nexport type LoopHandler<M> = (\n cmd: never,\n ctx: unknown,\n dispatch: (msg: M) => void,\n) => unknown;\n\n/**\n * A Sub runner as the loop calls it. `fail` is how an engine edge reports that\n * a Sub's source died with an error the Sub did not turn into a Msg; the loop\n * then drops the Sub and stops the run. A user runner is never handed it.\n */\nexport type LoopRunner<Ctx, M> = (\n sub: Sub,\n ctx: Ctx,\n dispatch: (msg: M) => void,\n fail: (error: unknown) => void,\n) => Dispose;\n\n/** Everything the loop needs from `run`. */\nexport interface LoopConfig<S, M extends { type: string }, C, Ctx> {\n readonly init: (loaded: S | null, ctx: Ctx) => Transition<S, C>;\n /** The innermost fold: the machine's own `update`. */\n readonly reduce: (state: S, msg: M) => Transition<S, C>;\n readonly subs: readonly SubEntry<S>[];\n readonly runnerFor: (type: string) => LoopRunner<Ctx, M> | undefined;\n readonly handlerFor: (type: string) => LoopHandler<M> | undefined;\n readonly store: Store<S> | undefined;\n readonly ctx: Ctx;\n readonly onError: OnError | undefined;\n readonly disposeTimeoutMs: number;\n readonly idleCap: number;\n readonly extensions: readonly ExtensionFactory<S, M, C>[];\n /**\n * How the engine stops the run once tea itself closed it because of a\n * failure: a Sub failed with an error it did not handle (#309), or an\n * extension halted the run, as the `stop` strategy does on a reducer throw\n * (ADR 0033). The loop has already reported the error and closed the gate to\n * new work; this does the rest — `stop()` on the Promise engine, closing the\n * run's Scope with the failure on the Effect engine. Called at most once,\n * possibly before `startLoop` has returned.\n */\n readonly stopOnFailure: (failure: RunFailure) => void;\n}\n\n/** Why tea itself stops a run, as {@link LoopConfig.stopOnFailure} hears it. */\nexport type RunFailure =\n /** A Sub's source died with an error the Sub did not turn into a Msg. */\n | { readonly kind: \"sub\"; readonly error: unknown }\n /** An extension halted the run with `error`: a reducer throw under `stop`. */\n | { readonly kind: \"halt\"; readonly error: unknown };\n\n// === liveWork: \"can anything still transition me without a dispatch?\" ===\n//\n// The one read `driveToDone` needs that the public `Runtime` does not carry:\n// after `start`'s chain quiesces, only a live Sub or an in-flight Cmd can still\n// enqueue a transition; with neither, waiting is a leak (#68). Module-private\n// and symbol-keyed so it reaches no export (the export map is the contract —\n// MAINTAINING.md), yet enumerable so it survives the spread a wrapper does over\n// the handle.\nexport const liveWork: unique symbol = Symbol(\"demlik-tea.liveWork\");\n\n/** The runtime's own sources of a caller-less transition, counted. */\nexport interface LiveWork {\n /** Live Subs — the running `machine.subs` entries. */\n readonly subs: number;\n /** Interpret handlers currently awaiting. */\n readonly cmds: number;\n}\n\nexport interface LiveWorkProbe {\n readonly [liveWork]: () => LiveWork;\n}\n\n// === post: the one entry onto the line that waits for nothing ===\n//\n// What `tell` stands on (ADR 0029, item 5). Module-private and symbol-keyed for\n// the same reason `liveWork` is: it reaches no export, and it survives the\n// spread a wrapper does over the handle.\nexport const post: unique symbol = Symbol(\"demlik-tea.post\");\n\n/**\n * What `tell` answers, at once, about the Msg it was handed. It says where the\n * Msg stands at that moment and nothing about how it ends.\n *\n * - `\"queued\"`: the Msg is on the receiver's line. It has not been handled.\n * - `\"stopped\"`: the receiver is stopping or has stopped, so the Msg is not on\n * its line and never will be.\n * - `\"no_cell\"`: the receiver's current State has no cell for the Msg, so the\n * Msg is not on its line. That reads the State as it is now, not the State\n * the Msgs already in line will leave.\n */\nexport type TellAnswer = \"queued\" | \"stopped\" | \"no_cell\";\n\n/** A run handle `tell` can reach the line of. */\nexport interface Postable<S, M> {\n readonly [post]: (msg: M, takes: (state: S) => boolean) => TellAnswer;\n}\n\n/** The members the core itself puts on the run handle. */\nexport interface LoopHandle<S, M>\n extends LiveWorkProbe,\n Postable<S, M>,\n InstalledStateRead<S> {\n dispatch(msg: M, opts?: { readonly settle?: DispatchSettle }): Promise<void>;\n dispatchOnce(msg: M): Promise<void>;\n getState(): S;\n ready: Promise<unknown>;\n idle(): Promise<void>;\n stop(): Promise<void>;\n}\n\n// Default `onError` sink: re-throw on a fresh macrotask so the failure reaches\n// the host's global error handler instead of vanishing — surface, not swallow\n// (invariant 6).\n//\n// A `RuntimeDiscardNotice` is NOT a failure of the runtime's own contract — a\n// host tearing a runtime down with Cmds in flight (a React ctx change, a\n// navigation) is legal, merely lossy. Rethrowing it would make every\n// unmount-during-fetch an uncaught error for consumers who never configured a\n// sink, so the default WARNS: loud enough that the silent discard #365\n// describes cannot happen again, never fatal. A configured `onError` sees\n// `\"discard\"` like any other phase and can route or ignore it.\n//\n// The branch keys on the ERROR CLASS, never on `context.phase`: `report`\n// hands a THROWING consumer sink's own error back here with the phase it was\n// handling, so a phase-keyed branch would warn away a broken sink and re-create\n// the very silent failure this exists to remove.\n//\n// Everything else is rethrown on a fresh macrotask, which ends a Node process\n// and every run in it: a failing Sub (`\"sub\"`) on a run with no sink keeps that\n// behaviour on purpose. A store that refuses a second writer never gets here by\n// omission: a run on one must pass an `onError`, held by its type\n// (`StoreAndOnError`, ADR 0031) and, where the type was thrown away, by each\n// engine's `run` refusing to start (`./builtins`). So there is no case here for\n// `StoreConflictError`: one that arrives came through a throwing sink, or from a\n// store that does not say what it is, and both stay loud.\nexport function defaultOnError(\n error: unknown,\n _context: RuntimeErrorContext,\n): void {\n if (error instanceof RuntimeDiscardNotice) {\n console.warn(error);\n return;\n }\n setTimeout(() => {\n throw error;\n }, 0);\n}\n\n/**\n * The rejection of a dispatch into a run whose gate is closed: `stop()` has\n * returned, or a built-in halted it. Internal, so the Promise engine's\n * rejection reads as before, an `Error` with this message; the Effect engine\n * reads the class to fail the dispatch with `Stopped`.\n */\nexport class RuntimeStoppedError extends Error {\n constructor(readonly msgType: string) {\n super(\"@demlik/tea: runtime stopped\");\n }\n}\n\n/** One started Sub: its type, the cleanup its runner returned, and whether it failed. */\nclass RunningSub {\n dispose: Dispose = () => {};\n failed = false;\n constructor(readonly type: string) {}\n}\n\n/**\n * The Msgs on the line, per Msg type: one more when a Msg joins the tail, one\n * fewer when its turn comes. Types and counts only, so a sink that logs what\n * this reports never sees a Msg's payload.\n */\nclass MsgLine {\n private readonly counts = new Map<string, number>();\n\n joined(type: string): void {\n this.counts.set(type, (this.counts.get(type) ?? 0) + 1);\n }\n\n reachedTurn(type: string): void {\n const left = (this.counts.get(type) ?? 0) - 1;\n if (left > 0) this.counts.set(type, left);\n else this.counts.delete(type);\n }\n\n /** The counts now, in a fresh object later turns cannot change. */\n snapshot(): Readonly<Record<string, number>> {\n return Object.fromEntries(this.counts);\n }\n}\n\n/**\n * Start the loop. Returns the handle synchronously; boot runs as the FIRST entry\n * on the serial tail. Save-then-effects ordering is structural: every\n * transition installs State, awaits the save, reconciles Subs, tells `subscribe`\n * listeners, runs the Cmds, then calls the commit callbacks — even when a Cmd\n * handler throws.\n */\nexport function startLoop<S, M extends { type: string }, C, Ctx>(\n config: LoopConfig<S, M, C, Ctx>,\n): LoopHandle<S, M> {\n const { idleCap, disposeTimeoutMs } = config;\n const onError: OnError = config.onError ?? defaultOnError;\n\n // A throwing sink routes THAT throw through `defaultOnError`, with the context\n // the sink was handling, so it cannot re-create a silent failure.\n function report(error: unknown, phase: RuntimeErrorPhase): void {\n const context: RuntimeErrorContext = { phase };\n try {\n onError(error, context);\n } catch (sinkError) {\n defaultOnError(sinkError, context);\n }\n }\n\n // Throw-isolated fanout: one bad consumer never strands its siblings\n // (invariant 6). The single home for that isolation discipline.\n function fanout<T>(\n items: Iterable<T>,\n phase: RuntimeErrorPhase,\n fn: (item: T) => void,\n ): void {\n for (const item of items) {\n try {\n fn(item);\n } catch (err) {\n report(err, phase);\n }\n }\n }\n\n // `state` is late-initialized: synchronously when there is no store to read,\n // otherwise inside the boot step (the head of the tail).\n let state: S | undefined;\n // The State the listeners were last told about. Behind `state` while a save is\n // pending, and for good when one fails.\n let installed: S | undefined;\n let saveStatus: SaveStatus = { type: \"pending\" };\n let bootError: unknown = null;\n // The dispatch gate. It only ever ADVANCES — `\"open\"` → `\"draining\"` →\n // `\"closed\"` or `\"abandoned\"` — so the discard window can never re-open under\n // a second `stop()`.\n //\n // \"open\" — normal operation; `enqueueDispatch` accepts.\n // \"draining\" — inside `stop()`, before the tail has settled. New work is\n // still refused (refusing is what makes the drain terminate),\n // but a Msg refused HERE was discarded BY the teardown: an\n // in-flight Cmd's follow-up, a detached handler's last Msg, or\n // a Sub still live because subs are torn down after the drain.\n // So the rejection is a `DispatchDiscardedError` reported\n // under `phase: \"discard\"` — lossy, legal, warn-only.\n // \"closed\" — halted by an extension, or `stop()` has drained the tail. A\n // dispatch refused here is a consumer using a retired runtime\n // — a real error, and it stays loud.\n // \"abandoned\" — `stop()` gave up on the tail at `disposeTimeoutMs` (ADR\n // 0025). Closed to a caller exactly as `\"closed\"` is, and the\n // work still on the tail is dropped as it surfaces: a stuck\n // handler's late result, the next Cmd of its step, the Msgs\n // queued behind it. Each is a teardown discard, never a save.\n // A boot whose load returns only now saves nothing either\n // (`commit`): no store call starts once `stop()` gave up.\n let gate: \"open\" | \"draining\" | \"closed\" | \"abandoned\" = \"open\";\n // The work currently awaiting: one entry per interpret handler call, named by\n // its Cmd type, and one unnamed entry per piece of detached work. Written only\n // by `trackInFlight`, read by `stop()` to make a mid-flight teardown LOUD\n // instead of silent (#365) and to name what it gave up on.\n const inFlight = new Set<{ readonly cmdType: string | undefined }>();\n\n const services: LoopServices<S> = {\n report,\n fanout,\n halt(error) {\n // Only a run that was open still needs stopping: past that, a Sub failure\n // or the host's `stop()` has already started the teardown.\n const stopping = gate !== \"open\";\n if (gate !== \"abandoned\") gate = \"closed\";\n for (const ext of extensions) ext.halted?.(error);\n // The same stop a Sub failure starts (ADR 0033). Its teardown waits for\n // `tail`, which already covers this step and every Msg behind it, so a\n // Msg in line still folds before the Subs close and the final save runs.\n if (!stopping) config.stopOnFailure({ kind: \"halt\", error });\n },\n state: () => state,\n saveStatus: () =>\n config.store === undefined ? { type: \"saved\" } : saveStatus,\n };\n const extensions = config.extensions.map((make) => make(services));\n\n function lastStateReached(): void {\n fanout(extensions, \"sub\", (ext) => ext.drained?.());\n }\n\n // The fold, the handler call and the store, each wrapped by the extensions\n // that ask for it. `reduceRight` makes the first extension the outermost.\n const update: Step<S, M, C> = extensions.reduceRight<Step<S, M, C>>(\n (next, ext) => (ext.update ? ext.update(next) : next),\n config.reduce,\n );\n const interpret: InterpretStep<C, M> = extensions.reduceRight<\n InterpretStep<C, M>\n >((next, ext) => (ext.interpret ? ext.interpret(next) : next), callHandler);\n const store: Store<S> | undefined =\n config.store === undefined\n ? undefined\n : extensions.reduceRight<Store<S>>(\n (inner, ext) => (ext.store ? ext.store(inner) : inner),\n config.store,\n );\n const installedCallbacks = extensions.flatMap((ext) =>\n ext.installed ? [ext.installed] : [],\n );\n const commitCallbacks = extensions.flatMap((ext) =>\n ext.commit ? [ext.commit] : [],\n );\n\n // Copied into a fresh object so handlers get the contributed keys without\n // mutating the caller's ctx (which may be shared across runtimes / tests).\n // `Object.assign`, not a spread: tsc cannot prove a generic `Ctx` is an\n // object type, and a spread refuses it.\n const handlerCtx: unknown = Object.assign(\n {},\n config.ctx,\n ...extensions.map((ext) => ext.ctx ?? {}),\n { [detachWork]: detachInFlight },\n );\n\n // Every step chains onto `tail` — the single concurrency gate.\n let tail: Promise<void> = Promise.resolve();\n // Every Msg on `tail` whose turn has not come. All of them are dropped if\n // `stop()` gives up, so this is what its notice counts.\n const line = new MsgLine();\n\n // The running Subs, keyed by their derived id. An id present here is a runner\n // that started and has neither been disposed nor failed.\n const subRegistry = new Map<string, RunningSub>();\n\n // Tear down each named sub: run its cleanup (throws routed to the sink under\n // `\"sub-cleanup\"`), then drop it from the registry regardless.\n function stopSubs(ids: Iterable<string>): void {\n for (const id of ids) {\n const running = subRegistry.get(id);\n if (running === undefined) continue;\n try {\n trackDisposal(running.dispose());\n } catch (err) {\n report(err, \"sub-cleanup\");\n }\n subRegistry.delete(id);\n }\n }\n\n // Teardown work that returned a Promise and has not settled. Reconcile runs\n // inside the synchronous transition path (invariant 2) and cannot await a\n // cleanup, so every async disposal is remembered here the moment it starts,\n // and `stop()` drains the set before resolving: `await runtime.stop()` then\n // means \"teardown is done\", the only reading a host evicting an isolate can\n // act on. The rejection is attached HERE, once, so it can never become an\n // unhandled rejection.\n const pendingDisposals = new Set<Promise<void>>();\n\n function trackDisposal(result: void | Promise<void>): void {\n if (!(result instanceof Promise)) return;\n const settling: Promise<void> = result\n .catch((err) => {\n report(err, \"sub-cleanup\");\n })\n .finally(() => {\n pendingDisposals.delete(settling);\n });\n pendingDisposals.add(settling);\n }\n\n /**\n * Wait for `work`, for at most `disposeTimeoutMs`. The one bound both of\n * `stop()`'s waits share: `stop()` resolves regardless (contract), so neither\n * a handler nor a release that never settles may become a host that never\n * shuts down (ADR 0025).\n */\n async function withinLimit(\n work: Promise<unknown>,\n ): Promise<\"settled\" | \"timeout\"> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n work.then(() => \"settled\" as const),\n new Promise<\"timeout\">((resolve) => {\n timer = setTimeout(() => resolve(\"timeout\"), disposeTimeoutMs);\n }),\n ]);\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n }\n\n /**\n * Wait for the tail, up to the limit, and settle the gate on what happened.\n * On expiry report a `DrainTimeoutNotice` naming the handlers still awaiting\n * and counting the Msgs on the line, and leave the gate `\"abandoned\"`, which\n * is what drops their late work and those Msgs. The gate has refused new work\n * since `stop()` began, so the count cannot grow after this.\n */\n async function drainTail(): Promise<void> {\n if ((await withinLimit(tail)) === \"settled\") {\n gate = \"closed\";\n return;\n }\n report(\n new DrainTimeoutNotice(\n [...inFlight].flatMap(({ cmdType }) => cmdType ?? []),\n inFlight.size,\n disposeTimeoutMs,\n line.snapshot(),\n ),\n \"discard\",\n );\n gate = \"abandoned\";\n }\n\n /**\n * Wait for the disposals started so far, up to the limit. On expiry report a\n * `DisposeTimeoutNotice` and return anyway.\n */\n async function drainDisposals(): Promise<void> {\n if (pendingDisposals.size === 0) return;\n const outstanding = [...pendingDisposals];\n if ((await withinLimit(Promise.all(outstanding))) === \"timeout\") {\n report(\n new DisposeTimeoutNotice(outstanding.length, disposeTimeoutMs),\n \"discard\",\n );\n }\n }\n\n /**\n * Reconcile the running Subs against `state`, after every save. An id already\n * running is left alone, a running id no longer wanted is stopped, and a\n * wanted id not yet running is started through its runner.\n *\n * Every failure is collected, never thrown mid-pass, so one bad entry cannot\n * strand its siblings: a throwing `deps` leaves the running Subs of that type\n * untouched, and a throwing runner is not registered. The first error is\n * thrown after the pass. A Sub type with no runner is a failure too — nothing\n * would ever start it.\n */\n function reconcileSubs(): void {\n let firstError: unknown = null;\n const remember = (err: unknown): void => {\n if (firstError === null) firstError = err;\n };\n const desired = new Map<string, Sub>();\n // Types whose entry could not be read this pass: keep what is running.\n const unreadTypes = new Set<string>();\n for (const entry of config.subs) {\n try {\n const sub = desiredSub(entry, state as S);\n if (sub !== null) desired.set(sub.id, sub);\n } catch (err) {\n remember(err);\n unreadTypes.add(entry.type);\n }\n }\n\n stopSubs(\n [...subRegistry].flatMap(([id, running]) =>\n desired.has(id) || unreadTypes.has(running.type) ? [] : [id],\n ),\n );\n\n // A run that is stopping starts nothing: stop() would only tear it down,\n // and a Sub that failed must not be re-armed by a step still queued.\n const starting = gate === \"open\" ? desired : new Map<string, Sub>();\n for (const [id, sub] of starting) {\n if (subRegistry.has(id)) continue;\n const runner = config.runnerFor(sub.type);\n if (runner === undefined) {\n remember(\n new Error(\n `@demlik/tea: no subscribe runner for Sub type \"${sub.type}\". ` +\n \"Pass one to run in `subscribe`.\",\n ),\n );\n continue;\n }\n const running = new RunningSub(sub.type);\n try {\n // A runner's dispatch is unawaited by construction, so it gets the\n // wrapped form, which also queues the transition behind this step —\n // never on the runner's own stack (spike #260).\n running.dispose = runner(sub, config.ctx, dispatchUnawaited, (error) =>\n subFailed(id, running, error),\n );\n } catch (err) {\n // A runner that throws while starting is a Sub failure too: the step\n // that started it rejects with the throw, and the run stops.\n remember(err);\n subFailed(id, running, err);\n continue;\n }\n if (!running.failed) {\n subRegistry.set(id, running);\n continue;\n }\n // The source died before its runner returned: never registered, but\n // its cleanup still runs.\n try {\n trackDisposal(running.dispose());\n } catch (err) {\n report(err, \"sub-cleanup\");\n }\n }\n if (firstError !== null) throw firstError;\n }\n\n /**\n * A Sub's source died with an error the Sub did not turn into a Msg (#309,\n * ruling R3.1 of #325). The Elm answer: a Sub maps the failures it expects to\n * Msgs itself, so one that reaches here is unhandled, and the run stops\n * rather than keep a dead Sub counted as live. The Sub leaves the registry,\n * the error reaches the sink under `\"sub\"`, the gate starts draining so no\n * new Msg is accepted, `done()` hears it, and the engine stops the run. A\n * failure while the run is already stopping is reported and nothing more.\n */\n function subFailed(id: string, running: RunningSub, error: unknown): void {\n if (running.failed) return;\n running.failed = true;\n if (subRegistry.get(id) === running) subRegistry.delete(id);\n report(error, \"sub\");\n if (gate !== \"open\") return;\n gate = \"draining\";\n for (const ext of extensions) ext.subFailed?.(error);\n config.stopOnFailure({ kind: \"sub\", error });\n }\n\n // The ONE `(msg) => void` handed to every producer that cannot await its own\n // dispatch: a Cmd handler's late tail, a Sub runner. Its rejection has no\n // caller, so it routes to the sink with the phase derived from the error\n // class (`reportUndelivered`). Handing those sites the raw `enqueueDispatch`\n // would turn a Sub firing during `stop()`'s drain into an unhandled rejection\n // the sink never sees.\n function dispatchUnawaited(msg: M): void {\n enqueueDispatch(msg, \"loop\").catch(reportUndelivered);\n }\n\n // A `DispatchDiscardedError` means the teardown refused the Msg (`\"discard\"`,\n // warn-only); anything else is a genuine failure of the follow-up itself.\n function reportUndelivered(error: unknown): void {\n report(\n error,\n error instanceof DispatchDiscardedError ? \"discard\" : \"follow-up\",\n );\n }\n\n /**\n * Count a handler's work as in flight for exactly the lifetime of its\n * promise. `finally`-balanced, so a rejecting handler can never strand the\n * count above zero. A handler that throws SYNCHRONOUSLY never reaches here,\n * which is correct — it was never in flight. `cmdType` names a handler call;\n * detached work has no Cmd of its own to name.\n */\n function trackInFlight<T>(\n work: T | Promise<T>,\n cmdType?: string,\n ): Promise<T> {\n const entry = { cmdType };\n inFlight.add(entry);\n return Promise.resolve(work).finally(() => {\n inFlight.delete(entry);\n });\n }\n\n /**\n * Enlist work a handler will NOT return — the `detachWork` key on ctx. A\n * handler that fans out inside its own Cmd (ADR 0018) returns before its\n * effect finishes; handing the promise here puts it back on both accountings\n * a returned promise had: `trackInFlight`, so `stop()` still reports it, and\n * the serial `tail`, so `idle()` drains it. The tail extension is\n * SYNCHRONOUS, so a `drainToQuiescence` that already read `tail` sees the\n * reference change and loops again.\n */\n function detachInFlight(work: Promise<unknown>): void {\n const tracked = trackInFlight(work);\n tracked.catch(reportUndelivered);\n tail = tail\n .then(async () => {\n await tracked;\n })\n .catch(() => {});\n }\n\n // The innermost interpret step: call the Cmd's handler, if one is wired. A\n // missing handler returns nothing, which is invariant 6's forward progress\n // for a miswired consumer.\n function callHandler(cmd: C, dispatch: (msg: M) => void): Promise<unknown> {\n const { type } = cmd as { type: string };\n const handler = config.handlerFor(type);\n if (handler === undefined) return Promise.resolve(undefined);\n return trackInFlight(handler(cmd as never, handlerCtx, dispatch), type);\n }\n\n /**\n * Run each emitted Cmd. A returned Msg is enqueued onto the tail, never\n * dispatched re-entrantly; a returned list enqueues each of its Msgs in\n * order, before the next Cmd's handler runs (#324). The first error stops\n * further handlers in this transition.\n *\n * THIS LOOP IS SERIAL BY RULING, NOT BY OVERSIGHT (ADR 0018). It runs a\n * transition's Cmds one at a time and never interleaves two handlers, so the\n * Msgs it enqueues fold in Cmd-EMISSION order and a replayed log reproduces\n * the same fold — invariant 2's serializability. Overlap in time belongs\n * INSIDE one Cmd's handler, never across the Cmds of one transition.\n *\n * Once `stop()` has given up on this step, no further handler starts; what\n * the stuck one returned is refused at the gate like any other late Msg.\n */\n async function runCmds(cmds: readonly C[]): Promise<void> {\n for (const cmd of cmds) {\n if (gate === \"abandoned\") return;\n const returned = await interpret(cmd, dispatchUnawaited);\n for (const follow of followUps<M>(returned)) dispatchUnawaited(follow);\n }\n }\n\n // Install State, then save → reconcile subs → tell `subscribe` listeners →\n // run Cmds → commit callbacks. Save-before-effects is the hard ordering; tests\n // pin it. Boot and every transition end here; boot passes no Msg.\n //\n // A listener hears here, once per transition, because it is the view: it\n // reads the new State while that State's Cmds run and never waits on them, as\n // in Elm (#695). A failed save returns before this point, so a listener never\n // hears unsaved State.\n //\n // The commit callbacks run in a `finally`: a Cmd handler that throws still\n // rejects the dispatch with its own error, but the State it left installed\n // and saved still reaches every observer, `on` handler, `done()` waiter and\n // the telemetry sink (#311). Those stay after the Cmds: `driveToDone` settles\n // on `observe`, so the Cmds of the State it settles on have finished by then.\n //\n // No store call starts once `stop()` has given up (ADR 0025). A step never\n // gets here abandoned, because the queued step in `enqueueDispatch` drops it\n // first; boot does, when `stop()` gave up while `store.load()` was pending and\n // the load returns afterwards. That boot installs the loaded State, so\n // `getState()` stays total, and saves nothing: the store may already belong\n // to a newer run. It starts no Sub and no handler either, as the gate rules.\n async function commit(\n next: S,\n msg: M | undefined,\n cmds: readonly C[],\n ): Promise<void> {\n state = next;\n saveStatus = { type: \"pending\" };\n if (store && gate !== \"abandoned\") {\n try {\n await store.save(next);\n saveStatus = { type: \"saved\" };\n } catch (error) {\n saveStatus = { type: \"failed\", error };\n for (const ext of extensions) ext.saveFailed?.(next, error);\n throw error;\n }\n }\n reconcileSubs();\n installed = next;\n for (const callback of installedCallbacks) callback();\n try {\n await runCmds(cmds);\n } finally {\n for (const callback of commitCallbacks) callback(msg, next);\n }\n }\n\n // One full transition. A `null` from the fold is no transition at all, and\n // it RESOLVES the dispatch. A throw from the fold rejects it.\n async function stepDispatch(msg: M): Promise<void> {\n if (state === undefined) {\n throw new Error(\"@demlik/tea: runtime not booted\");\n }\n const transition = update(state, msg);\n if (transition === null) return;\n await commit(transition[0], msg, transition[1]);\n }\n\n // With NO store there is nothing to read, so `init` runs IMMEDIATELY and\n // `getState()` is observable synchronously (what `useSyncExternalStore`\n // consumers need to render the first commit without a flicker); an `init`\n // throw leaves `run` itself. With a store, the read is the first thing boot\n // awaits; saved state it cannot restore rejects `ready` with a\n // `StoreRefusedError` before `init` runs, so nothing is saved over it.\n const storeless: Transition<S, C> | null =\n store === undefined ? config.init(null, config.ctx) : null;\n if (storeless !== null) state = storeless[0];\n\n async function boot(): Promise<void> {\n // Boundary parse (invariant 8): `store.load()` returns `unknown`;\n // `store.migrate(raw)` is the required parse — `S` on a recognized shape,\n // `null` when nothing was saved (boots fresh), a refusal otherwise.\n const [initial, cmds] =\n storeless ?? config.init(await restore(store as Store<S>), config.ctx);\n await commit(initial, undefined, cmds);\n }\n\n /**\n * Enqueue a dispatch on the tail — the single gate re-entrant handler and\n * runner calls also go through. Rejects when the gate is not open (with a\n * `DispatchDiscardedError` while `stop()` drains, a `RuntimeStoppedError`\n * once it has), boot failed, or the fold / save / sub start / handler throws.\n *\n * `origin` separates the two refusals an abandoned run makes. A Msg from the\n * loop's own producers is the late work `stop()` gave up on, so it is a\n * discard; a caller's dispatch is still a retired runtime being used. A Msg\n * accepted before `stop()` gave up is dropped when its turn comes, unfolded\n * and unsaved: a discard for a caller, and no word at all for a Msg with no\n * caller, since the notice already counted it (`enqueueStep`).\n */\n function enqueueDispatch(\n msg: M,\n origin: \"caller\" | \"loop\" = \"caller\",\n ): Promise<void> {\n if (gate !== \"open\") {\n return Promise.reject(\n gate === \"draining\" || (gate === \"abandoned\" && origin === \"loop\")\n ? new DispatchDiscardedError(msg.type)\n : new RuntimeStoppedError(msg.type),\n );\n }\n return enqueueStep(msg, origin, stepDispatch);\n }\n\n /**\n * Put `step` on the tail, past the gate: the caller has already checked it.\n *\n * Every Msg dropped at its turn was on the line when `stop()` gave up, so the\n * `DrainTimeoutNotice` has already counted it. A caller holds a promise that\n * must settle, so it gets a `DispatchDiscardedError`. A Msg with no caller\n * goes without a word: an error here would reach the sink and count it twice.\n */\n function enqueueStep(\n msg: M,\n origin: \"caller\" | \"loop\" | \"tell\",\n step: (msg: M) => Promise<void> | undefined,\n ): Promise<void> {\n line.joined(msg.type);\n const next = tail.then(() => {\n line.reachedTurn(msg.type);\n if (gate === \"abandoned\") {\n if (origin === \"caller\") throw new DispatchDiscardedError(msg.type);\n return;\n }\n if (bootError !== null) throw bootError;\n return step(msg);\n });\n // Swallow the rejection on the tail so one failing dispatch does NOT poison\n // every later one. The original `next` still rejects for the caller.\n tail = next.catch(() => {});\n return next;\n }\n\n /**\n * Put a Msg on the tail and answer at once, with no caller left to reject at.\n * The tail is extended synchronously, so two posts from one sender fold in\n * the order they were made. Whatever the step ends with goes to this run's\n * own sink, as for any Msg with no caller. The one exception is a cell that\n * is gone by the Msg's turn: the Msg is dropped there, before any fold, so\n * nothing is raised and the default sink has nothing to rethrow. A `stop()`\n * that gave up counts the Msg in its notice instead (`enqueueStep`).\n */\n function postMsg(msg: M, takes: (state: S) => boolean): TellAnswer {\n if (gate !== \"open\") return \"stopped\";\n if (!takes(state as S)) return \"no_cell\";\n enqueueStep(msg, \"tell\", (queued) =>\n takes(state as S) ? stepDispatch(queued) : undefined,\n ).catch(reportUndelivered);\n return \"queued\";\n }\n\n /**\n * Drain the serial tail to quiescence. Every follow-up reassigns `tail`\n * SYNCHRONOUSLY before its parent step resolves, so awaiting the current\n * `tail` and re-reading it catches every transitively enqueued follow-up.\n * Bounded by `idleCap` — on cap REJECT with `QuiescenceTimeoutError`, keeping\n * a livelock distinguishable from quiescence (invariant 6).\n */\n async function drainToQuiescence(): Promise<void> {\n for (let i = 0; i < idleCap; i++) {\n const observed = tail;\n await observed;\n if (tail === observed) return;\n }\n throw new QuiescenceTimeoutError(idleCap);\n }\n\n /**\n * The public `dispatch`: await the Msg's OWN transition first (so its own\n * failure surfaces before any drain), then — unless `{ settle: \"once\" }` —\n * drain the transitive follow-up chain.\n */\n async function dispatchToQuiescence(\n msg: M,\n opts?: { readonly settle?: DispatchSettle },\n ): Promise<void> {\n await enqueueDispatch(msg);\n if (opts?.settle === \"once\") return;\n await drainToQuiescence();\n }\n\n // `bootPromise` is the un-swallowed promise `ready` chains off (so callers\n // see the boot error directly); `tail` gets the swallowed branch so a failed\n // boot does not poison every later dispatch's chain (each surfaces\n // `bootError` in `enqueueDispatch`).\n const bootPromise = boot();\n tail = bootPromise.catch((err) => {\n bootError = err;\n });\n\n async function teardown(): Promise<void> {\n // Open the discard window unless the gate is already past it (a halt):\n // the gate only advances.\n if (gate === \"open\") gate = \"draining\";\n // Report BEFORE the drain: a drained tail leaves nothing in flight, and\n // the fact worth surfacing is what was outstanding at the moment the\n // host let go (#365).\n if (inFlight.size > 0) {\n report(new RuntimeDiscardedError(inFlight.size), \"discard\");\n }\n // Drain in-flight work, up to `disposeTimeoutMs`. The gate refuses the\n // follow-ups those handlers return, so the tail ends once each handler\n // has returned; a handler that never returns is what the limit is for\n // (ADR 0025). Either way this resolves, and the teardown below runs.\n await drainTail();\n lastStateReached();\n stopSubs([...subRegistry.keys()]);\n // …then WAIT for the teardown still settling, up to the same limit (see\n // `drainDisposals`).\n await drainDisposals();\n // Flush final State. A save throw does not reject `stop()` (contract:\n // resolves regardless) but IS loss of the last write, so it reaches the\n // sink (invariant 6).\n if (store && state !== undefined && bootError === null) {\n try {\n await store.save(state);\n } catch (error) {\n report(error, \"stop-save\");\n }\n }\n }\n\n // The teardown runs once. A second `stop()` — a host calling it again, or the\n // Effect engine's Scope closing after the handle's own `stop()` — gets the\n // first one's promise, so it reports nothing twice and, above all, runs no\n // second final save: that would be a store call after `stop()` has returned\n // (ADR 0025), over a store that may by then belong to a newer run.\n let stopped: Promise<void> | undefined;\n\n const core: LoopHandle<S, M> = {\n [liveWork]: () => ({ subs: subRegistry.size, cmds: inFlight.size }),\n [post]: postMsg,\n [installedState]: () => installed,\n dispatch: dispatchToQuiescence,\n dispatchOnce: (msg) => enqueueDispatch(msg),\n getState(): S {\n // TOTAL. A booted handle is only obtainable by awaiting `ready`, which\n // resolves AFTER boot set `state`. That holds for a run `stop()` gave up\n // on mid-load too: its late boot installs the loaded State (`commit`).\n return state as S;\n },\n // A failed boot never hands out a handle. The forward reference resolves\n // at `.then` time, after `handle` below is built.\n ready: bootPromise.then(() => handle),\n idle: drainToQuiescence,\n stop(): Promise<void> {\n stopped ??= teardown();\n return stopped;\n },\n };\n const handle: LoopHandle<S, M> = Object.assign(\n core,\n ...extensions.map((ext) => ext.handle ?? {}),\n );\n return handle;\n}\n","/**\n * The one `tell` both engines' helpers call (ADR 0029, item 5), so what each\n * answer means cannot drift between them. It reads the machine's accepted Msgs\n * for the loop, which holds the gate and the State but not the cell table.\n */\n\nimport { acceptedTypes } from \"../../pure/core\";\nimport { type Postable, post, type TellAnswer } from \"./loop\";\n\n/**\n * Hand `msg` to the run behind `runtime`. Both `tell`s ask for a type that carries\n * the `post` symbol, so a handle that did not come from `run` reaches this only\n * through a cast. It is refused here, loudly: it has no line to put a Msg on.\n */\nexport function tellRun<S, M extends { type: string }>(\n machine: Parameters<typeof acceptedTypes>[0],\n runtime: object,\n msg: M,\n): TellAnswer {\n const postable = (runtime as Partial<Postable<S, M>>)[post];\n if (postable === undefined) {\n throw new Error(\n \"@demlik/tea: `tell` needs a run handle from `run`; this object has no line to post to.\",\n );\n }\n return postable(msg, (state) =>\n acceptedTypes(machine, state).includes(msg.type),\n );\n}\n"]}
@@ -1,15 +1,10 @@
1
- import { startLoop, builtinExtensions, liveWork } from './chunk-UHAQ4PI6.js';
2
- import { subEntriesOf, applyCell, DriveFailedError, DriveStalledError } from './chunk-RKVUVALV.js';
3
-
4
- // src/promise/builtin-runners.ts
5
- function timer(sub, _ctx, dispatch) {
6
- const handle = setTimeout(() => dispatch(sub.deps.msg), sub.deps.ms);
7
- return () => clearTimeout(handle);
8
- }
9
- var builtinRunners = { timer };
1
+ import { builtinRunners } from './chunk-GFGOQIEC.js';
2
+ import { refuseFencedRunWithoutSink, startLoop, builtinExtensions, tellRun, liveWork } from './chunk-2A5XTKQQ.js';
3
+ import { subEntriesOf, applyCell, DriveFailedError, DriveStalledError } from './chunk-A3QPMX5M.js';
10
4
 
11
5
  // src/promise/run.ts
12
6
  function run(machine, opts) {
7
+ refuseFencedRunWithoutSink(opts.store, opts.onError);
13
8
  const interpretMap = opts.interpret ?? {};
14
9
  const subscribeTable = opts.subscribe;
15
10
  const builtins = builtinRunners;
@@ -32,9 +27,10 @@ function run(machine, opts) {
32
27
  disposeTimeoutMs: opts.disposeTimeoutMs ?? 5e3,
33
28
  idleCap: opts.__idleCap ?? 1e5,
34
29
  extensions: builtinExtensions(machine, opts),
35
- // Deferred: a runner that throws during a storeless boot fails before
36
- // `startLoop` has returned the handle.
37
- stopOnSubFailure: () => {
30
+ // A Sub failure and a halting reducer throw stop the run the same way
31
+ // (ADR 0033). Deferred: a runner that throws during a storeless boot fails
32
+ // before `startLoop` has returned the handle.
33
+ stopOnFailure: () => {
38
34
  queueMicrotask(() => void handle.stop());
39
35
  }
40
36
  });
@@ -103,6 +99,11 @@ async function driveToDone(handle, start, isTerminal, opts = {}) {
103
99
  }
104
100
  }
105
101
 
106
- export { driveToDone, run };
107
- //# sourceMappingURL=chunk-JAKM53JF.js.map
108
- //# sourceMappingURL=chunk-JAKM53JF.js.map
102
+ // src/promise/tell.ts
103
+ function tell(machine, runtime, msg) {
104
+ return tellRun(machine, runtime, msg);
105
+ }
106
+
107
+ export { driveToDone, run, tell };
108
+ //# sourceMappingURL=chunk-7K7SEYCH.js.map
109
+ //# sourceMappingURL=chunk-7K7SEYCH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/promise/run.ts","../src/promise/tell.ts"],"names":[],"mappings":"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","file":"chunk-7K7SEYCH.js","sourcesContent":["/**\n * @demlik/tea runtime — `run`: boot a machine and drive its serial dispatch loop\n * on Promises; `driveToDone`: run one to its terminal State.\n *\n * `run` is assembly. The loop itself is `src/internal/engine/loop.ts` — a small\n * core with no special case for any built-in, shared with the Effect engine —\n * and every built-in is an extension of it (`src/internal/engine/builtins.ts`),\n * built from `run`'s options in the order both engines share.\n */\n\nimport { builtinRunners } from \"../internal/engine/builtin-runners\";\nimport {\n builtinExtensions,\n refuseFencedRunWithoutSink,\n} from \"../internal/engine/builtins\";\nimport {\n type LiveWorkProbe,\n type LoopHandler,\n type LoopRunner,\n liveWork,\n type Postable,\n startLoop,\n} from \"../internal/engine/loop\";\nimport type {\n Dispose,\n Interpret,\n Machine,\n RunHandlers,\n Sub,\n} from \"../pure/core\";\nimport { applyCell, type Cmd, subEntriesOf } from \"../pure/core\";\nimport type {\n BootingRuntime,\n CtxArg,\n Runtime,\n StoreAndOnError,\n Supervision,\n TelemetrySink,\n} from \"../runtime-types\";\nimport { DriveFailedError, DriveStalledError } from \"../runtime-types\";\n\n// `ctx` is a plain object (ADR 0020): tea does no dependency injection, so\n// a handler's services are whatever the host put on it. The Cmd handlers\n// arrive here, beside the machine and never on it (#251 R1.1). `NoInfer`\n// keeps them a check against the machine's `M` / `C` rather than a second\n// inference site that could widen either.\n//\n// It is a named alias because the reference is generated from it: written inline\n// on `run`, the union in `StoreAndOnError` makes typedoc give up on the source\n// and hand back the compiler's printed type, with no comments and cut off.\n/** The options of the Promise engine's `run`. */\nexport type PromiseRunOptions<\n S,\n M extends { type: string },\n C extends Cmd,\n U extends Sub,\n Ctx,\n E extends { type: string },\n> = CtxArg<Ctx> &\n NoInfer<RunHandlers<M, C, U, Ctx>> &\n StoreAndOnError<S> & {\n /**\n * The clock that stamps `at` on a `Cmd.define`d effect's settled Msg at\n * the interpret edge, and on each `telemetry` event. Defaults to\n * `Date.now`. Inject a fixed one for a deterministic run; a `replay` log\n * carries its own `at`s and never reads this.\n */\n clock?: () => number;\n /**\n * The SEMANTIC event projector. Maps one APPLIED transition `(msg, state)`\n * to zero-or-more public events of `E`; `[]` skips the transition. Maps the\n * machine's PRIVATE Msg vocabulary to NAMED events — the private names never\n * reach `on`'s `E` surface. Omit → `E = never` and `on` is uncallable. PURE.\n */\n events?: (msg: M, state: S) => readonly E[];\n /**\n * Declared policy for a reducer (`update`) throw. Always surfaced via\n * `onError` (`phase: \"reduce\"`); the strategy decides what the runtime does\n * next. Defaults to `\"stop\"`. See `Supervision`.\n */\n supervision?: Supervision<S, M>;\n /**\n * The run-terminality predicate — makes the run's outcome first-class. Fed to\n * `Runtime.result()` and `Runtime.done()`. PURE. Omit → never terminal.\n *\n * `done()` resolves with a saved terminal State. When a failure closes the\n * run short of one, it rejects with that failure, for waiting and later\n * callers: the save's own error, a `SubFailedError`, or what a reducer threw\n * under the `stop` strategy. A `stop()` with no failure leaves it pending.\n */\n terminal?: (state: S) => boolean;\n /**\n * A sink handed `{ seq, msgType, at }` for every applied transition —\n * the observe-only telemetry `withTelemetry` used to add by wrapping the\n * machine (#268). Fire-and-forget; see {@link TelemetrySink}.\n */\n telemetry?: TelemetrySink;\n /**\n * How long `stop()` waits for work it cannot interrupt before giving up\n * on it. Defaults to 5_000ms. It bounds two waits, one after the other:\n * the queue, where a Cmd handler may still be running, and then the\n * teardown work that returned a Promise (an async `release` in\n * `defineManagedResource`, an async Sub cleanup).\n *\n * `stop()` awaits those disposals so a host doing\n * `await runtime.stop(); env.evict()` cannot drop the isolate mid-release —\n * the leak the managed-resource battery exists to prevent, relocated to\n * shutdown. The bound is what keeps a handler that never returns, or a\n * release that never settles, from hanging the host: on expiry `stop()`\n * reports a `DrainTimeoutNotice` or a `DisposeTimeoutNotice` (warn-only,\n * like every `RuntimeDiscardNotice`) and resolves anyway, because `stop()`\n * resolving is a contract (ADR 0025). The Subs are still stopped and the\n * final save still runs. A handler `stop()` gave up on keeps running;\n * what it returns later is dropped.\n *\n * tea starts no store call after `stop()` has returned. A store call\n * already under way when `stop()` gave up is not cancelled and can\n * finish after `stop()` has returned. On a plain store that late save\n * can overwrite what a newer run saved; a fenced store refuses it with\n * `StoreConflictError`. So a host that starts a new run on the same\n * store after a `stop()` that gave up needs a fenced store. A run\n * stopped while its `store.load()` was pending saves nothing when the\n * load returns: `ready` resolves with the loaded State, unsaved.\n */\n disposeTimeoutMs?: number;\n /**\n * Iteration cap for `idle()`'s quiescence wait. Defaults to 100_000. Test\n * seam only. Production code must not set it.\n *\n * @internal test-only\n */\n __idleCap?: number;\n };\n\n/**\n * The handle `run` returns: a {@link BootingRuntime} whose `ready` resolves to a\n * {@link Run}. It does not compile as `tell`'s argument: wait for `ready`.\n */\nexport interface BootingRun<\n S,\n M extends { type: string },\n E extends { type: string } = never,\n> extends BootingRuntime<S, M, E> {\n ready: Promise<Run<S, M, E>>;\n}\n\n/**\n * What a {@link BootingRun}'s `ready` resolves to: a booted {@link Runtime} that\n * also carries the run's line, which is what `tell` asks for. A spread keeps the\n * line. An object built by hand cannot have one, because tea does not export its\n * key, so a {@link Runtime} that is not one of these does not compile as `tell`'s\n * argument. It fits anywhere a `Runtime` is asked for.\n */\nexport interface Run<\n S,\n M extends { type: string },\n E extends { type: string } = never,\n> extends Runtime<S, M, E>,\n Postable<S, M> {\n ready: Promise<Run<S, M, E>>;\n}\n\n// === run ===\n//\n// Boot runs as the FIRST entry on the serial dispatch tail, which is how every\n// public method of the returned `BootingRuntime<S, M>` waits for it.\n//\n// Save-then-effects ordering is structural: every transition mutates state,\n// awaits `store.save(newState)`, then reconciles subscriptions, then tells\n// `subscribe` listeners, then runs `interpret` for emitted cmds, then fires\n// observers, `on` handlers and `done()` waiters. Those fire even when a Cmd\n// handler throws: the dispatch rejects with the handler's error, and each of\n// them still hears the State that was installed and saved (#311), as the\n// listeners already have. A throw in any effect\n// phase leaves the persisted state ahead of the host's belief about what\n// executed — the Railway discipline (`tryInterpret` in handlers) makes that\n// safe in practice.\n/**\n * Start a machine on the Promise engine and return its runtime. Pass the Cmd\n * handlers, the Sub runners, `ctx` and an optional `Store`; the runtime is\n * returned at once and every method waits for boot.\n *\n * Throws at once, before anything is loaded, when the store is fenced at runtime\n * and no `onError` was passed, even when the store is typed plain `Store<S>`\n * (ADR 0031).\n */\nexport function run<\n S,\n M extends { type: string },\n C extends Cmd,\n U extends Sub,\n Ctx,\n E extends { type: string } = never,\n>(\n machine: Machine<S, M, C, U, Ctx>,\n opts: PromiseRunOptions<S, M, C, U, Ctx, E>,\n): BootingRun<S, M, E> {\n // Thrown here, before the loop starts, so nothing is loaded or saved.\n refuseFencedRunWithoutSink(opts.store, opts.onError);\n\n // `interpret` is optional when `C extends Cmd<never>`; default a missing map\n // to `{}` — a Cmd with no handler is skipped, invariant 6's forward progress\n // for a miswired consumer.\n const interpretMap = ((opts as { interpret?: Interpret<M, C, Ctx> })\n .interpret ?? {}) as Readonly<Record<string, LoopHandler<M> | undefined>>;\n\n // The runner for a Sub type: the one handed to `run` in `subscribe`, else\n // the engine's built-in of that name (#270 — a user entry overrides a\n // built-in). Looked up per start rather than merged once, so a handler table\n // that resolves its cells lazily (`/react` reads the latest render's) is\n // honoured.\n const subscribeTable = (opts as { subscribe?: unknown }).subscribe as\n | Readonly<Record<string, UserRunner<Ctx, M> | undefined>>\n | undefined;\n const builtins = builtinRunners as Readonly<\n Record<string, UserRunner<Ctx, M> | undefined>\n >;\n\n // A Promise runner has no failure channel of its own: the one failure the\n // engine sees is a throw while it starts, which the loop turns into a stopped\n // run (#309). So the runner is called with the three arguments it declares.\n function runnerFor(type: string): LoopRunner<Ctx, M> | undefined {\n const runner = subscribeTable?.[type] ?? builtins[type];\n if (runner === undefined) return undefined;\n return (sub, ctx, dispatch) => runner(sub, ctx, dispatch);\n }\n\n const handle = startLoop<S, M, C, Ctx>({\n init: machine.init,\n reduce: (state, msg) => applyCell<S, M, C>(machine, state, msg),\n subs: subEntriesOf<S>(machine),\n runnerFor,\n handlerFor: (type) => interpretMap[type],\n store: opts.store,\n // `ctx` is conditionally optional (see `CtxArg`); default the nullish case\n // to `{}` so the handler ctx and `init(loaded, ctx)` get a value.\n ctx: (opts.ctx ?? {}) as Ctx,\n onError: opts.onError,\n disposeTimeoutMs: opts.disposeTimeoutMs ?? 5_000,\n idleCap: opts.__idleCap ?? 100_000,\n extensions: builtinExtensions<S, M, C, E>(machine, opts),\n // A Sub failure and a halting reducer throw stop the run the same way\n // (ADR 0033). Deferred: a runner that throws during a storeless boot fails\n // before `startLoop` has returned the handle.\n stopOnFailure: () => {\n queueMicrotask(() => void handle.stop());\n },\n });\n return handle as unknown as BootingRun<S, M, E> & LiveWorkProbe;\n}\n\n/** A runner as a caller hands it to `run` in `subscribe`. */\ntype UserRunner<Ctx, M> = (\n sub: Sub,\n ctx: Ctx,\n dispatch: (msg: M) => void,\n) => Dispose;\n\n/**\n * Is the runtime provably out of ways to transition on its own? True only when\n * the handle carries the `liveWork` read and it counts zero live Subs and zero\n * in-flight Cmds. A handle without the read (a wrapper that rebuilt the object\n * without spreading it) cannot be proven stalled, so the drive keeps waiting —\n * the pre-#68 contract, never a false stall.\n */\nfunction isStalled(runtime: object): boolean {\n const probe = (runtime as Partial<LiveWorkProbe>)[liveWork];\n if (probe === undefined) return false;\n const live = probe();\n return live.subs === 0 && live.cmds === 0;\n}\n\n/**\n * The outside-in stop, as a PAIR. A signal is only cancellation if something can\n * turn \"aborted\" into a transition this machine understands, and the kernel has\n * no built-in cancel Msg any more than it has a built-in terminal set — so the\n * `signal` and the `cancel` that reads it are one option, present together or\n * absent together. A discriminated union rather than two optional fields, on the\n * same reasoning as `AgentCompactionConfig`: a signal with no `cancel` is a stop\n * button wired to nothing, and that is a state worth making unrepresentable\n * rather than checking for.\n */\ntype DriveCancellation<S, M> =\n | {\n readonly signal?: undefined;\n readonly cancel?: undefined;\n }\n | {\n /**\n * Abort the run through this signal. On abort the drive dispatches\n * `cancel`'s Msg and resolves on the State that lands — it does NOT reject,\n * and a cancellation is never a `DriveFailedError`. Already aborted when\n * the drive is called → the cancel Msg goes in place of `start`, so the\n * run ends without the start's effects ever firing.\n */\n readonly signal: AbortSignal;\n /**\n * The Msg that settles this machine as cancelled, chosen off the current\n * State exactly as `start` is. PURE. It must land a State `isTerminal`\n * holds for — the drive resolves on the terminal predicate, not on the\n * abort — and that State should be DURABLE, or a reload resumes the run\n * its caller stopped.\n */\n readonly cancel: (state: S) => M;\n };\n\n/** Options for `driveToDone`. */\nexport type DriveToDoneOptions<\n S,\n M extends { type: string } = never,\n> = DriveCancellation<S, M> & {\n /**\n * Marks a terminal State as a FAILURE. A State this holds for ends the drive\n * like any terminal one — the runtime is stopped — but the drive REJECTS with\n * `DriveFailedError` carrying it instead of resolving. A failed State is\n * terminal by definition; it need not also satisfy `isTerminal`. Omit → the\n * drive never rejects on State, only on a runtime error.\n */\n readonly failed?: (state: S) => boolean;\n};\n\n/**\n * Drive a machine from `start` to its terminal State in one call, then tear the\n * runtime down. The one-shot shape every \"run this machine to done\" test and\n * caller boundary otherwise hand-wires as six steps — `await ready`, `observe`,\n * park a promise, `dispatch(start)`, `getState()`, `stop()` — with the observer\n * leak and the forgotten `stop` those six steps invite.\n *\n * Takes the handle `run()` returns (a `Runtime` extends it, so a booted one is\n * accepted too), awaits `ready`, dispatches `start`, and resolves with the first\n * State for which `isTerminal` holds. A machine that boots already terminal (a\n * rehydrated finished run) resolves on its boot State and `start` is never\n * dispatched — a finished run has nothing to set in motion. `start` may be a\n * function of the boot State instead of a Msg: a machine rehydrated MID-run\n * needs its resume Msg, not its start Msg, and only the boot State says which\n * (the agent's `agent_boot` vs `agent_start` is the case in point). The\n * observer is detached and `stop()` awaited on EVERY exit: resolve, `failed`,\n * a stall, a boot or dispatch throw, the quiescence cap.\n *\n * Use this for a deliberate host `start` Msg after boot. Subs have already\n * opened by then. A machine whose restored first move must precede their Msgs\n * returns its resume Cmds and in-flight State from init instead; do not also\n * use `start` to resume that same work.\n *\n * Rejections are typed, never silent:\n * - `DriveFailedError<S>` when `opts.failed` marks the final State — the State\n * rides on `error.state`.\n * - `DriveStalledError<S>` when `start`'s follow-up chain quiesces on a State\n * that is neither terminal nor `failed` and the runtime has no live Sub and\n * no Cmd in flight — nothing inside it can deliver another transition, so\n * waiting would be a hang with the runtime leaked. The stalled State rides\n * on `error.state`. A machine that CAN still move is not stalled: a live Sub\n * that delivers the terminal Msg after the dispatch\n * quiesces keeps the drive waiting, and it resolves on that State. What the\n * runtime cannot see — a dispatch from outside it after quiescence — does\n * not count as live; a machine that depends on one declares it as a Sub.\n * - `QuiescenceTimeoutError` when `start`'s follow-up chain never settles —\n * the SAME cap `dispatch` and `idle()` already reject on (invariant 6), not a\n * second clock. A livelocking machine surfaces as its own failure class.\n * - the boot error, or whatever `dispatch(start)` rejects with, otherwise.\n *\n * `isTerminal` is caller-supplied, exactly as `run()`'s `terminal` option is —\n * the kernel has no built-in terminal-set concept and this does not add one.\n *\n * Cancellation is the same story: `{ signal, cancel }` stops the drive from\n * outside, and it settles the run rather than escaping it. On abort the drive\n * dispatches `cancel`'s Msg and RESOLVES on the terminal State that transition\n * lands — no rejection, no `DriveFailedError`, no `AbortError`. That is the whole\n * point of routing a stop through the Model: the outcome is durable, so a killed\n * process resumes reading a run that ended instead of restarting one someone\n * stopped. A cancel that THROWS is the one abort that rejects: it lands\n * no State, so its error is what the drive has to report — and that holds\n * whether the `cancel` function throws synchronously or the fold it produced\n * throws later, since both leave the run with no State to settle on. A State the\n * caller's `failed` predicate marks rejects on an abort exit exactly as it does\n * anywhere else. In-flight effects are not recalled — a promise cannot be cancelled —\n * so they settle to their own end and `stop()` drains them, up to\n * `disposeTimeoutMs`;\n * keeping their results off the public channels is the machine's own business.\n * Omit the pair and every path here behaves exactly as it did before.\n *\n * @param handle the handle `run(machine, opts)` returned.\n * @param start the Msg that sets the run in motion, or a function choosing\n * it off the boot State. PURE.\n * @param isTerminal the terminal predicate over the machine's State. PURE.\n * @param opts an optional `failed` predicate and an optional\n * `{ signal, cancel }` pair (see {@link DriveToDoneOptions}).\n */\nexport async function driveToDone<\n S,\n M extends { type: string },\n E extends { type: string } = never,\n>(\n handle: BootingRuntime<S, M, E>,\n start: M | ((booted: S) => M),\n isTerminal: (state: S) => boolean,\n opts: DriveToDoneOptions<S, M> = {},\n): Promise<S> {\n const failed = opts.failed ?? (() => false);\n const settles = (state: S): boolean => isTerminal(state) || failed(state);\n let detach: (() => void) | undefined;\n let unlisten: (() => void) | undefined;\n try {\n const runtime = await handle.ready;\n // A run that rehydrated already terminal has nothing to start: resolve on\n // the boot State without dispatching, so `start`'s Cmds are never left in\n // flight for `stop()` to discard. Read BEFORE the signal so a run that\n // already ended keeps the outcome it ended on — an abort arriving after the\n // fact does not restate a finished run as cancelled.\n const booted = runtime.getState();\n // The one exit check every branch below shares: a State the caller's\n // `failed` predicate marks rejects, wherever the drive reached it.\n const outcome = (state: S): S => {\n if (failed(state)) throw new DriveFailedError(state);\n return state;\n };\n if (settles(booted)) return outcome(booted);\n // Attach BEFORE dispatching so a terminal transition landing inside the\n // start dispatch is caught.\n const terminal = new Promise<S>((resolve) => {\n detach = runtime.observe((_msg, state) => {\n if (settles(state)) resolve(state);\n });\n });\n // An abort mid-run enqueues the cancel Msg on the SAME serial tail every\n // other dispatch uses, so it lands between transitions rather than inside\n // one. Work already enqueued when the abort arrives still folds; work the\n // machine would have enqueued after it does not, because the cancelled State\n // is terminal and its verbs stop emitting. `dispatchOnce` (not `dispatch`)\n // because the cancel has no follow-up chain to drain. Its rejection is NOT\n // swallowed: only the cancel fold can land the terminal State on an abort,\n // so a cancel that throws leaves `terminal` with nothing to resolve it and\n // the drive would park forever (#170). `cancelFailed` carries that rejection\n // into whichever race the branch below awaits.\n let cancelFailed: Promise<never> | undefined;\n if (opts.signal !== undefined) {\n const { signal, cancel } = opts;\n let onCancelError!: (error: unknown) => void;\n cancelFailed = new Promise<never>((_resolve, reject) => {\n onCancelError = reject;\n });\n // The try covers the SYNCHRONOUS call site too, not just the dispatch it\n // returns: a caller-supplied `cancel` that throws before it ever produces\n // a Msg would otherwise escape this listener, and a listener's throw goes\n // nowhere — no caller frame to catch it, `terminal` still unresolved, the\n // drive parked exactly as #170 described (#174). Both throws are the same\n // fact — the cancel fold could not land a State — so both take the one\n // route out through `onCancelError`.\n const onAbort = () => {\n try {\n runtime.dispatchOnce(cancel(runtime.getState())).catch(onCancelError);\n } catch (error) {\n onCancelError(error);\n }\n };\n // Already aborted → cancel INSTEAD of starting, so `start`'s effects (a\n // model call, for the agent) never fire at all.\n if (signal.aborted) {\n onAbort();\n return outcome(await Promise.race([terminal, cancelFailed]));\n }\n signal.addEventListener(\"abort\", onAbort, { once: true });\n unlisten = () => signal.removeEventListener(\"abort\", onAbort);\n }\n // The race lets a dispatch rejection (reducer / interpret throw, the\n // quiescence cap) surface here instead of floating as an unhandled rejection\n // while the terminal await parks forever.\n const msg = typeof start === \"function\" ? start(booted) : start;\n const started = runtime.dispatch(msg).then(() => {\n // Quiesced. A settling State already went through the observer, so\n // `terminal` is resolved; otherwise the wait is legitimate only while the\n // runtime itself can still transition. With no live Sub and no Cmd in\n // flight nothing is coming, and the wait becomes the hang #68 names.\n const parked = runtime.getState();\n if (!settles(parked) && isStalled(runtime)) {\n throw new DriveStalledError(parked);\n }\n return terminal;\n });\n // `cancelFailed` rides the race for the mid-run abort: `started` cannot\n // carry the cancel's rejection, having usually resolved long before the\n // abort arrives.\n const racers: Promise<S>[] = [terminal, started];\n if (cancelFailed !== undefined) racers.push(cancelFailed);\n return outcome(await Promise.race(racers));\n } finally {\n detach?.();\n // The abort listener outlives this call unless it is removed: a signal a\n // caller reuses across runs would otherwise accumulate one dispatch per run\n // it has already finished.\n unlisten?.();\n // `stop()` resolves by contract, so awaiting it here cannot mask the error\n // a rejecting branch above is carrying. It can delay it, by up to\n // `disposeTimeoutMs` per wait, while a Cmd handler has not returned.\n await handle.stop();\n }\n}\n","import type { TellAnswer } from \"../internal/engine/loop\";\nimport { tellRun } from \"../internal/engine/tell\";\nimport type { Cmd, Machine, Sub } from \"../pure/core\";\nimport type { Run } from \"./run\";\n\nexport type { TellAnswer } from \"../internal/engine/loop\";\n\n/**\n * Put `msg` on a run's line and return at once. The answer means queued, not\n * handled: the receiver's step has not run yet, and any result comes back later\n * as its own Msg. So two machines can tell each other from their Cmd handlers\n * and neither stops. `machine` is the machine `runtime` runs.\n *\n * The answer is `\"queued\"`, `\"stopped\"` for a run that is stopping or has\n * stopped, or `\"no_cell\"` when its current State has no cell for the Msg. Msgs\n * already in line have not folded yet, so a Msg that only a queued one makes\n * acceptable answers `\"no_cell\"`.\n *\n * `runtime` is what `ready` resolved to, or a spread of it. Those carry the run's\n * line, and the type asks for it, so a `Runtime` built by hand, a fake or\n * `noopRuntime` is a compile error. So is the handle `run` returned, with a store\n * or without one: wait for `ready`. A hand-built object cast past the type has no\n * line to put a Msg on, and `tell` throws there.\n *\n * What happens after `\"queued\"` is the receiver's. Two `tell`s from one sender\n * fold in the order they were sent. A failed save or a handler's throw goes to\n * the receiver's `onError`, never back to the sender. A Msg whose cell is gone\n * by its turn is dropped without a word, and a `stop()` that gives up drops\n * what is still in line and counts it, per Msg type, in its\n * `DrainTimeoutNotice`.\n *\n * Two hand-written `await runtime.dispatch(...)` calls into each other, one from\n * each machine's Cmd handler, still stop both machines: `dispatch` waits, and\n * tea has no lock-up detector. Use `tell` there.\n *\n * ```ts\n * const answer = tell(parent, parentRun, { type: \"child_result\", id });\n * ```\n */\nexport function tell<\n S,\n M extends { type: string },\n C extends Cmd,\n U extends Sub,\n Ctx,\n E extends { type: string } = never,\n>(\n machine: Machine<S, M, C, U, Ctx>,\n runtime: Run<S, M, E>,\n msg: NoInfer<M>,\n): TellAnswer {\n return tellRun<S, M>(machine, runtime, msg);\n}\n"]}
@@ -530,6 +530,15 @@ var PortNameCollisionError = class extends Error {
530
530
  function __resetPortRegistry() {
531
531
  definedPortNames.clear();
532
532
  }
533
+ var SubFailedError = class extends Error {
534
+ constructor(cause) {
535
+ super("@demlik/tea: a Sub failed and stopped the run.");
536
+ this.cause = cause;
537
+ }
538
+ cause;
539
+ name = "SubFailedError";
540
+ _tag = "SubFailedError";
541
+ };
533
542
  var QuiescenceTimeoutError = class extends Error {
534
543
  constructor(iterations) {
535
544
  super(
@@ -600,10 +609,28 @@ var DisposeTimeoutNotice = class extends RuntimeDiscardNotice {
600
609
  name = "DisposeTimeoutNotice";
601
610
  _tag = "DisposeTimeoutNotice";
602
611
  };
612
+ var DrainTimeoutNotice = class extends RuntimeDiscardNotice {
613
+ constructor(cmdTypes, pendingCmds, timeoutMs, droppedMsgs = {}) {
614
+ const dropped = Object.entries(droppedMsgs);
615
+ super(
616
+ `@demlik/tea: stop() gave up waiting for the queue after ${timeoutMs}ms with ${pendingCmds} Cmd(s) still in flight` + (cmdTypes.length > 0 ? ` (${cmdTypes.map((type) => `"${type}"`).join(", ")})` : "") + (dropped.length > 0 ? ` and these Msgs queued: ${dropped.map(([type, count]) => `"${type}" x${count}`).join(", ")}` : "") + ` \u2014 whatever they return, the rest of their step and the Msgs queued behind them are dropped. No store call starts after stop() has returned; one already under way can still land. Bound the handler's own IO so it returns, or raise run({ disposeTimeoutMs }).`
617
+ );
618
+ this.cmdTypes = cmdTypes;
619
+ this.pendingCmds = pendingCmds;
620
+ this.timeoutMs = timeoutMs;
621
+ this.droppedMsgs = droppedMsgs;
622
+ }
623
+ cmdTypes;
624
+ pendingCmds;
625
+ timeoutMs;
626
+ droppedMsgs;
627
+ name = "DrainTimeoutNotice";
628
+ _tag = "DrainTimeoutNotice";
629
+ };
603
630
  var DispatchDiscardedError = class extends RuntimeDiscardNotice {
604
631
  constructor(msgType) {
605
632
  super(
606
- `@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.`
633
+ `@demlik/tea: Msg "${msgType}" was discarded by stop() \u2014 it arrived while the runtime was stopping, or was still waiting behind a Cmd handler stop() gave up on. stop() refuses new work so the drain terminates. If 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.`
607
634
  );
608
635
  this.msgType = msgType;
609
636
  }
@@ -693,11 +720,6 @@ function asReducer(reducer) {
693
720
  function replay(machine, opts) {
694
721
  const loaded = opts.loaded ?? null;
695
722
  const [initialState, initCmds] = machine.init(loaded, opts.ctx);
696
- if (loaded !== null && initCmds.length > 0) {
697
- throw new Error(
698
- "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)."
699
- );
700
- }
701
723
  const { state, cmds: foldedCmds } = foldUpdates(
702
724
  machine,
703
725
  initialState,
@@ -757,6 +779,6 @@ function tryInterpret(work, onOk, onErr) {
757
779
  };
758
780
  }
759
781
 
760
- export { AsyncSchemaError, Cmd, DispatchDiscardedError, DisposeTimeoutNotice, DriveFailedError, DriveStalledError, IdentityDropNotice, NoCellError, Outcome, OutcomeContractError, PortNameCollisionError, QuiescenceTimeoutError, Refusal, RuntimeDiscardNotice, RuntimeDiscardedError, StoreConflictError, StoreRefusedError, UndeclaredFailureError, __resetPortRegistry, absurd, acceptedTypes, acceptsOf, applyCell, applyCellChecked, asReducer, checkedStep, cmdContractOver, cmdEdge, cmdEdgeOf, defineMachine, definePort, describeError, describeMachine, desiredSub, detachWork, detachWorkOf, detectUpdateForm, foldMsgs, foldUpdates, followUps, formOf, isFencedStore, lookupCell, malformedResult, msgKeysOf, noop, refuse, replay, schemaMigrate, structuralHash, subEntriesOf, subId, subIdOf, tryApplyCell, tryFoldMsgs, tryInterpret, validateSync, without, wrapDetached };
761
- //# sourceMappingURL=chunk-RKVUVALV.js.map
762
- //# sourceMappingURL=chunk-RKVUVALV.js.map
782
+ export { AsyncSchemaError, Cmd, DispatchDiscardedError, DisposeTimeoutNotice, DrainTimeoutNotice, DriveFailedError, DriveStalledError, IdentityDropNotice, NoCellError, Outcome, OutcomeContractError, PortNameCollisionError, QuiescenceTimeoutError, Refusal, RuntimeDiscardNotice, RuntimeDiscardedError, StoreConflictError, StoreRefusedError, SubFailedError, UndeclaredFailureError, __resetPortRegistry, absurd, acceptedTypes, acceptsOf, applyCell, applyCellChecked, asReducer, checkedStep, cmdContractOver, cmdEdge, cmdEdgeOf, defineMachine, definePort, describeError, describeMachine, desiredSub, detachWork, detachWorkOf, detectUpdateForm, foldMsgs, foldUpdates, followUps, formOf, isFencedStore, lookupCell, malformedResult, msgKeysOf, noop, refuse, replay, schemaMigrate, structuralHash, subEntriesOf, subId, subIdOf, tryApplyCell, tryFoldMsgs, tryInterpret, validateSync, without, wrapDetached };
783
+ //# sourceMappingURL=chunk-A3QPMX5M.js.map
784
+ //# sourceMappingURL=chunk-A3QPMX5M.js.map