@demlik/tea 0.13.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (373) hide show
  1. package/README.md +11 -9
  2. package/dist/agent/index.d.ts +638 -45
  3. package/dist/agent/index.js +9 -19
  4. package/dist/{chunk-RH5EFRVJ.js → chunk-22POWGFA.js} +31 -5
  5. package/dist/chunk-22POWGFA.js.map +1 -0
  6. package/dist/{chunk-DMYGQB4O.js → chunk-3B5X7SBB.js} +23 -6
  7. package/dist/chunk-3B5X7SBB.js.map +1 -0
  8. package/dist/chunk-66PY5WYF.js +1816 -0
  9. package/dist/chunk-66PY5WYF.js.map +1 -0
  10. package/dist/{chunk-25LBDCBC.js → chunk-6IQPODUF.js} +2 -2
  11. package/dist/{chunk-25LBDCBC.js.map → chunk-6IQPODUF.js.map} +1 -1
  12. package/dist/chunk-AYS5N6WY.js +505 -0
  13. package/dist/chunk-AYS5N6WY.js.map +1 -0
  14. package/dist/{chunk-EWJP3YYP.js → chunk-HWVW4AXC.js} +3 -3
  15. package/dist/chunk-HWVW4AXC.js.map +1 -0
  16. package/dist/{chunk-O4MVQTEJ.js → chunk-L3TND7LA.js} +20 -16
  17. package/dist/chunk-L3TND7LA.js.map +1 -0
  18. package/dist/{chunk-J6527VRQ.js → chunk-LFZUK6J2.js} +3 -3
  19. package/dist/chunk-LFZUK6J2.js.map +1 -0
  20. package/dist/{chunk-D736QUGF.js → chunk-MYXFNWAJ.js} +4 -5
  21. package/dist/chunk-MYXFNWAJ.js.map +1 -0
  22. package/dist/{chunk-K575PT4S.js → chunk-PR6TB3BL.js} +15 -4
  23. package/dist/chunk-PR6TB3BL.js.map +1 -0
  24. package/dist/{chunk-YUXP55T2.js → chunk-Q5CQTBFA.js} +57 -7
  25. package/dist/chunk-Q5CQTBFA.js.map +1 -0
  26. package/dist/{batch-window/index.js → chunk-QPEVCJ5Q.js} +4 -8
  27. package/dist/chunk-QPEVCJ5Q.js.map +1 -0
  28. package/dist/chunk-TCLBCERH.js +1480 -0
  29. package/dist/chunk-TCLBCERH.js.map +1 -0
  30. package/dist/{chunk-FV3Z5MBE.js → chunk-TXN2KFHF.js} +14 -4
  31. package/dist/chunk-TXN2KFHF.js.map +1 -0
  32. package/dist/{chunk-MUUROGIH.js → chunk-V46HSVCK.js} +62 -12
  33. package/dist/chunk-V46HSVCK.js.map +1 -0
  34. package/dist/{chunk-Q2UM7BXU.js → chunk-VBDU4JL6.js} +2 -2
  35. package/dist/chunk-VBDU4JL6.js.map +1 -0
  36. package/dist/{chunk-ZVJZ72HY.js → chunk-VTQI2NHP.js} +25 -11
  37. package/dist/chunk-VTQI2NHP.js.map +1 -0
  38. package/dist/{core-Co0LWkIA.d.ts → core-DnzqWy6u.d.ts} +72 -23
  39. package/dist/devtools/index.d.ts +2 -2
  40. package/dist/devtools/index.js +207 -2
  41. package/dist/devtools/index.js.map +1 -1
  42. package/dist/do/index.d.ts +43 -29
  43. package/dist/do/index.js +36 -25
  44. package/dist/do/index.js.map +1 -1
  45. package/dist/{durable-effects-C6uwzjb5.d.ts → durable-effects-CWzA-o2B.d.ts} +2 -2
  46. package/dist/extension/index.d.ts +300 -3
  47. package/dist/extension/index.js +596 -5
  48. package/dist/extension/index.js.map +1 -1
  49. package/dist/flow/index.d.ts +1284 -0
  50. package/dist/flow/index.js +732 -0
  51. package/dist/flow/index.js.map +1 -0
  52. package/dist/idempotency/index.d.ts +90 -116
  53. package/dist/idempotency/index.js +4 -1
  54. package/dist/index-Bc40JWVl.d.ts +131 -0
  55. package/dist/{batch-window/index.d.ts → index-C2DwkjlP.d.ts} +7 -12
  56. package/dist/index-CA_7I5g9.d.ts +806 -0
  57. package/dist/index-CSyMYDAB.d.ts +69 -0
  58. package/dist/{fan-out/index.d.ts → index-CuNO9m8i.d.ts} +7 -9
  59. package/dist/{debounce/index.d.ts → index-DHSUmQTR.d.ts} +7 -7
  60. package/dist/{recorder/index.d.ts → index-DrIRb_Ch.d.ts} +4 -7
  61. package/dist/index-HSYgG2Yt.d.ts +380 -0
  62. package/dist/{monitored-run/index.d.ts → index-KXqTRJyb.d.ts} +37 -13
  63. package/dist/{snapshot/index.d.ts → index-ZCMhnVKN.d.ts} +15 -78
  64. package/dist/index.d.ts +771 -6
  65. package/dist/index.js +1 -2
  66. package/dist/jev/index.d.ts +646 -0
  67. package/dist/jev/index.js +485 -0
  68. package/dist/jev/index.js.map +1 -0
  69. package/dist/machine-DGlPWCWI.d.ts +1781 -0
  70. package/dist/machine-viz/index.d.ts +1 -1
  71. package/dist/machine-viz/index.js +12 -5
  72. package/dist/machine-viz/index.js.map +1 -1
  73. package/dist/mem/index.d.ts +18 -3
  74. package/dist/mem/index.js +22 -2
  75. package/dist/mem/index.js.map +1 -1
  76. package/dist/node/index.d.ts +104 -6
  77. package/dist/node/index.js +132 -9
  78. package/dist/node/index.js.map +1 -1
  79. package/dist/{paginator → paginate}/index.d.ts +140 -6
  80. package/dist/paginate/index.js +7 -0
  81. package/dist/parity/index.d.ts +4 -10
  82. package/dist/parity/index.js +4 -7
  83. package/dist/parity/index.js.map +1 -1
  84. package/dist/pbt/index.d.ts +247 -5
  85. package/dist/pbt/index.js +124 -5
  86. package/dist/pbt/index.js.map +1 -1
  87. package/dist/{trace-replay → persistence}/index.d.ts +7 -5
  88. package/dist/persistence/index.js +6 -0
  89. package/dist/{protocol-B5YmJr0d.d.ts → protocol-D8VbH-VH.d.ts} +10 -1
  90. package/dist/react/index.d.ts +2 -2
  91. package/dist/react/index.js +1 -2
  92. package/dist/react/index.js.map +1 -1
  93. package/dist/resilience/index.d.ts +744 -0
  94. package/dist/resilience/index.js +657 -0
  95. package/dist/resilience/index.js.map +1 -0
  96. package/dist/retry-backoff/index.d.ts +3 -2
  97. package/dist/retry-backoff/index.js +1 -1
  98. package/dist/runtime-types-CMF13BBh.d.ts +998 -0
  99. package/dist/testing/index.d.ts +147 -3
  100. package/dist/testing/index.js +95 -3
  101. package/dist/testing/index.js.map +1 -1
  102. package/dist/{throttled-input → timing}/index.d.ts +143 -12
  103. package/dist/{throttled-input → timing}/index.js +57 -12
  104. package/dist/timing/index.js.map +1 -0
  105. package/dist/{types-XS_miRnB.d.ts → types-BseNPIhr.d.ts} +1 -1
  106. package/dist/work-queue/index.d.ts +130 -54
  107. package/dist/work-queue/index.js +3 -2
  108. package/dist/work-queue/index.js.map +1 -1
  109. package/package.json +45 -218
  110. package/dist/authed-call/index.d.ts +0 -120
  111. package/dist/authed-call/index.js +0 -134
  112. package/dist/authed-call/index.js.map +0 -1
  113. package/dist/await-terminal/index.d.ts +0 -101
  114. package/dist/await-terminal/index.js +0 -76
  115. package/dist/await-terminal/index.js.map +0 -1
  116. package/dist/batch-window/index.js.map +0 -1
  117. package/dist/cache/index.d.ts +0 -152
  118. package/dist/cache/index.js +0 -8
  119. package/dist/chart/index.d.ts +0 -218
  120. package/dist/chart/index.js +0 -16
  121. package/dist/chart/index.js.map +0 -1
  122. package/dist/chart/inspect/index.d.ts +0 -86
  123. package/dist/chart/inspect/index.js +0 -5
  124. package/dist/chart/inspect/react.d.ts +0 -113
  125. package/dist/chart/inspect/react.js +0 -11
  126. package/dist/chart/inspect/react.js.map +0 -1
  127. package/dist/chart/inspect/styles.css +0 -286
  128. package/dist/chart/lane/index.d.ts +0 -362
  129. package/dist/chart/lane/index.js +0 -9
  130. package/dist/chart/lane/index.js.map +0 -1
  131. package/dist/chart/lane/react.d.ts +0 -84
  132. package/dist/chart/lane/react.js +0 -559
  133. package/dist/chart/lane/react.js.map +0 -1
  134. package/dist/chart/lane/server.d.ts +0 -148
  135. package/dist/chart/lane/server.js +0 -209
  136. package/dist/chart/lane/server.js.map +0 -1
  137. package/dist/chart/lane/styles.css +0 -498
  138. package/dist/chart/lane/viewer/assets/abnfDiagram-N423BO3Z-C729LI31.js +0 -1
  139. package/dist/chart/lane/viewer/assets/architectureDiagram-T3A2C74G-C729LI31.js +0 -1
  140. package/dist/chart/lane/viewer/assets/blockDiagram-VBNYF7ZC-C729LI31.js +0 -1
  141. package/dist/chart/lane/viewer/assets/c4Diagram-5PPSVZJV-C729LI31.js +0 -1
  142. package/dist/chart/lane/viewer/assets/chunk-2GRJ4B5K-HdDf8SI3.js +0 -1
  143. package/dist/chart/lane/viewer/assets/chunk-5RXB4S5H-CcNtpUd7.js +0 -231
  144. package/dist/chart/lane/viewer/assets/chunk-5VM5RSS4-BP4fRS_5.js +0 -15
  145. package/dist/chart/lane/viewer/assets/chunk-KBJHAD2P-DZOw7xU6.js +0 -1
  146. package/dist/chart/lane/viewer/assets/chunk-NSK5VX7P-CBCyTZMs.js +0 -128
  147. package/dist/chart/lane/viewer/assets/classDiagram-JCYQIIEL-C729LI31.js +0 -1
  148. package/dist/chart/lane/viewer/assets/classDiagram-v2-OCEON4UE-D4uAiFr8.js +0 -206
  149. package/dist/chart/lane/viewer/assets/cose-bilkent-JH36ORCC-DOwCrGXH.js +0 -1
  150. package/dist/chart/lane/viewer/assets/cynefinDiagram-MW4NZA55-C729LI31.js +0 -1
  151. package/dist/chart/lane/viewer/assets/dagre-K_PewWfS.js +0 -1
  152. package/dist/chart/lane/viewer/assets/dagre-VZM6K2ZE-831qZcA8.js +0 -4
  153. package/dist/chart/lane/viewer/assets/diagram-7IWD3JNH-C729LI31.js +0 -1
  154. package/dist/chart/lane/viewer/assets/diagram-B4RE2ZJO-C729LI31.js +0 -1
  155. package/dist/chart/lane/viewer/assets/diagram-LBJQPF4R-C729LI31.js +0 -1
  156. package/dist/chart/lane/viewer/assets/diagram-Q27KOJAE-C729LI31.js +0 -1
  157. package/dist/chart/lane/viewer/assets/diagram-UB23O5K3-C729LI31.js +0 -1
  158. package/dist/chart/lane/viewer/assets/ebnfDiagram-BXEA7PRR-C729LI31.js +0 -1
  159. package/dist/chart/lane/viewer/assets/erDiagram-JOGREHBK-C729LI31.js +0 -1
  160. package/dist/chart/lane/viewer/assets/flowDiagram-UKHOOZJN-C729LI31.js +0 -1
  161. package/dist/chart/lane/viewer/assets/ganttDiagram-PKOTCBZU-C729LI31.js +0 -1
  162. package/dist/chart/lane/viewer/assets/gitGraphDiagram-DS77QQ5N-C729LI31.js +0 -1
  163. package/dist/chart/lane/viewer/assets/index-9SkH5NA3.css +0 -1
  164. package/dist/chart/lane/viewer/assets/index-Bgt4sXpW.js +0 -195
  165. package/dist/chart/lane/viewer/assets/infoDiagram-6WML65LV-C729LI31.js +0 -1
  166. package/dist/chart/lane/viewer/assets/ishikawaDiagram-WSZJBQD7-C729LI31.js +0 -1
  167. package/dist/chart/lane/viewer/assets/journeyDiagram-NVQOT4AX-C729LI31.js +0 -1
  168. package/dist/chart/lane/viewer/assets/kanban-definition-27J2QSJJ-G7PaPzy-.js +0 -89
  169. package/dist/chart/lane/viewer/assets/katex-DOwCrGXH.js +0 -1
  170. package/dist/chart/lane/viewer/assets/mindmap-definition-FAOFIHXS-CGj9nrVk.js +0 -96
  171. package/dist/chart/lane/viewer/assets/path-fybaL0A-.js +0 -1
  172. package/dist/chart/lane/viewer/assets/pegDiagram-VL7TDLO6-C729LI31.js +0 -1
  173. package/dist/chart/lane/viewer/assets/pieDiagram-7S7Q4E2Y-C729LI31.js +0 -1
  174. package/dist/chart/lane/viewer/assets/quadrantDiagram-CIZ2JOQS-C729LI31.js +0 -1
  175. package/dist/chart/lane/viewer/assets/railroadDiagram-AXF67PYL-C729LI31.js +0 -1
  176. package/dist/chart/lane/viewer/assets/requirementDiagram-LRYGKXZP-C729LI31.js +0 -1
  177. package/dist/chart/lane/viewer/assets/sankeyDiagram-W5VNT64P-C729LI31.js +0 -1
  178. package/dist/chart/lane/viewer/assets/sequenceDiagram-SI44F4Z6-C729LI31.js +0 -1
  179. package/dist/chart/lane/viewer/assets/stateDiagram-OKZ733FA-B_88AzBS.js +0 -1
  180. package/dist/chart/lane/viewer/assets/stateDiagram-v2-UEYNNEHI-CR5gcgq6.js +0 -1
  181. package/dist/chart/lane/viewer/assets/swimlanes-SLNWSIFB-B4xK-rwg.js +0 -1
  182. package/dist/chart/lane/viewer/assets/swimlanesDiagram-ULZ7WXOC-C729LI31.js +0 -1
  183. package/dist/chart/lane/viewer/assets/timeline-definition-Z64GVDOM-CCv52MfY.js +0 -120
  184. package/dist/chart/lane/viewer/assets/vennDiagram-T6HMQDX7-C729LI31.js +0 -1
  185. package/dist/chart/lane/viewer/assets/wardleyDiagram-T6FBY63Y-C729LI31.js +0 -1
  186. package/dist/chart/lane/viewer/assets/xychartDiagram-ELKLHX3M-C729LI31.js +0 -1
  187. package/dist/chart/lane/viewer/index.html +0 -15
  188. package/dist/chart/report/index.d.ts +0 -117
  189. package/dist/chart/report/index.js +0 -32
  190. package/dist/chart/report/index.js.map +0 -1
  191. package/dist/chunk-2YFLOCWX.js +0 -15
  192. package/dist/chunk-2YFLOCWX.js.map +0 -1
  193. package/dist/chunk-3I52QZZ5.js +0 -519
  194. package/dist/chunk-3I52QZZ5.js.map +0 -1
  195. package/dist/chunk-3ZAFFRRB.js +0 -457
  196. package/dist/chunk-3ZAFFRRB.js.map +0 -1
  197. package/dist/chunk-4EQZ76JC.js +0 -33
  198. package/dist/chunk-4EQZ76JC.js.map +0 -1
  199. package/dist/chunk-4KLG43GY.js +0 -223
  200. package/dist/chunk-4KLG43GY.js.map +0 -1
  201. package/dist/chunk-7FRZ2CT2.js +0 -424
  202. package/dist/chunk-7FRZ2CT2.js.map +0 -1
  203. package/dist/chunk-AZZLE7XR.js +0 -62
  204. package/dist/chunk-AZZLE7XR.js.map +0 -1
  205. package/dist/chunk-BYQUGDD3.js +0 -16
  206. package/dist/chunk-BYQUGDD3.js.map +0 -1
  207. package/dist/chunk-CIQG5L42.js +0 -685
  208. package/dist/chunk-CIQG5L42.js.map +0 -1
  209. package/dist/chunk-CLM6ERNO.js +0 -61
  210. package/dist/chunk-CLM6ERNO.js.map +0 -1
  211. package/dist/chunk-COS5MSTO.js +0 -88
  212. package/dist/chunk-COS5MSTO.js.map +0 -1
  213. package/dist/chunk-CRPZJVD2.js +0 -71
  214. package/dist/chunk-CRPZJVD2.js.map +0 -1
  215. package/dist/chunk-D62FDQKE.js +0 -53
  216. package/dist/chunk-D62FDQKE.js.map +0 -1
  217. package/dist/chunk-D736QUGF.js.map +0 -1
  218. package/dist/chunk-DGE4PV4A.js +0 -26
  219. package/dist/chunk-DGE4PV4A.js.map +0 -1
  220. package/dist/chunk-DMYGQB4O.js.map +0 -1
  221. package/dist/chunk-EWJP3YYP.js.map +0 -1
  222. package/dist/chunk-FV3Z5MBE.js.map +0 -1
  223. package/dist/chunk-HCEVHFJ7.js +0 -54
  224. package/dist/chunk-HCEVHFJ7.js.map +0 -1
  225. package/dist/chunk-J6527VRQ.js.map +0 -1
  226. package/dist/chunk-JELSZN25.js +0 -47
  227. package/dist/chunk-JELSZN25.js.map +0 -1
  228. package/dist/chunk-K575PT4S.js.map +0 -1
  229. package/dist/chunk-L57ZOT5K.js +0 -184
  230. package/dist/chunk-L57ZOT5K.js.map +0 -1
  231. package/dist/chunk-MU6MCIAC.js +0 -15
  232. package/dist/chunk-MU6MCIAC.js.map +0 -1
  233. package/dist/chunk-MUUROGIH.js.map +0 -1
  234. package/dist/chunk-NR7BU22N.js +0 -758
  235. package/dist/chunk-NR7BU22N.js.map +0 -1
  236. package/dist/chunk-O4MVQTEJ.js.map +0 -1
  237. package/dist/chunk-OOYD44JI.js +0 -317
  238. package/dist/chunk-OOYD44JI.js.map +0 -1
  239. package/dist/chunk-Q2UM7BXU.js.map +0 -1
  240. package/dist/chunk-RH5EFRVJ.js.map +0 -1
  241. package/dist/chunk-S2EGRPCM.js +0 -47
  242. package/dist/chunk-S2EGRPCM.js.map +0 -1
  243. package/dist/chunk-SINXE47Y.js +0 -55
  244. package/dist/chunk-SINXE47Y.js.map +0 -1
  245. package/dist/chunk-UF4MZSLT.js +0 -53
  246. package/dist/chunk-UF4MZSLT.js.map +0 -1
  247. package/dist/chunk-UOC2PL46.js +0 -13
  248. package/dist/chunk-UOC2PL46.js.map +0 -1
  249. package/dist/chunk-VYFAZN3F.js +0 -372
  250. package/dist/chunk-VYFAZN3F.js.map +0 -1
  251. package/dist/chunk-WRAA7GVZ.js +0 -209
  252. package/dist/chunk-WRAA7GVZ.js.map +0 -1
  253. package/dist/chunk-XGELA764.js +0 -163
  254. package/dist/chunk-XGELA764.js.map +0 -1
  255. package/dist/chunk-YUXP55T2.js.map +0 -1
  256. package/dist/chunk-YWIKDKHY.js +0 -307
  257. package/dist/chunk-YWIKDKHY.js.map +0 -1
  258. package/dist/chunk-ZJ5AOYBH.js +0 -8
  259. package/dist/chunk-ZJ5AOYBH.js.map +0 -1
  260. package/dist/chunk-ZSUUOEPL.js +0 -731
  261. package/dist/chunk-ZSUUOEPL.js.map +0 -1
  262. package/dist/chunk-ZVJZ72HY.js.map +0 -1
  263. package/dist/circuit-breaker/index.d.ts +0 -197
  264. package/dist/circuit-breaker/index.js +0 -3
  265. package/dist/circuit-breaker/index.js.map +0 -1
  266. package/dist/deadline/index.d.ts +0 -199
  267. package/dist/deadline/index.js +0 -6
  268. package/dist/deadline/index.js.map +0 -1
  269. package/dist/debounce/index.js +0 -3
  270. package/dist/debounce/index.js.map +0 -1
  271. package/dist/extension/react.d.ts +0 -121
  272. package/dist/extension/react.js +0 -75
  273. package/dist/extension/react.js.map +0 -1
  274. package/dist/extension/subs/index.d.ts +0 -45
  275. package/dist/extension/subs/index.js +0 -80
  276. package/dist/extension/subs/index.js.map +0 -1
  277. package/dist/extension/test-utils.d.ts +0 -128
  278. package/dist/extension/test-utils.js +0 -277
  279. package/dist/extension/test-utils.js.map +0 -1
  280. package/dist/fan-out/index.js +0 -5
  281. package/dist/fan-out/index.js.map +0 -1
  282. package/dist/fold-BJPdjc9w.d.ts +0 -435
  283. package/dist/graph-B3L5e0N1.d.ts +0 -923
  284. package/dist/idempotency/adapter.d.ts +0 -62
  285. package/dist/idempotency/adapter.js +0 -4
  286. package/dist/idempotency/adapter.js.map +0 -1
  287. package/dist/idempotent-intake/index.d.ts +0 -188
  288. package/dist/idempotent-intake/index.js +0 -7
  289. package/dist/idempotent-intake/index.js.map +0 -1
  290. package/dist/journal/index.d.ts +0 -373
  291. package/dist/journal/index.js +0 -3
  292. package/dist/journal/index.js.map +0 -1
  293. package/dist/llm-call/index.d.ts +0 -311
  294. package/dist/llm-call/index.js +0 -16
  295. package/dist/llm-call/index.js.map +0 -1
  296. package/dist/machine-BtFWQmmq.d.ts +0 -804
  297. package/dist/monitored-run/index.js +0 -10
  298. package/dist/monitored-run/index.js.map +0 -1
  299. package/dist/paginated-walk/index.d.ts +0 -235
  300. package/dist/paginated-walk/index.js +0 -16
  301. package/dist/paginated-walk/index.js.map +0 -1
  302. package/dist/paginator/index.js +0 -3
  303. package/dist/paginator/index.js.map +0 -1
  304. package/dist/pbt/arbitraries/index.d.ts +0 -136
  305. package/dist/pbt/arbitraries/index.js +0 -3
  306. package/dist/pbt/arbitraries/index.js.map +0 -1
  307. package/dist/pbt/runners/index.d.ts +0 -118
  308. package/dist/pbt/runners/index.js +0 -5
  309. package/dist/pbt/runners/index.js.map +0 -1
  310. package/dist/poller/index.d.ts +0 -352
  311. package/dist/poller/index.js +0 -115
  312. package/dist/poller/index.js.map +0 -1
  313. package/dist/prediction/index.d.ts +0 -131
  314. package/dist/prediction/index.js +0 -4
  315. package/dist/prediction/index.js.map +0 -1
  316. package/dist/pure/index.d.ts +0 -3
  317. package/dist/pure/index.js +0 -4
  318. package/dist/pure/index.js.map +0 -1
  319. package/dist/rate-limit/index.d.ts +0 -115
  320. package/dist/rate-limit/index.js +0 -3
  321. package/dist/rate-limit/index.js.map +0 -1
  322. package/dist/reconciler/index.d.ts +0 -193
  323. package/dist/reconciler/index.js +0 -164
  324. package/dist/reconciler/index.js.map +0 -1
  325. package/dist/recorder/index.js +0 -3
  326. package/dist/recorder/index.js.map +0 -1
  327. package/dist/reducer-4GNR6b8B.d.ts +0 -447
  328. package/dist/resilient-call/index.d.ts +0 -320
  329. package/dist/resilient-call/index.js +0 -14
  330. package/dist/resilient-call/index.js.map +0 -1
  331. package/dist/retry-to-success/index.d.ts +0 -109
  332. package/dist/retry-to-success/index.js +0 -37
  333. package/dist/retry-to-success/index.js.map +0 -1
  334. package/dist/run-pAcmBpah.d.ts +0 -713
  335. package/dist/runtime-types-CNLmhWif.d.ts +0 -517
  336. package/dist/saga/index.d.ts +0 -241
  337. package/dist/saga/index.js +0 -150
  338. package/dist/saga/index.js.map +0 -1
  339. package/dist/samples-B3My5oh2.d.ts +0 -59
  340. package/dist/snapshot/index.js +0 -5
  341. package/dist/snapshot/index.js.map +0 -1
  342. package/dist/subs/index.d.ts +0 -472
  343. package/dist/subs/index.js +0 -7
  344. package/dist/subs/index.js.map +0 -1
  345. package/dist/throttle/index.d.ts +0 -134
  346. package/dist/throttle/index.js +0 -3
  347. package/dist/throttle/index.js.map +0 -1
  348. package/dist/throttled-input/index.js.map +0 -1
  349. package/dist/token-refresh/index.d.ts +0 -216
  350. package/dist/token-refresh/index.js +0 -6
  351. package/dist/token-refresh/index.js.map +0 -1
  352. package/dist/trace-replay/index.js +0 -6
  353. package/dist/trace-replay/index.js.map +0 -1
  354. package/dist/with-deadline/index.d.ts +0 -197
  355. package/dist/with-deadline/index.js +0 -111
  356. package/dist/with-deadline/index.js.map +0 -1
  357. package/dist/with-resilience/index.d.ts +0 -225
  358. package/dist/with-resilience/index.js +0 -240
  359. package/dist/with-resilience/index.js.map +0 -1
  360. package/dist/with-telemetry/index.d.ts +0 -150
  361. package/dist/with-telemetry/index.js +0 -70
  362. package/dist/with-telemetry/index.js.map +0 -1
  363. package/dist/work-queue/adapter.d.ts +0 -84
  364. package/dist/work-queue/adapter.js +0 -4
  365. package/dist/work-queue/adapter.js.map +0 -1
  366. package/dist/work-queue/ops.d.ts +0 -71
  367. package/dist/work-queue/ops.js +0 -3
  368. package/dist/work-queue/ops.js.map +0 -1
  369. package/dist/workflow/index.d.ts +0 -485
  370. package/dist/workflow/index.js +0 -244
  371. package/dist/workflow/index.js.map +0 -1
  372. /package/dist/{cache → paginate}/index.js.map +0 -0
  373. /package/dist/{chart/inspect → persistence}/index.js.map +0 -0
