@demlik/tea 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (372) hide show
  1. package/README.md +11 -9
  2. package/dist/agent/index.d.ts +637 -45
  3. package/dist/agent/index.js +9 -19
  4. package/dist/{chunk-25LBDCBC.js → chunk-6IQPODUF.js} +2 -2
  5. package/dist/{chunk-25LBDCBC.js.map → chunk-6IQPODUF.js.map} +1 -1
  6. package/dist/chunk-AQ6ZIMEA.js +421 -0
  7. package/dist/chunk-AQ6ZIMEA.js.map +1 -0
  8. package/dist/{chunk-MUUROGIH.js → chunk-BLJ2JQSH.js} +62 -12
  9. package/dist/chunk-BLJ2JQSH.js.map +1 -0
  10. package/dist/{chunk-RH5EFRVJ.js → chunk-F2US5BW6.js} +25 -5
  11. package/dist/chunk-F2US5BW6.js.map +1 -0
  12. package/dist/{batch-window/index.js → chunk-F7FMAWLA.js} +4 -8
  13. package/dist/chunk-F7FMAWLA.js.map +1 -0
  14. package/dist/{chunk-O4MVQTEJ.js → chunk-HUKZQX6U.js} +20 -16
  15. package/dist/chunk-HUKZQX6U.js.map +1 -0
  16. package/dist/{chunk-EWJP3YYP.js → chunk-HWVW4AXC.js} +3 -3
  17. package/dist/chunk-HWVW4AXC.js.map +1 -0
  18. package/dist/{chunk-DMYGQB4O.js → chunk-HYDWG35Q.js} +23 -6
  19. package/dist/chunk-HYDWG35Q.js.map +1 -0
  20. package/dist/{chunk-YUXP55T2.js → chunk-I5MQMJDW.js} +57 -7
  21. package/dist/chunk-I5MQMJDW.js.map +1 -0
  22. package/dist/{chunk-J6527VRQ.js → chunk-LFZUK6J2.js} +3 -3
  23. package/dist/chunk-LFZUK6J2.js.map +1 -0
  24. package/dist/{chunk-ZVJZ72HY.js → chunk-LYLTKJWM.js} +25 -11
  25. package/dist/chunk-LYLTKJWM.js.map +1 -0
  26. package/dist/{chunk-D736QUGF.js → chunk-MYXFNWAJ.js} +4 -5
  27. package/dist/chunk-MYXFNWAJ.js.map +1 -0
  28. package/dist/{chunk-K575PT4S.js → chunk-PR6TB3BL.js} +15 -4
  29. package/dist/chunk-PR6TB3BL.js.map +1 -0
  30. package/dist/chunk-RQULHGYH.js +1804 -0
  31. package/dist/chunk-RQULHGYH.js.map +1 -0
  32. package/dist/{chunk-FV3Z5MBE.js → chunk-TXN2KFHF.js} +14 -4
  33. package/dist/chunk-TXN2KFHF.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-Z2L3LSNV.js +1470 -0
  37. package/dist/chunk-Z2L3LSNV.js.map +1 -0
  38. package/dist/{core-Co0LWkIA.d.ts → core-CTzMJ82M.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 +42 -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-B0-qGQDy.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 +1295 -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/{batch-window/index.d.ts → index-4vZzljCD.d.ts} +7 -12
  55. package/dist/{fan-out/index.d.ts → index-6A7dB8f6.d.ts} +7 -9
  56. package/dist/index-B5BZ-_cT.d.ts +616 -0
  57. package/dist/index-Bc40JWVl.d.ts +131 -0
  58. package/dist/{debounce/index.d.ts → index-DHSUmQTR.d.ts} +7 -7
  59. package/dist/index-DJWIER_3.d.ts +69 -0
  60. package/dist/{snapshot/index.d.ts → index-DMCeMPMJ.d.ts} +15 -78
  61. package/dist/{monitored-run/index.d.ts → index-NjrT3fL2.d.ts} +37 -13
  62. package/dist/{recorder/index.d.ts → index-TvRb1KVf.d.ts} +4 -7
  63. package/dist/{deadline/index.d.ts → index-q0hXFeZ0.d.ts} +155 -9
  64. package/dist/index.d.ts +711 -6
  65. package/dist/index.js +1 -2
  66. package/dist/jev/index.d.ts +634 -0
  67. package/dist/jev/index.js +433 -0
  68. package/dist/jev/index.js.map +1 -0
  69. package/dist/machine-CdIcN2Xm.d.ts +1773 -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 +151 -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/react/index.d.ts +2 -2
  90. package/dist/react/index.js +1 -2
  91. package/dist/react/index.js.map +1 -1
  92. package/dist/resilience/index.d.ts +743 -0
  93. package/dist/resilience/index.js +657 -0
  94. package/dist/resilience/index.js.map +1 -0
  95. package/dist/retry-backoff/index.d.ts +3 -2
  96. package/dist/retry-backoff/index.js +1 -1
  97. package/dist/runtime-types-LWDoi943.d.ts +998 -0
  98. package/dist/testing/index.d.ts +2 -2
  99. package/dist/testing/index.js +1 -2
  100. package/dist/testing/index.js.map +1 -1
  101. package/dist/{throttled-input → timing}/index.d.ts +143 -12
  102. package/dist/{throttled-input → timing}/index.js +57 -12
  103. package/dist/timing/index.js.map +1 -0
  104. package/dist/{types-XS_miRnB.d.ts → types-DP3f5NIl.d.ts} +1 -1
  105. package/dist/work-queue/index.d.ts +130 -54
  106. package/dist/work-queue/index.js +3 -2
  107. package/dist/work-queue/index.js.map +1 -1
  108. package/package.json +45 -218
  109. package/dist/authed-call/index.d.ts +0 -120
  110. package/dist/authed-call/index.js +0 -134
  111. package/dist/authed-call/index.js.map +0 -1
  112. package/dist/await-terminal/index.d.ts +0 -101
  113. package/dist/await-terminal/index.js +0 -76
  114. package/dist/await-terminal/index.js.map +0 -1
  115. package/dist/batch-window/index.js.map +0 -1
  116. package/dist/cache/index.d.ts +0 -152
  117. package/dist/cache/index.js +0 -8
  118. package/dist/chart/index.d.ts +0 -218
  119. package/dist/chart/index.js +0 -16
  120. package/dist/chart/index.js.map +0 -1
  121. package/dist/chart/inspect/index.d.ts +0 -86
  122. package/dist/chart/inspect/index.js +0 -5
  123. package/dist/chart/inspect/react.d.ts +0 -113
  124. package/dist/chart/inspect/react.js +0 -11
  125. package/dist/chart/inspect/react.js.map +0 -1
  126. package/dist/chart/inspect/styles.css +0 -286
  127. package/dist/chart/lane/index.d.ts +0 -362
  128. package/dist/chart/lane/index.js +0 -9
  129. package/dist/chart/lane/index.js.map +0 -1
  130. package/dist/chart/lane/react.d.ts +0 -84
  131. package/dist/chart/lane/react.js +0 -559
  132. package/dist/chart/lane/react.js.map +0 -1
  133. package/dist/chart/lane/server.d.ts +0 -148
  134. package/dist/chart/lane/server.js +0 -209
  135. package/dist/chart/lane/server.js.map +0 -1
  136. package/dist/chart/lane/styles.css +0 -498
  137. package/dist/chart/lane/viewer/assets/abnfDiagram-N423BO3Z-C729LI31.js +0 -1
  138. package/dist/chart/lane/viewer/assets/architectureDiagram-T3A2C74G-C729LI31.js +0 -1
  139. package/dist/chart/lane/viewer/assets/blockDiagram-VBNYF7ZC-C729LI31.js +0 -1
  140. package/dist/chart/lane/viewer/assets/c4Diagram-5PPSVZJV-C729LI31.js +0 -1
  141. package/dist/chart/lane/viewer/assets/chunk-2GRJ4B5K-HdDf8SI3.js +0 -1
  142. package/dist/chart/lane/viewer/assets/chunk-5RXB4S5H-CcNtpUd7.js +0 -231
  143. package/dist/chart/lane/viewer/assets/chunk-5VM5RSS4-BP4fRS_5.js +0 -15
  144. package/dist/chart/lane/viewer/assets/chunk-KBJHAD2P-DZOw7xU6.js +0 -1
  145. package/dist/chart/lane/viewer/assets/chunk-NSK5VX7P-CBCyTZMs.js +0 -128
  146. package/dist/chart/lane/viewer/assets/classDiagram-JCYQIIEL-C729LI31.js +0 -1
  147. package/dist/chart/lane/viewer/assets/classDiagram-v2-OCEON4UE-D4uAiFr8.js +0 -206
  148. package/dist/chart/lane/viewer/assets/cose-bilkent-JH36ORCC-DOwCrGXH.js +0 -1
  149. package/dist/chart/lane/viewer/assets/cynefinDiagram-MW4NZA55-C729LI31.js +0 -1
  150. package/dist/chart/lane/viewer/assets/dagre-K_PewWfS.js +0 -1
  151. package/dist/chart/lane/viewer/assets/dagre-VZM6K2ZE-831qZcA8.js +0 -4
  152. package/dist/chart/lane/viewer/assets/diagram-7IWD3JNH-C729LI31.js +0 -1
  153. package/dist/chart/lane/viewer/assets/diagram-B4RE2ZJO-C729LI31.js +0 -1
  154. package/dist/chart/lane/viewer/assets/diagram-LBJQPF4R-C729LI31.js +0 -1
  155. package/dist/chart/lane/viewer/assets/diagram-Q27KOJAE-C729LI31.js +0 -1
  156. package/dist/chart/lane/viewer/assets/diagram-UB23O5K3-C729LI31.js +0 -1
  157. package/dist/chart/lane/viewer/assets/ebnfDiagram-BXEA7PRR-C729LI31.js +0 -1
  158. package/dist/chart/lane/viewer/assets/erDiagram-JOGREHBK-C729LI31.js +0 -1
  159. package/dist/chart/lane/viewer/assets/flowDiagram-UKHOOZJN-C729LI31.js +0 -1
  160. package/dist/chart/lane/viewer/assets/ganttDiagram-PKOTCBZU-C729LI31.js +0 -1
  161. package/dist/chart/lane/viewer/assets/gitGraphDiagram-DS77QQ5N-C729LI31.js +0 -1
  162. package/dist/chart/lane/viewer/assets/index-9SkH5NA3.css +0 -1
  163. package/dist/chart/lane/viewer/assets/index-Bgt4sXpW.js +0 -195
  164. package/dist/chart/lane/viewer/assets/infoDiagram-6WML65LV-C729LI31.js +0 -1
  165. package/dist/chart/lane/viewer/assets/ishikawaDiagram-WSZJBQD7-C729LI31.js +0 -1
  166. package/dist/chart/lane/viewer/assets/journeyDiagram-NVQOT4AX-C729LI31.js +0 -1
  167. package/dist/chart/lane/viewer/assets/kanban-definition-27J2QSJJ-G7PaPzy-.js +0 -89
  168. package/dist/chart/lane/viewer/assets/katex-DOwCrGXH.js +0 -1
  169. package/dist/chart/lane/viewer/assets/mindmap-definition-FAOFIHXS-CGj9nrVk.js +0 -96
  170. package/dist/chart/lane/viewer/assets/path-fybaL0A-.js +0 -1
  171. package/dist/chart/lane/viewer/assets/pegDiagram-VL7TDLO6-C729LI31.js +0 -1
  172. package/dist/chart/lane/viewer/assets/pieDiagram-7S7Q4E2Y-C729LI31.js +0 -1
  173. package/dist/chart/lane/viewer/assets/quadrantDiagram-CIZ2JOQS-C729LI31.js +0 -1
  174. package/dist/chart/lane/viewer/assets/railroadDiagram-AXF67PYL-C729LI31.js +0 -1
  175. package/dist/chart/lane/viewer/assets/requirementDiagram-LRYGKXZP-C729LI31.js +0 -1
  176. package/dist/chart/lane/viewer/assets/sankeyDiagram-W5VNT64P-C729LI31.js +0 -1
  177. package/dist/chart/lane/viewer/assets/sequenceDiagram-SI44F4Z6-C729LI31.js +0 -1
  178. package/dist/chart/lane/viewer/assets/stateDiagram-OKZ733FA-B_88AzBS.js +0 -1
  179. package/dist/chart/lane/viewer/assets/stateDiagram-v2-UEYNNEHI-CR5gcgq6.js +0 -1
  180. package/dist/chart/lane/viewer/assets/swimlanes-SLNWSIFB-B4xK-rwg.js +0 -1
  181. package/dist/chart/lane/viewer/assets/swimlanesDiagram-ULZ7WXOC-C729LI31.js +0 -1
  182. package/dist/chart/lane/viewer/assets/timeline-definition-Z64GVDOM-CCv52MfY.js +0 -120
  183. package/dist/chart/lane/viewer/assets/vennDiagram-T6HMQDX7-C729LI31.js +0 -1
  184. package/dist/chart/lane/viewer/assets/wardleyDiagram-T6FBY63Y-C729LI31.js +0 -1
  185. package/dist/chart/lane/viewer/assets/xychartDiagram-ELKLHX3M-C729LI31.js +0 -1
  186. package/dist/chart/lane/viewer/index.html +0 -15
  187. package/dist/chart/report/index.d.ts +0 -117
  188. package/dist/chart/report/index.js +0 -32
  189. package/dist/chart/report/index.js.map +0 -1
  190. package/dist/chunk-2YFLOCWX.js +0 -15
  191. package/dist/chunk-2YFLOCWX.js.map +0 -1
  192. package/dist/chunk-3I52QZZ5.js +0 -519
  193. package/dist/chunk-3I52QZZ5.js.map +0 -1
  194. package/dist/chunk-3ZAFFRRB.js +0 -457
  195. package/dist/chunk-3ZAFFRRB.js.map +0 -1
  196. package/dist/chunk-4EQZ76JC.js +0 -33
  197. package/dist/chunk-4EQZ76JC.js.map +0 -1
  198. package/dist/chunk-4KLG43GY.js +0 -223
  199. package/dist/chunk-4KLG43GY.js.map +0 -1
  200. package/dist/chunk-7FRZ2CT2.js +0 -424
  201. package/dist/chunk-7FRZ2CT2.js.map +0 -1
  202. package/dist/chunk-AZZLE7XR.js +0 -62
  203. package/dist/chunk-AZZLE7XR.js.map +0 -1
  204. package/dist/chunk-BYQUGDD3.js +0 -16
  205. package/dist/chunk-BYQUGDD3.js.map +0 -1
  206. package/dist/chunk-CIQG5L42.js +0 -685
  207. package/dist/chunk-CIQG5L42.js.map +0 -1
  208. package/dist/chunk-CLM6ERNO.js +0 -61
  209. package/dist/chunk-CLM6ERNO.js.map +0 -1
  210. package/dist/chunk-COS5MSTO.js +0 -88
  211. package/dist/chunk-COS5MSTO.js.map +0 -1
  212. package/dist/chunk-CRPZJVD2.js +0 -71
  213. package/dist/chunk-CRPZJVD2.js.map +0 -1
  214. package/dist/chunk-D62FDQKE.js +0 -53
  215. package/dist/chunk-D62FDQKE.js.map +0 -1
  216. package/dist/chunk-D736QUGF.js.map +0 -1
  217. package/dist/chunk-DGE4PV4A.js +0 -26
  218. package/dist/chunk-DGE4PV4A.js.map +0 -1
  219. package/dist/chunk-DMYGQB4O.js.map +0 -1
  220. package/dist/chunk-EWJP3YYP.js.map +0 -1
  221. package/dist/chunk-FV3Z5MBE.js.map +0 -1
  222. package/dist/chunk-HCEVHFJ7.js +0 -54
  223. package/dist/chunk-HCEVHFJ7.js.map +0 -1
  224. package/dist/chunk-J6527VRQ.js.map +0 -1
  225. package/dist/chunk-JELSZN25.js +0 -47
  226. package/dist/chunk-JELSZN25.js.map +0 -1
  227. package/dist/chunk-K575PT4S.js.map +0 -1
  228. package/dist/chunk-L57ZOT5K.js +0 -184
  229. package/dist/chunk-L57ZOT5K.js.map +0 -1
  230. package/dist/chunk-MU6MCIAC.js +0 -15
  231. package/dist/chunk-MU6MCIAC.js.map +0 -1
  232. package/dist/chunk-MUUROGIH.js.map +0 -1
  233. package/dist/chunk-NR7BU22N.js +0 -758
  234. package/dist/chunk-NR7BU22N.js.map +0 -1
  235. package/dist/chunk-O4MVQTEJ.js.map +0 -1
  236. package/dist/chunk-OOYD44JI.js +0 -317
  237. package/dist/chunk-OOYD44JI.js.map +0 -1
  238. package/dist/chunk-Q2UM7BXU.js.map +0 -1
  239. package/dist/chunk-RH5EFRVJ.js.map +0 -1
  240. package/dist/chunk-S2EGRPCM.js +0 -47
  241. package/dist/chunk-S2EGRPCM.js.map +0 -1
  242. package/dist/chunk-SINXE47Y.js +0 -55
  243. package/dist/chunk-SINXE47Y.js.map +0 -1
  244. package/dist/chunk-UF4MZSLT.js +0 -53
  245. package/dist/chunk-UF4MZSLT.js.map +0 -1
  246. package/dist/chunk-UOC2PL46.js +0 -13
  247. package/dist/chunk-UOC2PL46.js.map +0 -1
  248. package/dist/chunk-VYFAZN3F.js +0 -372
  249. package/dist/chunk-VYFAZN3F.js.map +0 -1
  250. package/dist/chunk-WRAA7GVZ.js +0 -209
  251. package/dist/chunk-WRAA7GVZ.js.map +0 -1
  252. package/dist/chunk-XGELA764.js +0 -163
  253. package/dist/chunk-XGELA764.js.map +0 -1
  254. package/dist/chunk-YUXP55T2.js.map +0 -1
  255. package/dist/chunk-YWIKDKHY.js +0 -307
  256. package/dist/chunk-YWIKDKHY.js.map +0 -1
  257. package/dist/chunk-ZJ5AOYBH.js +0 -8
  258. package/dist/chunk-ZJ5AOYBH.js.map +0 -1
  259. package/dist/chunk-ZSUUOEPL.js +0 -731
  260. package/dist/chunk-ZSUUOEPL.js.map +0 -1
  261. package/dist/chunk-ZVJZ72HY.js.map +0 -1
  262. package/dist/circuit-breaker/index.d.ts +0 -197
  263. package/dist/circuit-breaker/index.js +0 -3
  264. package/dist/circuit-breaker/index.js.map +0 -1
  265. package/dist/deadline/index.js +0 -6
  266. package/dist/deadline/index.js.map +0 -1
  267. package/dist/debounce/index.js +0 -3
  268. package/dist/debounce/index.js.map +0 -1
  269. package/dist/extension/react.d.ts +0 -121
  270. package/dist/extension/react.js +0 -75
  271. package/dist/extension/react.js.map +0 -1
  272. package/dist/extension/subs/index.d.ts +0 -45
  273. package/dist/extension/subs/index.js +0 -80
  274. package/dist/extension/subs/index.js.map +0 -1
  275. package/dist/extension/test-utils.d.ts +0 -128
  276. package/dist/extension/test-utils.js +0 -277
  277. package/dist/extension/test-utils.js.map +0 -1
  278. package/dist/fan-out/index.js +0 -5
  279. package/dist/fan-out/index.js.map +0 -1
  280. package/dist/fold-BJPdjc9w.d.ts +0 -435
  281. package/dist/graph-B3L5e0N1.d.ts +0 -923
  282. package/dist/idempotency/adapter.d.ts +0 -62
  283. package/dist/idempotency/adapter.js +0 -4
  284. package/dist/idempotency/adapter.js.map +0 -1
  285. package/dist/idempotent-intake/index.d.ts +0 -188
  286. package/dist/idempotent-intake/index.js +0 -7
  287. package/dist/idempotent-intake/index.js.map +0 -1
  288. package/dist/journal/index.d.ts +0 -373
  289. package/dist/journal/index.js +0 -3
  290. package/dist/journal/index.js.map +0 -1
  291. package/dist/llm-call/index.d.ts +0 -311
  292. package/dist/llm-call/index.js +0 -16
  293. package/dist/llm-call/index.js.map +0 -1
  294. package/dist/machine-BtFWQmmq.d.ts +0 -804
  295. package/dist/monitored-run/index.js +0 -10
  296. package/dist/monitored-run/index.js.map +0 -1
  297. package/dist/paginated-walk/index.d.ts +0 -235
  298. package/dist/paginated-walk/index.js +0 -16
  299. package/dist/paginated-walk/index.js.map +0 -1
  300. package/dist/paginator/index.js +0 -3
  301. package/dist/paginator/index.js.map +0 -1
  302. package/dist/pbt/arbitraries/index.d.ts +0 -136
  303. package/dist/pbt/arbitraries/index.js +0 -3
  304. package/dist/pbt/arbitraries/index.js.map +0 -1
  305. package/dist/pbt/runners/index.d.ts +0 -118
  306. package/dist/pbt/runners/index.js +0 -5
  307. package/dist/pbt/runners/index.js.map +0 -1
  308. package/dist/poller/index.d.ts +0 -352
  309. package/dist/poller/index.js +0 -115
  310. package/dist/poller/index.js.map +0 -1
  311. package/dist/prediction/index.d.ts +0 -131
  312. package/dist/prediction/index.js +0 -4
  313. package/dist/prediction/index.js.map +0 -1
  314. package/dist/protocol-B5YmJr0d.d.ts +0 -45
  315. package/dist/pure/index.d.ts +0 -3
  316. package/dist/pure/index.js +0 -4
  317. package/dist/pure/index.js.map +0 -1
  318. package/dist/rate-limit/index.d.ts +0 -115
  319. package/dist/rate-limit/index.js +0 -3
  320. package/dist/rate-limit/index.js.map +0 -1
  321. package/dist/reconciler/index.d.ts +0 -193
  322. package/dist/reconciler/index.js +0 -164
  323. package/dist/reconciler/index.js.map +0 -1
  324. package/dist/recorder/index.js +0 -3
  325. package/dist/recorder/index.js.map +0 -1
  326. package/dist/reducer-4GNR6b8B.d.ts +0 -447
  327. package/dist/resilient-call/index.d.ts +0 -320
  328. package/dist/resilient-call/index.js +0 -14
  329. package/dist/resilient-call/index.js.map +0 -1
  330. package/dist/retry-to-success/index.d.ts +0 -109
  331. package/dist/retry-to-success/index.js +0 -37
  332. package/dist/retry-to-success/index.js.map +0 -1
  333. package/dist/run-pAcmBpah.d.ts +0 -713
  334. package/dist/runtime-types-CNLmhWif.d.ts +0 -517
  335. package/dist/saga/index.d.ts +0 -241
  336. package/dist/saga/index.js +0 -150
  337. package/dist/saga/index.js.map +0 -1
  338. package/dist/samples-B3My5oh2.d.ts +0 -59
  339. package/dist/snapshot/index.js +0 -5
  340. package/dist/snapshot/index.js.map +0 -1
  341. package/dist/subs/index.d.ts +0 -472
  342. package/dist/subs/index.js +0 -7
  343. package/dist/subs/index.js.map +0 -1
  344. package/dist/throttle/index.d.ts +0 -134
  345. package/dist/throttle/index.js +0 -3
  346. package/dist/throttle/index.js.map +0 -1
  347. package/dist/throttled-input/index.js.map +0 -1
  348. package/dist/token-refresh/index.d.ts +0 -216
  349. package/dist/token-refresh/index.js +0 -6
  350. package/dist/token-refresh/index.js.map +0 -1
  351. package/dist/trace-replay/index.js +0 -6
  352. package/dist/trace-replay/index.js.map +0 -1
  353. package/dist/with-deadline/index.d.ts +0 -197
  354. package/dist/with-deadline/index.js +0 -111
  355. package/dist/with-deadline/index.js.map +0 -1
  356. package/dist/with-resilience/index.d.ts +0 -225
  357. package/dist/with-resilience/index.js +0 -240
  358. package/dist/with-resilience/index.js.map +0 -1
  359. package/dist/with-telemetry/index.d.ts +0 -150
  360. package/dist/with-telemetry/index.js +0 -70
  361. package/dist/with-telemetry/index.js.map +0 -1
  362. package/dist/work-queue/adapter.d.ts +0 -84
  363. package/dist/work-queue/adapter.js +0 -4
  364. package/dist/work-queue/adapter.js.map +0 -1
  365. package/dist/work-queue/ops.d.ts +0 -71
  366. package/dist/work-queue/ops.js +0 -3
  367. package/dist/work-queue/ops.js.map +0 -1
  368. package/dist/workflow/index.d.ts +0 -485
  369. package/dist/workflow/index.js +0 -244
  370. package/dist/workflow/index.js.map +0 -1
  371. /package/dist/{cache → paginate}/index.js.map +0 -0
  372. /package/dist/{chart/inspect → persistence}/index.js.map +0 -0
@@ -1,352 +0,0 @@
1
- import { DeadlineSub } from '../deadline/index.js';
2
- import { IdempotencyStore } from '../idempotency/index.js';
3
- import { C as Cmd, S as Sub } from '../core-Co0LWkIA.js';
4
- import { RetryState, AnyRetryPolicy } from '../retry-backoff/index.js';
5
- import '../types-XS_miRnB.js';
6
- import 'zod';
7
-
8
- /**
9
- * @demlik/tea/poller — "poll a source every N ms until a predicate holds, with
10
- * backoff on failure" as a TEA knob: one config object + a few pre-wired hooks
11
- * you spread into your machine.
12
- *
13
- * The recipe (which bricks it composes):
14
- *
15
- * - `../deadline` — the recurring tick is an ABSOLUTE-deadline Sub.
16
- * Each successful tick computes the NEXT absolute
17
- * fire time (`at + everyMs`) and the knob re-arms a
18
- * deadline against it. Absolute (not relative) so a
19
- * poller resumed after a DO eviction / page reload
20
- * fires at the correct wall-clock moment, not
21
- * `everyMs` after the reload (`../deadline`'s late-
22
- * subscribe property).
23
- * - `../retry-backoff` — a failed tick does NOT reschedule on the steady
24
- * cadence; it backs off. The next attempt is armed
25
- * `nextDelayMs(retry, policy)` from now, the retry
26
- * counter advances, and `shouldRetry` decides whether
27
- * the poller keeps trying or gives up. The bound may
28
- * be a COUNT or a wall-clock OUTAGE DURATION — see
29
- * `PollerConfig.retry`; `tickErr`'s `at` is the
30
- * streak clock, so both flow through unchanged.
31
- * - `../idempotency` — successive ticks against a flaky source can deliver
32
- * the SAME observation twice (a retried fetch, a
33
- * duplicate webhook the poll re-reads). `dedupeKey`
34
- * lets the consumer key each tick result; a duplicate
35
- * key is recorded but emits no fresh `onTick` follow-
36
- * up Cmd, so the side effect runs once per distinct
37
- * observation.
38
- *
39
- * Typical wiring (spread the knob's hooks into your machine):
40
- *
41
- * const poll = createPoller<MyState, MyResult>({
42
- * everyMs: 5_000,
43
- * until: (s) => s.poll.lastResult?.status === "ready",
44
- * onTick: () => ({ type: "fetch_status" }),
45
- * retry: { ...defaultRetryPolicy, maxAttempts: 4 },
46
- * });
47
- *
48
- * // Model slice:
49
- * init: (loaded) => [loaded ?? { poll: poll.init(), ... }, []],
50
- *
51
- * // The deadline Sub fires `deadline_exceeded` on the cadence/backoff target;
52
- * // route it to `tick`, the ONLY place the `onTick` fetch is emitted:
53
- * deadline_exceeded: (s) => {
54
- * const [slice, cmds] = poll.tick(s.poll);
55
- * return [{ ...s, poll: slice }, cmds];
56
- * },
57
- *
58
- * // update cells (thread `at` in from the firing Msg / the runtime clock):
59
- * poll_result: (s, m) => {
60
- * const untilHeld = config.until({ ...s, ...folded });
61
- * const [slice, cmds] = poll.tickResult(s.poll, m.result, m.at, untilHeld);
62
- * return [{ ...s, poll: slice }, cmds];
63
- * },
64
- * poll_error: (s, m) => {
65
- * const [slice, cmds] = poll.tickErr(s.poll, m.error, m.at);
66
- * return [{ ...s, poll: slice }, cmds];
67
- * },
68
- *
69
- * // Subs — the knob owns the interval/backoff deadline:
70
- * subscriptions: (s) => poll.subs(s.poll),
71
- *
72
- * The cadence has exactly ONE source: the `everyMs` deadline Sub. `start`,
73
- * `tickResult`, and `tickErr` only RE-ARM the deadline (they emit no cadence
74
- * Cmd); the fetch fires solely from `tick`, which the consumer routes the
75
- * deadline's `deadline_exceeded` Msg to. No verb performs an immediate
76
- * "fire now" observation, so the poller never polls faster than `everyMs`.
77
- *
78
- * The two non-negotiables every knob preserves hold here:
79
- * - **Durable** — `tick`, `lastResult`, `retry`, and the next-fire target all
80
- * live in the Model slice, so a poller survives eviction and resumes its
81
- * cadence from the persisted target.
82
- * - **Replayable** — every transition is a pure verb returning new state; the
83
- * clock is never read inside a verb (the firing Msg carries `at`), and the
84
- * retry RNG is injected ONCE at `createPoller` and threaded internally (no
85
- * verb body names the global RNG). `replay` reconstructs a poll run exactly.
86
- *
87
- * NOT a substrate primitive: it depends only on sibling subpaths
88
- * (`../deadline`, `../retry-backoff`, `../idempotency`) and the core `Cmd` /
89
- * `Sub` types. Consumers reach it via the `@demlik/tea/poller` subpath; the L1
90
- * escape hatch is those three sibling subpaths threaded by hand.
91
- */
92
-
93
- /**
94
- * The poller knob's config — the single object you hand `createPoller`.
95
- *
96
- * `State` is the consumer's WHOLE Model (so `until` can read any field), `R` is
97
- * the shape of one tick observation (`lastResult` carries it forward).
98
- */
99
- interface PollerConfig<State, R> {
100
- /**
101
- * The steady cadence, in milliseconds, between successful ticks. The next
102
- * tick is armed at the absolute target `at + everyMs` (computed from the
103
- * `at` the prior tick's Msg carried), NOT `everyMs` from when the Sub
104
- * happens to be reconciled — so the cadence does not drift across resumes.
105
- */
106
- readonly everyMs: number;
107
- /**
108
- * The stop predicate, read against the consumer's whole Model. When it
109
- * returns `true`, the poller is DONE: `subs` returns `[]` (the timer
110
- * disarms) and no further tick is scheduled. Pure — it must not read the
111
- * clock or mutate; the substrate calls it inside `subscriptions(state)`.
112
- */
113
- readonly until: (state: State) => boolean;
114
- /**
115
- * The effect to run on each tick — the actual "go observe the source" Cmd
116
- * (a fetch, a status read, a list call). The knob returns it from
117
- * `tickResult` when the run continues; the consumer's `interpret` performs
118
- * it and routes the observation back as the next tick-result Msg.
119
- *
120
- * Nullary by contract: a tick carries no per-call argument (the poller
121
- * re-reads the same source every cadence). Capture any target in the Cmd
122
- * literal the consumer's `onTick` returns.
123
- */
124
- readonly onTick: () => Cmd;
125
- /**
126
- * Backoff policy for FAILED ticks. Omit to use `defaultRetryPolicy`
127
- * (full-jitter, 5 attempts). A success resets the retry counter, so the
128
- * policy only governs consecutive failures.
129
- *
130
- * Any bound the `../retry-backoff` union admits: a count (`RetryPolicy`), a
131
- * wall-clock outage budget (`DurationRetryPolicy`), or explicit
132
- * `unbounded: true`. The duration bound needs no extra wiring here — every
133
- * failure already arrives through `tickErr(state, error, at)` carrying the
134
- * instant it was observed, so the streak clock is fed from the Msg's own
135
- * data and the poller never reads a clock of its own (invariant 2).
136
- */
137
- readonly retry?: AnyRetryPolicy;
138
- /**
139
- * Optional dedupe key derived from a tick result. When provided, a result
140
- * whose key was already `seen` records the observation but emits NO fresh
141
- * `onTick` follow-up — the side effect runs once per distinct observation.
142
- * Omit to treat every tick result as fresh (no dedupe). The dedupe store is
143
- * bounded by `dedupeTtlMs` if set; otherwise it grows with distinct keys.
144
- */
145
- readonly dedupeKey?: (result: R) => string;
146
- /**
147
- * TTL for the dedupe store, in milliseconds. Only meaningful when
148
- * `dedupeKey` is set. An observation older than `dedupeTtlMs` is forgotten,
149
- * so a key seen long ago is treated as fresh again. Omit for an unbounded
150
- * dedupe window (every distinct key remembered for the poller's lifetime).
151
- */
152
- readonly dedupeTtlMs?: number;
153
- }
154
- /**
155
- * The bookkeeping every poller phase carries in common, split out so each arm of
156
- * the `PollerState` discriminated union names only what it adds (`nextAtMs` on
157
- * `polling`) — the same discipline the sibling `PaginatorState` uses.
158
- *
159
- * - `tick` — count of ticks recorded so far (success or failure). Doubles
160
- * as an observability cursor and a stable per-tick discriminant.
161
- * - `lastResult` — the most recent successful observation, or `undefined`
162
- * before the first success. `until` typically reads it (via the
163
- * consumer's Model), but the knob never interprets it.
164
- * - `retry` — the `../retry-backoff` counter for consecutive failures.
165
- * Reset to `initRetry()` on every success. Once a failure has
166
- * been recorded it is a `TimedRetryState` (it carries the
167
- * streak's `firstFailureAtMs`, minted from `tickErr`'s `at`);
168
- * the field is typed at the `RetryState` supertype because a
169
- * poller that has never failed has no streak, and a slice
170
- * persisted before the origin existed rehydrates without one.
171
- * - `dedupe` — the `../idempotency` store backing `dedupeKey`. An empty,
172
- * unbounded store when `dedupeKey` is unset (never written).
173
- */
174
- interface PollerCore<R> {
175
- readonly tick: number;
176
- readonly lastResult?: R;
177
- readonly retry: RetryState;
178
- readonly dedupe: IdempotencyStore<true>;
179
- }
180
- /**
181
- * The Model field the poller knob owns — its visible slice (the knob principle:
182
- * managed state lives in the Model, never a closure, so it is durable and
183
- * replayable). A discriminated union on `phase` so the armed-timer target lives
184
- * ONLY where it is meaningful and impossible combinations are unrepresentable
185
- * (pattern 11), the sibling `PaginatorState` idiom:
186
- *
187
- * - `polling` — ticks are scheduled. Carries `nextAtMs`, the ABSOLUTE target
188
- * the interval/backoff timer is armed against (persisted so a
189
- * resumed poller re-arms the same moment), or `null` before the
190
- * first `start` primes it.
191
- * - `done` — `until` held; the poll is finished. Carries NO `nextAtMs` — a
192
- * finished poll can never sit on an armed target.
193
- * - `gave_up` — backoff exhausted `maxAttempts`. Carries NO `nextAtMs` either.
194
- *
195
- * Because only `polling` carries `nextAtMs`, `subs` guards on `phase` alone to
196
- * decide whether a timer is desired — a `done`/`gave_up` state with a live target
197
- * (the old flat record's hazard) simply cannot be built.
198
- */
199
- type PollerState<R> = (PollerCore<R> & {
200
- readonly phase: "polling";
201
- readonly nextAtMs: number | null;
202
- }) | (PollerCore<R> & {
203
- readonly phase: "done";
204
- }) | (PollerCore<R> & {
205
- readonly phase: "gave_up";
206
- });
207
- /**
208
- * The three arms, named — so a verb can DECLARE the phases it can actually
209
- * reach instead of the whole union.
210
- *
211
- * A verb whose return type is the full `PollerState<R>` tells a caller nothing
212
- * about where the poller went, and a caller that needs to know (a chart
213
- * declaring an edge's fan-out; an exhaustive `switch`) has to re-derive it by
214
- * reading the verb's body. Every one of these narrowings is already true of the
215
- * implementation — `start` only ever builds a `polling` arm, `tickResult` never
216
- * builds `gave_up`, `tickErr` never builds `done` — so naming them costs
217
- * nothing at runtime and moves a fact out of the source and into the signature.
218
- */
219
- type PollerPolling<R> = Extract<PollerState<R>, {
220
- phase: "polling";
221
- }>;
222
- type PollerDone<R> = Extract<PollerState<R>, {
223
- phase: "done";
224
- }>;
225
- type PollerGaveUp<R> = Extract<PollerState<R>, {
226
- phase: "gave_up";
227
- }>;
228
- /**
229
- * The poller Sub type — a `../deadline` Sub under a fixed id family. One id per
230
- * knob instance keeps the reconcile pass from churning the timer: the same id
231
- * across transitions means "same armed deadline", even as `nextAtMs` advances.
232
- */
233
- type PollerSub = DeadlineSub;
234
- /**
235
- * The knob handle returned by `createPoller`. Spread its hooks into your
236
- * machine: `init()` seeds the slice, `start(...)` arms the first tick,
237
- * `tickResult` / `tickErr` are the two update verbs, and `subs(...)` returns the
238
- * timer Sub while the poller is live.
239
- *
240
- * Pure-ops + subs module: there is no `handlers(ports)` cell. The poller's I/O
241
- * is the consumer's own `onTick` Cmd run by the consumer's `interpret` — the
242
- * knob never owns a port. (Compare `../deadline`, which ships a `subscribe`
243
- * cell; the poller reuses `../deadline`'s, so it has nothing of its own to
244
- * splice into `interpret`.)
245
- */
246
- interface Poller<State, R> {
247
- /** Seed the Model slice. Idle until `start(...)` arms the first tick. */
248
- init(): PollerPolling<R>;
249
- /**
250
- * Arm the first tick. `at` is the current clock (carried in from the Msg /
251
- * runtime that kicks the poller off — never read inside the verb). Returns
252
- * the slice with the first deadline target set to `at + everyMs` and emits NO
253
- * Cmd. The cadence has ONE source — the deadline Sub — so `start` does not
254
- * perform the first observation itself (an immediate `onTick` here would race
255
- * the timer and poll as fast as the source responds). The first observation
256
- * fires when the deadline crosses `at + everyMs` and the consumer routes
257
- * `deadline_exceeded` → `tick`.
258
- */
259
- start(state: PollerState<R>, at: number): readonly [PollerPolling<R>, readonly Cmd[]];
260
- /**
261
- * Perform one observation — the cadence verb. The consumer routes the
262
- * deadline Sub's `deadline_exceeded` Msg here; `tick` emits the single
263
- * `config.onTick()` Cmd that goes and reads the source. This is the ONLY
264
- * next-tick mechanism: the timer fires, the consumer calls `tick`, the fetch
265
- * runs, and the observation comes back through `tickResult` / `tickErr`
266
- * (which re-arm the next deadline). A no-op on a finished poller — a stale
267
- * deadline fire racing a terminal transition the reconcile pass has not yet
268
- * retired emits nothing.
269
- *
270
- * Takes no `at`: `tick` does not touch the schedule (the just-fired deadline
271
- * is exhausted; the next target is set when the result lands), so it needs no
272
- * clock — keeping it trivially pure.
273
- */
274
- tick(state: PollerState<R>): readonly [PollerState<R>, readonly Cmd[]];
275
- /**
276
- * Record a successful tick observation at clock `at`.
277
- *
278
- * - Resets the retry counter (a success clears consecutive-failure state).
279
- * - Stores `result` as `lastResult` and bumps `tick`.
280
- * - Re-arms the next tick at the absolute target `at + everyMs` (the steady
281
- * cadence). It emits NO cadence `onTick` — the next observation fires from
282
- * the deadline Sub via `tick`, never immediately from a result.
283
- * - Dedupe (opt-in, orthogonal to cadence): when `dedupeKey` is set, a FRESH
284
- * observation emits one `onTick` FOLLOW-UP (the consumer's "run the
285
- * downstream side effect once per distinct observation" hook) and a
286
- * DUPLICATE key records the sighting but suppresses the follow-up. With no
287
- * `dedupeKey`, `tickResult` emits nothing — the cadence `tick` is the only
288
- * `onTick`, so an unconfigured poller never double-fetches.
289
- * - UNLESS `untilHeld` is `true` (the consumer evaluated `config.until`
290
- * against the post-result Model) — then the poller enters `"done"`,
291
- * disarms (`nextAtMs: null`), and emits no Cmd, dedupe or otherwise.
292
- *
293
- * `untilHeld` is passed in rather than computed here because `until` reads
294
- * the consumer's WHOLE Model, which this verb does not hold — the consumer
295
- * evaluates it at the call site after folding `result` into its Model and
296
- * passes the boolean. (`subs` re-checks `phase` to decide arming, so a
297
- * mis-passed `untilHeld` cannot leave a "done" poller arming timers.)
298
- */
299
- tickResult(state: PollerState<R>, result: R, at: number, untilHeld: boolean): readonly [PollerPolling<R> | PollerDone<R>, readonly Cmd[]];
300
- /**
301
- * Record a FAILED tick at clock `at`. Backs off instead of holding the
302
- * steady cadence:
303
- *
304
- * - Advances the retry counter (`recordFailure`).
305
- * - If `shouldRetry` still permits another attempt, arms the next tick at
306
- * `at + nextDelayMs(retry, policy)` (the backoff curve) and emits NO Cmd —
307
- * the retry observation fires when that backoff deadline crosses and the
308
- * consumer routes `deadline_exceeded` → `tick`. The timer is the single
309
- * next-tick mechanism, on the backoff curve here instead of `everyMs`.
310
- * - If backoff is exhausted (`!shouldRetry`), enters `"gave_up"`, disarms
311
- * (`nextAtMs: null`), and emits no Cmd.
312
- *
313
- * `at` is both the backoff anchor AND the streak clock: it is passed to
314
- * `recordFailure` (starting / preserving `firstFailureAtMs`) and to
315
- * `shouldRetry`, so a `DurationRetryPolicy` on `config.retry` is honoured
316
- * with no extra wiring. Under a duration bound the poller keeps retrying
317
- * however many attempts the outage takes, and stops at the declared
318
- * wall-clock budget measured from the streak's FIRST failure.
319
- *
320
- * The backoff jitter uses the `rng` injected ONCE at `createPoller` (default
321
- * `Math.random` at the effect boundary, a fixed value in tests); the verb
322
- * body never names the global RNG, so a poller built with a fixed `rng`
323
- * replays a failure-and-backoff run bit-for-bit.
324
- */
325
- tickErr(state: PollerState<R>, error: unknown, at: number): readonly [PollerPolling<R> | PollerGaveUp<R>, readonly Cmd[]];
326
- /**
327
- * The pre-wired subscriptions cell. Returns the single tick-deadline Sub
328
- * while the poller is `"polling"` with an armed `nextAtMs`; returns `[]`
329
- * once `"done"` / `"gave_up"` (the timer disarms) or before `start`. Assign
330
- * directly: `subscriptions: (s) => poll.subs(s.poll)`.
331
- *
332
- * The `DeadlineSub` it returns is consumed by `../deadline`'s
333
- * `subscribeDeadline` cell, which the consumer wires into `subscribe` —
334
- * the poller does not redraw the timer lifecycle.
335
- */
336
- subs(state: PollerState<R>): readonly Sub[];
337
- }
338
- /**
339
- * Build a poller knob from `config`. Returns the hook bag to spread into a
340
- * machine (see the module doc-comment for the wiring). Pure factory — no clock
341
- * read, no timer; everything happens when the consumer calls the returned
342
- * verbs / `subs` with an injected `at`.
343
- *
344
- * `rng` is injected ONCE here (default `Math.random` at the effect boundary, a
345
- * fixed value in tests) and threaded internally into the backoff jitter. No
346
- * verb body ever names the global RNG, so a poller built with a fixed `rng`
347
- * replays a failure-and-backoff run bit-for-bit (invariant 2: the verbs are
348
- * pure given the injected `rng`).
349
- */
350
- declare function createPoller<State, R>(config: PollerConfig<State, R>, rng?: () => number): Poller<State, R>;
351
-
352
- export { type Poller, type PollerConfig, type PollerDone, type PollerGaveUp, type PollerPolling, type PollerState, type PollerSub, createPoller };
@@ -1,115 +0,0 @@
1
- import { deadlineSub } from '../chunk-DGE4PV4A.js';
2
- import { asRng, defaultRetryPolicy, initRetry, recordFailure, shouldRetry, nextDelayMs } from '../chunk-Q2UM7BXU.js';
3
- import { idempotencyMemory } from '../chunk-BYQUGDD3.js';
4
- import '../chunk-K575PT4S.js';
5
- import '../chunk-2YFLOCWX.js';
6
- import '../chunk-ZSUUOEPL.js';
7
- import '../chunk-OOYD44JI.js';
8
-
9
- // src/poller/index.ts
10
- function pollerSubId(atMs) {
11
- return `poller:tick:${atMs}`;
12
- }
13
- function createPoller(config, rng = Math.random) {
14
- const rngBranded = asRng(rng);
15
- const policy = config.retry ?? defaultRetryPolicy;
16
- const memory = idempotencyMemory();
17
- function init() {
18
- return {
19
- phase: "polling",
20
- tick: 0,
21
- retry: initRetry(),
22
- nextAtMs: null,
23
- // The dedupe store is created regardless; it is only WRITTEN when
24
- // `dedupeKey` is set, so an unconfigured poller carries an inert empty
25
- // store (no per-op cost, JSON-serializable, durable like the rest of
26
- // the slice).
27
- dedupe: memory.init({ ttlMs: config.dedupeTtlMs })
28
- };
29
- }
30
- function start(state, at) {
31
- return [
32
- {
33
- phase: "polling",
34
- tick: state.tick,
35
- lastResult: state.lastResult,
36
- retry: state.retry,
37
- nextAtMs: at + config.everyMs,
38
- dedupe: state.dedupe
39
- },
40
- []
41
- ];
42
- }
43
- function tick(state) {
44
- if (state.phase !== "polling") return [state, []];
45
- return [state, [config.onTick()]];
46
- }
47
- function tickResult(state, result, at, untilHeld) {
48
- const tick2 = state.tick + 1;
49
- if (untilHeld) {
50
- return [
51
- {
52
- phase: "done",
53
- tick: tick2,
54
- lastResult: result,
55
- retry: initRetry(),
56
- dedupe: state.dedupe
57
- },
58
- []
59
- ];
60
- }
61
- const next = {
62
- phase: "polling",
63
- tick: tick2,
64
- lastResult: result,
65
- retry: initRetry(),
66
- nextAtMs: at + config.everyMs,
67
- dedupe: state.dedupe
68
- };
69
- if (!config.dedupeKey) return [next, []];
70
- const key = config.dedupeKey(result);
71
- const suppress = memory.isSeen(next.dedupe, key, at);
72
- const deduped = {
73
- ...next,
74
- dedupe: memory.remember(next.dedupe, key, true, at)
75
- };
76
- return [deduped, suppress ? [] : [config.onTick()]];
77
- }
78
- function tickErr(state, error, at) {
79
- const retry = recordFailure(state.retry, error, at);
80
- const tick2 = state.tick + 1;
81
- if (!shouldRetry(retry, policy, at)) {
82
- return [
83
- {
84
- phase: "gave_up",
85
- tick: tick2,
86
- lastResult: state.lastResult,
87
- retry,
88
- dedupe: state.dedupe
89
- },
90
- []
91
- ];
92
- }
93
- const delayMs = nextDelayMs(retry, policy, rngBranded);
94
- return [
95
- {
96
- phase: "polling",
97
- tick: tick2,
98
- lastResult: state.lastResult,
99
- retry,
100
- nextAtMs: at + delayMs,
101
- dedupe: state.dedupe
102
- },
103
- []
104
- ];
105
- }
106
- function subs(state) {
107
- if (state.phase !== "polling" || state.nextAtMs === null) return [];
108
- return [deadlineSub(pollerSubId(state.nextAtMs), state.nextAtMs)];
109
- }
110
- return { init, start, tick, tickResult, tickErr, subs };
111
- }
112
-
113
- export { createPoller };
114
- //# sourceMappingURL=index.js.map
115
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/poller/index.ts"],"names":["tick"],"mappings":";;;;;;;;;AA6PA,SAAS,YAAY,IAAA,EAAsB;AACzC,EAAA,OAAO,eAAe,IAAI,CAAA,CAAA;AAC5B;AA4IO,SAAS,YAAA,CACd,MAAA,EACA,GAAA,GAAoB,IAAA,CAAK,MAAA,EACP;AAKlB,EAAA,MAAM,UAAA,GAAa,MAAM,GAAG,CAAA;AAC5B,EAAA,MAAM,MAAA,GAAyB,OAAO,KAAA,IAAS,kBAAA;AAK/C,EAAA,MAAM,SAAS,iBAAA,EAAwB;AAEvC,EAAA,SAAS,IAAA,GAAyB;AAChC,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,SAAA;AAAA,MACP,IAAA,EAAM,CAAA;AAAA,MACN,OAAO,SAAA,EAAU;AAAA,MACjB,QAAA,EAAU,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAKV,QAAQ,MAAA,CAAO,IAAA,CAAK,EAAE,KAAA,EAAO,MAAA,CAAO,aAAa;AAAA,KACnD;AAAA,EACF;AAEA,EAAA,SAAS,KAAA,CACP,OACA,EAAA,EAC6C;AAU7C,IAAA,OAAO;AAAA,MACL;AAAA,QACE,KAAA,EAAO,SAAA;AAAA,QACP,MAAM,KAAA,CAAM,IAAA;AAAA,QACZ,YAAY,KAAA,CAAM,UAAA;AAAA,QAClB,OAAO,KAAA,CAAM,KAAA;AAAA,QACb,QAAA,EAAU,KAAK,MAAA,CAAO,OAAA;AAAA,QACtB,QAAQ,KAAA,CAAM;AAAA,OAChB;AAAA,MACA;AAAC,KACH;AAAA,EACF;AAEA,EAAA,SAAS,KACP,KAAA,EAC2C;AAO3C,IAAA,IAAI,MAAM,KAAA,KAAU,SAAA,SAAkB,CAAC,KAAA,EAAO,EAAE,CAAA;AAChD,IAAA,OAAO,CAAC,KAAA,EAAO,CAAC,MAAA,CAAO,MAAA,EAAQ,CAAC,CAAA;AAAA,EAClC;AAEA,EAAA,SAAS,UAAA,CACP,KAAA,EACA,MAAA,EACA,EAAA,EACA,SAAA,EAC6D;AAI7D,IAAA,MAAMA,KAAAA,GAAO,MAAM,IAAA,GAAO,CAAA;AAK1B,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,OAAO;AAAA,QACL;AAAA,UACE,KAAA,EAAO,MAAA;AAAA,UACP,IAAA,EAAAA,KAAAA;AAAA,UACA,UAAA,EAAY,MAAA;AAAA,UACZ,OAAO,SAAA,EAAU;AAAA,UACjB,QAAQ,KAAA,CAAM;AAAA,SAChB;AAAA,QACA;AAAC,OACH;AAAA,IACF;AAOA,IAAA,MAAM,IAAA,GAAyB;AAAA,MAC7B,KAAA,EAAO,SAAA;AAAA,MACP,IAAA,EAAAA,KAAAA;AAAA,MACA,UAAA,EAAY,MAAA;AAAA,MACZ,OAAO,SAAA,EAAU;AAAA,MACjB,QAAA,EAAU,KAAK,MAAA,CAAO,OAAA;AAAA,MACtB,QAAQ,KAAA,CAAM;AAAA,KAChB;AAQA,IAAA,IAAI,CAAC,MAAA,CAAO,SAAA,SAAkB,CAAC,IAAA,EAAM,EAAE,CAAA;AAEvC,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,SAAA,CAAU,MAAM,CAAA;AACnC,IAAA,MAAM,WAAW,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,MAAA,EAAQ,KAAK,EAAE,CAAA;AAKnD,IAAA,MAAM,OAAA,GAA4B;AAAA,MAChC,GAAG,IAAA;AAAA,MACH,QAAQ,MAAA,CAAO,QAAA,CAAS,KAAK,MAAA,EAAQ,GAAA,EAAK,MAAM,EAAE;AAAA,KACpD;AACA,IAAA,OAAO,CAAC,SAAS,QAAA,GAAW,KAAK,CAAC,MAAA,CAAO,MAAA,EAAQ,CAAC,CAAA;AAAA,EACpD;AAEA,EAAA,SAAS,OAAA,CACP,KAAA,EACA,KAAA,EACA,EAAA,EAC+D;AAO/D,IAAA,MAAM,KAAA,GAAQ,aAAA,CAAc,KAAA,CAAM,KAAA,EAAO,OAAO,EAAE,CAAA;AAClD,IAAA,MAAMA,KAAAA,GAAO,MAAM,IAAA,GAAO,CAAA;AAO1B,IAAA,IAAI,CAAC,WAAA,CAAY,KAAA,EAAO,MAAA,EAAQ,EAAE,CAAA,EAAG;AACnC,MAAA,OAAO;AAAA,QACL;AAAA,UACE,KAAA,EAAO,SAAA;AAAA,UACP,IAAA,EAAAA,KAAAA;AAAA,UACA,YAAY,KAAA,CAAM,UAAA;AAAA,UAClB,KAAA;AAAA,UACA,QAAQ,KAAA,CAAM;AAAA,SAChB;AAAA,QACA;AAAC,OACH;AAAA,IACF;AASA,IAAA,MAAM,OAAA,GAAU,WAAA,CAAY,KAAA,EAAO,MAAA,EAAQ,UAAU,CAAA;AACrD,IAAA,OAAO;AAAA,MACL;AAAA,QACE,KAAA,EAAO,SAAA;AAAA,QACP,IAAA,EAAAA,KAAAA;AAAA,QACA,YAAY,KAAA,CAAM,UAAA;AAAA,QAClB,KAAA;AAAA,QACA,UAAU,EAAA,GAAK,OAAA;AAAA,QACf,QAAQ,KAAA,CAAM;AAAA,OAChB;AAAA,MACA;AAAC,KACH;AAAA,EACF;AAEA,EAAA,SAAS,KAAK,KAAA,EAAuC;AAMnD,IAAA,IAAI,MAAM,KAAA,KAAU,SAAA,IAAa,MAAM,QAAA,KAAa,IAAA,SAAa,EAAC;AASlE,IAAA,OAAO,CAAC,YAAY,WAAA,CAAY,KAAA,CAAM,QAAQ,CAAA,EAAG,KAAA,CAAM,QAAQ,CAAC,CAAA;AAAA,EAClE;AAEA,EAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,IAAA,EAAM,UAAA,EAAY,SAAS,IAAA,EAAK;AACxD","file":"index.js","sourcesContent":["/**\n * @demlik/tea/poller — \"poll a source every N ms until a predicate holds, with\n * backoff on failure\" as a TEA knob: one config object + a few pre-wired hooks\n * you spread into your machine.\n *\n * The recipe (which bricks it composes):\n *\n * - `../deadline` — the recurring tick is an ABSOLUTE-deadline Sub.\n * Each successful tick computes the NEXT absolute\n * fire time (`at + everyMs`) and the knob re-arms a\n * deadline against it. Absolute (not relative) so a\n * poller resumed after a DO eviction / page reload\n * fires at the correct wall-clock moment, not\n * `everyMs` after the reload (`../deadline`'s late-\n * subscribe property).\n * - `../retry-backoff` — a failed tick does NOT reschedule on the steady\n * cadence; it backs off. The next attempt is armed\n * `nextDelayMs(retry, policy)` from now, the retry\n * counter advances, and `shouldRetry` decides whether\n * the poller keeps trying or gives up. The bound may\n * be a COUNT or a wall-clock OUTAGE DURATION — see\n * `PollerConfig.retry`; `tickErr`'s `at` is the\n * streak clock, so both flow through unchanged.\n * - `../idempotency` — successive ticks against a flaky source can deliver\n * the SAME observation twice (a retried fetch, a\n * duplicate webhook the poll re-reads). `dedupeKey`\n * lets the consumer key each tick result; a duplicate\n * key is recorded but emits no fresh `onTick` follow-\n * up Cmd, so the side effect runs once per distinct\n * observation.\n *\n * Typical wiring (spread the knob's hooks into your machine):\n *\n * const poll = createPoller<MyState, MyResult>({\n * everyMs: 5_000,\n * until: (s) => s.poll.lastResult?.status === \"ready\",\n * onTick: () => ({ type: \"fetch_status\" }),\n * retry: { ...defaultRetryPolicy, maxAttempts: 4 },\n * });\n *\n * // Model slice:\n * init: (loaded) => [loaded ?? { poll: poll.init(), ... }, []],\n *\n * // The deadline Sub fires `deadline_exceeded` on the cadence/backoff target;\n * // route it to `tick`, the ONLY place the `onTick` fetch is emitted:\n * deadline_exceeded: (s) => {\n * const [slice, cmds] = poll.tick(s.poll);\n * return [{ ...s, poll: slice }, cmds];\n * },\n *\n * // update cells (thread `at` in from the firing Msg / the runtime clock):\n * poll_result: (s, m) => {\n * const untilHeld = config.until({ ...s, ...folded });\n * const [slice, cmds] = poll.tickResult(s.poll, m.result, m.at, untilHeld);\n * return [{ ...s, poll: slice }, cmds];\n * },\n * poll_error: (s, m) => {\n * const [slice, cmds] = poll.tickErr(s.poll, m.error, m.at);\n * return [{ ...s, poll: slice }, cmds];\n * },\n *\n * // Subs — the knob owns the interval/backoff deadline:\n * subscriptions: (s) => poll.subs(s.poll),\n *\n * The cadence has exactly ONE source: the `everyMs` deadline Sub. `start`,\n * `tickResult`, and `tickErr` only RE-ARM the deadline (they emit no cadence\n * Cmd); the fetch fires solely from `tick`, which the consumer routes the\n * deadline's `deadline_exceeded` Msg to. No verb performs an immediate\n * \"fire now\" observation, so the poller never polls faster than `everyMs`.\n *\n * The two non-negotiables every knob preserves hold here:\n * - **Durable** — `tick`, `lastResult`, `retry`, and the next-fire target all\n * live in the Model slice, so a poller survives eviction and resumes its\n * cadence from the persisted target.\n * - **Replayable** — every transition is a pure verb returning new state; the\n * clock is never read inside a verb (the firing Msg carries `at`), and the\n * retry RNG is injected ONCE at `createPoller` and threaded internally (no\n * verb body names the global RNG). `replay` reconstructs a poll run exactly.\n *\n * NOT a substrate primitive: it depends only on sibling subpaths\n * (`../deadline`, `../retry-backoff`, `../idempotency`) and the core `Cmd` /\n * `Sub` types. Consumers reach it via the `@demlik/tea/poller` subpath; the L1\n * escape hatch is those three sibling subpaths threaded by hand.\n */\n\nimport { type DeadlineSub, deadlineSub } from \"../deadline\";\nimport type { IdempotencyStore } from \"../idempotency\";\nimport { idempotencyMemory } from \"../idempotency/adapter\";\nimport type { Cmd, Sub } from \"../index\";\nimport {\n type AnyRetryPolicy,\n asRng,\n defaultRetryPolicy,\n initRetry,\n nextDelayMs,\n type RetryState,\n recordFailure,\n shouldRetry,\n} from \"../retry-backoff\";\n\n/**\n * The poller knob's config — the single object you hand `createPoller`.\n *\n * `State` is the consumer's WHOLE Model (so `until` can read any field), `R` is\n * the shape of one tick observation (`lastResult` carries it forward).\n */\nexport interface PollerConfig<State, R> {\n /**\n * The steady cadence, in milliseconds, between successful ticks. The next\n * tick is armed at the absolute target `at + everyMs` (computed from the\n * `at` the prior tick's Msg carried), NOT `everyMs` from when the Sub\n * happens to be reconciled — so the cadence does not drift across resumes.\n */\n readonly everyMs: number;\n /**\n * The stop predicate, read against the consumer's whole Model. When it\n * returns `true`, the poller is DONE: `subs` returns `[]` (the timer\n * disarms) and no further tick is scheduled. Pure — it must not read the\n * clock or mutate; the substrate calls it inside `subscriptions(state)`.\n */\n readonly until: (state: State) => boolean;\n /**\n * The effect to run on each tick — the actual \"go observe the source\" Cmd\n * (a fetch, a status read, a list call). The knob returns it from\n * `tickResult` when the run continues; the consumer's `interpret` performs\n * it and routes the observation back as the next tick-result Msg.\n *\n * Nullary by contract: a tick carries no per-call argument (the poller\n * re-reads the same source every cadence). Capture any target in the Cmd\n * literal the consumer's `onTick` returns.\n */\n readonly onTick: () => Cmd;\n /**\n * Backoff policy for FAILED ticks. Omit to use `defaultRetryPolicy`\n * (full-jitter, 5 attempts). A success resets the retry counter, so the\n * policy only governs consecutive failures.\n *\n * Any bound the `../retry-backoff` union admits: a count (`RetryPolicy`), a\n * wall-clock outage budget (`DurationRetryPolicy`), or explicit\n * `unbounded: true`. The duration bound needs no extra wiring here — every\n * failure already arrives through `tickErr(state, error, at)` carrying the\n * instant it was observed, so the streak clock is fed from the Msg's own\n * data and the poller never reads a clock of its own (invariant 2).\n */\n readonly retry?: AnyRetryPolicy;\n /**\n * Optional dedupe key derived from a tick result. When provided, a result\n * whose key was already `seen` records the observation but emits NO fresh\n * `onTick` follow-up — the side effect runs once per distinct observation.\n * Omit to treat every tick result as fresh (no dedupe). The dedupe store is\n * bounded by `dedupeTtlMs` if set; otherwise it grows with distinct keys.\n */\n readonly dedupeKey?: (result: R) => string;\n /**\n * TTL for the dedupe store, in milliseconds. Only meaningful when\n * `dedupeKey` is set. An observation older than `dedupeTtlMs` is forgotten,\n * so a key seen long ago is treated as fresh again. Omit for an unbounded\n * dedupe window (every distinct key remembered for the poller's lifetime).\n */\n readonly dedupeTtlMs?: number;\n}\n\n/**\n * The bookkeeping every poller phase carries in common, split out so each arm of\n * the `PollerState` discriminated union names only what it adds (`nextAtMs` on\n * `polling`) — the same discipline the sibling `PaginatorState` uses.\n *\n * - `tick` — count of ticks recorded so far (success or failure). Doubles\n * as an observability cursor and a stable per-tick discriminant.\n * - `lastResult` — the most recent successful observation, or `undefined`\n * before the first success. `until` typically reads it (via the\n * consumer's Model), but the knob never interprets it.\n * - `retry` — the `../retry-backoff` counter for consecutive failures.\n * Reset to `initRetry()` on every success. Once a failure has\n * been recorded it is a `TimedRetryState` (it carries the\n * streak's `firstFailureAtMs`, minted from `tickErr`'s `at`);\n * the field is typed at the `RetryState` supertype because a\n * poller that has never failed has no streak, and a slice\n * persisted before the origin existed rehydrates without one.\n * - `dedupe` — the `../idempotency` store backing `dedupeKey`. An empty,\n * unbounded store when `dedupeKey` is unset (never written).\n */\ninterface PollerCore<R> {\n readonly tick: number;\n readonly lastResult?: R;\n readonly retry: RetryState;\n readonly dedupe: IdempotencyStore<true>;\n}\n\n/**\n * The Model field the poller knob owns — its visible slice (the knob principle:\n * managed state lives in the Model, never a closure, so it is durable and\n * replayable). A discriminated union on `phase` so the armed-timer target lives\n * ONLY where it is meaningful and impossible combinations are unrepresentable\n * (pattern 11), the sibling `PaginatorState` idiom:\n *\n * - `polling` — ticks are scheduled. Carries `nextAtMs`, the ABSOLUTE target\n * the interval/backoff timer is armed against (persisted so a\n * resumed poller re-arms the same moment), or `null` before the\n * first `start` primes it.\n * - `done` — `until` held; the poll is finished. Carries NO `nextAtMs` — a\n * finished poll can never sit on an armed target.\n * - `gave_up` — backoff exhausted `maxAttempts`. Carries NO `nextAtMs` either.\n *\n * Because only `polling` carries `nextAtMs`, `subs` guards on `phase` alone to\n * decide whether a timer is desired — a `done`/`gave_up` state with a live target\n * (the old flat record's hazard) simply cannot be built.\n */\nexport type PollerState<R> =\n | (PollerCore<R> & {\n readonly phase: \"polling\";\n readonly nextAtMs: number | null;\n })\n | (PollerCore<R> & { readonly phase: \"done\" })\n | (PollerCore<R> & { readonly phase: \"gave_up\" });\n\n/**\n * The three arms, named — so a verb can DECLARE the phases it can actually\n * reach instead of the whole union.\n *\n * A verb whose return type is the full `PollerState<R>` tells a caller nothing\n * about where the poller went, and a caller that needs to know (a chart\n * declaring an edge's fan-out; an exhaustive `switch`) has to re-derive it by\n * reading the verb's body. Every one of these narrowings is already true of the\n * implementation — `start` only ever builds a `polling` arm, `tickResult` never\n * builds `gave_up`, `tickErr` never builds `done` — so naming them costs\n * nothing at runtime and moves a fact out of the source and into the signature.\n */\nexport type PollerPolling<R> = Extract<PollerState<R>, { phase: \"polling\" }>;\nexport type PollerDone<R> = Extract<PollerState<R>, { phase: \"done\" }>;\nexport type PollerGaveUp<R> = Extract<PollerState<R>, { phase: \"gave_up\" }>;\n\n/**\n * The poller Sub type — a `../deadline` Sub under a fixed id family. One id per\n * knob instance keeps the reconcile pass from churning the timer: the same id\n * across transitions means \"same armed deadline\", even as `nextAtMs` advances.\n */\nexport type PollerSub = DeadlineSub;\n\n/**\n * The Sub id the poller arms its tick deadline under, keyed on the absolute\n * target. The id ROTATES per target because a one-shot deadline timer is\n * exhausted once it fires and the substrate reconciles subs by `id` alone: a\n * fixed id would leave the fired timer registered and never re-arm, so the\n * cadence would die after exactly one tick. Encoding `atMs` in the id makes each\n * cadence/backoff target a distinct identity — the reconcile pass retires the\n * spent timer and arms the next — while a resumed poller re-arms the SAME id\n * from its persisted `nextAtMs` (eviction is idempotent).\n *\n * A single poller machine arms exactly one tick timer at a time; a consumer\n * running several pollers on one machine namespaces them by composing the knob\n * under distinct slices (a future multi-poller config would thread a prefix).\n */\nfunction pollerSubId(atMs: number): string {\n return `poller:tick:${atMs}`;\n}\n\n/**\n * The knob handle returned by `createPoller`. Spread its hooks into your\n * machine: `init()` seeds the slice, `start(...)` arms the first tick,\n * `tickResult` / `tickErr` are the two update verbs, and `subs(...)` returns the\n * timer Sub while the poller is live.\n *\n * Pure-ops + subs module: there is no `handlers(ports)` cell. The poller's I/O\n * is the consumer's own `onTick` Cmd run by the consumer's `interpret` — the\n * knob never owns a port. (Compare `../deadline`, which ships a `subscribe`\n * cell; the poller reuses `../deadline`'s, so it has nothing of its own to\n * splice into `interpret`.)\n */\nexport interface Poller<\n // State is a phantom-style parameter — present so consumers can spell\n // `Poller<MyState, MyResult>` matching `createPoller<State, R>`. It is\n // consumed by the config's `until` predicate, not by any handle method, so\n // it does not appear in the interface body. Same discipline as\n // `BoundMachine`'s `Ctx`.\n // biome-ignore lint/correctness/noUnusedVariables: phantom type parameter (see above)\n State,\n R,\n> {\n /** Seed the Model slice. Idle until `start(...)` arms the first tick. */\n init(): PollerPolling<R>;\n /**\n * Arm the first tick. `at` is the current clock (carried in from the Msg /\n * runtime that kicks the poller off — never read inside the verb). Returns\n * the slice with the first deadline target set to `at + everyMs` and emits NO\n * Cmd. The cadence has ONE source — the deadline Sub — so `start` does not\n * perform the first observation itself (an immediate `onTick` here would race\n * the timer and poll as fast as the source responds). The first observation\n * fires when the deadline crosses `at + everyMs` and the consumer routes\n * `deadline_exceeded` → `tick`.\n */\n start(\n state: PollerState<R>,\n at: number,\n ): readonly [PollerPolling<R>, readonly Cmd[]];\n /**\n * Perform one observation — the cadence verb. The consumer routes the\n * deadline Sub's `deadline_exceeded` Msg here; `tick` emits the single\n * `config.onTick()` Cmd that goes and reads the source. This is the ONLY\n * next-tick mechanism: the timer fires, the consumer calls `tick`, the fetch\n * runs, and the observation comes back through `tickResult` / `tickErr`\n * (which re-arm the next deadline). A no-op on a finished poller — a stale\n * deadline fire racing a terminal transition the reconcile pass has not yet\n * retired emits nothing.\n *\n * Takes no `at`: `tick` does not touch the schedule (the just-fired deadline\n * is exhausted; the next target is set when the result lands), so it needs no\n * clock — keeping it trivially pure.\n */\n tick(state: PollerState<R>): readonly [PollerState<R>, readonly Cmd[]];\n /**\n * Record a successful tick observation at clock `at`.\n *\n * - Resets the retry counter (a success clears consecutive-failure state).\n * - Stores `result` as `lastResult` and bumps `tick`.\n * - Re-arms the next tick at the absolute target `at + everyMs` (the steady\n * cadence). It emits NO cadence `onTick` — the next observation fires from\n * the deadline Sub via `tick`, never immediately from a result.\n * - Dedupe (opt-in, orthogonal to cadence): when `dedupeKey` is set, a FRESH\n * observation emits one `onTick` FOLLOW-UP (the consumer's \"run the\n * downstream side effect once per distinct observation\" hook) and a\n * DUPLICATE key records the sighting but suppresses the follow-up. With no\n * `dedupeKey`, `tickResult` emits nothing — the cadence `tick` is the only\n * `onTick`, so an unconfigured poller never double-fetches.\n * - UNLESS `untilHeld` is `true` (the consumer evaluated `config.until`\n * against the post-result Model) — then the poller enters `\"done\"`,\n * disarms (`nextAtMs: null`), and emits no Cmd, dedupe or otherwise.\n *\n * `untilHeld` is passed in rather than computed here because `until` reads\n * the consumer's WHOLE Model, which this verb does not hold — the consumer\n * evaluates it at the call site after folding `result` into its Model and\n * passes the boolean. (`subs` re-checks `phase` to decide arming, so a\n * mis-passed `untilHeld` cannot leave a \"done\" poller arming timers.)\n */\n tickResult(\n state: PollerState<R>,\n result: R,\n at: number,\n untilHeld: boolean,\n ): readonly [PollerPolling<R> | PollerDone<R>, readonly Cmd[]];\n /**\n * Record a FAILED tick at clock `at`. Backs off instead of holding the\n * steady cadence:\n *\n * - Advances the retry counter (`recordFailure`).\n * - If `shouldRetry` still permits another attempt, arms the next tick at\n * `at + nextDelayMs(retry, policy)` (the backoff curve) and emits NO Cmd —\n * the retry observation fires when that backoff deadline crosses and the\n * consumer routes `deadline_exceeded` → `tick`. The timer is the single\n * next-tick mechanism, on the backoff curve here instead of `everyMs`.\n * - If backoff is exhausted (`!shouldRetry`), enters `\"gave_up\"`, disarms\n * (`nextAtMs: null`), and emits no Cmd.\n *\n * `at` is both the backoff anchor AND the streak clock: it is passed to\n * `recordFailure` (starting / preserving `firstFailureAtMs`) and to\n * `shouldRetry`, so a `DurationRetryPolicy` on `config.retry` is honoured\n * with no extra wiring. Under a duration bound the poller keeps retrying\n * however many attempts the outage takes, and stops at the declared\n * wall-clock budget measured from the streak's FIRST failure.\n *\n * The backoff jitter uses the `rng` injected ONCE at `createPoller` (default\n * `Math.random` at the effect boundary, a fixed value in tests); the verb\n * body never names the global RNG, so a poller built with a fixed `rng`\n * replays a failure-and-backoff run bit-for-bit.\n */\n tickErr(\n state: PollerState<R>,\n error: unknown,\n at: number,\n ): readonly [PollerPolling<R> | PollerGaveUp<R>, readonly Cmd[]];\n /**\n * The pre-wired subscriptions cell. Returns the single tick-deadline Sub\n * while the poller is `\"polling\"` with an armed `nextAtMs`; returns `[]`\n * once `\"done\"` / `\"gave_up\"` (the timer disarms) or before `start`. Assign\n * directly: `subscriptions: (s) => poll.subs(s.poll)`.\n *\n * The `DeadlineSub` it returns is consumed by `../deadline`'s\n * `subscribeDeadline` cell, which the consumer wires into `subscribe` —\n * the poller does not redraw the timer lifecycle.\n */\n subs(state: PollerState<R>): readonly Sub[];\n}\n\n/**\n * Build a poller knob from `config`. Returns the hook bag to spread into a\n * machine (see the module doc-comment for the wiring). Pure factory — no clock\n * read, no timer; everything happens when the consumer calls the returned\n * verbs / `subs` with an injected `at`.\n *\n * `rng` is injected ONCE here (default `Math.random` at the effect boundary, a\n * fixed value in tests) and threaded internally into the backoff jitter. No\n * verb body ever names the global RNG, so a poller built with a fixed `rng`\n * replays a failure-and-backoff run bit-for-bit (invariant 2: the verbs are\n * pure given the injected `rng`).\n */\nexport function createPoller<State, R>(\n config: PollerConfig<State, R>,\n rng: () => number = Math.random,\n): Poller<State, R> {\n // Re-affirm the `[0, 1)` contract at the seam where the injected generator\n // enters the backoff math (brand from `../retry-backoff`). The factory's\n // public param stays a plain `() => number` so transitive callers are\n // unchanged; `asRng` is the single point where it's branded for `nextDelayMs`.\n const rngBranded = asRng(rng);\n const policy: AnyRetryPolicy = config.retry ?? defaultRetryPolicy;\n\n // The dedupe store seam, bound once. The poller delegates its dedupe-window\n // reads (`memory.isSeen`) and the per-sighting touch (`memory.remember`) to\n // the verbs, so the `IdempotencyStore` shape stays insulated.\n const memory = idempotencyMemory<true>();\n\n function init(): PollerPolling<R> {\n return {\n phase: \"polling\",\n tick: 0,\n retry: initRetry(),\n nextAtMs: null,\n // The dedupe store is created regardless; it is only WRITTEN when\n // `dedupeKey` is set, so an unconfigured poller carries an inert empty\n // store (no per-op cost, JSON-serializable, durable like the rest of\n // the slice).\n dedupe: memory.init({ ttlMs: config.dedupeTtlMs }),\n };\n }\n\n function start(\n state: PollerState<R>,\n at: number,\n ): readonly [PollerPolling<R>, readonly Cmd[]] {\n // Arm the first deadline at `at + everyMs` and emit NOTHING. The cadence has\n // ONE source — the `everyMs` deadline Sub. `start` does not perform the\n // first observation itself: that would be a second, immediate next-tick\n // mechanism racing the timer (it would fire as fast as the source responds,\n // never honoring `everyMs`). The first observation fires when the deadline\n // crosses `at + everyMs` and the consumer routes `deadline_exceeded` → the\n // `tick` verb (which emits `onTick`). No drift, no double-fire. Build the\n // `polling` arm explicitly so a (re)start from a terminal state adopts a live\n // target rather than spreading a terminal arm that never had one.\n return [\n {\n phase: \"polling\",\n tick: state.tick,\n lastResult: state.lastResult,\n retry: state.retry,\n nextAtMs: at + config.everyMs,\n dedupe: state.dedupe,\n },\n [],\n ];\n }\n\n function tick(\n state: PollerState<R>,\n ): readonly [PollerState<R>, readonly Cmd[]] {\n // The deadline fired. Perform the observation — this is the ONLY place the\n // `onTick` Cmd is emitted, so the timer is the single next-tick mechanism.\n // No schedule change here: the just-fired deadline is exhausted, and the\n // NEXT target is re-armed when the observation lands (`tickResult` /\n // `tickErr`). A no-op on a finished poller (a stale fire racing a terminal\n // transition the reconcile pass has not yet retired).\n if (state.phase !== \"polling\") return [state, []];\n return [state, [config.onTick()]];\n }\n\n function tickResult(\n state: PollerState<R>,\n result: R,\n at: number,\n untilHeld: boolean,\n ): readonly [PollerPolling<R> | PollerDone<R>, readonly Cmd[]] {\n // A success always clears consecutive-failure state and records the datum.\n // The next arm is built explicitly (not spread from `state`) so `done`\n // carries no `nextAtMs` — a finished poll can never sit on an armed target.\n const tick = state.tick + 1;\n\n // Stop condition first: if the consumer's `until` held against the\n // post-result Model, we are DONE — disarm and emit nothing, regardless of\n // dedupe (the final observation is still recorded as `lastResult`).\n if (untilHeld) {\n return [\n {\n phase: \"done\",\n tick,\n lastResult: result,\n retry: initRetry(),\n dedupe: state.dedupe,\n },\n [],\n ];\n }\n\n // Re-arm the steady cadence: the next observation fires when THIS deadline\n // (`at + everyMs`) crosses and the consumer routes `deadline_exceeded` →\n // `tick`. `tickResult` itself never emits the cadence `onTick` — the timer\n // is the single next-tick mechanism (recording a result is not a reason to\n // immediately re-fetch; that would poll as fast as the source responds).\n const next: PollerPolling<R> = {\n phase: \"polling\",\n tick,\n lastResult: result,\n retry: initRetry(),\n nextAtMs: at + config.everyMs,\n dedupe: state.dedupe,\n };\n\n // Dedupe is an OPT-IN follow-up, orthogonal to the cadence above. When\n // `dedupeKey` is set, a FRESH observation emits one `onTick` follow-up (the\n // consumer's \"run the downstream side effect once per distinct observation\"\n // hook); a DUPLICATE key records the sighting but suppresses that follow-up.\n // With no `dedupeKey` there is no follow-up at all — the cadence `tick` is\n // the only `onTick`, so an unconfigured poller never double-fetches.\n if (!config.dedupeKey) return [next, []];\n\n const key = config.dedupeKey(result);\n const suppress = memory.isSeen(next.dedupe, key, at);\n // `remember` refreshes the key's TTL clock on every sighting (the\n // idempotency \"touch\" semantics), so a steadily-repeating observation never\n // ages out mid-poll. The stored value is the unit `true` — the poller only\n // needs presence, not a payload.\n const deduped: PollerPolling<R> = {\n ...next,\n dedupe: memory.remember(next.dedupe, key, true, at),\n };\n return [deduped, suppress ? [] : [config.onTick()]];\n }\n\n function tickErr(\n state: PollerState<R>,\n error: unknown,\n at: number,\n ): readonly [PollerPolling<R> | PollerGaveUp<R>, readonly Cmd[]] {\n // `at` is the failure's OBSERVATION instant, already carried in from the\n // Msg — so it doubles as the streak clock a duration bound is measured\n // against. The first failure of a streak sets `firstFailureAtMs`; every\n // later one preserves it, and a success resets to `initRetry()` (dropping\n // the origin with it). Nothing here reads a clock: `at` is Msg data,\n // exactly as `rng` is factory-injected data (invariant 2).\n const retry = recordFailure(state.retry, error, at);\n const tick = state.tick + 1;\n\n // Backoff exhausted → give up: emit nothing. `shouldRetry` reads the\n // just-advanced `retry`, so under a count bound the (maxAttempts)-th\n // failure is the one that stops the poller, and under a duration bound the\n // first failure observed at or past `firstFailureAtMs + maxElapsedMs` is.\n // The `gave_up` arm carries no `nextAtMs` — there is no next attempt to arm.\n if (!shouldRetry(retry, policy, at)) {\n return [\n {\n phase: \"gave_up\",\n tick,\n lastResult: state.lastResult,\n retry,\n dedupe: state.dedupe,\n },\n [],\n ];\n }\n\n // Back off: arm the next attempt at `at + backoff(retry)` rather than the\n // steady cadence, and emit NOTHING. The retry observation fires when this\n // backoff deadline crosses and the consumer routes `deadline_exceeded` →\n // `tick` — the timer is the single next-tick mechanism, on the backoff\n // curve here instead of `everyMs`. `rng` is the value injected once at\n // `createPoller`; the verb body never names the global RNG, so a fixed\n // `rng` makes the backoff target replay bit-for-bit.\n const delayMs = nextDelayMs(retry, policy, rngBranded);\n return [\n {\n phase: \"polling\",\n tick,\n lastResult: state.lastResult,\n retry,\n nextAtMs: at + delayMs,\n dedupe: state.dedupe,\n },\n [],\n ];\n }\n\n function subs(state: PollerState<R>): readonly Sub[] {\n // Arm the tick deadline only while live. `phase` is the authority (so a\n // mis-passed `untilHeld` into `tickResult` cannot resurrect a finished\n // poller); `nextAtMs` is the absolute target `../deadline` translates to a\n // remaining delay at subscribe time — a resumed poller re-arms the exact\n // persisted moment.\n if (state.phase !== \"polling\" || state.nextAtMs === null) return [];\n // The Sub id ROTATES with the target. A one-shot deadline timer is\n // exhausted once it fires, and the substrate's reconcile pass keys identity\n // by `id` alone — a fixed id would leave the fired timer in the registry and\n // NEVER re-arm for the next cadence (cadence dies after one tick). Folding\n // `nextAtMs` into the id makes each successive target a distinct identity:\n // the reconcile pass retires the spent timer (old id absent from the desired\n // set) and arms the next one (new id). A resumed poller re-arms the SAME id\n // from its persisted `nextAtMs`, so eviction is idempotent.\n return [deadlineSub(pollerSubId(state.nextAtMs), state.nextAtMs)];\n }\n\n return { init, start, tick, tickResult, tickErr, subs };\n}\n"]}