@@ -1,14 +1,145 @@
1
- import { TtlCache } from '../cache/index.js';
2
- import { DeadlineSub } from '../deadline/index.js';
3
- export { DeadlineExceeded as ThrottledInputSettled, subscribeDeadline as subscribeThrottledInput, deadlineExceeded as throttledInputSettled } from '../deadline/index.js';
4
- import { C as Cmd, S as Sub } from '../core-Co0LWkIA.js';
5
- export { Debounced, debounce } from '../debounce/index.js';
6
- export { Throttled, throttle } from '../throttle/index.js';
7
- import '../types-XS_miRnB.js';
1
+ export { D as Debounced, d as debounce } from '../index-DHSUmQTR.js';
2
+ import { C as Cmd, S as Sub } from '../core-DnzqWy6u.js';
3
+ import { T as TtlCache, a as DeadlineSub } from '../index-HSYgG2Yt.js';
4
+ export { D as ThrottledInputSettled, s as subscribeThrottledInput, d as throttledInputSettled } from '../index-HSYgG2Yt.js';
8
5
  import 'zod';
6
+ import '../types-BseNPIhr.js';
9
7
 
10
8
  /**
11
- * @demlik/tea/throttled-input — gate a high-frequency input stream into a
9
+ * internal/timing/throttle — a timer-based call transformer that caps invocation
10
+ * to at most once per `ms` window.
11
+ *
12
+ * Sibling of `../debounce` — the two share a SYMMETRIC surface
13
+ * (`Throttled<A>` / `Debounced<A>`, both callable + `.cancel()` + `.flush()`,
14
+ * both `{ leading?, trailing? }`) so they read as a pair. They are kept in
15
+ * separate files with NO cross-import: each is a self-contained timer, and the
16
+ * coalesce-vs-drop policies differ enough that sharing code would hide the
17
+ * distinction. The contrast IS the lesson:
18
+ *
19
+ * - **debounce** waits for quiet — fires once AFTER a burst settles.
20
+ * - **throttle** enforces a rate — fires AT MOST once per `ms` while the
21
+ * burst is ongoing, dropping the calls in between.
22
+ *
23
+ * Layering with `../throttled-input`: `throttle` and `debounce` are
24
+ * the two host-boundary PRIMITIVES — two distinct algorithms
25
+ * (at-most-once-per-window vs collapse-a-burst) behind one signature shape.
26
+ * `throttled-input` is NOT a third primitive: it is a TEA machine composed
27
+ * OVER them (the same semantics, reimplemented as pure, durable Model state)
28
+ * that re-exports both. Wrapping a raw host event → these primitives; durable, replayable
29
+ * gating inside a machine → `throttled-input` (see its module doc for the full
30
+ * layering map).
31
+ *
32
+ * WHAT THIS IS NOT — and why it lives outside `update`:
33
+ *
34
+ * - NOT a reducer / Transitions cell. Reducers are PURE (invariant 2 — same
35
+ * inputs → same outputs, no `Date.now`, no timers). A throttle holds a live
36
+ * `setTimeout` handle and a window cursor; folding it into `update` would
37
+ * smuggle a timer into the pure core.
38
+ * - NOT a Sub. A Sub is a continuous SOURCE of Msgs the substrate reconciles
39
+ * by id every transition (invariant 4). A throttle is a SINK transformer:
40
+ * it wraps a `void`-returning handler (the canonical one is
41
+ * `Runtime.dispatch`) so a high-frequency HOST event is rate-limited BEFORE
42
+ * it ever becomes a Msg.
43
+ *
44
+ * It is a higher-order function at the host boundary (pattern 14 — TEA owns
45
+ * state, JS owns timing). The host attaches the wrapped function to a
46
+ * high-frequency event source (`mousemove`, `scroll`, `pointermove`, a game
47
+ * loop) and the substrate downstream only ever sees the rate-limited Msg:
48
+ *
49
+ * const onMoved = throttle(
50
+ * (e: PointerEvent) =>
51
+ * runtime.dispatch({ type: "UserMovedCursor", x: e.clientX, y: e.clientY }),
52
+ * 16, // ~60fps cap
53
+ * );
54
+ * window.addEventListener("pointermove", onMoved);
55
+ * // cleanup: onMoved.cancel(); window.removeEventListener("pointermove", onMoved);
56
+ *
57
+ * Internal since #47 — not published on any subpath; reached from inside the
58
+ * package as `internal/timing/throttle`. Same one-shape-per-package rule as
59
+ * `rate-limit`, `deadline`, and `work-queue`.
60
+ *
61
+ * Uses the universal `setTimeout` / `clearTimeout` timer idiom (same discipline
62
+ * as `subs/from-timeout.ts`): exactly one live handle at a time, the window
63
+ * timer clears itself on expiry, `cancel` / `flush` clear and null it so a
64
+ * stale callback can never run.
65
+ */
66
+ /**
67
+ * A throttled wrapper around `fn`. Callable with the SAME argument tuple as
68
+ * `fn` — `(...args: A) => void` — plus two control methods that share names and
69
+ * shapes with `Debounced<A>` so the two modules read as a symmetric pair.
70
+ */
71
+ interface Throttled<A extends readonly unknown[]> {
72
+ /** Invoke `fn` if the window is open, else record args for the trailing fire. */
73
+ (...args: A): void;
74
+ /**
75
+ * Drop any pending trailing fire WITHOUT invoking `fn`, and close the active
76
+ * window. Clears the timer, forgets the captured trailing args, and resets
77
+ * the cursor so the next call fires immediately on the leading edge (if
78
+ * `leading` is enabled). Idempotent.
79
+ *
80
+ * The host-cleanup partner of `removeEventListener`: cancel the pending fire
81
+ * when the component unmounts / the listener detaches, so a queued
82
+ * `dispatch` can't land after teardown.
83
+ */
84
+ cancel(): void;
85
+ /**
86
+ * Fire any pending trailing call IMMEDIATELY with its latest captured args,
87
+ * then close the window. No-op when nothing is pending. Use to force the last
88
+ * dropped call out early — e.g. flush the final cursor position when a drag
89
+ * ends, so the rest state isn't a stale mid-drag sample.
90
+ */
91
+ flush(): void;
92
+ }
93
+ /**
94
+ * Wrap `fn` so it runs AT MOST once per `ms` window, no matter how often it is
95
+ * called.
96
+ *
97
+ * Leading + trailing (the default): the first call fires `fn` IMMEDIATELY (the
98
+ * leading edge) and opens a `ms` window. Calls during the window are dropped
99
+ * from immediate firing but their args are remembered; when the window closes,
100
+ * `fn` fires ONCE more with the LATEST dropped args (the trailing edge) and a
101
+ * new window opens. A call after the window has already closed leads a fresh
102
+ * window immediately. Spacing every call at least `ms` apart therefore fires
103
+ * each one on its own leading edge.
104
+ *
105
+ * @param fn The handler to rate-limit. Typically `(...) => runtime.dispatch(...)`,
106
+ * but any `(...args: A) => void` works. The return value is
107
+ * ignored — throttle is a fire transformer, not a value pipe.
108
+ * @param ms Window length in milliseconds. `fn` fires at most once per `ms`.
109
+ * @param opts.leading Fire on the FIRST call of a window (the leading edge),
110
+ * immediately. Default `true`.
111
+ * @param opts.trailing Fire once at window END with the latest args dropped
112
+ * during the window. Default `true`.
113
+ *
114
+ * Edge combinations (matching lodash's settled semantics, the de-facto
115
+ * standard the ecosystem rediscovered):
116
+ *
117
+ * - `{ leading: true, trailing: true }` (default): immediate fire + a
118
+ * trailing fire per window while calls keep arriving. The trailing fire is
119
+ * SUPPRESSED when no extra call arrived during the window (a lone call
120
+ * already fired on the leading edge — no stale trailing double-fire).
121
+ * - `{ leading: true, trailing: false }`: only the immediate fire; everything
122
+ * in the window is dropped with no catch-up at the end.
123
+ * - `{ leading: false, trailing: true }`: no immediate fire; the FIRST call
124
+ * opens a window and `fn` fires at the window's end with the latest args.
125
+ * Steady "sample every `ms`" behavior with no instant response.
126
+ * - `{ leading: false, trailing: false }`: never fires. Degenerate but legal;
127
+ * we don't throw — the caller asked for a no-op transformer.
128
+ *
129
+ * WHY a default of leading + trailing both `true`: a throttle's job is "respond
130
+ * now, then keep responding at a steady rate." Leading gives the instant
131
+ * response (the first `mousemove` updates immediately); trailing guarantees the
132
+ * FINAL sample of a window isn't lost (the cursor ends where the user actually
133
+ * left it, not one window-width behind). Dropping either loses one of those two
134
+ * guarantees, so both default on.
135
+ */
136
+ declare function throttle<A extends readonly unknown[]>(fn: (...args: A) => void, ms: number, opts?: {
137
+ leading?: boolean;
138
+ trailing?: boolean;
139
+ }): Throttled<A>;
140
+
141
+ /**
142
+ * internal/timing/throttled-input — gate a high-frequency input stream into a
12
143
  * SETTLED, RATE-CAPPED, optionally DEDUPED sequence of emits, as a TEA knob: one
13
144
  * config object + a few pre-wired hooks you spread into your machine.
14
145
  *
@@ -90,9 +221,9 @@ import 'zod';
90
221
  *
91
222
  * NOT a substrate primitive: it depends only on sibling subpaths (`../throttle`,
92
223
  * `../debounce`, `../cache`, `../deadline`) and the core `Cmd` / `Sub` types.
93
- * Consumers reach it via the `@demlik/tea/throttled-input` subpath; the L1
94
- * escape hatch is those sibling subpaths threaded by hand. NOT exported from the
95
- * package root — same one-shape-per-package rule as `batch-window` and `poller`.
224
+ * Internal since #47 — reached from inside the package as
225
+ * `internal/timing/throttled-input`; the L1 escape hatch is those siblings
226
+ * threaded by hand. Same one-shape-per-package rule as `batch-window` and `poller`.
96
227
  */
97
228
 
98
229
  /**
@@ -378,4 +509,4 @@ interface ThrottledInputKnob<V, C extends Cmd> {
378
509
  */
379
510
  declare function createThrottledInput<V, C extends Cmd>(config: ThrottledInputConfig<V, C>): ThrottledInputKnob<V, C>;
380
511
 
381
- export { type PendingInput, type ThrottledInput, type ThrottledInputConfig, type ThrottledInputKnob, type ThrottledInputNoCache, type ThrottledInputSub, type ThrottledInputWithCache, createThrottledInput, initThrottledInput, input, onFlush, subsFor };
512
+ export { type PendingInput, type Throttled, type ThrottledInput, type ThrottledInputConfig, type ThrottledInputKnob, type ThrottledInputNoCache, type ThrottledInputSub, type ThrottledInputWithCache, createThrottledInput, initThrottledInput, input, onFlush, subsFor, throttle };
@@ -1,15 +1,60 @@
1
- export { debounce } from '../chunk-J6527VRQ.js';
2
- export { throttle } from '../chunk-HCEVHFJ7.js';
3
- import { initCache, get, set } from '../chunk-RH5EFRVJ.js';
4
- import { deadlineSub } from '../chunk-DGE4PV4A.js';
5
- export { subscribeDeadline as subscribeThrottledInput, deadlineExceeded as throttledInputSettled } from '../chunk-DGE4PV4A.js';
6
- import '../chunk-VYFAZN3F.js';
7
- import '../chunk-2YFLOCWX.js';
8
- import '../chunk-ZJ5AOYBH.js';
9
- import '../chunk-ZSUUOEPL.js';
10
- import '../chunk-OOYD44JI.js';
1
+ export { debounce } from '../chunk-LFZUK6J2.js';
2
+ import { deadlineSub, initCache, get, set } from '../chunk-22POWGFA.js';
3
+ export { subscribeDeadline as subscribeThrottledInput, deadlineExceeded as throttledInputSettled } from '../chunk-22POWGFA.js';
4
+ import '../chunk-66PY5WYF.js';
11
5
 
12
- // src/throttled-input/index.ts
6
+ // src/internal/timing/throttle/index.ts
7
+ function throttle(fn, ms, opts) {
8
+ const leading = opts?.leading ?? true;
9
+ const trailing = opts?.trailing ?? true;
10
+ let handle = null;
11
+ let pendingArgs = null;
12
+ function clearHandle() {
13
+ if (handle !== null) {
14
+ clearTimeout(handle);
15
+ handle = null;
16
+ }
17
+ }
18
+ function onWindowExpired() {
19
+ if (trailing && pendingArgs !== null) {
20
+ const args = pendingArgs;
21
+ pendingArgs = null;
22
+ handle = setTimeout(onWindowExpired, ms);
23
+ fn(...args);
24
+ } else {
25
+ handle = null;
26
+ }
27
+ }
28
+ const throttled = (...args) => {
29
+ if (handle === null) {
30
+ if (leading) {
31
+ fn(...args);
32
+ } else if (trailing) {
33
+ pendingArgs = args;
34
+ }
35
+ handle = setTimeout(onWindowExpired, ms);
36
+ } else if (trailing) {
37
+ pendingArgs = args;
38
+ }
39
+ };
40
+ throttled.cancel = () => {
41
+ clearHandle();
42
+ pendingArgs = null;
43
+ };
44
+ throttled.flush = () => {
45
+ if (pendingArgs !== null) {
46
+ const args = pendingArgs;
47
+ pendingArgs = null;
48
+ clearHandle();
49
+ fn(...args);
50
+ } else {
51
+ clearHandle();
52
+ }
53
+ };
54
+ return throttled;
55
+ }
56
+
57
+ // src/internal/timing/throttled-input/index.ts
13
58
  var DEFAULT_SUB_ID = "throttled-input:settle";
14
59
  function initThrottledInput() {
15
60
  return { lastAt: null, pending: null };
@@ -84,6 +129,6 @@ function createThrottledInput(config) {
84
129
  };
85
130
  }
86
131
 
87
- export { createThrottledInput, initThrottledInput, input, onFlush, subsFor };
132
+ export { createThrottledInput, initThrottledInput, input, onFlush, subsFor, throttle };
88
133
  //# sourceMappingURL=index.js.map
89
134
  //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/internal/timing/throttle/index.ts","../../src/internal/timing/throttled-input/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * internal/timing/throttle — a timer-based call transformer that caps invocation\n * to at most once per `ms` window.\n *\n * Sibling of `../debounce` — the two share a SYMMETRIC surface\n * (`Throttled<A>` / `Debounced<A>`, both callable + `.cancel()` + `.flush()`,\n * both `{ leading?, trailing? }`) so they read as a pair. They are kept in\n * separate files with NO cross-import: each is a self-contained timer, and the\n * coalesce-vs-drop policies differ enough that sharing code would hide the\n * distinction. The contrast IS the lesson:\n *\n * - **debounce** waits for quiet — fires once AFTER a burst settles.\n * - **throttle** enforces a rate — fires AT MOST once per `ms` while the\n * burst is ongoing, dropping the calls in between.\n *\n * Layering with `../throttled-input`: `throttle` and `debounce` are\n * the two host-boundary PRIMITIVES — two distinct algorithms\n * (at-most-once-per-window vs collapse-a-burst) behind one signature shape.\n * `throttled-input` is NOT a third primitive: it is a TEA machine composed\n * OVER them (the same semantics, reimplemented as pure, durable Model state)\n * that re-exports both. Wrapping a raw host event → these primitives; durable, replayable\n * gating inside a machine → `throttled-input` (see its module doc for the full\n * layering map).\n *\n * WHAT THIS IS NOT — and why it lives outside `update`:\n *\n * - NOT a reducer / Transitions cell. Reducers are PURE (invariant 2 — same\n * inputs → same outputs, no `Date.now`, no timers). A throttle holds a live\n * `setTimeout` handle and a window cursor; folding it into `update` would\n * smuggle a timer into the pure core.\n * - NOT a Sub. A Sub is a continuous SOURCE of Msgs the substrate reconciles\n * by id every transition (invariant 4). A throttle is a SINK transformer:\n * it wraps a `void`-returning handler (the canonical one is\n * `Runtime.dispatch`) so a high-frequency HOST event is rate-limited BEFORE\n * it ever becomes a Msg.\n *\n * It is a higher-order function at the host boundary (pattern 14 — TEA owns\n * state, JS owns timing). The host attaches the wrapped function to a\n * high-frequency event source (`mousemove`, `scroll`, `pointermove`, a game\n * loop) and the substrate downstream only ever sees the rate-limited Msg:\n *\n * const onMoved = throttle(\n * (e: PointerEvent) =>\n * runtime.dispatch({ type: \"UserMovedCursor\", x: e.clientX, y: e.clientY }),\n * 16, // ~60fps cap\n * );\n * window.addEventListener(\"pointermove\", onMoved);\n * // cleanup: onMoved.cancel(); window.removeEventListener(\"pointermove\", onMoved);\n *\n * Internal since #47 — not published on any subpath; reached from inside the\n * package as `internal/timing/throttle`. Same one-shape-per-package rule as\n * `rate-limit`, `deadline`, and `work-queue`.\n *\n * Uses the universal `setTimeout` / `clearTimeout` timer idiom (same discipline\n * as `subs/from-timeout.ts`): exactly one live handle at a time, the window\n * timer clears itself on expiry, `cancel` / `flush` clear and null it so a\n * stale callback can never run.\n */\n\n/**\n * A throttled wrapper around `fn`. Callable with the SAME argument tuple as\n * `fn` — `(...args: A) => void` — plus two control methods that share names and\n * shapes with `Debounced<A>` so the two modules read as a symmetric pair.\n */\nexport interface Throttled<A extends readonly unknown[]> {\n /** Invoke `fn` if the window is open, else record args for the trailing fire. */\n (...args: A): void;\n /**\n * Drop any pending trailing fire WITHOUT invoking `fn`, and close the active\n * window. Clears the timer, forgets the captured trailing args, and resets\n * the cursor so the next call fires immediately on the leading edge (if\n * `leading` is enabled). Idempotent.\n *\n * The host-cleanup partner of `removeEventListener`: cancel the pending fire\n * when the component unmounts / the listener detaches, so a queued\n * `dispatch` can't land after teardown.\n */\n cancel(): void;\n /**\n * Fire any pending trailing call IMMEDIATELY with its latest captured args,\n * then close the window. No-op when nothing is pending. Use to force the last\n * dropped call out early — e.g. flush the final cursor position when a drag\n * ends, so the rest state isn't a stale mid-drag sample.\n */\n flush(): void;\n}\n\n/**\n * Wrap `fn` so it runs AT MOST once per `ms` window, no matter how often it is\n * called.\n *\n * Leading + trailing (the default): the first call fires `fn` IMMEDIATELY (the\n * leading edge) and opens a `ms` window. Calls during the window are dropped\n * from immediate firing but their args are remembered; when the window closes,\n * `fn` fires ONCE more with the LATEST dropped args (the trailing edge) and a\n * new window opens. A call after the window has already closed leads a fresh\n * window immediately. Spacing every call at least `ms` apart therefore fires\n * each one on its own leading edge.\n *\n * @param fn The handler to rate-limit. Typically `(...) => runtime.dispatch(...)`,\n * but any `(...args: A) => void` works. The return value is\n * ignored — throttle is a fire transformer, not a value pipe.\n * @param ms Window length in milliseconds. `fn` fires at most once per `ms`.\n * @param opts.leading Fire on the FIRST call of a window (the leading edge),\n * immediately. Default `true`.\n * @param opts.trailing Fire once at window END with the latest args dropped\n * during the window. Default `true`.\n *\n * Edge combinations (matching lodash's settled semantics, the de-facto\n * standard the ecosystem rediscovered):\n *\n * - `{ leading: true, trailing: true }` (default): immediate fire + a\n * trailing fire per window while calls keep arriving. The trailing fire is\n * SUPPRESSED when no extra call arrived during the window (a lone call\n * already fired on the leading edge — no stale trailing double-fire).\n * - `{ leading: true, trailing: false }`: only the immediate fire; everything\n * in the window is dropped with no catch-up at the end.\n * - `{ leading: false, trailing: true }`: no immediate fire; the FIRST call\n * opens a window and `fn` fires at the window's end with the latest args.\n * Steady \"sample every `ms`\" behavior with no instant response.\n * - `{ leading: false, trailing: false }`: never fires. Degenerate but legal;\n * we don't throw — the caller asked for a no-op transformer.\n *\n * WHY a default of leading + trailing both `true`: a throttle's job is \"respond\n * now, then keep responding at a steady rate.\" Leading gives the instant\n * response (the first `mousemove` updates immediately); trailing guarantees the\n * FINAL sample of a window isn't lost (the cursor ends where the user actually\n * left it, not one window-width behind). Dropping either loses one of those two\n * guarantees, so both default on.\n */\nexport function throttle<A extends readonly unknown[]>(\n fn: (...args: A) => void,\n ms: number,\n opts?: { leading?: boolean; trailing?: boolean },\n): Throttled<A> {\n const leading = opts?.leading ?? true;\n const trailing = opts?.trailing ?? true;\n\n // Exactly one live handle at a time (the from-timeout discipline). `null`\n // when no window is open — the single source of truth for \"is a window\n // active?\". The window timer arms on a fire and clears itself on expiry; the\n // call path never stacks overlapping timers.\n let handle: ReturnType<typeof setTimeout> | null = null;\n // The latest args seen DURING an open window, held for the trailing fire.\n // Overwritten by every dropped call (the trailing edge fires with the LAST\n // args), cleared the instant we fire / cancel. `null` (not `undefined`) is\n // the empty sentinel because `A` may itself contain `undefined` elements — a\n // present-but-empty tuple is still a pending call, distinct from \"nothing\n // pending\".\n let pendingArgs: A | null = null;\n\n function clearHandle(): void {\n if (handle !== null) {\n clearTimeout(handle);\n handle = null;\n }\n }\n\n // Window expiry: the `ms` window just closed. If a call arrived during the\n // window (`pendingArgs !== null`) and trailing is enabled, fire it now and\n // open a FRESH window so the rate cap continues across a sustained burst.\n // If nothing was dropped, let the window close (handle → null) so the next\n // call leads a new window immediately.\n function onWindowExpired(): void {\n if (trailing && pendingArgs !== null) {\n const args = pendingArgs;\n pendingArgs = null;\n // Re-arm BEFORE firing so a re-entrant call from inside `fn` sees an open\n // window (and is correctly dropped/queued) rather than leading a second\n // window — keeps the \"at most once per `ms`\" invariant under re-entry.\n handle = setTimeout(onWindowExpired, ms);\n fn(...args);\n } else {\n // No trailing fire owed — close the window.\n handle = null;\n }\n }\n\n const throttled = (...args: A): void => {\n if (handle === null) {\n // Window is closed → this call leads a new window.\n if (leading) {\n fn(...args);\n } else if (trailing) {\n // No leading fire, but trailing wants the first call's args so the\n // window's end has something to fire. Without this, a leading:false\n // throttle would swallow a lone call entirely.\n pendingArgs = args;\n }\n handle = setTimeout(onWindowExpired, ms);\n } else if (trailing) {\n // Window is open → drop this call from immediate firing, but remember its\n // args as the latest candidate for the trailing edge.\n pendingArgs = args;\n }\n // Window open + trailing disabled → pure drop, nothing to remember.\n };\n\n throttled.cancel = (): void => {\n clearHandle();\n pendingArgs = null;\n };\n\n throttled.flush = (): void => {\n // Force the pending trailing fire out now and close the window. Mirrors\n // `onWindowExpired`'s fire branch but is caller-driven, so it tears the\n // timer down rather than re-arming.\n if (pendingArgs !== null) {\n const args = pendingArgs;\n pendingArgs = null;\n clearHandle();\n fn(...args);\n } else {\n // Nothing pending — still close a lingering window so a post-flush call\n // leads cleanly.\n clearHandle();\n }\n };\n\n return throttled;\n}\n","/**\n * internal/timing/throttled-input — gate a high-frequency input stream into a\n * SETTLED, RATE-CAPPED, optionally DEDUPED sequence of emits, as a TEA knob: one\n * config object + a few pre-wired hooks you spread into your machine.\n *\n * Layering (the throttle-family map): `../throttle` and `../debounce` are the\n * two host-boundary PRIMITIVES — two distinct algorithms\n * (at-most-once-per-window vs collapse-a-burst) behind one signature shape.\n * THIS module is the third name but NOT a third primitive: a TEA machine\n * composed OVER them that re-exports both. Three exports, one layering — not\n * duplication. The reuse list below spells out composition vs reimplemented\n * semantic per sibling.\n *\n * What it reuses, and HOW (composition vs. reimplemented semantic — the two are\n * not the same, so this list keeps them apart):\n *\n * - `../cache` — COMPOSED directly. The DEDUPE / memoize layer is `../cache`'s\n * `TtlCache` plus its `get` / `set` / `initCache` ops, called at runtime —\n * not reinvented. While `cacheTtlMs` is set, an input whose `cacheKey` is\n * already cached and unexpired is served from the cache and emits NOTHING\n * (the downstream effect ran once for that key within its TTL); a fresh emit\n * writes the value into the cache so the next identical input within\n * `cacheTtlMs` is suppressed. The optional eviction Sub is the consumer's to\n * wire if they want memory reclaim (this knob's correctness needs only TTL\n * reads).\n * - `../deadline` — COMPOSED directly. The settle timer IS a `../deadline`\n * Sub: `subsFor` builds it via `deadlineSub`, and the subscribe cell +\n * Msg constructor are RE-EXPORTS of `../deadline`'s own (`subscribeDeadline`\n * → `subscribeThrottledInput`, `deadlineExceeded` → `throttledInputSettled`).\n * The timer lifecycle stays owned by `../deadline`; this knob redraws none\n * of it.\n * - `../throttle` / `../debounce` — TYPE + SEMANTIC reuse only, NOT composed.\n * Those siblings are host-boundary SINK transformers that hold a live\n * `setTimeout`; a `setTimeout` in a closure is exactly what a durable,\n * replayable knob must NOT hold. So their CODE is never called here. Instead\n * the RATE-cap semantic (\"at most once per `ms`\", leading-edge) and the\n * SETTLE semantic (\"wait until quiet\", trailing-edge) are REIMPLEMENTED as\n * pure Model state: `lastAt` is the durable rate cursor (half-open cutoff\n * `at - lastAt >= throttleMs`), and `pending` + the `../deadline` Sub realize\n * the debounce window inside `update`. The `throttle` / `debounce`\n * transformers themselves are RE-EXPORTED (the only reuse of their actual\n * code) so a consumer can pre-throttle / pre-coalesce a genuinely bursty\n * HOST event at the boundary BEFORE it ever becomes an `input` Msg — a\n * separate, optional escape hatch, not part of this knob's gates.\n *\n * \"Omit a brick, omit its gate\" (the resilient-call config rule): every gate\n * field is optional. Omit `throttleMs` → no rate cap (every input passes the\n * rate gate). Omit `debounceMs` → no settle wait (an input that clears the rate\n * gate emits IMMEDIATELY rather than being held). Omit `cacheTtlMs` → no cache\n * slice at all (the `cache` field is absent; no dedupe). A config with all three\n * omitted is a pass-through: `input` always emits.\n *\n * Why this is a knob and not hand-wired logic: the managed state (`lastAt`,\n * `pending`, `cache`) lives in the Model, so it survives DO eviction / reload\n * (durable) and every transition is still a Msg through `update` (replayable). A\n * closure holding a `setTimeout` and a mutable \"last value\" would break both —\n * banned. `input` / `onFlush` are PURE: time arrives as an `at` parameter, never\n * `Date.now()`; they return NEW slice values, never mutate.\n *\n * Typical wiring (combinator form):\n *\n * const search = createThrottledInput<string, Msg>({\n * debounceMs: 200, // wait for the user to stop typing\n * throttleMs: 1_000, // but never fire more than 1/s during a long burst\n * cacheTtlMs: 30_000, // skip a query repeated within 30s\n * cacheKey: (q) => q,\n * emit: (q) => ({ type: \"RunSearch\", query: q }),\n * });\n *\n * // Model: { search: ThrottledInput<string>, ... }\n * // init: (loaded) => [loaded ?? { search: search.init(), ... }, []]\n * // update cells:\n * // QueryTyped: (s, m) => mapInput(s, search.input(s.search, m.value, m.at))\n * // SettleFired: (s, m) => mapInput(s, search.onFlush(s.search, m.atMs))\n * // subscriptions: (s) => search.subs(s.search)\n * // subscribe: { ...search.handlers() }\n *\n * where `mapInput(s, [slice, cmds]) => [{ ...s, search: slice }, cmds]` lifts the\n * slice transition into the consumer's Model. The `RunSearch` Cmd's interpret\n * handler is the consumer's — it is where the settled input meets I/O.\n *\n * NOT a substrate primitive: it depends only on sibling subpaths (`../throttle`,\n * `../debounce`, `../cache`, `../deadline`) and the core `Cmd` / `Sub` types.\n * Internal since #47 — reached from inside the package as\n * `internal/timing/throttled-input`; the L1 escape hatch is those siblings\n * threaded by hand. Same one-shape-per-package rule as `batch-window` and `poller`.\n */\n\nimport type { Cmd, Sub } from \"../../../index\";\nimport {\n get as cacheGet,\n set as cacheSet,\n initCache,\n type TtlCache,\n} from \"../../resilience/cache\";\nimport { type DeadlineSub, deadlineSub } from \"../../resilience/deadline\";\n\n// `../throttle` + `../debounce` — host-boundary pre-transformers (see file\n// header). Re-exported so a consumer that wants to throttle/debounce a bursty\n// HOST source BEFORE it becomes an `input` Msg reaches them from the same\n// import as the durable gate.\nexport { type Debounced, debounce } from \"../debounce\";\nexport { type Throttled, throttle } from \"../throttle\";\n\n/**\n * The gate fields every throttled-input config shares, regardless of whether\n * dedupe is on. The two dedupe variants below extend this with mutually\n * exclusive cache fields.\n *\n * `emit` is a pure Cmd CONSTRUCTOR, not a closure-with-state: it maps a settled\n * value to the single Cmd the runtime performs when the gates let a value\n * through. Keeping it `(value) => Cmd` (not `(value) => void`) is what keeps the\n * trigger replayable — the emit is a Cmd in the transition's output, never a\n * side effect inside the verb (mirrors `batch-window`'s `flush`).\n */\ninterface ThrottledInputGates<V, C extends Cmd> {\n /**\n * Rate cap, in milliseconds. An input that lands within `throttleMs` of the\n * last EMIT (`at - lastAt < throttleMs`) is dropped from immediate firing —\n * the leading-edge \"at most once per `throttleMs`\" rate-cap rule, applied to\n * emits. The half-open cutoff (`>=` passes) matches `../throttle` and\n * `../cache`'s window-edge convention. Omit for no rate cap.\n *\n * Interacts with `debounceMs`: when both are set, a rate-blocked input is\n * still HELD as `pending` (so the settle timer eventually trails it out at a\n * legal moment) rather than silently dropped — the trailing-edge guarantee\n * that the FINAL sample of a window is never lost.\n */\n readonly throttleMs?: number;\n /**\n * Settle wait, in milliseconds. An input that clears the rate gate is not\n * emitted immediately; it is held as `pending` and a debounce deadline is\n * armed at `pendingAt + debounceMs`. A fresh input re-arms (slides) the\n * window. `onFlush` emits the pending value when the window finally expires.\n * Omit for no settle wait — a passing input emits on arrival.\n */\n readonly debounceMs?: number;\n /**\n * Map a settled value to the single Cmd the runtime performs. Called with the\n * value the gates let through; the returned Cmd is what `input` / `onFlush`\n * emit. PURE constructor — no I/O, no clock; the I/O happens later in the\n * consumer's interpret handler for the returned Cmd.\n */\n readonly emit: (value: V) => C;\n}\n\n/**\n * Configuration for a throttled input — the knob. Pure config, no mutable state\n * (the `ThrottledInput<V>` slice carries that). One config object is shared\n * across every input of one logical stream (often a module-scope const).\n *\n * A DISCRIMINATED UNION on the presence of dedupe, so the type system makes a\n * cache-key collision UNREPRESENTABLE (\"omit a brick, omit its gate\"):\n *\n * - **No dedupe** (`ThrottledInputNoCache`): `cacheTtlMs` absent ⇒ no cache\n * slice, no dedupe. `cacheKey` is statically forbidden here (`never`) — a\n * key with no cache to feed is dead config, so the type rejects it rather\n * than silently ignoring it.\n * - **Dedupe** (`ThrottledInputWithCache`): `cacheTtlMs` set ⇒ `cacheKey` is\n * REQUIRED. There is no `String(value)` default to fall back to, so a\n * structured value can NEVER collapse two distinct values to one slot (the\n * `\"[object Object]\"` collision). The consumer must state the identity that\n * keys the cache; a primitive stream still trivially passes `(v) => v` /\n * `String`, but it does so EXPLICITLY.\n */\nexport type ThrottledInputConfig<V, C extends Cmd> =\n | ThrottledInputNoCache<V, C>\n | ThrottledInputWithCache<V, C>;\n\n/**\n * The no-dedupe config variant: gates only, no cache. `cacheTtlMs` is absent\n * and `cacheKey` is statically `never` so a stray key (which would feed no\n * cache) is a type error, not a silently-ignored field.\n */\nexport interface ThrottledInputNoCache<V, C extends Cmd>\n extends ThrottledInputGates<V, C> {\n readonly cacheTtlMs?: undefined;\n readonly cacheKey?: never;\n}\n\n/**\n * The dedupe config variant: a per-entry TTL plus a REQUIRED `cacheKey`. An\n * input whose `cacheKey` is already cached and unexpired emits NOTHING (the\n * downstream effect ran once for that key within its TTL); a fresh emit writes\n * the value into the cache.\n *\n * `cacheKey` is required (no `String(value)` default) precisely so a structured\n * value cannot silently collide — the consumer names the identity, the cache\n * keys on exactly that.\n */\nexport interface ThrottledInputWithCache<V, C extends Cmd>\n extends ThrottledInputGates<V, C> {\n /**\n * Dedupe / memoize TTL, in milliseconds. An input whose `cacheKey` is already\n * cached and unexpired emits NOTHING; a fresh emit writes the value into the\n * cache so the next identical input within `cacheTtlMs` is suppressed.\n */\n readonly cacheTtlMs: number;\n /**\n * Key a value for the dedupe cache. REQUIRED whenever `cacheTtlMs` is set:\n * there is no `String(value)` fallback, so a structured value's identity is\n * always the consumer's explicit choice and two distinct values can never\n * collapse to one slot. A primitive stream passes `(v) => v` / `String`.\n */\n readonly cacheKey: (value: V) => string;\n}\n\n/**\n * The Model slice a throttled input owns — its visible slice (the knob\n * principle: managed state lives in the Model, never a closure, so it is durable\n * and replayable).\n *\n * - `lastAt` — the `at` of the most recent EMIT, or `null` before the first\n * emit. The `../throttle` rate cap measures against it: an input\n * within `throttleMs` of `lastAt` is rate-blocked. Persisted so a\n * resumed gate keeps its rate cursor.\n * - `pending` — the value HELD for the settle (debounce) window, paired with the\n * `at` it was held (the anchor the deadline targets), or `null`\n * when nothing is waiting. The single source of truth for \"is a\n * settle window open?\" — the debounce timer Sub arms iff this is\n * non-null.\n * - `cache` — the `../cache` TTL store backing dedupe, present IFF\n * `cacheTtlMs` is configured. Absent (the field omitted) for a\n * gate with no dedupe — no per-op cost, nothing to serialize.\n */\nexport interface ThrottledInput<V> {\n readonly lastAt: number | null;\n readonly pending: PendingInput<V> | null;\n readonly cache?: TtlCache<V>;\n}\n\n/**\n * A value held for the settle window: the `value` itself and the `at` it was\n * held (the anchor the debounce deadline targets, `at + debounceMs`). A distinct\n * type (not a bare `V`) because `V` may itself be `null` — a present-but-null\n * value is still a real pending input, distinct from \"nothing pending\", exactly\n * the `null`-sentinel discipline `../throttle` / `../debounce` use for their\n * `pendingArgs`.\n */\nexport interface PendingInput<V> {\n readonly value: V;\n readonly at: number;\n}\n\n/**\n * The Sub variant a throttled input's settle timer produces — a `../deadline`\n * Sub (so the window fires at the correct ABSOLUTE moment even after a late\n * subscribe / rehydrate, and so a consumer running several gates routes each by\n * `id`). `atMs` is the absolute settle-by instant (`pendingAt + debounceMs`).\n */\nexport type ThrottledInputSub = DeadlineSub;\n\n/**\n * The stable Sub id the gate arms its settle deadline under. A single gate arms\n * exactly one settle timer at a time, so one id suffices; a consumer running\n * several gates on one machine namespaces them by composing the knob under\n * distinct slices with distinct ids (the `subs(state, id)` parameter).\n */\nconst DEFAULT_SUB_ID = \"throttled-input:settle\";\n\n/**\n * The starting slice: no prior emit, nothing pending. The `cache` field is\n * seeded only when `cacheTtlMs` is configured (see `createThrottledInput`); the\n * free `initThrottledInput` leaves it absent (the no-dedupe shape).\n */\nexport function initThrottledInput<V>(): ThrottledInput<V> {\n return { lastAt: null, pending: null };\n}\n\n/**\n * Resolve a value's cache key under a DEDUPE config. PURE. Takes the narrowed\n * `ThrottledInputWithCache` (not the union) because `cacheKey` is only present —\n * and only meaningful — when dedupe is on; there is no `String(value)` default\n * to fall back to, so a structured value's identity is always the consumer's\n * explicit choice and two distinct values can never collapse to one slot.\n */\nfunction keyOf<V, C extends Cmd>(\n config: ThrottledInputWithCache<V, C>,\n value: V,\n): string {\n return config.cacheKey(value);\n}\n\n/**\n * Narrow `config` to its dedupe variant iff a cache slice is actually wired —\n * `cacheTtlMs` set AND a `cache` store present. Returns the narrowed config\n * (carrying the required `cacheKey`) paired with the resolved `cache` store, or\n * `null` when no dedupe is configured. The single place the union is\n * discriminated, so `isCacheHit` / `commitEmit` share one narrowing — and reuse\n * the resolved `cache` — rather than re-deriving the predicate and re-narrowing\n * `state.cache`.\n */\nfunction cacheConfig<V, C extends Cmd>(\n config: ThrottledInputConfig<V, C>,\n state: ThrottledInput<V>,\n): {\n readonly config: ThrottledInputWithCache<V, C>;\n readonly cache: TtlCache<V>;\n} | null {\n return config.cacheTtlMs !== undefined && state.cache !== undefined\n ? { config, cache: state.cache }\n : null;\n}\n\n/**\n * Whether `value` is a cache HIT under `config` at `at` — present and unexpired.\n * PURE — reads only. Always `false` when `cacheTtlMs` is unset or no `cache`\n * slice exists (no dedupe configured), so the dedupe gate is a no-op for an\n * unconfigured gate.\n */\nfunction isCacheHit<V, C extends Cmd>(\n config: ThrottledInputConfig<V, C>,\n state: ThrottledInput<V>,\n value: V,\n at: number,\n): boolean {\n const cached = cacheConfig(config, state);\n if (cached === null) return false;\n return cacheGet(cached.cache, keyOf(cached.config, value), at) !== undefined;\n}\n\n/**\n * Emit `value` at clock `at`: bump the rate cursor, refresh the dedupe cache,\n * and clear any pending hold. PURE. The single place an emit's bookkeeping\n * lives, shared by `input` (immediate emit) and `onFlush` (trailing emit) so the\n * two paths can never drift on what an emit updates.\n *\n * - `lastAt` advances to `at` — the next input is rate-measured against this\n * emit, the `../throttle` window cursor.\n * - `cache` (when configured) records `value` under its key with `cacheTtlMs`\n * from `at` — so the next identical input within the TTL is suppressed.\n * - `pending` clears — the value just went out; nothing is waiting.\n */\nfunction commitEmit<V, C extends Cmd>(\n config: ThrottledInputConfig<V, C>,\n state: ThrottledInput<V>,\n value: V,\n at: number,\n): readonly [ThrottledInput<V>, readonly C[]] {\n const cached = cacheConfig(config, state);\n const cache =\n cached !== null\n ? cacheSet(\n cached.cache,\n keyOf(cached.config, value),\n value,\n at,\n cached.config.cacheTtlMs,\n )\n : state.cache;\n const next: ThrottledInput<V> = {\n ...state,\n lastAt: at,\n pending: null,\n ...(cache !== undefined ? { cache } : {}),\n };\n return [next, [config.emit(value)]];\n}\n\n/**\n * Feed a new input `value` arriving at clock `at` through the gates. PURE.\n *\n * The gate order is DEDUPE → RATE → SETTLE (each skipped when its config field\n * is omitted), the same cache-first-then-gate order `resilient-call` uses (a hit\n * short-circuits before the expensive path):\n *\n * 1. **Dedupe** (`cacheTtlMs` set): if `value`'s key is cached and unexpired,\n * suppress — return the slice UNCHANGED (no emit, no pending, no re-arm).\n * The downstream effect already ran for this key within its TTL.\n * 2. **Rate** (`throttleMs` set): if `at` is within `throttleMs` of the last\n * emit (`at - lastAt < throttleMs`), this input is rate-blocked.\n * - With `debounceMs` set → HOLD it as `pending` (the trailing edge: the\n * settle timer will emit it at a legal moment, so the final sample is\n * never lost). The deadline `subs` arms targets `at + debounceMs`.\n * - Without `debounceMs` → DROP it (pure rate cap, no catch-up).\n * 3. **Settle** (`debounceMs` set): the input cleared the rate gate. HOLD it\n * as `pending` and let the debounce window slide; `onFlush` emits it once\n * the window expires. A fresh input before expiry overwrites `pending` (the\n * trailing edge fires with the LAST value, the `../debounce` default).\n * 4. **Pass-through**: no `debounceMs`, cleared the rate gate → EMIT now.\n *\n * @param config the knob (the three optional gates + `emit`)\n * @param state the current slice\n * @param value the input value\n * @param at the arrival instant (epoch ms) — the caller stamps it; the verb\n * never reads the clock\n */\nexport function input<V, C extends Cmd>(\n config: ThrottledInputConfig<V, C>,\n state: ThrottledInput<V>,\n value: V,\n at: number,\n): readonly [ThrottledInput<V>, readonly C[]] {\n // 1. Dedupe gate — a cached, unexpired key short-circuits everything.\n if (isCacheHit(config, state, value, at)) {\n return [state, []];\n }\n\n // 2. Rate gate — half-open cutoff (`>=` passes). `lastAt === null` (no prior\n // emit) always passes: the first input is never rate-blocked. Shared with\n // `onFlush` via `rateBlockedAt` so the arrival and trailing-edge paths agree\n // on the window.\n if (rateBlockedAt(config, state, at)) {\n // With a settle window, a rate-blocked input is HELD (trailing edge) so it\n // emits at the next legal moment; without one, it is a pure drop.\n if (config.debounceMs !== undefined) {\n return [{ ...state, pending: { value, at } }, []];\n }\n return [state, []];\n }\n\n // 3. Settle gate — passed the rate gate; if a debounce window is configured,\n // hold the value and (re)arm the settle deadline rather than emit now.\n if (config.debounceMs !== undefined) {\n return [{ ...state, pending: { value, at } }, []];\n }\n\n // 4. Pass-through — no settle wait, cleared the rate gate: emit immediately.\n return commitEmit(config, state, value, at);\n}\n\n/**\n * Whether emitting at clock `at` would breach the rate cap — `at` lands within\n * `throttleMs` of the last emit (`at - lastAt < throttleMs`). PURE — reads only.\n * Always `false` when `throttleMs` is unset (no rate cap) or before the first\n * emit (`lastAt === null`), so an unconfigured / never-fired gate never holds on\n * the rate gate. The single rate-gate predicate, shared by `input` (drop / hold\n * on arrival) and `onFlush` (re-hold a still-early trailing edge) so the two\n * paths can never drift on what \"within the rate window\" means.\n */\nfunction rateBlockedAt<V, C extends Cmd>(\n config: ThrottledInputConfig<V, C>,\n state: ThrottledInput<V>,\n at: number,\n): boolean {\n return (\n config.throttleMs !== undefined &&\n state.lastAt !== null &&\n at - state.lastAt < config.throttleMs\n );\n}\n\n/**\n * Emit the pending value because the settle (debounce) window closed. PURE.\n *\n * - Pending present, rate gate CLEAR → emit `config.emit(pending.value)`,\n * advance the rate cursor (`lastAt = at`), refresh the dedupe cache, and clear\n * `pending`. The trailing edge of `../debounce` realized as a Model transition.\n * - Pending present, rate gate STILL BLOCKED → re-HOLD: return the slice with\n * `pending` intact and NO Cmds. A settle Msg can fire at `pending.at +\n * debounceMs`, which may still be inside the rate window (`lastAt +\n * throttleMs`) — emitting then would breach the headline \"at most once per\n * `throttleMs`\" cap. Re-holding keeps the value waiting; `subs` re-arms the\n * deadline at `max(pending.at + debounceMs, lastAt + throttleMs)` so the next\n * timer fires at a LEGAL moment and the trailing edge is deferred, never lost.\n * - Pending absent → no-op: return the same slice and no Cmds. Guards the race\n * where an `input` already emitted (or a dedupe hit cleared interest) before\n * the settle timer's Msg lands — a stale `onFlush` must NOT emit. Symmetric\n * with `batch-window`'s closed-window guard.\n *\n * `at` is the firing instant the settle Msg carried (the caller stamps it; the\n * verb never reads the clock). It becomes the new rate cursor and the cache\n * write's `nowMs`, so a settled emit rate-blocks subsequent inputs from its\n * actual fire moment, not the moment the value was first held.\n *\n * @param config the knob (`throttleMs`, `emit`, cache config)\n * @param state the current slice\n * @param at the settle-timer firing instant (epoch ms)\n */\nexport function onFlush<V, C extends Cmd>(\n config: ThrottledInputConfig<V, C>,\n state: ThrottledInput<V>,\n at: number,\n): readonly [ThrottledInput<V>, readonly C[]] {\n // No pending value = an immediate emit already fired, or a dedupe hit cleared\n // interest. A stale timer Msg must not emit — return the slice untouched.\n if (state.pending === null) return [state, []];\n // Rate gate re-check: a settle Msg can land before the rate window opens (its\n // naive deadline is pending.at + debounceMs, which `subs` lifts to a legal\n // target — but a stale / early timer can still arrive). Emitting now would\n // breach \"at most once per throttleMs\", so re-hold and let `subs` re-arm at\n // the legal moment. The value stays pending; nothing is dropped.\n if (rateBlockedAt(config, state, at)) return [state, []];\n return commitEmit(config, state, state.pending.value, at);\n}\n\n/**\n * The settle timer Sub, derived from the slice. PURE.\n *\n * Returns the single `../deadline` Sub while a value is held AND a settle window\n * is configured, or `[]` otherwise. The deadline target is the LATER of two\n * constraints (so the timer never fires before BOTH are satisfied):\n *\n * - `pending.at + debounceMs` — the settle (debounce) deadline: the value has\n * stopped sliding, the burst has gone quiet.\n * - `lastAt + throttleMs` — the rate cap: emitting earlier would breach \"at\n * most once per `throttleMs`\". Only applies once a prior emit exists\n * (`lastAt !== null`) and a rate cap is configured (`throttleMs` set).\n *\n * `max(settleAt, rateAt)` is the earliest LEGAL trailing-edge moment. Anchoring\n * the timer here — rather than the naive `pending.at + debounceMs` — is what\n * keeps the rate cap intact across the trailing edge: a value held while still\n * inside the rate window arms its timer at `lastAt + throttleMs`, so `onFlush`\n * fires at a moment the rate gate already permits. (`onFlush` re-checks the gate\n * anyway and re-holds if an early/stale timer slips through, so the cap holds\n * even if a timer fires ahead of this target.)\n *\n * The substrate's reconcile pass arms the timer when the array gains the Sub and\n * disarms it (clearing the pending `setTimeout`) when the array loses it — so an\n * `onFlush` (or a dedupe hit) that clears `pending` auto-cancels the now-stale\n * settle timer on the next transition, and a sliding input that re-stamps\n * `pending.at` re-arms a fresh absolute target.\n *\n * `debounceMs` undefined ⇒ no settle window ⇒ `[]` even with a `pending` value\n * (an unconfigured settle never holds, but the guard keeps `subs` total).\n *\n * @param config the knob (`debounceMs`, `throttleMs`)\n * @param state the current slice\n * @param id stable identity for this gate's settle timer (default\n * `\"throttled-input:settle\"`); pass a distinct id per gate when a\n * machine runs several so the dispatched Msg routes distinctly.\n */\nexport function subsFor<V, C extends Cmd>(\n config: ThrottledInputConfig<V, C>,\n state: ThrottledInput<V>,\n id = DEFAULT_SUB_ID,\n): readonly ThrottledInputSub[] {\n if (config.debounceMs === undefined || state.pending === null) return [];\n const settleAt = state.pending.at + config.debounceMs;\n // The rate floor: the earliest moment the rate cap permits an emit. Absent\n // when no rate cap is configured or no prior emit set a cursor — then the\n // settle deadline alone governs.\n const rateAt =\n config.throttleMs !== undefined && state.lastAt !== null\n ? state.lastAt + config.throttleMs\n : settleAt;\n return [deadlineSub(id, Math.max(settleAt, rateAt))];\n}\n\n/**\n * The bound knob returned by `createThrottledInput`. `init` + the two pure verbs\n * + `subs`, all closing over one `ThrottledInputConfig`. The verbs return\n * `readonly [ThrottledInput<V>, readonly C[]]`: the next slice and the Cmds to\n * emit (one `emit` Cmd when a value passes, none while held / dropped / deduped).\n *\n * Pure-ops + subs module: there is no `handlers(ports)` cell. The settle timer's\n * subscribe cell IS `../deadline`'s `subscribeDeadline` (re-exported below) —\n * the consumer wires it into `subscribe` directly; the knob redraws no timer\n * lifecycle of its own. (Compare `poller`, identical: it too reuses\n * `../deadline`'s cell and ships no `handlers`.)\n */\nexport interface ThrottledInputKnob<V, C extends Cmd> {\n /** Seed the Model slice (with a cache iff `cacheTtlMs` is configured). */\n init(): ThrottledInput<V>;\n /**\n * Feed a new input through the dedupe → rate → settle gates. See `input`.\n */\n input(\n state: ThrottledInput<V>,\n value: V,\n at: number,\n ): readonly [ThrottledInput<V>, readonly C[]];\n /**\n * Emit the held value because the settle window closed. See `onFlush`.\n */\n onFlush(\n state: ThrottledInput<V>,\n at: number,\n ): readonly [ThrottledInput<V>, readonly C[]];\n /**\n * The settle timer Sub, armed only while a value is held. See `subsFor`.\n * `id` keys the deadline so several gates on one machine route distinctly.\n */\n subs(state: ThrottledInput<V>, id?: string): readonly Sub[];\n}\n\n/**\n * Build a throttled-input knob from `config`. Combinator form (the default L2\n * ergonomic): hand it the config, splice the returned hooks into your machine.\n * The pure verbs (`input` / `onFlush`) close over the config so the consumer's\n * reducer cells stay a uniform `(state, ...args)` shape; `subs` pre-wires the\n * settle timer.\n *\n * `init()` seeds a `cache` slice IFF `cacheTtlMs` is configured — an unconfigured\n * gate carries no cache field (nothing to serialize, no dedupe). Pure factory —\n * no clock read, no timer; everything happens when the consumer calls the\n * returned verbs / `subs` with an injected `at`.\n *\n * @typeParam V the input value type\n * @typeParam C the Cmd type `config.emit` returns\n */\nexport function createThrottledInput<V, C extends Cmd>(\n config: ThrottledInputConfig<V, C>,\n): ThrottledInputKnob<V, C> {\n function init(): ThrottledInput<V> {\n const base = initThrottledInput<V>();\n // Seed the cache only when dedupe is configured — an unconfigured gate\n // carries no cache field at all (the no-dedupe shape).\n return config.cacheTtlMs !== undefined\n ? { ...base, cache: initCache<V>() }\n : base;\n }\n\n return {\n init,\n input: (state, value, at) => input(config, state, value, at),\n onFlush: (state, at) => onFlush(config, state, at),\n subs: (state, id) => subsFor(config, state, id),\n };\n}\n\n/**\n * The settle-timer wiring, RE-EXPORTED from `../deadline` (not redrawn) so the\n * timer lifecycle stays owned there. Consolidated into one `export ... from`:\n *\n * - `subscribeThrottledInput` (= `../deadline`'s `subscribeDeadline`) — the\n * `subscribe[\"deadline\"]` cell. Arms a one-shot timer for `max(0, atMs -\n * now)`, dispatches the deadline Msg, returns a cleanup that clears it. The\n * consumer assigns it: `subscribe: { deadline: subscribeThrottledInput }`.\n * - `throttledInputSettled` (= `../deadline`'s `deadlineExceeded`) +\n * `ThrottledInputSettled` (= `DeadlineExceeded`) — the settle-timer Msg\n * constructor and type the consumer handles via `onFlush`. Sharing one\n * constructor with the subscribe cell keeps the two from drifting; the\n * reducer reads `msg.atMs` as the `at` it threads into `onFlush`.\n */\nexport {\n type DeadlineExceeded as ThrottledInputSettled,\n deadlineExceeded as throttledInputSettled,\n subscribeDeadline as subscribeThrottledInput,\n} from \"../../resilience/deadline\";\n"]}
@@ -1,4 +1,4 @@
1
- import { S as Sub } from './core-Co0LWkIA.js';
1
+ import { S as Sub } from './core-DnzqWy6u.js';
2
2
 
3
3
  type SubscribeHandler<S extends Sub, M, Ctx> = (sub: S, ctx: Ctx, dispatch: (msg: M) => void) => () => void;
4
4
 
@@ -1,73 +1,149 @@
1
- import { S as Store } from '../runtime-types-CNLmhWif.js';
1
+ import { Q as QueueItem } from '../index-CSyMYDAB.js';
2
+ export { E as EnqueueInput, a as QueueItemStatus, c as createQueue } from '../index-CSyMYDAB.js';
3
+ import '../runtime-types-CMF13BBh.js';
2
4
  import 'better-result';
3
- import '../core-Co0LWkIA.js';
5
+ import '../core-DnzqWy6u.js';
4
6
  import 'zod';
5
7
 
6
8
  /**
7
- * @packageDocumentation
8
- * @demlik/tea/work-queue — substrate-agnostic work-queue lifecycle on `Store<S>`.
9
+ * internal/work-queue/adapter — the verb seam over the pure queue ops.
9
10
  *
10
- * Two public surfaces, one shape:
11
- * - `createQueue(store)` (this file) is the in-process adapter — it binds the
12
- * pure ops to an injected `Store` and runs `load → mutate → save`.
13
- * - `@demlik/tea/work-queue/ops` (`./ops`) is the BLESSED, importable surface
14
- * of those same pure ops. L2 compositions that own their own Model slice
15
- * (`monitored-run`, `idempotent-intake`, …) import the ops directly and
16
- * delegate status flips to them instead of re-rolling the transitions.
17
- * Both routes call the identical ops, so the lifecycle rules live in exactly
18
- * one place. This mirrors `@demlik/tea/do`'s one-shape-per-package rule.
11
+ * The pure ops in `./ops` are the BLESSED transitions, but their names and
12
+ * argument tuples (`enqueueOp(queue, input, now, id)`, `claimNextOp(queue,
13
+ * now)`, …) and their `{ next, item }` / `{ next, changed }` result shapes are
14
+ * the STORE's vocabulary, not the consumer's. An L2 composition that owns a
15
+ * `QueueItem<I>[]` slice (`monitored-run`, `saga`, `idempotent-intake`,
16
+ * `fan-out`) used to import those ops by name and call them directly, so a
17
+ * change to the op surface — or to `QueueItem`'s fields — cascaded to every
18
+ * call site.
19
19
  *
20
- * The package is generic in the input payload `I` (audit-specific fields go
21
- * here in the extension host). `output` is a free-form side-channel correlation
22
- * token (a backend id, URL, trace id) — typed as `string` because that's its
23
- * only honest type. Consumers that need structured per-item data persist it in
24
- * their own store and put the foreign-key string in `output`.
20
+ * `QueueAdapter<I>` is the insulating interface: four VERBS (`enqueue` /
21
+ * `claim` / `markDone` / `patch`) that consumers depend on instead of the raw
22
+ * ops. The verbs keep the ops' pure `(queue, …) => { next, … }` contract — they
23
+ * are pure array transforms, no I/O, no `Date.now` (the clock is injected as
24
+ * `now`, exactly as the ops require it) — so a consumer folding the adapter
25
+ * through its reducer stays inside invariant 2 (pure transitions).
26
+ *
27
+ * `queueAdapter<I>()` is the canonical implementation, a thin binding of the
28
+ * blessed ops. Because the verbs are the only surface consumers touch, a
29
+ * `QueueItem` shape change (a new field, a renamed status, a different op
30
+ * signature) is now absorbed HERE — re-bind the verb once — rather than at the
31
+ * 4 consumer call sites. The `patch` verb deliberately takes the same
32
+ * `(item) => item` closure `patchItemOp` does, so the one place a `QueueItem`
33
+ * literal is spread stays the consumer's patch closure, never a re-rolled
34
+ * record.
35
+ *
36
+ * This is an INTERNAL seam (no public-API port): consumers import the adapter
37
+ * from this subpath the same way they imported the ops. The ops remain
38
+ * exported for the in-process `createQueue` adapter (`./index`) and for any
39
+ * call site that genuinely wants the op directly.
25
40
  */
26
41
 
27
- type QueueItemStatus = "pending" | "running" | "done" | "failed" | "cancelled";
28
42
  /**
29
- * A single queue entry. Every field is `readonly`: a persisted slice is
30
- * immutable, so a transition returns a NEW item (the ops always spread —
31
- * `{ ...item, status: … }`) rather than mutating in place. This type-enforces
32
- * the durability invariant the consumers already honor by convention, and
33
- * keeps a slice round-trippable through JSON unchanged across a reload.
43
+ * The verb interface over a `QueueItem<I>[]` slice. Each verb mirrors a blessed
44
+ * op's pure contract but speaks the consumer's lifecycle vocabulary, so the
45
+ * consumer never names a `*Op` function or reaches into a `QueueItem` field it
46
+ * did not put there.
34
47
  */
35
- interface QueueItem<I> {
36
- readonly id: string;
37
- readonly status: QueueItemStatus;
38
- readonly input: I;
39
- readonly enqueuedAt: number;
40
- readonly startedAt?: number;
41
- readonly finishedAt?: number;
42
- readonly output?: string;
43
- readonly error?: string;
48
+ interface QueueAdapter<I> {
49
+ /** Append a new `pending` item stamped `now` under `id`. */
50
+ enqueue(queue: readonly QueueItem<I>[], input: I, now: number, id: string): {
51
+ next: QueueItem<I>[];
52
+ item: QueueItem<I>;
53
+ };
54
+ /**
55
+ * Claim the first `pending` item — flip it `running`, stamp `startedAt` to
56
+ * `now` — or `null` if nothing is pending.
57
+ */
58
+ claim(queue: readonly QueueItem<I>[], now: number): {
59
+ next: QueueItem<I>[];
60
+ claimed: QueueItem<I>;
61
+ } | null;
62
+ /** Drop the item `id` from the queue (completed runs leave the queue). */
63
+ markDone(queue: readonly QueueItem<I>[], id: string): {
64
+ next: QueueItem<I>[];
65
+ changed: boolean;
66
+ };
67
+ /**
68
+ * Single-item transition: replace the item `id` with `patch(item)`. The
69
+ * closure is the only place a `QueueItem` literal is constructed, so the
70
+ * field shape stays out of the consumer's hands except through this verb.
71
+ */
72
+ patch(queue: readonly QueueItem<I>[], id: string, patch: (item: QueueItem<I>) => QueueItem<I>): {
73
+ next: QueueItem<I>[];
74
+ changed: boolean;
75
+ };
44
76
  }
45
77
  /**
46
- * Caller-facing enqueue payload. Just `I` today — kept named so future
47
- * variants (priority, deferUntil, …) can grow without breaking callers.
78
+ * The canonical `QueueAdapter<I>`, binding each verb to its blessed op. Pure
79
+ * and stateless — call once at module scope in a consumer and fold its verbs
80
+ * through the reducer. A `QueueItem` shape change is absorbed by re-binding a
81
+ * verb here, not at the consumers.
48
82
  */
49
- type EnqueueInput<I> = I;
83
+ declare function queueAdapter<I>(): QueueAdapter<I>;
84
+
50
85
  /**
51
- * Adapter that binds the pure ops to an injected `Store<QueueItem<I>[]>`.
86
+ * Pure queue-lifecycle ops over `QueueItem<I>[]` — the BLESSED delegation
87
+ * surface for this package.
88
+ *
89
+ * Each op is `(queue, ...args) => { next, result? }`. No I/O, no Date.now
90
+ * indirection beyond a plain call site — the adapter in `./index.ts` injects
91
+ * `Store<QueueItem<I>[]>` and orchestrates `load → mutate → save`.
52
92
  *
53
- * `load → mutate → save` is the only durability discipline this package
54
- * imposes. The store decides what "save" means (chrome.storage, KV, DO
55
- * storage, in-memory) — that decision belongs at the caller.
93
+ * Substrate-agnostic by construction: nothing here references chrome.storage,
94
+ * Cloudflare, or any concrete persistence layer. The audit-specific shape
95
+ * (journeyId, projectId, ...) is lifted into the caller's `I` parameter.
56
96
  *
57
- * Ops that don't change the queue (e.g. `markDone` on an unknown id) skip the
58
- * save call so the underlying store doesn't observe a write churn.
97
+ * Importable two ways. The `createQueue(...)` adapter in `./index.ts` binds
98
+ * these ops to a `Store` for in-process use (same one-shape-per-package rule
99
+ * as `@demlik/tea/do`). L2 compositions that own their own Model slice
100
+ * (`monitored-run`, `idempotent-intake`, …) instead reach these ops directly
101
+ * from `internal/work-queue/ops`, so a status flip is delegated
102
+ * here rather than re-rolled per call site.
103
+ */
104
+
105
+ /** Append a new pending item. Returns the new queue and the created item. */
106
+ declare function enqueueOp<I>(queue: readonly QueueItem<I>[], input: I, now: number, id: string): {
107
+ next: QueueItem<I>[];
108
+ item: QueueItem<I>;
109
+ };
110
+ /**
111
+ * Claim the first pending item by flipping it to `running` and stamping
112
+ * `startedAt`. Returns the new queue and the claimed item, or `null` if no
113
+ * pending item exists.
59
114
  */
60
- declare function createQueue<I>(store: Store<QueueItem<I>[]>): {
61
- enqueue: (input: EnqueueInput<I>) => Promise<QueueItem<I>>;
62
- claimNext: () => Promise<QueueItem<I> | null>;
63
- markDone: (id: string) => Promise<void>;
64
- markFailed: (id: string, error: string) => Promise<void>;
65
- markCancelled: (id: string) => Promise<void>;
66
- resetRunningToPending: () => Promise<void>;
67
- removeItem: (id: string) => Promise<void>;
68
- retryItem: (id: string) => Promise<void>;
69
- bindOutput: (id: string, value: string) => Promise<void>;
70
- list: () => Promise<QueueItem<I>[]>;
115
+ declare function claimNextOp<I>(queue: readonly QueueItem<I>[], now: number): {
116
+ next: QueueItem<I>[];
117
+ claimed: QueueItem<I>;
118
+ } | null;
119
+ /**
120
+ * Done items leave the queue — completed runs live wherever the caller
121
+ * persists their output. Returns the new queue (or the original reference if
122
+ * no item matched, so the adapter can skip a save).
123
+ */
124
+ declare function markDoneOp<I>(queue: readonly QueueItem<I>[], id: string): {
125
+ next: QueueItem<I>[];
126
+ changed: boolean;
127
+ };
128
+ /**
129
+ * Generic single-item status transition. Used by `markFailed`,
130
+ * `markCancelled`, `retryItem`, `bindOutput`. The patch closure receives the
131
+ * matched item and returns its replacement; returning the same reference is
132
+ * fine (the adapter only saves on `changed`).
133
+ */
134
+ declare function patchItemOp<I>(queue: readonly QueueItem<I>[], id: string, patch: (item: QueueItem<I>) => QueueItem<I>): {
135
+ next: QueueItem<I>[];
136
+ changed: boolean;
137
+ };
138
+ /** Reset every `running` item back to `pending`, clearing `startedAt`. */
139
+ declare function resetRunningOp<I>(queue: readonly QueueItem<I>[]): {
140
+ next: QueueItem<I>[];
141
+ changed: boolean;
142
+ };
143
+ /** Hard-delete an item regardless of status. */
144
+ declare function removeOp<I>(queue: readonly QueueItem<I>[], id: string): {
145
+ next: QueueItem<I>[];
146
+ changed: boolean;
71
147
  };
72
148
 
73
- export { type EnqueueInput, type QueueItem, type QueueItemStatus, createQueue };
149
+ export { type QueueAdapter, QueueItem, claimNextOp, enqueueOp, markDoneOp, patchItemOp, queueAdapter, removeOp, resetRunningOp };
@@ -1,6 +1,7 @@
1
- import { enqueueOp, claimNextOp, markDoneOp, patchItemOp, resetRunningOp, removeOp } from '../chunk-FV3Z5MBE.js';
1
+ import { enqueueOp, claimNextOp, markDoneOp, patchItemOp, resetRunningOp, removeOp } from '../chunk-TXN2KFHF.js';
2
+ export { claimNextOp, enqueueOp, markDoneOp, patchItemOp, queueAdapter, removeOp, resetRunningOp } from '../chunk-TXN2KFHF.js';
2
3
 
3
- // src/work-queue/index.ts
4
+ // src/internal/work-queue/index.ts
4
5
  function genId() {
5
6
  return globalThis.crypto?.randomUUID?.() ?? `q_${Date.now()}_${Math.random().toString(36).slice(2)}`;
6
7
  }