@shware/workflow 4.1.1 → 5.0.1

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 (485) hide show
  1. package/README.md +16 -38
  2. package/dist/_virtual/_rolldown/runtime.cjs +1 -2
  3. package/dist/apns-relay.cjs +1 -2
  4. package/dist/apns-relay.d.cts +0 -2
  5. package/dist/apns-relay.d.cts.map +1 -1
  6. package/dist/apns-relay.d.mts +0 -2
  7. package/dist/apns-relay.d.mts.map +1 -1
  8. package/dist/apns-relay.mjs +1 -2
  9. package/dist/apns.cjs +1 -2
  10. package/dist/apns.d.cts +0 -2
  11. package/dist/apns.d.cts.map +1 -1
  12. package/dist/apns.d.mts +0 -2
  13. package/dist/apns.d.mts.map +1 -1
  14. package/dist/apns.mjs +1 -2
  15. package/dist/aws/engine-step.cjs +1 -2
  16. package/dist/aws/engine-step.d.cts +0 -2
  17. package/dist/aws/engine-step.d.cts.map +1 -1
  18. package/dist/aws/engine-step.d.mts +0 -2
  19. package/dist/aws/engine-step.d.mts.map +1 -1
  20. package/dist/aws/engine-step.mjs +1 -2
  21. package/dist/aws/function-url.cjs +1 -2
  22. package/dist/aws/function-url.d.cts +0 -2
  23. package/dist/aws/function-url.d.cts.map +1 -1
  24. package/dist/aws/function-url.d.mts +0 -2
  25. package/dist/aws/function-url.d.mts.map +1 -1
  26. package/dist/aws/function-url.mjs +1 -2
  27. package/dist/aws/index.cjs +3 -5
  28. package/dist/aws/index.cjs.map +1 -1
  29. package/dist/aws/index.d.cts +1 -3
  30. package/dist/aws/index.d.cts.map +1 -1
  31. package/dist/aws/index.d.mts +1 -3
  32. package/dist/aws/index.d.mts.map +1 -1
  33. package/dist/aws/index.mjs +3 -5
  34. package/dist/aws/index.mjs.map +1 -1
  35. package/dist/aws/instances.cjs +2 -3
  36. package/dist/aws/instances.cjs.map +1 -1
  37. package/dist/aws/instances.d.cts +1 -3
  38. package/dist/aws/instances.d.cts.map +1 -1
  39. package/dist/aws/instances.d.mts +1 -3
  40. package/dist/aws/instances.d.mts.map +1 -1
  41. package/dist/aws/instances.mjs +2 -3
  42. package/dist/aws/instances.mjs.map +1 -1
  43. package/dist/aws/lambda-api.cjs +1 -2
  44. package/dist/aws/lambda-api.d.cts +0 -2
  45. package/dist/aws/lambda-api.d.cts.map +1 -1
  46. package/dist/aws/lambda-api.d.mts +0 -2
  47. package/dist/aws/lambda-api.d.mts.map +1 -1
  48. package/dist/aws/lambda-api.mjs +1 -2
  49. package/dist/client.cjs +1 -2
  50. package/dist/client.d.cts +0 -2
  51. package/dist/client.d.cts.map +1 -1
  52. package/dist/client.d.mts +0 -2
  53. package/dist/client.d.mts.map +1 -1
  54. package/dist/client.mjs +1 -2
  55. package/dist/cloudflare/bindings.cjs +1 -2
  56. package/dist/cloudflare/bindings.cjs.map +1 -1
  57. package/dist/cloudflare/bindings.d.cts +0 -21
  58. package/dist/cloudflare/bindings.d.cts.map +1 -1
  59. package/dist/cloudflare/bindings.d.mts +0 -21
  60. package/dist/cloudflare/bindings.d.mts.map +1 -1
  61. package/dist/cloudflare/bindings.mjs +1 -2
  62. package/dist/cloudflare/bindings.mjs.map +1 -1
  63. package/dist/cloudflare/index.cjs +0 -5
  64. package/dist/cloudflare/index.d.cts +4 -6
  65. package/dist/cloudflare/index.d.mts +4 -6
  66. package/dist/cloudflare/index.mjs +2 -4
  67. package/dist/cloudflare/runner.cjs +4 -6
  68. package/dist/cloudflare/runner.cjs.map +1 -1
  69. package/dist/cloudflare/runner.d.cts +3 -5
  70. package/dist/cloudflare/runner.d.cts.map +1 -1
  71. package/dist/cloudflare/runner.d.mts +3 -5
  72. package/dist/cloudflare/runner.d.mts.map +1 -1
  73. package/dist/cloudflare/runner.mjs +4 -6
  74. package/dist/cloudflare/runner.mjs.map +1 -1
  75. package/dist/cloudflare/worker.cjs +1 -2
  76. package/dist/cloudflare/worker.d.cts +0 -2
  77. package/dist/cloudflare/worker.d.cts.map +1 -1
  78. package/dist/cloudflare/worker.d.mts +0 -2
  79. package/dist/cloudflare/worker.d.mts.map +1 -1
  80. package/dist/cloudflare/worker.mjs +1 -2
  81. package/dist/cloudflare/workers.d.cts +0 -2
  82. package/dist/cloudflare/workers.d.cts.map +1 -1
  83. package/dist/cloudflare/workers.d.mts +0 -2
  84. package/dist/cloudflare/workers.d.mts.map +1 -1
  85. package/dist/config.cjs +1 -2
  86. package/dist/config.cjs.map +1 -1
  87. package/dist/config.d.cts +1 -3
  88. package/dist/config.d.cts.map +1 -1
  89. package/dist/config.d.mts +1 -3
  90. package/dist/config.d.mts.map +1 -1
  91. package/dist/config.mjs +1 -2
  92. package/dist/config.mjs.map +1 -1
  93. package/dist/contract.cjs +1 -2
  94. package/dist/contract.d.cts +0 -2
  95. package/dist/contract.d.cts.map +1 -1
  96. package/dist/contract.d.mts +0 -2
  97. package/dist/contract.d.mts.map +1 -1
  98. package/dist/contract.mjs +1 -2
  99. package/dist/dsl/action.cjs +1 -2
  100. package/dist/dsl/action.d.cts +0 -2
  101. package/dist/dsl/action.d.cts.map +1 -1
  102. package/dist/dsl/action.d.mts +0 -2
  103. package/dist/dsl/action.d.mts.map +1 -1
  104. package/dist/dsl/action.mjs +1 -2
  105. package/dist/dsl/base.cjs +1 -2
  106. package/dist/dsl/base.d.cts +0 -2
  107. package/dist/dsl/base.d.cts.map +1 -1
  108. package/dist/dsl/base.d.mts +0 -2
  109. package/dist/dsl/base.d.mts.map +1 -1
  110. package/dist/dsl/base.mjs +1 -2
  111. package/dist/dsl/bundle.cjs +1 -2
  112. package/dist/dsl/bundle.d.cts +0 -2
  113. package/dist/dsl/bundle.d.cts.map +1 -1
  114. package/dist/dsl/bundle.d.mts +0 -2
  115. package/dist/dsl/bundle.d.mts.map +1 -1
  116. package/dist/dsl/bundle.mjs +1 -2
  117. package/dist/dsl/condition.cjs +1 -2
  118. package/dist/dsl/condition.d.cts +0 -2
  119. package/dist/dsl/condition.d.cts.map +1 -1
  120. package/dist/dsl/condition.d.mts +0 -2
  121. package/dist/dsl/condition.d.mts.map +1 -1
  122. package/dist/dsl/condition.mjs +1 -2
  123. package/dist/dsl/flow.cjs +1 -2
  124. package/dist/dsl/flow.d.cts +0 -2
  125. package/dist/dsl/flow.d.cts.map +1 -1
  126. package/dist/dsl/flow.d.mts +0 -2
  127. package/dist/dsl/flow.d.mts.map +1 -1
  128. package/dist/dsl/flow.mjs +1 -2
  129. package/dist/dsl/refs.cjs +1 -2
  130. package/dist/dsl/refs.d.cts +0 -2
  131. package/dist/dsl/refs.d.cts.map +1 -1
  132. package/dist/dsl/refs.d.mts +0 -2
  133. package/dist/dsl/refs.d.mts.map +1 -1
  134. package/dist/dsl/refs.mjs +1 -2
  135. package/dist/dsl/template.cjs +1 -2
  136. package/dist/dsl/template.d.cts +0 -2
  137. package/dist/dsl/template.d.cts.map +1 -1
  138. package/dist/dsl/template.d.mts +0 -2
  139. package/dist/dsl/template.d.mts.map +1 -1
  140. package/dist/dsl/template.mjs +1 -2
  141. package/dist/dsl/trigger.cjs +1 -2
  142. package/dist/dsl/trigger.d.cts +0 -2
  143. package/dist/dsl/trigger.d.cts.map +1 -1
  144. package/dist/dsl/trigger.d.mts +0 -2
  145. package/dist/dsl/trigger.d.mts.map +1 -1
  146. package/dist/dsl/trigger.mjs +1 -2
  147. package/dist/dsl/workflow.cjs +1 -2
  148. package/dist/dsl/workflow.d.cts +0 -2
  149. package/dist/dsl/workflow.d.cts.map +1 -1
  150. package/dist/dsl/workflow.d.mts +0 -2
  151. package/dist/dsl/workflow.d.mts.map +1 -1
  152. package/dist/dsl/workflow.mjs +1 -2
  153. package/dist/email-context.cjs +1 -2
  154. package/dist/email-context.d.cts +0 -2
  155. package/dist/email-context.d.cts.map +1 -1
  156. package/dist/email-context.d.mts +0 -2
  157. package/dist/email-context.d.mts.map +1 -1
  158. package/dist/email-context.mjs +1 -2
  159. package/dist/email-sender.cjs +1 -2
  160. package/dist/email-sender.d.cts +0 -2
  161. package/dist/email-sender.d.cts.map +1 -1
  162. package/dist/email-sender.d.mts +0 -2
  163. package/dist/email-sender.d.mts.map +1 -1
  164. package/dist/email-sender.mjs +1 -2
  165. package/dist/email.cjs +1 -2
  166. package/dist/email.d.cts +0 -2
  167. package/dist/email.d.cts.map +1 -1
  168. package/dist/email.d.mts +0 -2
  169. package/dist/email.d.mts.map +1 -1
  170. package/dist/email.mjs +1 -2
  171. package/dist/engine/actions.cjs +1 -2
  172. package/dist/engine/actions.d.cts +0 -2
  173. package/dist/engine/actions.d.cts.map +1 -1
  174. package/dist/engine/actions.d.mts +0 -2
  175. package/dist/engine/actions.d.mts.map +1 -1
  176. package/dist/engine/actions.mjs +1 -2
  177. package/dist/engine/bucket.cjs +1 -2
  178. package/dist/engine/bucket.d.cts +0 -2
  179. package/dist/engine/bucket.d.cts.map +1 -1
  180. package/dist/engine/bucket.d.mts +0 -2
  181. package/dist/engine/bucket.d.mts.map +1 -1
  182. package/dist/engine/bucket.mjs +1 -2
  183. package/dist/engine/condition.cjs +3 -4
  184. package/dist/engine/condition.cjs.map +1 -1
  185. package/dist/engine/condition.d.cts +1 -3
  186. package/dist/engine/condition.d.cts.map +1 -1
  187. package/dist/engine/condition.d.mts +1 -3
  188. package/dist/engine/condition.d.mts.map +1 -1
  189. package/dist/engine/condition.mjs +3 -4
  190. package/dist/engine/condition.mjs.map +1 -1
  191. package/dist/engine/duration.cjs +1 -2
  192. package/dist/engine/duration.d.cts +0 -2
  193. package/dist/engine/duration.d.cts.map +1 -1
  194. package/dist/engine/duration.d.mts +0 -2
  195. package/dist/engine/duration.d.mts.map +1 -1
  196. package/dist/engine/duration.mjs +1 -2
  197. package/dist/engine/interpreter.cjs +1 -2
  198. package/dist/engine/interpreter.d.cts +0 -2
  199. package/dist/engine/interpreter.d.cts.map +1 -1
  200. package/dist/engine/interpreter.d.mts +0 -2
  201. package/dist/engine/interpreter.d.mts.map +1 -1
  202. package/dist/engine/interpreter.mjs +1 -2
  203. package/dist/engine/ports.d.cts +1 -3
  204. package/dist/engine/ports.d.cts.map +1 -1
  205. package/dist/engine/ports.d.mts +1 -3
  206. package/dist/engine/ports.d.mts.map +1 -1
  207. package/dist/engine/recipient.cjs +1 -2
  208. package/dist/engine/recipient.d.cts +0 -2
  209. package/dist/engine/recipient.d.cts.map +1 -1
  210. package/dist/engine/recipient.d.mts +0 -2
  211. package/dist/engine/recipient.d.mts.map +1 -1
  212. package/dist/engine/recipient.mjs +1 -2
  213. package/dist/engine/retry.cjs +1 -2
  214. package/dist/engine/retry.d.cts +0 -2
  215. package/dist/engine/retry.d.cts.map +1 -1
  216. package/dist/engine/retry.d.mts +0 -2
  217. package/dist/engine/retry.d.mts.map +1 -1
  218. package/dist/engine/retry.mjs +1 -2
  219. package/dist/engine/time-scale.cjs +1 -2
  220. package/dist/engine/time-scale.d.cts +0 -2
  221. package/dist/engine/time-scale.d.cts.map +1 -1
  222. package/dist/engine/time-scale.d.mts +0 -2
  223. package/dist/engine/time-scale.d.mts.map +1 -1
  224. package/dist/engine/time-scale.mjs +1 -2
  225. package/dist/engine/time-window.cjs +1 -2
  226. package/dist/engine/time-window.d.cts +0 -2
  227. package/dist/engine/time-window.d.cts.map +1 -1
  228. package/dist/engine/time-window.d.mts +0 -2
  229. package/dist/engine/time-window.d.mts.map +1 -1
  230. package/dist/engine/time-window.mjs +1 -2
  231. package/dist/fcm.cjs +1 -2
  232. package/dist/fcm.d.cts +0 -2
  233. package/dist/fcm.d.cts.map +1 -1
  234. package/dist/fcm.d.mts +0 -2
  235. package/dist/fcm.d.mts.map +1 -1
  236. package/dist/fcm.mjs +1 -2
  237. package/dist/hash.cjs +1 -2
  238. package/dist/hash.d.cts +0 -2
  239. package/dist/hash.d.cts.map +1 -1
  240. package/dist/hash.d.mts +0 -2
  241. package/dist/hash.d.mts.map +1 -1
  242. package/dist/hash.mjs +1 -2
  243. package/dist/host/auth.cjs +1 -2
  244. package/dist/host/auth.d.cts +0 -2
  245. package/dist/host/auth.d.cts.map +1 -1
  246. package/dist/host/auth.d.mts +0 -2
  247. package/dist/host/auth.d.mts.map +1 -1
  248. package/dist/host/auth.mjs +1 -2
  249. package/dist/host/channels.cjs +1 -2
  250. package/dist/host/channels.d.cts +1 -3
  251. package/dist/host/channels.d.cts.map +1 -1
  252. package/dist/host/channels.d.mts +1 -3
  253. package/dist/host/channels.d.mts.map +1 -1
  254. package/dist/host/channels.mjs +1 -2
  255. package/dist/host/execute.cjs +1 -2
  256. package/dist/host/execute.d.cts +1 -3
  257. package/dist/host/execute.d.cts.map +1 -1
  258. package/dist/host/execute.d.mts +1 -3
  259. package/dist/host/execute.d.mts.map +1 -1
  260. package/dist/host/execute.mjs +1 -2
  261. package/dist/host/fresh-read.cjs +1 -2
  262. package/dist/host/fresh-read.d.cts +0 -2
  263. package/dist/host/fresh-read.d.cts.map +1 -1
  264. package/dist/host/fresh-read.d.mts +0 -2
  265. package/dist/host/fresh-read.d.mts.map +1 -1
  266. package/dist/host/fresh-read.mjs +1 -2
  267. package/dist/host/http.cjs +4 -6
  268. package/dist/host/http.cjs.map +1 -1
  269. package/dist/host/http.d.cts +2 -4
  270. package/dist/host/http.d.cts.map +1 -1
  271. package/dist/host/http.d.mts +2 -4
  272. package/dist/host/http.d.mts.map +1 -1
  273. package/dist/host/http.mjs +4 -6
  274. package/dist/host/http.mjs.map +1 -1
  275. package/dist/host/ingest.cjs +12 -24
  276. package/dist/host/ingest.cjs.map +1 -1
  277. package/dist/host/ingest.d.cts +8 -15
  278. package/dist/host/ingest.d.cts.map +1 -1
  279. package/dist/host/ingest.d.mts +8 -15
  280. package/dist/host/ingest.d.mts.map +1 -1
  281. package/dist/host/ingest.mjs +13 -24
  282. package/dist/host/ingest.mjs.map +1 -1
  283. package/dist/host/journey-host.cjs +3 -6
  284. package/dist/host/journey-host.cjs.map +1 -1
  285. package/dist/host/journey-host.d.cts +6 -8
  286. package/dist/host/journey-host.d.cts.map +1 -1
  287. package/dist/host/journey-host.d.mts +6 -8
  288. package/dist/host/journey-host.d.mts.map +1 -1
  289. package/dist/host/journey-host.mjs +3 -6
  290. package/dist/host/journey-host.mjs.map +1 -1
  291. package/dist/host/platform.cjs +1 -2
  292. package/dist/host/platform.cjs.map +1 -1
  293. package/dist/host/platform.d.cts +1 -9
  294. package/dist/host/platform.d.cts.map +1 -1
  295. package/dist/host/platform.d.mts +1 -9
  296. package/dist/host/platform.d.mts.map +1 -1
  297. package/dist/host/platform.mjs +1 -2
  298. package/dist/host/platform.mjs.map +1 -1
  299. package/dist/host/senders.cjs +1 -2
  300. package/dist/host/senders.d.cts +0 -2
  301. package/dist/host/senders.d.cts.map +1 -1
  302. package/dist/host/senders.d.mts +0 -2
  303. package/dist/host/senders.d.mts.map +1 -1
  304. package/dist/host/senders.mjs +1 -2
  305. package/dist/http2-client.cjs +1 -2
  306. package/dist/http2-client.d.cts +0 -2
  307. package/dist/http2-client.d.cts.map +1 -1
  308. package/dist/http2-client.d.mts +0 -2
  309. package/dist/http2-client.d.mts.map +1 -1
  310. package/dist/http2-client.mjs +1 -2
  311. package/dist/ir.cjs +1 -2
  312. package/dist/ir.d.cts +0 -2
  313. package/dist/ir.d.cts.map +1 -1
  314. package/dist/ir.d.mts +0 -2
  315. package/dist/ir.d.mts.map +1 -1
  316. package/dist/ir.mjs +1 -2
  317. package/dist/jwt.cjs +1 -2
  318. package/dist/jwt.d.cts +0 -2
  319. package/dist/jwt.d.cts.map +1 -1
  320. package/dist/jwt.d.mts +0 -2
  321. package/dist/jwt.d.mts.map +1 -1
  322. package/dist/jwt.mjs +1 -2
  323. package/dist/plan.cjs +1 -2
  324. package/dist/plan.d.cts +0 -2
  325. package/dist/plan.d.cts.map +1 -1
  326. package/dist/plan.d.mts +0 -2
  327. package/dist/plan.d.mts.map +1 -1
  328. package/dist/plan.mjs +1 -2
  329. package/dist/postgres-js.cjs +1 -2
  330. package/dist/postgres-js.d.cts +0 -2
  331. package/dist/postgres-js.d.cts.map +1 -1
  332. package/dist/postgres-js.d.mts +0 -2
  333. package/dist/postgres-js.d.mts.map +1 -1
  334. package/dist/postgres-js.mjs +1 -2
  335. package/dist/provenance.cjs +1 -2
  336. package/dist/provenance.d.cts +0 -2
  337. package/dist/provenance.d.cts.map +1 -1
  338. package/dist/provenance.d.mts +0 -2
  339. package/dist/provenance.d.mts.map +1 -1
  340. package/dist/provenance.mjs +1 -2
  341. package/dist/push.cjs +1 -2
  342. package/dist/push.d.cts +0 -2
  343. package/dist/push.d.cts.map +1 -1
  344. package/dist/push.d.mts +0 -2
  345. package/dist/push.d.mts.map +1 -1
  346. package/dist/push.mjs +1 -2
  347. package/dist/react-email.cjs +1 -2
  348. package/dist/react-email.d.cts +0 -2
  349. package/dist/react-email.d.cts.map +1 -1
  350. package/dist/react-email.d.mts +0 -2
  351. package/dist/react-email.d.mts.map +1 -1
  352. package/dist/react-email.mjs +1 -2
  353. package/dist/reporting/classify.cjs +1 -2
  354. package/dist/reporting/classify.d.cts +0 -2
  355. package/dist/reporting/classify.d.cts.map +1 -1
  356. package/dist/reporting/classify.d.mts +0 -2
  357. package/dist/reporting/classify.d.mts.map +1 -1
  358. package/dist/reporting/classify.mjs +1 -2
  359. package/dist/reporting/observer.cjs +1 -2
  360. package/dist/reporting/observer.d.cts +0 -2
  361. package/dist/reporting/observer.d.cts.map +1 -1
  362. package/dist/reporting/observer.d.mts +0 -2
  363. package/dist/reporting/observer.d.mts.map +1 -1
  364. package/dist/reporting/observer.mjs +1 -2
  365. package/dist/reporting/tracking.cjs +1 -2
  366. package/dist/reporting/tracking.d.cts +0 -2
  367. package/dist/reporting/tracking.d.cts.map +1 -1
  368. package/dist/reporting/tracking.d.mts +0 -2
  369. package/dist/reporting/tracking.d.mts.map +1 -1
  370. package/dist/reporting/tracking.mjs +1 -2
  371. package/dist/runtime.cjs +1 -2
  372. package/dist/runtime.d.cts +0 -2
  373. package/dist/runtime.d.cts.map +1 -1
  374. package/dist/runtime.d.mts +0 -2
  375. package/dist/runtime.d.mts.map +1 -1
  376. package/dist/runtime.mjs +1 -2
  377. package/dist/store/erasure.cjs +1 -2
  378. package/dist/store/erasure.d.cts +0 -2
  379. package/dist/store/erasure.d.cts.map +1 -1
  380. package/dist/store/erasure.d.mts +0 -2
  381. package/dist/store/erasure.d.mts.map +1 -1
  382. package/dist/store/erasure.mjs +1 -2
  383. package/dist/store/facts.cjs +2 -3
  384. package/dist/store/facts.cjs.map +1 -1
  385. package/dist/store/facts.d.cts +0 -2
  386. package/dist/store/facts.d.cts.map +1 -1
  387. package/dist/store/facts.d.mts +0 -2
  388. package/dist/store/facts.d.mts.map +1 -1
  389. package/dist/store/facts.mjs +2 -3
  390. package/dist/store/facts.mjs.map +1 -1
  391. package/dist/store/index.cjs +1 -4
  392. package/dist/store/index.cjs.map +1 -1
  393. package/dist/store/index.d.cts +21 -28
  394. package/dist/store/index.d.cts.map +1 -1
  395. package/dist/store/index.d.mts +21 -28
  396. package/dist/store/index.d.mts.map +1 -1
  397. package/dist/store/index.mjs +2 -4
  398. package/dist/store/index.mjs.map +1 -1
  399. package/dist/store/postgres-reporting.cjs +1 -2
  400. package/dist/store/postgres-reporting.d.cts +0 -2
  401. package/dist/store/postgres-reporting.d.cts.map +1 -1
  402. package/dist/store/postgres-reporting.d.mts +0 -2
  403. package/dist/store/postgres-reporting.d.mts.map +1 -1
  404. package/dist/store/postgres-reporting.mjs +1 -2
  405. package/dist/store/postgres.cjs +3 -5
  406. package/dist/store/postgres.cjs.map +1 -1
  407. package/dist/store/postgres.d.cts +2 -5
  408. package/dist/store/postgres.d.cts.map +1 -1
  409. package/dist/store/postgres.d.mts +2 -5
  410. package/dist/store/postgres.d.mts.map +1 -1
  411. package/dist/store/postgres.mjs +3 -5
  412. package/dist/store/postgres.mjs.map +1 -1
  413. package/dist/store/sql.cjs +1 -2
  414. package/dist/store/sql.d.cts +0 -2
  415. package/dist/store/sql.d.cts.map +1 -1
  416. package/dist/store/sql.d.mts +0 -2
  417. package/dist/store/sql.d.mts.map +1 -1
  418. package/dist/store/sql.mjs +1 -2
  419. package/dist/store/tables.cjs +1 -2
  420. package/dist/store/tables.d.cts +0 -2
  421. package/dist/store/tables.d.cts.map +1 -1
  422. package/dist/store/tables.d.mts +0 -2
  423. package/dist/store/tables.d.mts.map +1 -1
  424. package/dist/store/tables.mjs +1 -2
  425. package/dist/store/user-lock.cjs +1 -2
  426. package/dist/store/user-lock.d.cts +0 -2
  427. package/dist/store/user-lock.d.cts.map +1 -1
  428. package/dist/store/user-lock.d.mts +0 -2
  429. package/dist/store/user-lock.d.mts.map +1 -1
  430. package/dist/store/user-lock.mjs +1 -2
  431. package/dist/templates.cjs +1 -2
  432. package/dist/templates.d.cts +0 -2
  433. package/dist/templates.d.cts.map +1 -1
  434. package/dist/templates.d.mts +0 -2
  435. package/dist/templates.d.mts.map +1 -1
  436. package/dist/templates.mjs +1 -2
  437. package/dist/transports/cloudflare-email.cjs +1 -2
  438. package/dist/transports/cloudflare-email.d.cts +1 -3
  439. package/dist/transports/cloudflare-email.d.cts.map +1 -1
  440. package/dist/transports/cloudflare-email.d.mts +1 -3
  441. package/dist/transports/cloudflare-email.d.mts.map +1 -1
  442. package/dist/transports/cloudflare-email.mjs +1 -2
  443. package/dist/transports/ses.cjs +1 -2
  444. package/dist/transports/ses.d.cts +0 -2
  445. package/dist/transports/ses.d.cts.map +1 -1
  446. package/dist/transports/ses.d.mts +0 -2
  447. package/dist/transports/ses.d.mts.map +1 -1
  448. package/dist/transports/ses.mjs +1 -2
  449. package/dist/transports/sigv4.cjs +1 -2
  450. package/dist/transports/sigv4.d.cts +0 -2
  451. package/dist/transports/sigv4.d.cts.map +1 -1
  452. package/dist/transports/sigv4.d.mts +0 -2
  453. package/dist/transports/sigv4.d.mts.map +1 -1
  454. package/dist/transports/sigv4.mjs +1 -2
  455. package/dist/webhooks.cjs +1 -2
  456. package/dist/webhooks.d.cts +0 -2
  457. package/dist/webhooks.d.cts.map +1 -1
  458. package/dist/webhooks.d.mts +0 -2
  459. package/dist/webhooks.d.mts.map +1 -1
  460. package/dist/webhooks.mjs +1 -2
  461. package/dist/webpush.cjs +1 -2
  462. package/dist/webpush.d.cts +0 -2
  463. package/dist/webpush.d.cts.map +1 -1
  464. package/dist/webpush.d.mts +0 -2
  465. package/dist/webpush.d.mts.map +1 -1
  466. package/dist/webpush.mjs +1 -2
  467. package/package.json +5 -7
  468. package/dist/cloudflare/d1-env.cjs +0 -17
  469. package/dist/cloudflare/d1-env.cjs.map +0 -1
  470. package/dist/cloudflare/d1-env.d.cts +0 -12
  471. package/dist/cloudflare/d1-env.d.cts.map +0 -1
  472. package/dist/cloudflare/d1-env.d.mts +0 -12
  473. package/dist/cloudflare/d1-env.d.mts.map +0 -1
  474. package/dist/cloudflare/d1-env.mjs +0 -16
  475. package/dist/cloudflare/d1-env.mjs.map +0 -1
  476. package/dist/cloudflare/schema.sql +0 -148
  477. package/dist/store/d1.cjs +0 -245
  478. package/dist/store/d1.cjs.map +0 -1
  479. package/dist/store/d1.d.cts +0 -73
  480. package/dist/store/d1.d.cts.map +0 -1
  481. package/dist/store/d1.d.mts +0 -73
  482. package/dist/store/d1.d.mts.map +0 -1
  483. package/dist/store/d1.mjs +0 -244
  484. package/dist/store/d1.mjs.map +0 -1
  485. package/src/cloudflare/schema.sql +0 -148
@@ -12,7 +12,7 @@ import { AwsInstances, RUN_EVENT_TYPE, executionName, isRunInput } from "./insta
12
12
  import { sdkLambdaApi } from "./lambda-api.mjs";
13
13
  import { withDurableExecution } from "@aws/durable-execution-sdk-js";
14
14
  import { AsyncLocalStorage } from "node:async_hooks";
15
- //#region src/aws/index.ts
15
+ // src/aws/index.ts
16
16
  /**
17
17
  * `@shware/workflow/aws` — the journey host as one Lambda durable function behind a Function
18
18
  * URL, on Postgres.
@@ -74,8 +74,7 @@ function journeyLambda(options) {
74
74
  const placeholder = { ...baseEnv };
75
75
  invocation.lease ??= host.lease(placeholder);
76
76
  const { store } = invocation.lease;
77
- const executions = store.executions;
78
- if (executions === void 0) throw new Error("journeyLambda needs a store with an execution registry (PostgresJourneyStore)");
77
+ const { executions } = store;
79
78
  const functionArn = unqualified(context.lambdaContext.invokedFunctionArn);
80
79
  const target = async (contentHash, version) => {
81
80
  if (version !== void 0 && /^\d+$/.test(version)) return `${functionArn}:${version}`;
@@ -166,7 +165,7 @@ function journeyLambda(options) {
166
165
  }
167
166
  const sizes = await context.step("sweep:snapshot", async () => {
168
167
  const { store } = open(context);
169
- return await store.reporting?.snapshotSegments(Date.now()) ?? [];
168
+ return store.reporting.snapshotSegments(Date.now());
170
169
  }, once);
171
170
  return {
172
171
  users,
@@ -192,7 +191,6 @@ function journeyLambda(options) {
192
191
  };
193
192
  return { handler };
194
193
  }
195
- //#endregion
196
194
  export { AwsEngineStep, AwsInstances, RUN_EVENT_TYPE, SWEEP_EVENT_TYPE, bearerMatches, executionName, fromResponse, isFunctionUrlEvent, isRunInput, journeyLambda, sdkLambdaApi, stepRetry, timingSafeEqual, toRequest };
197
195
 
198
196
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/aws/index.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\nimport {\n type DurableContext,\n type DurableExecutionInvocationInput,\n type DurableExecutionInvocationOutput,\n withDurableExecution,\n} from '@aws/durable-execution-sdk-js';\nimport { longestJourneyMs } from '../engine/duration';\nimport type { JourneyOutcome } from '../engine/ports';\nimport { PermanentError } from '../engine/retry';\nimport { executeJourney } from '../host/execute';\nimport { readWithRetry } from '../host/fresh-read';\nimport {\n SWEEP_PAGE_SIZE,\n type SweepResult,\n sweepMaintenance,\n sweepSegmentsPaged,\n} from '../host/ingest';\nimport { type JourneyHostOptions, createJourneyHost } from '../host/journey-host';\nimport type { JourneyEnv } from '../host/platform';\nimport { http2Fetch } from '../http2-client';\nimport type { BundleVersion, ExecutionRegistry, JourneyStore, StoreLease } from '../store/index';\nimport { AwsEngineStep } from './engine-step';\nimport {\n type FunctionUrlEvent,\n type FunctionUrlResult,\n fromResponse,\n isFunctionUrlEvent,\n toRequest,\n} from './function-url';\nimport { AwsInstances, type RunInput, isRunInput } from './instances';\nimport { type LambdaApi, sdkLambdaApi } from './lambda-api';\n\n/**\n * `@shware/workflow/aws` — the journey host as one Lambda durable function behind a Function\n * URL, on Postgres.\n *\n * The one handler tells three inputs apart by the event's top-level shape: a Function URL\n * request (the HTTP API — ingest, identify, devices, tracking, bundle, preview), an internal run\n * (one journey instance: one durable execution, started by an asynchronous invoke of this\n * function's own numbered version), and a scheduled maintenance tick. An HTTP body can never\n * pass for the other two: the Function URL always wraps it.\n *\n * const journeys = journeyLambda({\n * config,\n * env, // parsed from process.env (zod)\n * store: (env, database) => postgresJsStore(env.DATABASE_URL, database),\n * email: (env) => sesEmailTransport({ region: env.AWS_REGION }),\n * });\n * export const handler = journeys.handler;\n */\n\n/** The scheduled tick (EventBridge Scheduler's payload): the segment sweep and maintenance. */\nexport const SWEEP_EVENT_TYPE = '$workflow.sweep';\n\n/** What journeyLambda reads from its env: `JourneyEnv` without the binding it supplies itself. */\nexport type JourneyLambdaEnv = Omit<JourneyEnv, 'JOURNEY' | 'DB' | 'EMAIL'>;\n\nexport interface JourneyLambdaOptions<Env extends JourneyLambdaEnv> extends Omit<\n JourneyHostOptions<Env & JourneyEnv>,\n 'env' | 'store'\n> {\n /** The validated environment (parsed from `process.env` with zod by the app). */\n env: Env;\n /** The Postgres store: AWS needs its execution registry (`postgresJsStore`). */\n store: (env: Env, database: { schema: string }) => JourneyStore | StoreLease;\n /** The Lambda control plane; `@aws-sdk/client-lambda` with the execution role by default. */\n lambda?: LambdaApi;\n /** How long an unconfirmed start is retried (default 12 hours; keep it under the retention). */\n startRetryMs?: number;\n /**\n * How long an erasure waits after stopping an execution before it erases: an invocation\n * running at the stop goes on to its next checkpoint. Set it to at least the function's\n * timeout; 15 minutes (Lambda's maximum) by default.\n */\n stopDrainMs?: number;\n /**\n * The function's `DurableConfig.ExecutionTimeout`, in milliseconds. With it, a workflow that\n * can outlive it (`longestJourneyMs`) fails the handler's creation — a deploy's smoke test —\n * instead of being stopped by the platform midway and recorded as failed.\n */\n executionTimeoutMs?: number;\n}\n\n/**\n * The Lambda invocation context, as far as the handler's signature needs it — declared here so\n * the package's types do not depend on `@types/aws-lambda`. Lambda passes the full object.\n */\nexport interface LambdaContext {\n functionName: string;\n functionVersion: string;\n invokedFunctionArn: string;\n awsRequestId: string;\n getRemainingTimeInMillis(): number;\n}\n\nexport interface JourneyLambda {\n /** Export as the function's handler. */\n handler: (\n event: DurableExecutionInvocationInput,\n context: LambdaContext\n ) => Promise<DurableExecutionInvocationOutput>;\n}\n\ninterface Invocation {\n lease?: Required<StoreLease>;\n}\n\n/** This function's ARN without its qualifier, from the ARN it was invoked under. */\nfunction unqualified(invokedFunctionArn: string): string {\n return invokedFunctionArn.split(':').slice(0, 7).join(':');\n}\n\nconst json = (body: unknown, status = 200) =>\n new Response(JSON.stringify(body), { status, headers: { 'content-type': 'application/json' } });\n\nexport function journeyLambda<Env extends JourneyLambdaEnv>(\n options: JourneyLambdaOptions<Env>\n): JourneyLambda {\n type HostEnv = Env & JourneyEnv;\n const {\n env: baseEnv,\n lambda: lambdaOption,\n startRetryMs,\n stopDrainMs,\n executionTimeoutMs,\n ...hostOptions\n } = options;\n const host = createJourneyHost<HostEnv>(\n { ...hostOptions, store: (env, database) => options.store(env, database) },\n // Node 24's fetch cannot reach APNs (HTTP/2 only): see http2-client.ts for when this can go\n { apnsFetch: http2Fetch() }\n );\n if (executionTimeoutMs !== undefined) {\n const tooLong = host\n .bundle()\n .workflows.filter((workflow) => longestJourneyMs(workflow) > executionTimeoutMs);\n if (tooLong.length > 0) {\n const days = (ms: number) => `${Math.ceil(ms / 86_400_000)} days`;\n throw new RangeError(\n `${tooLong.map((w) => `'${w.id}' can run ${days(longestJourneyMs(w))}`).join(', ')}, ` +\n `longer than the execution timeout (${days(executionTimeoutMs)}): raise ExecutionTimeout (up to 366 days)`\n );\n }\n }\n const lambda = lambdaOption ?? sdkLambdaApi();\n const ownHashes = new Set(host.bundle().workflows.map((workflow) => workflow.contentHash));\n const scope = new AsyncLocalStorage<Invocation>();\n\n /** The version this code was published as: `$LATEST` while developing. */\n const ownVersion = () => process.env.AWS_LAMBDA_FUNCTION_VERSION ?? '$LATEST';\n /** Numbered versions are ordered: the bundle compiled into a later one goes live by itself. */\n const bundleVersion = (): BundleVersion | undefined => {\n const version = ownVersion();\n return /^\\d+$/.test(version) ? { id: version, createdAt: Number(version) } : undefined;\n };\n\n /** The store and the env (with the instance port) of this invocation, opened on first use. */\n const open = (\n context: DurableContext\n ): { store: JourneyStore; env: HostEnv; executions: ExecutionRegistry } => {\n const invocation = scope.getStore();\n if (invocation === undefined) throw new Error('journeyLambda: outside an invocation');\n const placeholder = { ...baseEnv } as unknown as HostEnv;\n invocation.lease ??= host.lease(placeholder);\n const { store } = invocation.lease;\n const executions = store.executions;\n if (executions === undefined) {\n throw new Error(\n 'journeyLambda needs a store with an execution registry (PostgresJourneyStore)'\n );\n }\n const functionArn = unqualified(context.lambdaContext.invokedFunctionArn);\n const target = async (contentHash: string, version?: string): Promise<string> => {\n // An execution runs the code its IR was compiled with: the version whose bundle put the\n // route there, read in the same row as the hash — never a separately read \"live\" version,\n // which a release between the two reads would make another bundle's\n if (version !== undefined && /^\\d+$/.test(version)) return `${functionArn}:${version}`;\n // A forced deploy records no version: only this code's own workflows can run here\n if (ownHashes.has(contentHash)) return `${functionArn}:${ownVersion()}`;\n throw new Error(`no published version is known to carry workflow IR ${contentHash}`);\n };\n const instances = new AwsInstances({\n store,\n executions,\n lambda,\n target,\n ...(startRetryMs === undefined ? {} : { startRetryMs }),\n ...(stopDrainMs === undefined ? {} : { stopDrainMs }),\n });\n return { store, env: { ...baseEnv, JOURNEY: instances }, executions };\n };\n\n const run = async (input: RunInput, context: DurableContext): Promise<JourneyOutcome> => {\n const { store, env, executions } = open(context);\n const { instanceId, params } = input;\n // Only a start the router recorded may run, byte for byte: the function can be invoked by\n // anything its policy lets through, and an input of this shape would otherwise run any\n // workflow for any user. A stopped execution (an erasure) may not come back either. Outside\n // any step — a step would replay the first invocation's \"not stopped\" on every wake — so the\n // execution fails at once on a refusal; only the read itself is retried, briefly, when the\n // database stumbled.\n const record = await readWithRetry(() => executions.get(instanceId), {\n what: 'run entry',\n instanceId,\n });\n if (\n record === undefined ||\n record.stoppedAt !== undefined ||\n record.input !== JSON.stringify(input)\n ) {\n throw new PermanentError('journeyLambda: run input is not a recorded start');\n }\n // Running is the proof the start got through, whatever became of the invoke's response\n await context.step('$workflow:started', async () => {\n await executions.markSubmitted(\n instanceId,\n context.executionContext.durableExecutionArn,\n Date.now()\n );\n });\n return executeJourney(\n {\n instanceId,\n params,\n enteredAtMs: input.enteredAtMs,\n step: new AwsEngineStep(context, store, executions, lambda, params.userId, instanceId),\n },\n host.runParts(env, store, params)\n );\n };\n\n const http = (event: FunctionUrlEvent, context: DurableContext): Promise<FunctionUrlResult> => {\n const serve = async (): Promise<FunctionUrlResult> => {\n const method = event.requestContext.http.method;\n try {\n const { store, env } = open(context);\n const request = toRequest(event);\n // Only the bundle compiled into a version may route: one is never swapped in by hand\n if (new URL(request.url).pathname === '/deploy') {\n return await fromResponse(\n json(\n {\n error:\n 'deploy by publishing a version (POST /bundle/deploy applies its own bundle)',\n },\n 409\n ),\n method\n );\n }\n await host.applyOwnBundle(env, bundleVersion());\n return await fromResponse(await host.handle(request, env, store), method);\n } catch (error) {\n console.error('[workflow] request failed', error);\n return fromResponse(json({ error: 'internal error' }, 500), method);\n }\n };\n // A read (the bundle, a preview, a tracked link or pixel) answers straight from the handler:\n // its body can be large, and a step would checkpoint all of it. A write runs in one step,\n // never retried — the caller is waiting, and retries the request itself\n const method = event.requestContext.http.method.toUpperCase();\n if (method === 'GET' || method === 'HEAD') return serve();\n return context.step('http', serve, { retryStrategy: () => ({ shouldRetry: false }) });\n };\n\n /**\n * The sweep as durable steps, one per page of users: an invocation cut short (the function's\n * timeout) is re-invoked, and the re-invocation replays the pages already checkpointed\n * instead of evaluating everyone again. No step retries on its own — a page that failed is\n * evaluated again by the next tick.\n */\n const sweep = async (context: DurableContext): Promise<SweepResult> => {\n const once = { retryStrategy: () => ({ shouldRetry: false }) };\n await context.step(\n 'sweep:maintain',\n async () => {\n const { store, env } = open(context);\n await host.applyOwnBundle(env, bundleVersion());\n await sweepMaintenance(env, store);\n },\n once\n );\n let users = 0;\n const started: string[] = [];\n let after: string | undefined;\n for (let n = 0; ; n++) {\n const page = await context.step(\n `sweep:page:${n}`,\n async () => {\n const { store, env } = open(context);\n return sweepSegmentsPaged(env, store, { after, limit: SWEEP_PAGE_SIZE });\n },\n once\n );\n users += page.users;\n started.push(...page.started);\n if (!page.more || page.lastUserId === undefined) break;\n after = page.lastUserId;\n }\n const sizes = await context.step(\n 'sweep:snapshot',\n async () => {\n const { store } = open(context);\n return (await store.reporting?.snapshotSegments(Date.now())) ?? [];\n },\n once\n );\n return { users, started, sizes };\n };\n\n const durable = withDurableExecution(async (input: unknown, context: DurableContext) => {\n if (isFunctionUrlEvent(input)) return http(input, context);\n if (isRunInput(input)) return run(input, context);\n if (\n typeof input === 'object' &&\n input !== null &&\n (input as { type?: unknown }).type === SWEEP_EVENT_TYPE\n ) {\n return sweep(context);\n }\n throw new Error('journeyLambda: unrecognized event (not a Function URL request, run or sweep)');\n });\n\n const handler = async (\n event: DurableExecutionInvocationInput,\n context: LambdaContext\n ): Promise<DurableExecutionInvocationOutput> => {\n const invocation: Invocation = {};\n try {\n // The durable wrapper reads the whole context Lambda passed, not just the fields above\n return await scope.run(invocation, () =>\n durable(event, context as Parameters<typeof durable>[1])\n );\n } finally {\n // Outside the durable wrapper: a suspended run returns PENDING without unwinding the\n // handler, so a `finally` in there would never release the connection\n await invocation.lease?.close().catch((error: unknown) => {\n console.error('[workflow] closing the store failed', error);\n });\n }\n };\n\n return { handler };\n}\n\nexport { AwsEngineStep, stepRetry } from './engine-step';\nexport { AwsInstances, RUN_EVENT_TYPE, executionName, isRunInput } from './instances';\nexport type { AwsInstancesOptions, RunInput } from './instances';\nexport { sdkLambdaApi } from './lambda-api';\nexport { bearerMatches, timingSafeEqual } from '../host/auth';\nexport type { Authorize } from '../host/auth';\nexport type { ExecutionState, LambdaApi } from './lambda-api';\nexport { fromResponse, isFunctionUrlEvent, toRequest } from './function-url';\nexport type { FunctionUrlEvent, FunctionUrlResult } from './function-url';\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/aws/index.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\nimport {\n type DurableContext,\n type DurableExecutionInvocationInput,\n type DurableExecutionInvocationOutput,\n withDurableExecution,\n} from '@aws/durable-execution-sdk-js';\nimport { longestJourneyMs } from '../engine/duration';\nimport type { JourneyOutcome } from '../engine/ports';\nimport { PermanentError } from '../engine/retry';\nimport { executeJourney } from '../host/execute';\nimport { readWithRetry } from '../host/fresh-read';\nimport {\n SWEEP_PAGE_SIZE,\n type SweepResult,\n sweepMaintenance,\n sweepSegmentsPaged,\n} from '../host/ingest';\nimport { type JourneyHostOptions, createJourneyHost } from '../host/journey-host';\nimport type { JourneyEnv } from '../host/platform';\nimport { http2Fetch } from '../http2-client';\nimport type { BundleVersion, ExecutionRegistry, JourneyStore, StoreLease } from '../store/index';\nimport { AwsEngineStep } from './engine-step';\nimport {\n type FunctionUrlEvent,\n type FunctionUrlResult,\n fromResponse,\n isFunctionUrlEvent,\n toRequest,\n} from './function-url';\nimport { AwsInstances, type RunInput, isRunInput } from './instances';\nimport { type LambdaApi, sdkLambdaApi } from './lambda-api';\n\n/**\n * `@shware/workflow/aws` — the journey host as one Lambda durable function behind a Function\n * URL, on Postgres.\n *\n * The one handler tells three inputs apart by the event's top-level shape: a Function URL\n * request (the HTTP API — ingest, identify, devices, tracking, bundle, preview), an internal run\n * (one journey instance: one durable execution, started by an asynchronous invoke of this\n * function's own numbered version), and a scheduled maintenance tick. An HTTP body can never\n * pass for the other two: the Function URL always wraps it.\n *\n * const journeys = journeyLambda({\n * config,\n * env, // parsed from process.env (zod)\n * store: (env, database) => postgresJsStore(env.DATABASE_URL, database),\n * email: (env) => sesEmailTransport({ region: env.AWS_REGION }),\n * });\n * export const handler = journeys.handler;\n */\n\n/** The scheduled tick (EventBridge Scheduler's payload): the segment sweep and maintenance. */\nexport const SWEEP_EVENT_TYPE = '$workflow.sweep';\n\n/** What journeyLambda reads from its env: `JourneyEnv` without the binding it supplies itself. */\nexport type JourneyLambdaEnv = Omit<JourneyEnv, 'JOURNEY' | 'DB' | 'EMAIL'>;\n\nexport interface JourneyLambdaOptions<Env extends JourneyLambdaEnv> extends Omit<\n JourneyHostOptions<Env & JourneyEnv>,\n 'env' | 'store'\n> {\n /** The validated environment (parsed from `process.env` with zod by the app). */\n env: Env;\n /** The Postgres store: AWS needs its execution registry (`postgresJsStore`). */\n store: (env: Env, database: { schema: string }) => JourneyStore | StoreLease;\n /** The Lambda control plane; `@aws-sdk/client-lambda` with the execution role by default. */\n lambda?: LambdaApi;\n /** How long an unconfirmed start is retried (default 12 hours; keep it under the retention). */\n startRetryMs?: number;\n /**\n * How long an erasure waits after stopping an execution before it erases: an invocation\n * running at the stop goes on to its next checkpoint. Set it to at least the function's\n * timeout; 15 minutes (Lambda's maximum) by default.\n */\n stopDrainMs?: number;\n /**\n * The function's `DurableConfig.ExecutionTimeout`, in milliseconds. With it, a workflow that\n * can outlive it (`longestJourneyMs`) fails the handler's creation — a deploy's smoke test —\n * instead of being stopped by the platform midway and recorded as failed.\n */\n executionTimeoutMs?: number;\n}\n\n/**\n * The Lambda invocation context, as far as the handler's signature needs it — declared here so\n * the package's types do not depend on `@types/aws-lambda`. Lambda passes the full object.\n */\nexport interface LambdaContext {\n functionName: string;\n functionVersion: string;\n invokedFunctionArn: string;\n awsRequestId: string;\n getRemainingTimeInMillis(): number;\n}\n\nexport interface JourneyLambda {\n /** Export as the function's handler. */\n handler: (\n event: DurableExecutionInvocationInput,\n context: LambdaContext\n ) => Promise<DurableExecutionInvocationOutput>;\n}\n\ninterface Invocation {\n lease?: Required<StoreLease>;\n}\n\n/** This function's ARN without its qualifier, from the ARN it was invoked under. */\nfunction unqualified(invokedFunctionArn: string): string {\n return invokedFunctionArn.split(':').slice(0, 7).join(':');\n}\n\nconst json = (body: unknown, status = 200) =>\n new Response(JSON.stringify(body), { status, headers: { 'content-type': 'application/json' } });\n\nexport function journeyLambda<Env extends JourneyLambdaEnv>(\n options: JourneyLambdaOptions<Env>\n): JourneyLambda {\n type HostEnv = Env & JourneyEnv;\n const {\n env: baseEnv,\n lambda: lambdaOption,\n startRetryMs,\n stopDrainMs,\n executionTimeoutMs,\n ...hostOptions\n } = options;\n const host = createJourneyHost<HostEnv>(\n { ...hostOptions, store: (env, database) => options.store(env, database) },\n // Node 24's fetch cannot reach APNs (HTTP/2 only): see http2-client.ts for when this can go\n { apnsFetch: http2Fetch() }\n );\n if (executionTimeoutMs !== undefined) {\n const tooLong = host\n .bundle()\n .workflows.filter((workflow) => longestJourneyMs(workflow) > executionTimeoutMs);\n if (tooLong.length > 0) {\n const days = (ms: number) => `${Math.ceil(ms / 86_400_000)} days`;\n throw new RangeError(\n `${tooLong.map((w) => `'${w.id}' can run ${days(longestJourneyMs(w))}`).join(', ')}, ` +\n `longer than the execution timeout (${days(executionTimeoutMs)}): raise ExecutionTimeout (up to 366 days)`\n );\n }\n }\n const lambda = lambdaOption ?? sdkLambdaApi();\n const ownHashes = new Set(host.bundle().workflows.map((workflow) => workflow.contentHash));\n const scope = new AsyncLocalStorage<Invocation>();\n\n /** The version this code was published as: `$LATEST` while developing. */\n const ownVersion = () => process.env.AWS_LAMBDA_FUNCTION_VERSION ?? '$LATEST';\n /** Numbered versions are ordered: the bundle compiled into a later one goes live by itself. */\n const bundleVersion = (): BundleVersion | undefined => {\n const version = ownVersion();\n return /^\\d+$/.test(version) ? { id: version, createdAt: Number(version) } : undefined;\n };\n\n /** The store and the env (with the instance port) of this invocation, opened on first use. */\n const open = (\n context: DurableContext\n ): { store: JourneyStore; env: HostEnv; executions: ExecutionRegistry } => {\n const invocation = scope.getStore();\n if (invocation === undefined) throw new Error('journeyLambda: outside an invocation');\n const placeholder = { ...baseEnv } as unknown as HostEnv;\n invocation.lease ??= host.lease(placeholder);\n const { store } = invocation.lease;\n const { executions } = store;\n const functionArn = unqualified(context.lambdaContext.invokedFunctionArn);\n const target = async (contentHash: string, version?: string): Promise<string> => {\n // An execution runs the code its IR was compiled with: the version whose bundle put the\n // route there, read in the same row as the hash — never a separately read \"live\" version,\n // which a release between the two reads would make another bundle's\n if (version !== undefined && /^\\d+$/.test(version)) return `${functionArn}:${version}`;\n // A forced deploy records no version: only this code's own workflows can run here\n if (ownHashes.has(contentHash)) return `${functionArn}:${ownVersion()}`;\n throw new Error(`no published version is known to carry workflow IR ${contentHash}`);\n };\n const instances = new AwsInstances({\n store,\n executions,\n lambda,\n target,\n ...(startRetryMs === undefined ? {} : { startRetryMs }),\n ...(stopDrainMs === undefined ? {} : { stopDrainMs }),\n });\n return { store, env: { ...baseEnv, JOURNEY: instances }, executions };\n };\n\n const run = async (input: RunInput, context: DurableContext): Promise<JourneyOutcome> => {\n const { store, env, executions } = open(context);\n const { instanceId, params } = input;\n // Only a start the router recorded may run, byte for byte: the function can be invoked by\n // anything its policy lets through, and an input of this shape would otherwise run any\n // workflow for any user. A stopped execution (an erasure) may not come back either. Outside\n // any step — a step would replay the first invocation's \"not stopped\" on every wake — so the\n // execution fails at once on a refusal; only the read itself is retried, briefly, when the\n // database stumbled.\n const record = await readWithRetry(() => executions.get(instanceId), {\n what: 'run entry',\n instanceId,\n });\n if (\n record === undefined ||\n record.stoppedAt !== undefined ||\n record.input !== JSON.stringify(input)\n ) {\n throw new PermanentError('journeyLambda: run input is not a recorded start');\n }\n // Running is the proof the start got through, whatever became of the invoke's response\n await context.step('$workflow:started', async () => {\n await executions.markSubmitted(\n instanceId,\n context.executionContext.durableExecutionArn,\n Date.now()\n );\n });\n return executeJourney(\n {\n instanceId,\n params,\n enteredAtMs: input.enteredAtMs,\n step: new AwsEngineStep(context, store, executions, lambda, params.userId, instanceId),\n },\n host.runParts(env, store, params)\n );\n };\n\n const http = (event: FunctionUrlEvent, context: DurableContext): Promise<FunctionUrlResult> => {\n const serve = async (): Promise<FunctionUrlResult> => {\n const method = event.requestContext.http.method;\n try {\n const { store, env } = open(context);\n const request = toRequest(event);\n // Only the bundle compiled into a version may route: one is never swapped in by hand\n if (new URL(request.url).pathname === '/deploy') {\n return await fromResponse(\n json(\n {\n error:\n 'deploy by publishing a version (POST /bundle/deploy applies its own bundle)',\n },\n 409\n ),\n method\n );\n }\n await host.applyOwnBundle(env, bundleVersion());\n return await fromResponse(await host.handle(request, env, store), method);\n } catch (error) {\n console.error('[workflow] request failed', error);\n return fromResponse(json({ error: 'internal error' }, 500), method);\n }\n };\n // A read (the bundle, a preview, a tracked link or pixel) answers straight from the handler:\n // its body can be large, and a step would checkpoint all of it. A write runs in one step,\n // never retried — the caller is waiting, and retries the request itself\n const method = event.requestContext.http.method.toUpperCase();\n if (method === 'GET' || method === 'HEAD') return serve();\n return context.step('http', serve, { retryStrategy: () => ({ shouldRetry: false }) });\n };\n\n /**\n * The sweep as durable steps, one per page of users: an invocation cut short (the function's\n * timeout) is re-invoked, and the re-invocation replays the pages already checkpointed\n * instead of evaluating everyone again. No step retries on its own — a page that failed is\n * evaluated again by the next tick.\n */\n const sweep = async (context: DurableContext): Promise<SweepResult> => {\n const once = { retryStrategy: () => ({ shouldRetry: false }) };\n await context.step(\n 'sweep:maintain',\n async () => {\n const { store, env } = open(context);\n await host.applyOwnBundle(env, bundleVersion());\n await sweepMaintenance(env, store);\n },\n once\n );\n let users = 0;\n const started: string[] = [];\n let after: string | undefined;\n for (let n = 0; ; n++) {\n const page = await context.step(\n `sweep:page:${n}`,\n async () => {\n const { store, env } = open(context);\n return sweepSegmentsPaged(env, store, { after, limit: SWEEP_PAGE_SIZE });\n },\n once\n );\n users += page.users;\n started.push(...page.started);\n if (!page.more || page.lastUserId === undefined) break;\n after = page.lastUserId;\n }\n const sizes = await context.step(\n 'sweep:snapshot',\n async () => {\n const { store } = open(context);\n return store.reporting.snapshotSegments(Date.now());\n },\n once\n );\n return { users, started, sizes };\n };\n\n const durable = withDurableExecution(async (input: unknown, context: DurableContext) => {\n if (isFunctionUrlEvent(input)) return http(input, context);\n if (isRunInput(input)) return run(input, context);\n if (\n typeof input === 'object' &&\n input !== null &&\n (input as { type?: unknown }).type === SWEEP_EVENT_TYPE\n ) {\n return sweep(context);\n }\n throw new Error('journeyLambda: unrecognized event (not a Function URL request, run or sweep)');\n });\n\n const handler = async (\n event: DurableExecutionInvocationInput,\n context: LambdaContext\n ): Promise<DurableExecutionInvocationOutput> => {\n const invocation: Invocation = {};\n try {\n // The durable wrapper reads the whole context Lambda passed, not just the fields above\n return await scope.run(invocation, () =>\n durable(event, context as Parameters<typeof durable>[1])\n );\n } finally {\n // Outside the durable wrapper: a suspended run returns PENDING without unwinding the\n // handler, so a `finally` in there would never release the connection\n await invocation.lease?.close().catch((error: unknown) => {\n console.error('[workflow] closing the store failed', error);\n });\n }\n };\n\n return { handler };\n}\n\nexport { AwsEngineStep, stepRetry } from './engine-step';\nexport { AwsInstances, RUN_EVENT_TYPE, executionName, isRunInput } from './instances';\nexport type { AwsInstancesOptions, RunInput } from './instances';\nexport { sdkLambdaApi } from './lambda-api';\nexport { bearerMatches, timingSafeEqual } from '../host/auth';\nexport type { Authorize } from '../host/auth';\nexport type { ExecutionState, LambdaApi } from './lambda-api';\nexport { fromResponse, isFunctionUrlEvent, toRequest } from './function-url';\nexport type { FunctionUrlEvent, FunctionUrlResult } from './function-url';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqDA,MAAa,mBAAmB;;AAwDhC,SAAS,YAAY,oBAAoC;CACvD,OAAO,mBAAmB,MAAM,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG;AAC3D;AAEA,MAAM,QAAQ,MAAe,SAAS,QACpC,IAAI,SAAS,KAAK,UAAU,IAAI,GAAG;CAAE;CAAQ,SAAS,EAAE,gBAAgB,mBAAmB;AAAE,CAAC;AAEhG,SAAgB,cACd,SACe;CAEf,MAAM,EACJ,KAAK,SACL,QAAQ,cACR,cACA,aACA,oBACA,GAAG,gBACD;CACJ,MAAM,OAAO,kBACX;EAAE,GAAG;EAAa,QAAQ,KAAK,aAAa,QAAQ,MAAM,KAAK,QAAQ;CAAE,GAEzE,EAAE,WAAW,WAAW,EAAE,CAC5B;CACA,IAAI,uBAAuB,KAAA,GAAW;EACpC,MAAM,UAAU,KACb,OAAO,CAAC,CACR,UAAU,QAAQ,aAAa,iBAAiB,QAAQ,IAAI,kBAAkB;EACjF,IAAI,QAAQ,SAAS,GAAG;GACtB,MAAM,QAAQ,OAAe,GAAG,KAAK,KAAK,KAAK,KAAU,EAAE;GAC3D,MAAM,IAAI,WACR,GAAG,QAAQ,KAAK,MAAM,IAAI,EAAE,GAAG,YAAY,KAAK,iBAAiB,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,EAAE,uCAC3C,KAAK,kBAAkB,EAAE,2CACnE;EACF;CACF;CACA,MAAM,SAAS,gBAAgB,aAAa;CAC5C,MAAM,YAAY,IAAI,IAAI,KAAK,OAAO,CAAC,CAAC,UAAU,KAAK,aAAa,SAAS,WAAW,CAAC;CACzF,MAAM,QAAQ,IAAI,kBAA8B;;CAGhD,MAAM,mBAAmB,QAAQ,IAAI,+BAA+B;;CAEpE,MAAM,sBAAiD;EACrD,MAAM,UAAU,WAAW;EAC3B,OAAO,QAAQ,KAAK,OAAO,IAAI;GAAE,IAAI;GAAS,WAAW,OAAO,OAAO;EAAE,IAAI,KAAA;CAC/E;;CAGA,MAAM,QACJ,YACyE;EACzE,MAAM,aAAa,MAAM,SAAS;EAClC,IAAI,eAAe,KAAA,GAAW,MAAM,IAAI,MAAM,sCAAsC;EACpF,MAAM,cAAc,EAAE,GAAG,QAAQ;EACjC,WAAW,UAAU,KAAK,MAAM,WAAW;EAC3C,MAAM,EAAE,UAAU,WAAW;EAC7B,MAAM,EAAE,eAAe;EACvB,MAAM,cAAc,YAAY,QAAQ,cAAc,kBAAkB;EACxE,MAAM,SAAS,OAAO,aAAqB,YAAsC;GAI/E,IAAI,YAAY,KAAA,KAAa,QAAQ,KAAK,OAAO,GAAG,OAAO,GAAG,YAAY,GAAG;GAE7E,IAAI,UAAU,IAAI,WAAW,GAAG,OAAO,GAAG,YAAY,GAAG,WAAW;GACpE,MAAM,IAAI,MAAM,sDAAsD,aAAa;EACrF;EACA,MAAM,YAAY,IAAI,aAAa;GACjC;GACA;GACA;GACA;GACA,GAAI,iBAAiB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa;GACrD,GAAI,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,YAAY;EACrD,CAAC;EACD,OAAO;GAAE;GAAO,KAAK;IAAE,GAAG;IAAS,SAAS;GAAU;GAAG;EAAW;CACtE;CAEA,MAAM,MAAM,OAAO,OAAiB,YAAqD;EACvF,MAAM,EAAE,OAAO,KAAK,eAAe,KAAK,OAAO;EAC/C,MAAM,EAAE,YAAY,WAAW;EAO/B,MAAM,SAAS,MAAM,oBAAoB,WAAW,IAAI,UAAU,GAAG;GACnE,MAAM;GACN;EACF,CAAC;EACD,IACE,WAAW,KAAA,KACX,OAAO,cAAc,KAAA,KACrB,OAAO,UAAU,KAAK,UAAU,KAAK,GAErC,MAAM,IAAI,eAAe,kDAAkD;EAG7E,MAAM,QAAQ,KAAK,qBAAqB,YAAY;GAClD,MAAM,WAAW,cACf,YACA,QAAQ,iBAAiB,qBACzB,KAAK,IAAI,CACX;EACF,CAAC;EACD,OAAO,eACL;GACE;GACA;GACA,aAAa,MAAM;GACnB,MAAM,IAAI,cAAc,SAAS,OAAO,YAAY,QAAQ,OAAO,QAAQ,UAAU;EACvF,GACA,KAAK,SAAS,KAAK,OAAO,MAAM,CAClC;CACF;CAEA,MAAM,QAAQ,OAAyB,YAAwD;EAC7F,MAAM,QAAQ,YAAwC;GACpD,MAAM,SAAS,MAAM,eAAe,KAAK;GACzC,IAAI;IACF,MAAM,EAAE,OAAO,QAAQ,KAAK,OAAO;IACnC,MAAM,UAAU,UAAU,KAAK;IAE/B,IAAI,IAAI,IAAI,QAAQ,GAAG,CAAC,CAAC,aAAa,WACpC,OAAO,MAAM,aACX,KACE,EACE,OACE,8EACJ,GACA,GACF,GACA,MACF;IAEF,MAAM,KAAK,eAAe,KAAK,cAAc,CAAC;IAC9C,OAAO,MAAM,aAAa,MAAM,KAAK,OAAO,SAAS,KAAK,KAAK,GAAG,MAAM;GAC1E,SAAS,OAAO;IACd,QAAQ,MAAM,6BAA6B,KAAK;IAChD,OAAO,aAAa,KAAK,EAAE,OAAO,iBAAiB,GAAG,GAAG,GAAG,MAAM;GACpE;EACF;EAIA,MAAM,SAAS,MAAM,eAAe,KAAK,OAAO,YAAY;EAC5D,IAAI,WAAW,SAAS,WAAW,QAAQ,OAAO,MAAM;EACxD,OAAO,QAAQ,KAAK,QAAQ,OAAO,EAAE,sBAAsB,EAAE,aAAa,MAAM,GAAG,CAAC;CACtF;;;;;;;CAQA,MAAM,QAAQ,OAAO,YAAkD;EACrE,MAAM,OAAO,EAAE,sBAAsB,EAAE,aAAa,MAAM,GAAG;EAC7D,MAAM,QAAQ,KACZ,kBACA,YAAY;GACV,MAAM,EAAE,OAAO,QAAQ,KAAK,OAAO;GACnC,MAAM,KAAK,eAAe,KAAK,cAAc,CAAC;GAC9C,MAAM,iBAAiB,KAAK,KAAK;EACnC,GACA,IACF;EACA,IAAI,QAAQ;EACZ,MAAM,UAAoB,CAAC;EAC3B,IAAI;EACJ,KAAK,IAAI,IAAI,IAAK,KAAK;GACrB,MAAM,OAAO,MAAM,QAAQ,KACzB,cAAc,KACd,YAAY;IACV,MAAM,EAAE,OAAO,QAAQ,KAAK,OAAO;IACnC,OAAO,mBAAmB,KAAK,OAAO;KAAE;KAAO,OAAA;IAAuB,CAAC;GACzE,GACA,IACF;GACA,SAAS,KAAK;GACd,QAAQ,KAAK,GAAG,KAAK,OAAO;GAC5B,IAAI,CAAC,KAAK,QAAQ,KAAK,eAAe,KAAA,GAAW;GACjD,QAAQ,KAAK;EACf;EACA,MAAM,QAAQ,MAAM,QAAQ,KAC1B,kBACA,YAAY;GACV,MAAM,EAAE,UAAU,KAAK,OAAO;GAC9B,OAAO,MAAM,UAAU,iBAAiB,KAAK,IAAI,CAAC;EACpD,GACA,IACF;EACA,OAAO;GAAE;GAAO;GAAS;EAAM;CACjC;CAEA,MAAM,UAAU,qBAAqB,OAAO,OAAgB,YAA4B;EACtF,IAAI,mBAAmB,KAAK,GAAG,OAAO,KAAK,OAAO,OAAO;EACzD,IAAI,WAAW,KAAK,GAAG,OAAO,IAAI,OAAO,OAAO;EAChD,IACE,OAAO,UAAU,YACjB,UAAU,QACT,MAA6B,SAAA,mBAE9B,OAAO,MAAM,OAAO;EAEtB,MAAM,IAAI,MAAM,8EAA8E;CAChG,CAAC;CAED,MAAM,UAAU,OACd,OACA,YAC8C;EAC9C,MAAM,aAAyB,CAAC;EAChC,IAAI;GAEF,OAAO,MAAM,MAAM,IAAI,kBACrB,QAAQ,OAAO,OAAwC,CACzD;EACF,UAAU;GAGR,MAAM,WAAW,OAAO,MAAM,CAAC,CAAC,OAAO,UAAmB;IACxD,QAAQ,MAAM,uCAAuC,KAAK;GAC5D,CAAC;EACH;CACF;CAEA,OAAO,EAAE,QAAQ;AACnB"}
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_engine_bucket = require("../engine/bucket.cjs");
3
3
  const require_host_platform = require("../host/platform.cjs");
4
- //#region src/aws/instances.ts
4
+ // src/aws/instances.ts
5
5
  /**
6
6
  * The router's instance port over Lambda durable executions: an instance is one execution of
7
7
  * this same function, started by an asynchronous self-invoke under a stable execution name;
@@ -149,7 +149,7 @@ var AwsInstances = class {
149
149
  }
150
150
  const { store } = this.options;
151
151
  await store.setEntryStatus(record.instanceId, "failed");
152
- await store.reporting?.instanceFinished({
152
+ await store.reporting.instanceFinished({
153
153
  workflow: record.workflow,
154
154
  instanceId: record.instanceId,
155
155
  userId: record.userId,
@@ -210,7 +210,6 @@ var AwsInstances = class {
210
210
  };
211
211
  }
212
212
  };
213
- //#endregion
214
213
  exports.AwsInstances = AwsInstances;
215
214
  exports.RUN_EVENT_TYPE = RUN_EVENT_TYPE;
216
215
  exports.executionName = executionName;
@@ -1 +1 @@
1
- {"version":3,"file":"instances.cjs","names":["murmur3","InstanceNotFoundError"],"sources":["../../src/aws/instances.ts"],"sourcesContent":["import { murmur3 } from '../engine/bucket';\nimport {\n InstanceNotFoundError,\n type JourneyParams,\n type WorkflowBindingLike,\n type WorkflowInstanceLike,\n} from '../host/platform';\nimport type {\n ExecutionRecord,\n ExecutionRegistry,\n ExecutionStart,\n JourneyStore,\n} from '../store/index';\nimport type { LambdaApi } from './lambda-api';\n\n/**\n * The router's instance port over Lambda durable executions: an instance is one execution of\n * this same function, started by an asynchronous self-invoke under a stable execution name;\n * a wake completes the callback its current wait parks on; stopping stops the execution.\n */\n\n/** The top-level shape of an internal run: what the self-invoke sends, never an HTTP body. */\nexport const RUN_EVENT_TYPE = '$workflow.run';\n\nexport interface RunInput {\n type: typeof RUN_EVENT_TYPE;\n instanceId: string;\n params: JourneyParams;\n /** When the instance was created (as Cloudflare's event timestamp): its entry anchor, fixed with the start. */\n enteredAtMs: number;\n}\n\nexport function isRunInput(event: unknown): event is RunInput {\n if (typeof event !== 'object' || event === null) return false;\n const candidate = event as {\n type?: unknown;\n instanceId?: unknown;\n enteredAtMs?: unknown;\n params?: unknown;\n requestContext?: unknown;\n };\n return (\n candidate.type === RUN_EVENT_TYPE &&\n candidate.requestContext === undefined &&\n typeof candidate.instanceId === 'string' &&\n typeof candidate.enteredAtMs === 'number' &&\n typeof candidate.params === 'object' &&\n candidate.params !== null\n );\n}\n\nconst utf8 = new TextEncoder();\n\n/**\n * The durable execution name for one start of an instance: the instance id, cut to fit, with a\n * fingerprint of the whole id (so a cut never makes two instances collide) and the attempt's\n * token. Every retry of that start reuses the recorded name; a new attempt gets a new token.\n */\nexport function executionName(instanceId: string, attempt: string): string {\n const safe = instanceId.replace(/[^a-zA-Z0-9_-]/g, '-');\n const token = attempt.replace(/[^a-zA-Z0-9]/g, '').slice(0, 8);\n const fingerprint = `${murmur3(utf8.encode(instanceId)).toString(36)}${murmur3(utf8.encode(instanceId), 0x9747b28c).toString(36)}`;\n const suffix = `-${fingerprint}-${token}`;\n return `${safe.slice(0, 64 - suffix.length)}${suffix}`;\n}\n\nexport interface AwsInstancesOptions {\n store: JourneyStore;\n executions: ExecutionRegistry;\n lambda: LambdaApi;\n /**\n * The qualified function ARN an execution pinned to `contentHash` must run on; `version` is\n * the code version whose routes named it.\n */\n target(contentHash: string, version?: string): Promise<string>;\n /**\n * How long an unconfirmed start keeps being retried. It must stay shorter than the durable\n * execution retention: past that the platform forgets the name, and a retry would start a\n * second execution. Twelve hours by default.\n */\n startRetryMs?: number;\n /** How stale a running instance's last check must be before maintenance looks again. */\n reconcileEveryMs?: number;\n /**\n * How long after a stop an invocation already running may still act: Lambda cannot interrupt\n * one, and it runs on to its next checkpoint. An erasure waits this long before it erases.\n * The function's timeout is enough; 15 minutes (Lambda's maximum) by default.\n */\n stopDrainMs?: number;\n now?: () => number;\n}\n\nconst MINUTE = 60_000;\n\nexport class AwsInstances implements WorkflowBindingLike {\n private readonly now: () => number;\n private readonly startRetryMs: number;\n private readonly reconcileEveryMs: number;\n private readonly stopDrainMs: number;\n\n constructor(private readonly options: AwsInstancesOptions) {\n this.now = options.now ?? Date.now;\n this.startRetryMs = options.startRetryMs ?? 12 * 60 * MINUTE;\n this.reconcileEveryMs = options.reconcileEveryMs ?? 15 * MINUTE;\n this.stopDrainMs = options.stopDrainMs ?? 15 * MINUTE;\n }\n\n /**\n * A start, planned for one entry attempt. Its name is new every time: a failed entry reclaimed\n * under the same instance id (an event replayed with its ts) must start a new execution — the\n * old name would return the closed one. Retries of this attempt reuse the recorded name.\n */\n async plan(options: {\n id: string;\n params: JourneyParams;\n ts: number;\n version?: string | undefined;\n }): Promise<ExecutionStart> {\n const input: RunInput = {\n type: RUN_EVENT_TYPE,\n instanceId: options.id,\n params: options.params,\n // The moment the instance is created, like Cloudflare's: an event's own ts may be long past\n enteredAtMs: this.now(),\n };\n return {\n name: executionName(options.id, crypto.randomUUID().slice(0, 8)),\n target: await this.options.target(options.params.contentHash, options.version),\n input: JSON.stringify(input),\n };\n }\n\n async create(options: { id: string; params: unknown }): Promise<WorkflowInstanceLike> {\n const record = await this.options.executions.get(options.id);\n if (record === undefined) {\n throw new Error(`no start is recorded for ${options.id}: the entry must be planned first`);\n }\n await this.submit(record);\n return this.instance(options.id);\n }\n\n async get(id: string): Promise<WorkflowInstanceLike> {\n // A read of the registry alone: a Lambda failure must never read as \"no such instance\"\n if ((await this.options.executions.get(id)) === undefined) {\n throw new InstanceNotFoundError(id);\n }\n return this.instance(id);\n }\n\n async resume(entry: { workflow: string; userId: string }): Promise<void> {\n for (const record of await this.options.executions.pendingStarts({ ...entry, limit: 1 })) {\n if (!(await this.giveUpIfStale(record))) await this.submit(record);\n }\n }\n\n async maintain(): Promise<void> {\n const now = this.now();\n const failures: unknown[] = [];\n // Starts whose submit never confirmed: retried with the recorded name and payload\n for (const record of await this.options.executions.pendingStarts({\n createdBefore: now - MINUTE,\n limit: 25,\n })) {\n try {\n if (!(await this.giveUpIfStale(record))) await this.submit(record);\n } catch (error) {\n failures.push(error);\n }\n }\n // Executions the platform ended without the run finalizing (a timeout, a stop, a crash)\n for (const record of await this.options.executions.toReconcile(\n 25,\n now - this.reconcileEveryMs\n )) {\n try {\n await this.reconcile(record, now);\n } catch (error) {\n failures.push(error);\n }\n }\n if (failures.length > 0) throw failures[0];\n }\n\n private async submit(record: ExecutionRecord): Promise<void> {\n const { arn } = await this.options.lambda.startExecution({\n target: record.target,\n name: record.name,\n payload: record.input,\n });\n await this.options.executions.markSubmitted(record.instanceId, arn, this.now());\n }\n\n /** Past the retry budget a start is unresolved for good: no retry could tell a duplicate apart. */\n private async giveUpIfStale(record: ExecutionRecord): Promise<boolean> {\n if (this.now() - record.createdAt <= this.startRetryMs) return false;\n await this.options.executions.markUnresolved(record.instanceId, this.now());\n console.error(\n `[workflow] the start of ${record.instanceId} (${record.name}) was never confirmed: left unresolved`\n );\n return true;\n }\n\n private async arnOf(record: ExecutionRecord): Promise<string | undefined> {\n if (record.arn !== undefined) return record.arn;\n const arn = await this.options.lambda.findExecution(record.target, record.name);\n if (arn !== undefined) await this.options.executions.setArn(record.instanceId, arn);\n return arn;\n }\n\n /**\n * Past the start retry budget, an execution still nowhere to be seen never started: any queued\n * invoke has expired by then. Before that, not finding it says nothing.\n */\n private vanished(record: ExecutionRecord): boolean {\n return this.now() - record.createdAt > this.startRetryMs;\n }\n\n /** Stopped so recently that an invocation running at the time may still be acting. */\n private draining(record: ExecutionRecord): boolean {\n return record.stoppedAt !== undefined && this.now() - record.stoppedAt < this.stopDrainMs;\n }\n\n /**\n * The one judgment every path makes of an execution the platform reports stopped — by\n * `terminate`, by an operator, or seen by `reconcile` before the stop was recorded: the first\n * sighting is recorded (`markStopped` keeps an earlier time, so no poll ever extends the\n * drain), and the record is read again so the verdict rests on what is committed now, not on\n * the snapshot a caller read before its API calls. A write or read that fails throws: an\n * unknown stop time is never taken for \"safely stopped\". Undefined means the record is gone —\n * the erasure finished with it meanwhile.\n */\n private async observeStop(instanceId: string): Promise<ExecutionRecord | undefined> {\n await this.options.executions.markStopped(instanceId, this.now());\n return this.options.executions.get(instanceId);\n }\n\n private async reconcile(record: ExecutionRecord, now: number): Promise<void> {\n const arn = await this.arnOf(record);\n const state = arn === undefined ? undefined : await this.options.lambda.executionState(arn);\n // Only a state that will never run another step — or one missing for good — ends the entry;\n // a run still queued, or not visible yet, is left alone\n const ended =\n state === 'failed' ||\n state === 'stopped' ||\n state === 'timed_out' ||\n (state === undefined && this.vanished(record));\n if (ended) {\n // The verdict is taken on the record as it is now: `toReconcile` handed over a snapshot,\n // and a stop may have been recorded since — by `terminate`, or here, at its first sighting\n const fresh =\n state === 'stopped'\n ? await this.observeStop(record.instanceId)\n : await this.options.executions.get(record.instanceId);\n if (fresh === undefined) return;\n if (this.draining(fresh)) {\n // Stopped, but an invocation running at the stop may still be acting: the entry stays\n // running until the drain has passed, so an erasure keeps waiting for it (`status`\n // says running too), and the next look finalizes it\n await this.options.executions.markChecked(record.instanceId, now);\n return;\n }\n // Ended without its finalize step: the ledger must not show it running forever\n const { store } = this.options;\n await store.setEntryStatus(record.instanceId, 'failed');\n await store.reporting?.instanceFinished({\n workflow: record.workflow,\n instanceId: record.instanceId,\n userId: record.userId,\n status: 'failed',\n at: now,\n });\n console.warn(\n `[workflow] ${record.instanceId} ended on the platform (${state ?? 'unknown'}) without finishing: recorded as failed`\n );\n }\n await this.options.executions.markChecked(record.instanceId, now);\n }\n\n private instance(id: string): WorkflowInstanceLike {\n const { executions, lambda } = this.options;\n const current = async () => {\n const record = await executions.get(id);\n if (record === undefined) throw new InstanceNotFoundError(id);\n return record;\n };\n return {\n id,\n sendEvent: async (event) => {\n // The wait parked now, read at the moment of the wake: a newer wait's callback replaces\n // an older one, and a wake for none (the instance is between waits) is nothing to do —\n // its next wait re-reads the facts before parking\n const { callbackId } = await current();\n if (callbackId === undefined) return;\n await lambda.completeCallback(callbackId, JSON.stringify(event.payload ?? {}));\n },\n terminate: async () => {\n const record = await current();\n // Stopped before: done once an invocation that was running then has had time to end\n if (record.stoppedAt !== undefined) {\n if (this.draining(record)) {\n throw new Error(`${id} was stopped; its running invocation may still be finishing`);\n }\n return;\n }\n if (record.submittedAt === undefined && record.unresolvedAt === undefined) {\n // No retry may start it after this\n await executions.markUnresolved(id, this.now());\n }\n const arn = await this.arnOf(record);\n if (arn === undefined) {\n // Not visible yet is not stopped: the erasure stays pending, and the sweep retries\n if (this.vanished(record)) return;\n throw new Error(`cannot stop ${id} yet: its execution is not visible`);\n }\n // One that finished on its own has no invocation left to drain\n const state = await lambda.executionState(arn);\n if (state === 'succeeded' || state === 'failed' || state === 'timed_out') return;\n // A stop does not interrupt an invocation already running: it goes on to its next\n // checkpoint, side effects included. The erasure waits (see stopDrainMs). One already\n // stopped (by an operator, or a stop whose record did not land) is not stopped again:\n // its first sighting is recorded and the same drain judged\n if (state !== 'stopped' && !(await lambda.stopExecution(arn))) {\n throw new Error(`stopping ${id} failed`);\n }\n const fresh = await this.observeStop(id);\n if (fresh !== undefined && this.draining(fresh)) {\n throw new Error(`${id} is stopped; its running invocation may still be finishing`);\n }\n },\n status: async () => {\n const record = await current();\n if (this.draining(record)) return { status: 'running' };\n const arn = await this.arnOf(record);\n // Not visible yet may still run: only one missing past the budget is gone\n if (arn === undefined) return { status: this.vanished(record) ? 'terminated' : 'running' };\n const state = await lambda.executionState(arn);\n // In the router's vocabulary (Cloudflare's): what will never run another step\n if (state === 'succeeded') return { status: 'complete' };\n if (state === 'failed') return { status: 'errored' };\n if (state === 'running') return { status: 'running' };\n if (state === 'stopped') {\n // Stopped, seen here first or recorded since this read: the drain is the judgment\n const fresh = await this.observeStop(id);\n if (fresh !== undefined && this.draining(fresh)) return { status: 'running' };\n }\n return { status: 'terminated' };\n },\n };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"instances.cjs","names":["murmur3","InstanceNotFoundError"],"sources":["../../src/aws/instances.ts"],"sourcesContent":["import { murmur3 } from '../engine/bucket';\nimport {\n InstanceNotFoundError,\n type JourneyParams,\n type WorkflowBindingLike,\n type WorkflowInstanceLike,\n} from '../host/platform';\nimport type {\n ExecutionRecord,\n ExecutionRegistry,\n ExecutionStart,\n JourneyStore,\n} from '../store/index';\nimport type { LambdaApi } from './lambda-api';\n\n/**\n * The router's instance port over Lambda durable executions: an instance is one execution of\n * this same function, started by an asynchronous self-invoke under a stable execution name;\n * a wake completes the callback its current wait parks on; stopping stops the execution.\n */\n\n/** The top-level shape of an internal run: what the self-invoke sends, never an HTTP body. */\nexport const RUN_EVENT_TYPE = '$workflow.run';\n\nexport interface RunInput {\n type: typeof RUN_EVENT_TYPE;\n instanceId: string;\n params: JourneyParams;\n /** When the instance was created (as Cloudflare's event timestamp): its entry anchor, fixed with the start. */\n enteredAtMs: number;\n}\n\nexport function isRunInput(event: unknown): event is RunInput {\n if (typeof event !== 'object' || event === null) return false;\n const candidate = event as {\n type?: unknown;\n instanceId?: unknown;\n enteredAtMs?: unknown;\n params?: unknown;\n requestContext?: unknown;\n };\n return (\n candidate.type === RUN_EVENT_TYPE &&\n candidate.requestContext === undefined &&\n typeof candidate.instanceId === 'string' &&\n typeof candidate.enteredAtMs === 'number' &&\n typeof candidate.params === 'object' &&\n candidate.params !== null\n );\n}\n\nconst utf8 = new TextEncoder();\n\n/**\n * The durable execution name for one start of an instance: the instance id, cut to fit, with a\n * fingerprint of the whole id (so a cut never makes two instances collide) and the attempt's\n * token. Every retry of that start reuses the recorded name; a new attempt gets a new token.\n */\nexport function executionName(instanceId: string, attempt: string): string {\n const safe = instanceId.replace(/[^a-zA-Z0-9_-]/g, '-');\n const token = attempt.replace(/[^a-zA-Z0-9]/g, '').slice(0, 8);\n const fingerprint = `${murmur3(utf8.encode(instanceId)).toString(36)}${murmur3(utf8.encode(instanceId), 0x9747b28c).toString(36)}`;\n const suffix = `-${fingerprint}-${token}`;\n return `${safe.slice(0, 64 - suffix.length)}${suffix}`;\n}\n\nexport interface AwsInstancesOptions {\n store: JourneyStore;\n executions: ExecutionRegistry;\n lambda: LambdaApi;\n /**\n * The qualified function ARN an execution pinned to `contentHash` must run on; `version` is\n * the code version whose routes named it.\n */\n target(contentHash: string, version?: string): Promise<string>;\n /**\n * How long an unconfirmed start keeps being retried. It must stay shorter than the durable\n * execution retention: past that the platform forgets the name, and a retry would start a\n * second execution. Twelve hours by default.\n */\n startRetryMs?: number;\n /** How stale a running instance's last check must be before maintenance looks again. */\n reconcileEveryMs?: number;\n /**\n * How long after a stop an invocation already running may still act: Lambda cannot interrupt\n * one, and it runs on to its next checkpoint. An erasure waits this long before it erases.\n * The function's timeout is enough; 15 minutes (Lambda's maximum) by default.\n */\n stopDrainMs?: number;\n now?: () => number;\n}\n\nconst MINUTE = 60_000;\n\nexport class AwsInstances implements WorkflowBindingLike {\n private readonly now: () => number;\n private readonly startRetryMs: number;\n private readonly reconcileEveryMs: number;\n private readonly stopDrainMs: number;\n\n constructor(private readonly options: AwsInstancesOptions) {\n this.now = options.now ?? Date.now;\n this.startRetryMs = options.startRetryMs ?? 12 * 60 * MINUTE;\n this.reconcileEveryMs = options.reconcileEveryMs ?? 15 * MINUTE;\n this.stopDrainMs = options.stopDrainMs ?? 15 * MINUTE;\n }\n\n /**\n * A start, planned for one entry attempt. Its name is new every time: a failed entry reclaimed\n * under the same instance id (an event replayed with its ts) must start a new execution — the\n * old name would return the closed one. Retries of this attempt reuse the recorded name.\n */\n async plan(options: {\n id: string;\n params: JourneyParams;\n ts: number;\n version?: string | undefined;\n }): Promise<ExecutionStart> {\n const input: RunInput = {\n type: RUN_EVENT_TYPE,\n instanceId: options.id,\n params: options.params,\n // The moment the instance is created, like Cloudflare's: an event's own ts may be long past\n enteredAtMs: this.now(),\n };\n return {\n name: executionName(options.id, crypto.randomUUID().slice(0, 8)),\n target: await this.options.target(options.params.contentHash, options.version),\n input: JSON.stringify(input),\n };\n }\n\n async create(options: { id: string; params: unknown }): Promise<WorkflowInstanceLike> {\n const record = await this.options.executions.get(options.id);\n if (record === undefined) {\n throw new Error(`no start is recorded for ${options.id}: the entry must be planned first`);\n }\n await this.submit(record);\n return this.instance(options.id);\n }\n\n async get(id: string): Promise<WorkflowInstanceLike> {\n // A read of the registry alone: a Lambda failure must never read as \"no such instance\"\n if ((await this.options.executions.get(id)) === undefined) {\n throw new InstanceNotFoundError(id);\n }\n return this.instance(id);\n }\n\n async resume(entry: { workflow: string; userId: string }): Promise<void> {\n for (const record of await this.options.executions.pendingStarts({ ...entry, limit: 1 })) {\n if (!(await this.giveUpIfStale(record))) await this.submit(record);\n }\n }\n\n async maintain(): Promise<void> {\n const now = this.now();\n const failures: unknown[] = [];\n // Starts whose submit never confirmed: retried with the recorded name and payload\n for (const record of await this.options.executions.pendingStarts({\n createdBefore: now - MINUTE,\n limit: 25,\n })) {\n try {\n if (!(await this.giveUpIfStale(record))) await this.submit(record);\n } catch (error) {\n failures.push(error);\n }\n }\n // Executions the platform ended without the run finalizing (a timeout, a stop, a crash)\n for (const record of await this.options.executions.toReconcile(\n 25,\n now - this.reconcileEveryMs\n )) {\n try {\n await this.reconcile(record, now);\n } catch (error) {\n failures.push(error);\n }\n }\n if (failures.length > 0) throw failures[0];\n }\n\n private async submit(record: ExecutionRecord): Promise<void> {\n const { arn } = await this.options.lambda.startExecution({\n target: record.target,\n name: record.name,\n payload: record.input,\n });\n await this.options.executions.markSubmitted(record.instanceId, arn, this.now());\n }\n\n /** Past the retry budget a start is unresolved for good: no retry could tell a duplicate apart. */\n private async giveUpIfStale(record: ExecutionRecord): Promise<boolean> {\n if (this.now() - record.createdAt <= this.startRetryMs) return false;\n await this.options.executions.markUnresolved(record.instanceId, this.now());\n console.error(\n `[workflow] the start of ${record.instanceId} (${record.name}) was never confirmed: left unresolved`\n );\n return true;\n }\n\n private async arnOf(record: ExecutionRecord): Promise<string | undefined> {\n if (record.arn !== undefined) return record.arn;\n const arn = await this.options.lambda.findExecution(record.target, record.name);\n if (arn !== undefined) await this.options.executions.setArn(record.instanceId, arn);\n return arn;\n }\n\n /**\n * Past the start retry budget, an execution still nowhere to be seen never started: any queued\n * invoke has expired by then. Before that, not finding it says nothing.\n */\n private vanished(record: ExecutionRecord): boolean {\n return this.now() - record.createdAt > this.startRetryMs;\n }\n\n /** Stopped so recently that an invocation running at the time may still be acting. */\n private draining(record: ExecutionRecord): boolean {\n return record.stoppedAt !== undefined && this.now() - record.stoppedAt < this.stopDrainMs;\n }\n\n /**\n * The one judgment every path makes of an execution the platform reports stopped — by\n * `terminate`, by an operator, or seen by `reconcile` before the stop was recorded: the first\n * sighting is recorded (`markStopped` keeps an earlier time, so no poll ever extends the\n * drain), and the record is read again so the verdict rests on what is committed now, not on\n * the snapshot a caller read before its API calls. A write or read that fails throws: an\n * unknown stop time is never taken for \"safely stopped\". Undefined means the record is gone —\n * the erasure finished with it meanwhile.\n */\n private async observeStop(instanceId: string): Promise<ExecutionRecord | undefined> {\n await this.options.executions.markStopped(instanceId, this.now());\n return this.options.executions.get(instanceId);\n }\n\n private async reconcile(record: ExecutionRecord, now: number): Promise<void> {\n const arn = await this.arnOf(record);\n const state = arn === undefined ? undefined : await this.options.lambda.executionState(arn);\n // Only a state that will never run another step — or one missing for good — ends the entry;\n // a run still queued, or not visible yet, is left alone\n const ended =\n state === 'failed' ||\n state === 'stopped' ||\n state === 'timed_out' ||\n (state === undefined && this.vanished(record));\n if (ended) {\n // The verdict is taken on the record as it is now: `toReconcile` handed over a snapshot,\n // and a stop may have been recorded since — by `terminate`, or here, at its first sighting\n const fresh =\n state === 'stopped'\n ? await this.observeStop(record.instanceId)\n : await this.options.executions.get(record.instanceId);\n if (fresh === undefined) return;\n if (this.draining(fresh)) {\n // Stopped, but an invocation running at the stop may still be acting: the entry stays\n // running until the drain has passed, so an erasure keeps waiting for it (`status`\n // says running too), and the next look finalizes it\n await this.options.executions.markChecked(record.instanceId, now);\n return;\n }\n // Ended without its finalize step: the ledger must not show it running forever\n const { store } = this.options;\n await store.setEntryStatus(record.instanceId, 'failed');\n await store.reporting.instanceFinished({\n workflow: record.workflow,\n instanceId: record.instanceId,\n userId: record.userId,\n status: 'failed',\n at: now,\n });\n console.warn(\n `[workflow] ${record.instanceId} ended on the platform (${state ?? 'unknown'}) without finishing: recorded as failed`\n );\n }\n await this.options.executions.markChecked(record.instanceId, now);\n }\n\n private instance(id: string): WorkflowInstanceLike {\n const { executions, lambda } = this.options;\n const current = async () => {\n const record = await executions.get(id);\n if (record === undefined) throw new InstanceNotFoundError(id);\n return record;\n };\n return {\n id,\n sendEvent: async (event) => {\n // The wait parked now, read at the moment of the wake: a newer wait's callback replaces\n // an older one, and a wake for none (the instance is between waits) is nothing to do —\n // its next wait re-reads the facts before parking\n const { callbackId } = await current();\n if (callbackId === undefined) return;\n await lambda.completeCallback(callbackId, JSON.stringify(event.payload ?? {}));\n },\n terminate: async () => {\n const record = await current();\n // Stopped before: done once an invocation that was running then has had time to end\n if (record.stoppedAt !== undefined) {\n if (this.draining(record)) {\n throw new Error(`${id} was stopped; its running invocation may still be finishing`);\n }\n return;\n }\n if (record.submittedAt === undefined && record.unresolvedAt === undefined) {\n // No retry may start it after this\n await executions.markUnresolved(id, this.now());\n }\n const arn = await this.arnOf(record);\n if (arn === undefined) {\n // Not visible yet is not stopped: the erasure stays pending, and the sweep retries\n if (this.vanished(record)) return;\n throw new Error(`cannot stop ${id} yet: its execution is not visible`);\n }\n // One that finished on its own has no invocation left to drain\n const state = await lambda.executionState(arn);\n if (state === 'succeeded' || state === 'failed' || state === 'timed_out') return;\n // A stop does not interrupt an invocation already running: it goes on to its next\n // checkpoint, side effects included. The erasure waits (see stopDrainMs). One already\n // stopped (by an operator, or a stop whose record did not land) is not stopped again:\n // its first sighting is recorded and the same drain judged\n if (state !== 'stopped' && !(await lambda.stopExecution(arn))) {\n throw new Error(`stopping ${id} failed`);\n }\n const fresh = await this.observeStop(id);\n if (fresh !== undefined && this.draining(fresh)) {\n throw new Error(`${id} is stopped; its running invocation may still be finishing`);\n }\n },\n status: async () => {\n const record = await current();\n if (this.draining(record)) return { status: 'running' };\n const arn = await this.arnOf(record);\n // Not visible yet may still run: only one missing past the budget is gone\n if (arn === undefined) return { status: this.vanished(record) ? 'terminated' : 'running' };\n const state = await lambda.executionState(arn);\n // In the router's vocabulary (Cloudflare's): what will never run another step\n if (state === 'succeeded') return { status: 'complete' };\n if (state === 'failed') return { status: 'errored' };\n if (state === 'running') return { status: 'running' };\n if (state === 'stopped') {\n // Stopped, seen here first or recorded since this read: the drain is the judgment\n const fresh = await this.observeStop(id);\n if (fresh !== undefined && this.draining(fresh)) return { status: 'running' };\n }\n return { status: 'terminated' };\n },\n };\n }\n}\n"],"mappings":"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"}
@@ -1,7 +1,6 @@
1
- import { JourneyParams, WorkflowBindingLike, WorkflowInstanceLike } from "../host/platform.cjs";
2
1
  import { ExecutionRegistry, ExecutionStart, JourneyStore } from "../store/index.cjs";
3
2
  import { LambdaApi } from "./lambda-api.cjs";
4
- //#region src/aws/instances.d.ts
3
+ import { JourneyParams, WorkflowBindingLike, WorkflowInstanceLike } from "../host/platform.cjs";
5
4
  /**
6
5
  * The router's instance port over Lambda durable executions: an instance is one execution of
7
6
  * this same function, started by an asynchronous self-invoke under a stable execution name;
@@ -100,5 +99,4 @@ export declare class AwsInstances implements WorkflowBindingLike {
100
99
  private reconcile;
101
100
  private instance;
102
101
  }
103
- //#endregion
104
102
  //# sourceMappingURL=instances.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"instances.d.cts","names":[],"sources":["../../src/aws/instances.ts"],"mappings":";;;;;;;;;;qBAsBa;iBAEI;EACf,aAAa;EACb;EACA,QAAQ;;EAER;;wBAGc,WAAW,iBAAiB,SAAS;;;;;;wBA0BrC,cAAc,oBAAoB;iBAQjC;EACf,OAAO;EACP,YAAY;EACZ,QAAQ;;;;;EAKR,OAAO,qBAAqB,mBAAmB;;;;;;EAM/C;;EAEA;;;;;;EAMA;EACA;;qBAKW,wBAAwB;mBAMN;mBALZ;mBACA;mBACA;mBACA;EAEjB,YAA6B,SAAS;;;;;;EAYhC,KAAK;IACT;IACA,QAAQ;IACR;IACA;MACE,QAAQ;EAeN,OAAO;IAAW;IAAY;MAAoB,QAAQ;EAS1D,IAAI,aAAa,QAAQ;EAQzB,OAAO;IAAS;IAAkB;MAAmB;EAMrD,YAAY;UA4BJ;;UAUA;UASA;;;;;UAWN;;UAKA;;;;;;;;;;UAaM;UAKA;UA0CN"}
1
+ {"version":3,"file":"instances.d.cts","names":[],"sources":["../../src/aws/instances.ts"],"mappings":";;;;;;;;;qBAsBa;iBAEI;EACf,aAAa;EACb;EACA,QAAQ;;EAER;;wBAGc,WAAW,iBAAiB,SAAS;;;;;;wBA0BrC,cAAc,oBAAoB;iBAQjC;EACf,OAAO;EACP,YAAY;EACZ,QAAQ;;;;;EAKR,OAAO,qBAAqB,mBAAmB;;;;;;EAM/C;;EAEA;;;;;;EAMA;EACA;;qBAKW,wBAAwB;mBAMN;mBALZ;mBACA;mBACA;mBACA;EAEjB,YAA6B,SAAS;;;;;;EAYhC,KAAK;IACT;IACA,QAAQ;IACR;IACA;MACE,QAAQ;EAeN,OAAO;IAAW;IAAY;MAAoB,QAAQ;EAS1D,IAAI,aAAa,QAAQ;EAQzB,OAAO;IAAS;IAAkB;MAAmB;EAMrD,YAAY;UA4BJ;;UAUA;UASA;;;;;UAWN;;UAKA;;;;;;;;;;UAaM;UAKA;UA0CN"}
@@ -1,7 +1,6 @@
1
- import { JourneyParams, WorkflowBindingLike, WorkflowInstanceLike } from "../host/platform.mjs";
2
1
  import { ExecutionRegistry, ExecutionStart, JourneyStore } from "../store/index.mjs";
3
2
  import { LambdaApi } from "./lambda-api.mjs";
4
- //#region src/aws/instances.d.ts
3
+ import { JourneyParams, WorkflowBindingLike, WorkflowInstanceLike } from "../host/platform.mjs";
5
4
  /**
6
5
  * The router's instance port over Lambda durable executions: an instance is one execution of
7
6
  * this same function, started by an asynchronous self-invoke under a stable execution name;
@@ -100,5 +99,4 @@ export declare class AwsInstances implements WorkflowBindingLike {
100
99
  private reconcile;
101
100
  private instance;
102
101
  }
103
- //#endregion
104
102
  //# sourceMappingURL=instances.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"instances.d.mts","names":[],"sources":["../../src/aws/instances.ts"],"mappings":";;;;;;;;;;qBAsBa;iBAEI;EACf,aAAa;EACb;EACA,QAAQ;;EAER;;wBAGc,WAAW,iBAAiB,SAAS;;;;;;wBA0BrC,cAAc,oBAAoB;iBAQjC;EACf,OAAO;EACP,YAAY;EACZ,QAAQ;;;;;EAKR,OAAO,qBAAqB,mBAAmB;;;;;;EAM/C;;EAEA;;;;;;EAMA;EACA;;qBAKW,wBAAwB;mBAMN;mBALZ;mBACA;mBACA;mBACA;EAEjB,YAA6B,SAAS;;;;;;EAYhC,KAAK;IACT;IACA,QAAQ;IACR;IACA;MACE,QAAQ;EAeN,OAAO;IAAW;IAAY;MAAoB,QAAQ;EAS1D,IAAI,aAAa,QAAQ;EAQzB,OAAO;IAAS;IAAkB;MAAmB;EAMrD,YAAY;UA4BJ;;UAUA;UASA;;;;;UAWN;;UAKA;;;;;;;;;;UAaM;UAKA;UA0CN"}
1
+ {"version":3,"file":"instances.d.mts","names":[],"sources":["../../src/aws/instances.ts"],"mappings":";;;;;;;;;qBAsBa;iBAEI;EACf,aAAa;EACb;EACA,QAAQ;;EAER;;wBAGc,WAAW,iBAAiB,SAAS;;;;;;wBA0BrC,cAAc,oBAAoB;iBAQjC;EACf,OAAO;EACP,YAAY;EACZ,QAAQ;;;;;EAKR,OAAO,qBAAqB,mBAAmB;;;;;;EAM/C;;EAEA;;;;;;EAMA;EACA;;qBAKW,wBAAwB;mBAMN;mBALZ;mBACA;mBACA;mBACA;EAEjB,YAA6B,SAAS;;;;;;EAYhC,KAAK;IACT;IACA,QAAQ;IACR;IACA;MACE,QAAQ;EAeN,OAAO;IAAW;IAAY;MAAoB,QAAQ;EAS1D,IAAI,aAAa,QAAQ;EAQzB,OAAO;IAAS;IAAkB;MAAmB;EAMrD,YAAY;UA4BJ;;UAUA;UASA;;;;;UAWN;;UAKA;;;;;;;;;;UAaM;UAKA;UA0CN"}
@@ -1,6 +1,6 @@
1
1
  import { murmur3 } from "../engine/bucket.mjs";
2
2
  import { InstanceNotFoundError } from "../host/platform.mjs";
3
- //#region src/aws/instances.ts
3
+ // src/aws/instances.ts
4
4
  /**
5
5
  * The router's instance port over Lambda durable executions: an instance is one execution of
6
6
  * this same function, started by an asynchronous self-invoke under a stable execution name;
@@ -148,7 +148,7 @@ var AwsInstances = class {
148
148
  }
149
149
  const { store } = this.options;
150
150
  await store.setEntryStatus(record.instanceId, "failed");
151
- await store.reporting?.instanceFinished({
151
+ await store.reporting.instanceFinished({
152
152
  workflow: record.workflow,
153
153
  instanceId: record.instanceId,
154
154
  userId: record.userId,
@@ -209,7 +209,6 @@ var AwsInstances = class {
209
209
  };
210
210
  }
211
211
  };
212
- //#endregion
213
212
  export { AwsInstances, RUN_EVENT_TYPE, executionName, isRunInput };
214
213
 
215
214
  //# sourceMappingURL=instances.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"instances.mjs","names":[],"sources":["../../src/aws/instances.ts"],"sourcesContent":["import { murmur3 } from '../engine/bucket';\nimport {\n InstanceNotFoundError,\n type JourneyParams,\n type WorkflowBindingLike,\n type WorkflowInstanceLike,\n} from '../host/platform';\nimport type {\n ExecutionRecord,\n ExecutionRegistry,\n ExecutionStart,\n JourneyStore,\n} from '../store/index';\nimport type { LambdaApi } from './lambda-api';\n\n/**\n * The router's instance port over Lambda durable executions: an instance is one execution of\n * this same function, started by an asynchronous self-invoke under a stable execution name;\n * a wake completes the callback its current wait parks on; stopping stops the execution.\n */\n\n/** The top-level shape of an internal run: what the self-invoke sends, never an HTTP body. */\nexport const RUN_EVENT_TYPE = '$workflow.run';\n\nexport interface RunInput {\n type: typeof RUN_EVENT_TYPE;\n instanceId: string;\n params: JourneyParams;\n /** When the instance was created (as Cloudflare's event timestamp): its entry anchor, fixed with the start. */\n enteredAtMs: number;\n}\n\nexport function isRunInput(event: unknown): event is RunInput {\n if (typeof event !== 'object' || event === null) return false;\n const candidate = event as {\n type?: unknown;\n instanceId?: unknown;\n enteredAtMs?: unknown;\n params?: unknown;\n requestContext?: unknown;\n };\n return (\n candidate.type === RUN_EVENT_TYPE &&\n candidate.requestContext === undefined &&\n typeof candidate.instanceId === 'string' &&\n typeof candidate.enteredAtMs === 'number' &&\n typeof candidate.params === 'object' &&\n candidate.params !== null\n );\n}\n\nconst utf8 = new TextEncoder();\n\n/**\n * The durable execution name for one start of an instance: the instance id, cut to fit, with a\n * fingerprint of the whole id (so a cut never makes two instances collide) and the attempt's\n * token. Every retry of that start reuses the recorded name; a new attempt gets a new token.\n */\nexport function executionName(instanceId: string, attempt: string): string {\n const safe = instanceId.replace(/[^a-zA-Z0-9_-]/g, '-');\n const token = attempt.replace(/[^a-zA-Z0-9]/g, '').slice(0, 8);\n const fingerprint = `${murmur3(utf8.encode(instanceId)).toString(36)}${murmur3(utf8.encode(instanceId), 0x9747b28c).toString(36)}`;\n const suffix = `-${fingerprint}-${token}`;\n return `${safe.slice(0, 64 - suffix.length)}${suffix}`;\n}\n\nexport interface AwsInstancesOptions {\n store: JourneyStore;\n executions: ExecutionRegistry;\n lambda: LambdaApi;\n /**\n * The qualified function ARN an execution pinned to `contentHash` must run on; `version` is\n * the code version whose routes named it.\n */\n target(contentHash: string, version?: string): Promise<string>;\n /**\n * How long an unconfirmed start keeps being retried. It must stay shorter than the durable\n * execution retention: past that the platform forgets the name, and a retry would start a\n * second execution. Twelve hours by default.\n */\n startRetryMs?: number;\n /** How stale a running instance's last check must be before maintenance looks again. */\n reconcileEveryMs?: number;\n /**\n * How long after a stop an invocation already running may still act: Lambda cannot interrupt\n * one, and it runs on to its next checkpoint. An erasure waits this long before it erases.\n * The function's timeout is enough; 15 minutes (Lambda's maximum) by default.\n */\n stopDrainMs?: number;\n now?: () => number;\n}\n\nconst MINUTE = 60_000;\n\nexport class AwsInstances implements WorkflowBindingLike {\n private readonly now: () => number;\n private readonly startRetryMs: number;\n private readonly reconcileEveryMs: number;\n private readonly stopDrainMs: number;\n\n constructor(private readonly options: AwsInstancesOptions) {\n this.now = options.now ?? Date.now;\n this.startRetryMs = options.startRetryMs ?? 12 * 60 * MINUTE;\n this.reconcileEveryMs = options.reconcileEveryMs ?? 15 * MINUTE;\n this.stopDrainMs = options.stopDrainMs ?? 15 * MINUTE;\n }\n\n /**\n * A start, planned for one entry attempt. Its name is new every time: a failed entry reclaimed\n * under the same instance id (an event replayed with its ts) must start a new execution — the\n * old name would return the closed one. Retries of this attempt reuse the recorded name.\n */\n async plan(options: {\n id: string;\n params: JourneyParams;\n ts: number;\n version?: string | undefined;\n }): Promise<ExecutionStart> {\n const input: RunInput = {\n type: RUN_EVENT_TYPE,\n instanceId: options.id,\n params: options.params,\n // The moment the instance is created, like Cloudflare's: an event's own ts may be long past\n enteredAtMs: this.now(),\n };\n return {\n name: executionName(options.id, crypto.randomUUID().slice(0, 8)),\n target: await this.options.target(options.params.contentHash, options.version),\n input: JSON.stringify(input),\n };\n }\n\n async create(options: { id: string; params: unknown }): Promise<WorkflowInstanceLike> {\n const record = await this.options.executions.get(options.id);\n if (record === undefined) {\n throw new Error(`no start is recorded for ${options.id}: the entry must be planned first`);\n }\n await this.submit(record);\n return this.instance(options.id);\n }\n\n async get(id: string): Promise<WorkflowInstanceLike> {\n // A read of the registry alone: a Lambda failure must never read as \"no such instance\"\n if ((await this.options.executions.get(id)) === undefined) {\n throw new InstanceNotFoundError(id);\n }\n return this.instance(id);\n }\n\n async resume(entry: { workflow: string; userId: string }): Promise<void> {\n for (const record of await this.options.executions.pendingStarts({ ...entry, limit: 1 })) {\n if (!(await this.giveUpIfStale(record))) await this.submit(record);\n }\n }\n\n async maintain(): Promise<void> {\n const now = this.now();\n const failures: unknown[] = [];\n // Starts whose submit never confirmed: retried with the recorded name and payload\n for (const record of await this.options.executions.pendingStarts({\n createdBefore: now - MINUTE,\n limit: 25,\n })) {\n try {\n if (!(await this.giveUpIfStale(record))) await this.submit(record);\n } catch (error) {\n failures.push(error);\n }\n }\n // Executions the platform ended without the run finalizing (a timeout, a stop, a crash)\n for (const record of await this.options.executions.toReconcile(\n 25,\n now - this.reconcileEveryMs\n )) {\n try {\n await this.reconcile(record, now);\n } catch (error) {\n failures.push(error);\n }\n }\n if (failures.length > 0) throw failures[0];\n }\n\n private async submit(record: ExecutionRecord): Promise<void> {\n const { arn } = await this.options.lambda.startExecution({\n target: record.target,\n name: record.name,\n payload: record.input,\n });\n await this.options.executions.markSubmitted(record.instanceId, arn, this.now());\n }\n\n /** Past the retry budget a start is unresolved for good: no retry could tell a duplicate apart. */\n private async giveUpIfStale(record: ExecutionRecord): Promise<boolean> {\n if (this.now() - record.createdAt <= this.startRetryMs) return false;\n await this.options.executions.markUnresolved(record.instanceId, this.now());\n console.error(\n `[workflow] the start of ${record.instanceId} (${record.name}) was never confirmed: left unresolved`\n );\n return true;\n }\n\n private async arnOf(record: ExecutionRecord): Promise<string | undefined> {\n if (record.arn !== undefined) return record.arn;\n const arn = await this.options.lambda.findExecution(record.target, record.name);\n if (arn !== undefined) await this.options.executions.setArn(record.instanceId, arn);\n return arn;\n }\n\n /**\n * Past the start retry budget, an execution still nowhere to be seen never started: any queued\n * invoke has expired by then. Before that, not finding it says nothing.\n */\n private vanished(record: ExecutionRecord): boolean {\n return this.now() - record.createdAt > this.startRetryMs;\n }\n\n /** Stopped so recently that an invocation running at the time may still be acting. */\n private draining(record: ExecutionRecord): boolean {\n return record.stoppedAt !== undefined && this.now() - record.stoppedAt < this.stopDrainMs;\n }\n\n /**\n * The one judgment every path makes of an execution the platform reports stopped — by\n * `terminate`, by an operator, or seen by `reconcile` before the stop was recorded: the first\n * sighting is recorded (`markStopped` keeps an earlier time, so no poll ever extends the\n * drain), and the record is read again so the verdict rests on what is committed now, not on\n * the snapshot a caller read before its API calls. A write or read that fails throws: an\n * unknown stop time is never taken for \"safely stopped\". Undefined means the record is gone —\n * the erasure finished with it meanwhile.\n */\n private async observeStop(instanceId: string): Promise<ExecutionRecord | undefined> {\n await this.options.executions.markStopped(instanceId, this.now());\n return this.options.executions.get(instanceId);\n }\n\n private async reconcile(record: ExecutionRecord, now: number): Promise<void> {\n const arn = await this.arnOf(record);\n const state = arn === undefined ? undefined : await this.options.lambda.executionState(arn);\n // Only a state that will never run another step — or one missing for good — ends the entry;\n // a run still queued, or not visible yet, is left alone\n const ended =\n state === 'failed' ||\n state === 'stopped' ||\n state === 'timed_out' ||\n (state === undefined && this.vanished(record));\n if (ended) {\n // The verdict is taken on the record as it is now: `toReconcile` handed over a snapshot,\n // and a stop may have been recorded since — by `terminate`, or here, at its first sighting\n const fresh =\n state === 'stopped'\n ? await this.observeStop(record.instanceId)\n : await this.options.executions.get(record.instanceId);\n if (fresh === undefined) return;\n if (this.draining(fresh)) {\n // Stopped, but an invocation running at the stop may still be acting: the entry stays\n // running until the drain has passed, so an erasure keeps waiting for it (`status`\n // says running too), and the next look finalizes it\n await this.options.executions.markChecked(record.instanceId, now);\n return;\n }\n // Ended without its finalize step: the ledger must not show it running forever\n const { store } = this.options;\n await store.setEntryStatus(record.instanceId, 'failed');\n await store.reporting?.instanceFinished({\n workflow: record.workflow,\n instanceId: record.instanceId,\n userId: record.userId,\n status: 'failed',\n at: now,\n });\n console.warn(\n `[workflow] ${record.instanceId} ended on the platform (${state ?? 'unknown'}) without finishing: recorded as failed`\n );\n }\n await this.options.executions.markChecked(record.instanceId, now);\n }\n\n private instance(id: string): WorkflowInstanceLike {\n const { executions, lambda } = this.options;\n const current = async () => {\n const record = await executions.get(id);\n if (record === undefined) throw new InstanceNotFoundError(id);\n return record;\n };\n return {\n id,\n sendEvent: async (event) => {\n // The wait parked now, read at the moment of the wake: a newer wait's callback replaces\n // an older one, and a wake for none (the instance is between waits) is nothing to do —\n // its next wait re-reads the facts before parking\n const { callbackId } = await current();\n if (callbackId === undefined) return;\n await lambda.completeCallback(callbackId, JSON.stringify(event.payload ?? {}));\n },\n terminate: async () => {\n const record = await current();\n // Stopped before: done once an invocation that was running then has had time to end\n if (record.stoppedAt !== undefined) {\n if (this.draining(record)) {\n throw new Error(`${id} was stopped; its running invocation may still be finishing`);\n }\n return;\n }\n if (record.submittedAt === undefined && record.unresolvedAt === undefined) {\n // No retry may start it after this\n await executions.markUnresolved(id, this.now());\n }\n const arn = await this.arnOf(record);\n if (arn === undefined) {\n // Not visible yet is not stopped: the erasure stays pending, and the sweep retries\n if (this.vanished(record)) return;\n throw new Error(`cannot stop ${id} yet: its execution is not visible`);\n }\n // One that finished on its own has no invocation left to drain\n const state = await lambda.executionState(arn);\n if (state === 'succeeded' || state === 'failed' || state === 'timed_out') return;\n // A stop does not interrupt an invocation already running: it goes on to its next\n // checkpoint, side effects included. The erasure waits (see stopDrainMs). One already\n // stopped (by an operator, or a stop whose record did not land) is not stopped again:\n // its first sighting is recorded and the same drain judged\n if (state !== 'stopped' && !(await lambda.stopExecution(arn))) {\n throw new Error(`stopping ${id} failed`);\n }\n const fresh = await this.observeStop(id);\n if (fresh !== undefined && this.draining(fresh)) {\n throw new Error(`${id} is stopped; its running invocation may still be finishing`);\n }\n },\n status: async () => {\n const record = await current();\n if (this.draining(record)) return { status: 'running' };\n const arn = await this.arnOf(record);\n // Not visible yet may still run: only one missing past the budget is gone\n if (arn === undefined) return { status: this.vanished(record) ? 'terminated' : 'running' };\n const state = await lambda.executionState(arn);\n // In the router's vocabulary (Cloudflare's): what will never run another step\n if (state === 'succeeded') return { status: 'complete' };\n if (state === 'failed') return { status: 'errored' };\n if (state === 'running') return { status: 'running' };\n if (state === 'stopped') {\n // Stopped, seen here first or recorded since this read: the drain is the judgment\n const fresh = await this.observeStop(id);\n if (fresh !== undefined && this.draining(fresh)) return { status: 'running' };\n }\n return { status: 'terminated' };\n },\n };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"instances.mjs","names":[],"sources":["../../src/aws/instances.ts"],"sourcesContent":["import { murmur3 } from '../engine/bucket';\nimport {\n InstanceNotFoundError,\n type JourneyParams,\n type WorkflowBindingLike,\n type WorkflowInstanceLike,\n} from '../host/platform';\nimport type {\n ExecutionRecord,\n ExecutionRegistry,\n ExecutionStart,\n JourneyStore,\n} from '../store/index';\nimport type { LambdaApi } from './lambda-api';\n\n/**\n * The router's instance port over Lambda durable executions: an instance is one execution of\n * this same function, started by an asynchronous self-invoke under a stable execution name;\n * a wake completes the callback its current wait parks on; stopping stops the execution.\n */\n\n/** The top-level shape of an internal run: what the self-invoke sends, never an HTTP body. */\nexport const RUN_EVENT_TYPE = '$workflow.run';\n\nexport interface RunInput {\n type: typeof RUN_EVENT_TYPE;\n instanceId: string;\n params: JourneyParams;\n /** When the instance was created (as Cloudflare's event timestamp): its entry anchor, fixed with the start. */\n enteredAtMs: number;\n}\n\nexport function isRunInput(event: unknown): event is RunInput {\n if (typeof event !== 'object' || event === null) return false;\n const candidate = event as {\n type?: unknown;\n instanceId?: unknown;\n enteredAtMs?: unknown;\n params?: unknown;\n requestContext?: unknown;\n };\n return (\n candidate.type === RUN_EVENT_TYPE &&\n candidate.requestContext === undefined &&\n typeof candidate.instanceId === 'string' &&\n typeof candidate.enteredAtMs === 'number' &&\n typeof candidate.params === 'object' &&\n candidate.params !== null\n );\n}\n\nconst utf8 = new TextEncoder();\n\n/**\n * The durable execution name for one start of an instance: the instance id, cut to fit, with a\n * fingerprint of the whole id (so a cut never makes two instances collide) and the attempt's\n * token. Every retry of that start reuses the recorded name; a new attempt gets a new token.\n */\nexport function executionName(instanceId: string, attempt: string): string {\n const safe = instanceId.replace(/[^a-zA-Z0-9_-]/g, '-');\n const token = attempt.replace(/[^a-zA-Z0-9]/g, '').slice(0, 8);\n const fingerprint = `${murmur3(utf8.encode(instanceId)).toString(36)}${murmur3(utf8.encode(instanceId), 0x9747b28c).toString(36)}`;\n const suffix = `-${fingerprint}-${token}`;\n return `${safe.slice(0, 64 - suffix.length)}${suffix}`;\n}\n\nexport interface AwsInstancesOptions {\n store: JourneyStore;\n executions: ExecutionRegistry;\n lambda: LambdaApi;\n /**\n * The qualified function ARN an execution pinned to `contentHash` must run on; `version` is\n * the code version whose routes named it.\n */\n target(contentHash: string, version?: string): Promise<string>;\n /**\n * How long an unconfirmed start keeps being retried. It must stay shorter than the durable\n * execution retention: past that the platform forgets the name, and a retry would start a\n * second execution. Twelve hours by default.\n */\n startRetryMs?: number;\n /** How stale a running instance's last check must be before maintenance looks again. */\n reconcileEveryMs?: number;\n /**\n * How long after a stop an invocation already running may still act: Lambda cannot interrupt\n * one, and it runs on to its next checkpoint. An erasure waits this long before it erases.\n * The function's timeout is enough; 15 minutes (Lambda's maximum) by default.\n */\n stopDrainMs?: number;\n now?: () => number;\n}\n\nconst MINUTE = 60_000;\n\nexport class AwsInstances implements WorkflowBindingLike {\n private readonly now: () => number;\n private readonly startRetryMs: number;\n private readonly reconcileEveryMs: number;\n private readonly stopDrainMs: number;\n\n constructor(private readonly options: AwsInstancesOptions) {\n this.now = options.now ?? Date.now;\n this.startRetryMs = options.startRetryMs ?? 12 * 60 * MINUTE;\n this.reconcileEveryMs = options.reconcileEveryMs ?? 15 * MINUTE;\n this.stopDrainMs = options.stopDrainMs ?? 15 * MINUTE;\n }\n\n /**\n * A start, planned for one entry attempt. Its name is new every time: a failed entry reclaimed\n * under the same instance id (an event replayed with its ts) must start a new execution — the\n * old name would return the closed one. Retries of this attempt reuse the recorded name.\n */\n async plan(options: {\n id: string;\n params: JourneyParams;\n ts: number;\n version?: string | undefined;\n }): Promise<ExecutionStart> {\n const input: RunInput = {\n type: RUN_EVENT_TYPE,\n instanceId: options.id,\n params: options.params,\n // The moment the instance is created, like Cloudflare's: an event's own ts may be long past\n enteredAtMs: this.now(),\n };\n return {\n name: executionName(options.id, crypto.randomUUID().slice(0, 8)),\n target: await this.options.target(options.params.contentHash, options.version),\n input: JSON.stringify(input),\n };\n }\n\n async create(options: { id: string; params: unknown }): Promise<WorkflowInstanceLike> {\n const record = await this.options.executions.get(options.id);\n if (record === undefined) {\n throw new Error(`no start is recorded for ${options.id}: the entry must be planned first`);\n }\n await this.submit(record);\n return this.instance(options.id);\n }\n\n async get(id: string): Promise<WorkflowInstanceLike> {\n // A read of the registry alone: a Lambda failure must never read as \"no such instance\"\n if ((await this.options.executions.get(id)) === undefined) {\n throw new InstanceNotFoundError(id);\n }\n return this.instance(id);\n }\n\n async resume(entry: { workflow: string; userId: string }): Promise<void> {\n for (const record of await this.options.executions.pendingStarts({ ...entry, limit: 1 })) {\n if (!(await this.giveUpIfStale(record))) await this.submit(record);\n }\n }\n\n async maintain(): Promise<void> {\n const now = this.now();\n const failures: unknown[] = [];\n // Starts whose submit never confirmed: retried with the recorded name and payload\n for (const record of await this.options.executions.pendingStarts({\n createdBefore: now - MINUTE,\n limit: 25,\n })) {\n try {\n if (!(await this.giveUpIfStale(record))) await this.submit(record);\n } catch (error) {\n failures.push(error);\n }\n }\n // Executions the platform ended without the run finalizing (a timeout, a stop, a crash)\n for (const record of await this.options.executions.toReconcile(\n 25,\n now - this.reconcileEveryMs\n )) {\n try {\n await this.reconcile(record, now);\n } catch (error) {\n failures.push(error);\n }\n }\n if (failures.length > 0) throw failures[0];\n }\n\n private async submit(record: ExecutionRecord): Promise<void> {\n const { arn } = await this.options.lambda.startExecution({\n target: record.target,\n name: record.name,\n payload: record.input,\n });\n await this.options.executions.markSubmitted(record.instanceId, arn, this.now());\n }\n\n /** Past the retry budget a start is unresolved for good: no retry could tell a duplicate apart. */\n private async giveUpIfStale(record: ExecutionRecord): Promise<boolean> {\n if (this.now() - record.createdAt <= this.startRetryMs) return false;\n await this.options.executions.markUnresolved(record.instanceId, this.now());\n console.error(\n `[workflow] the start of ${record.instanceId} (${record.name}) was never confirmed: left unresolved`\n );\n return true;\n }\n\n private async arnOf(record: ExecutionRecord): Promise<string | undefined> {\n if (record.arn !== undefined) return record.arn;\n const arn = await this.options.lambda.findExecution(record.target, record.name);\n if (arn !== undefined) await this.options.executions.setArn(record.instanceId, arn);\n return arn;\n }\n\n /**\n * Past the start retry budget, an execution still nowhere to be seen never started: any queued\n * invoke has expired by then. Before that, not finding it says nothing.\n */\n private vanished(record: ExecutionRecord): boolean {\n return this.now() - record.createdAt > this.startRetryMs;\n }\n\n /** Stopped so recently that an invocation running at the time may still be acting. */\n private draining(record: ExecutionRecord): boolean {\n return record.stoppedAt !== undefined && this.now() - record.stoppedAt < this.stopDrainMs;\n }\n\n /**\n * The one judgment every path makes of an execution the platform reports stopped — by\n * `terminate`, by an operator, or seen by `reconcile` before the stop was recorded: the first\n * sighting is recorded (`markStopped` keeps an earlier time, so no poll ever extends the\n * drain), and the record is read again so the verdict rests on what is committed now, not on\n * the snapshot a caller read before its API calls. A write or read that fails throws: an\n * unknown stop time is never taken for \"safely stopped\". Undefined means the record is gone —\n * the erasure finished with it meanwhile.\n */\n private async observeStop(instanceId: string): Promise<ExecutionRecord | undefined> {\n await this.options.executions.markStopped(instanceId, this.now());\n return this.options.executions.get(instanceId);\n }\n\n private async reconcile(record: ExecutionRecord, now: number): Promise<void> {\n const arn = await this.arnOf(record);\n const state = arn === undefined ? undefined : await this.options.lambda.executionState(arn);\n // Only a state that will never run another step — or one missing for good — ends the entry;\n // a run still queued, or not visible yet, is left alone\n const ended =\n state === 'failed' ||\n state === 'stopped' ||\n state === 'timed_out' ||\n (state === undefined && this.vanished(record));\n if (ended) {\n // The verdict is taken on the record as it is now: `toReconcile` handed over a snapshot,\n // and a stop may have been recorded since — by `terminate`, or here, at its first sighting\n const fresh =\n state === 'stopped'\n ? await this.observeStop(record.instanceId)\n : await this.options.executions.get(record.instanceId);\n if (fresh === undefined) return;\n if (this.draining(fresh)) {\n // Stopped, but an invocation running at the stop may still be acting: the entry stays\n // running until the drain has passed, so an erasure keeps waiting for it (`status`\n // says running too), and the next look finalizes it\n await this.options.executions.markChecked(record.instanceId, now);\n return;\n }\n // Ended without its finalize step: the ledger must not show it running forever\n const { store } = this.options;\n await store.setEntryStatus(record.instanceId, 'failed');\n await store.reporting.instanceFinished({\n workflow: record.workflow,\n instanceId: record.instanceId,\n userId: record.userId,\n status: 'failed',\n at: now,\n });\n console.warn(\n `[workflow] ${record.instanceId} ended on the platform (${state ?? 'unknown'}) without finishing: recorded as failed`\n );\n }\n await this.options.executions.markChecked(record.instanceId, now);\n }\n\n private instance(id: string): WorkflowInstanceLike {\n const { executions, lambda } = this.options;\n const current = async () => {\n const record = await executions.get(id);\n if (record === undefined) throw new InstanceNotFoundError(id);\n return record;\n };\n return {\n id,\n sendEvent: async (event) => {\n // The wait parked now, read at the moment of the wake: a newer wait's callback replaces\n // an older one, and a wake for none (the instance is between waits) is nothing to do —\n // its next wait re-reads the facts before parking\n const { callbackId } = await current();\n if (callbackId === undefined) return;\n await lambda.completeCallback(callbackId, JSON.stringify(event.payload ?? {}));\n },\n terminate: async () => {\n const record = await current();\n // Stopped before: done once an invocation that was running then has had time to end\n if (record.stoppedAt !== undefined) {\n if (this.draining(record)) {\n throw new Error(`${id} was stopped; its running invocation may still be finishing`);\n }\n return;\n }\n if (record.submittedAt === undefined && record.unresolvedAt === undefined) {\n // No retry may start it after this\n await executions.markUnresolved(id, this.now());\n }\n const arn = await this.arnOf(record);\n if (arn === undefined) {\n // Not visible yet is not stopped: the erasure stays pending, and the sweep retries\n if (this.vanished(record)) return;\n throw new Error(`cannot stop ${id} yet: its execution is not visible`);\n }\n // One that finished on its own has no invocation left to drain\n const state = await lambda.executionState(arn);\n if (state === 'succeeded' || state === 'failed' || state === 'timed_out') return;\n // A stop does not interrupt an invocation already running: it goes on to its next\n // checkpoint, side effects included. The erasure waits (see stopDrainMs). One already\n // stopped (by an operator, or a stop whose record did not land) is not stopped again:\n // its first sighting is recorded and the same drain judged\n if (state !== 'stopped' && !(await lambda.stopExecution(arn))) {\n throw new Error(`stopping ${id} failed`);\n }\n const fresh = await this.observeStop(id);\n if (fresh !== undefined && this.draining(fresh)) {\n throw new Error(`${id} is stopped; its running invocation may still be finishing`);\n }\n },\n status: async () => {\n const record = await current();\n if (this.draining(record)) return { status: 'running' };\n const arn = await this.arnOf(record);\n // Not visible yet may still run: only one missing past the budget is gone\n if (arn === undefined) return { status: this.vanished(record) ? 'terminated' : 'running' };\n const state = await lambda.executionState(arn);\n // In the router's vocabulary (Cloudflare's): what will never run another step\n if (state === 'succeeded') return { status: 'complete' };\n if (state === 'failed') return { status: 'errored' };\n if (state === 'running') return { status: 'running' };\n if (state === 'stopped') {\n // Stopped, seen here first or recorded since this read: the drain is the judgment\n const fresh = await this.observeStop(id);\n if (fresh !== undefined && this.draining(fresh)) return { status: 'running' };\n }\n return { status: 'terminated' };\n },\n };\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- //#region src/aws/lambda-api.ts
2
+ // src/aws/lambda-api.ts
3
3
  const STATES = {
4
4
  RUNNING: "running",
5
5
  SUCCEEDED: "succeeded",
@@ -83,7 +83,6 @@ function sdkLambdaApi(options = {}) {
83
83
  }
84
84
  };
85
85
  }
86
- //#endregion
87
86
  exports.sdkLambdaApi = sdkLambdaApi;
88
87
 
89
88
  //# sourceMappingURL=lambda-api.cjs.map
@@ -1,5 +1,4 @@
1
1
  import * as LambdaSdk from "@aws-sdk/client-lambda";
2
- //#region src/aws/lambda-api.d.ts
3
2
  /**
4
3
  * The Lambda control-plane calls the adapter makes, as a port: starting an execution of this
5
4
  * function, completing a wake callback, and looking at or stopping an execution. The default
@@ -38,6 +37,5 @@ export declare function sdkLambdaApi(options?: {
38
37
  /** A configured client (endpoint, retries) instead of the default one. */
39
38
  client?: Pick<InstanceType<Sdk['LambdaClient']>, 'send'>;
40
39
  }): LambdaApi;
41
- //#endregion
42
40
  export {};
43
41
  //# sourceMappingURL=lambda-api.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lambda-api.d.cts","names":[],"sources":["../../src/aws/lambda-api.ts"],"mappings":";;;;;;;;YASY;iBAEK;;;;;EAKf,eAAe;IACb;IACA;IACA;MACE;IAAU;;;;;;EAKd,iBAAiB,oBAAoB,iBAAiB;;EAEtD,eAAe,cAAc,QAAQ;;EAErC,cAAc,gBAAgB,eAAe;;EAE7C,cAAc,cAAc;;KAoBzB,aAAa;;wBAGF,aACd;EACE;;EAEA,SAAS,KAAK,aAAa;IAE5B"}
1
+ {"version":3,"file":"lambda-api.d.cts","names":[],"sources":["../../src/aws/lambda-api.ts"],"mappings":";;;;;;;YASY;iBAEK;;;;;EAKf,eAAe;IACb;IACA;IACA;MACE;IAAU;;;;;;EAKd,iBAAiB,oBAAoB,iBAAiB;;EAEtD,eAAe,cAAc,QAAQ;;EAErC,cAAc,gBAAgB,eAAe;;EAE7C,cAAc,cAAc;;KAoBzB,aAAa;;wBAGF,aACd;EACE;;EAEA,SAAS,KAAK,aAAa;IAE5B"}
@@ -1,5 +1,4 @@
1
1
  import * as LambdaSdk from "@aws-sdk/client-lambda";
2
- //#region src/aws/lambda-api.d.ts
3
2
  /**
4
3
  * The Lambda control-plane calls the adapter makes, as a port: starting an execution of this
5
4
  * function, completing a wake callback, and looking at or stopping an execution. The default
@@ -38,6 +37,5 @@ export declare function sdkLambdaApi(options?: {
38
37
  /** A configured client (endpoint, retries) instead of the default one. */
39
38
  client?: Pick<InstanceType<Sdk['LambdaClient']>, 'send'>;
40
39
  }): LambdaApi;
41
- //#endregion
42
40
  export {};
43
41
  //# sourceMappingURL=lambda-api.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lambda-api.d.mts","names":[],"sources":["../../src/aws/lambda-api.ts"],"mappings":";;;;;;;;YASY;iBAEK;;;;;EAKf,eAAe;IACb;IACA;IACA;MACE;IAAU;;;;;;EAKd,iBAAiB,oBAAoB,iBAAiB;;EAEtD,eAAe,cAAc,QAAQ;;EAErC,cAAc,gBAAgB,eAAe;;EAE7C,cAAc,cAAc;;KAoBzB,aAAa;;wBAGF,aACd;EACE;;EAEA,SAAS,KAAK,aAAa;IAE5B"}
1
+ {"version":3,"file":"lambda-api.d.mts","names":[],"sources":["../../src/aws/lambda-api.ts"],"mappings":";;;;;;;YASY;iBAEK;;;;;EAKf,eAAe;IACb;IACA;IACA;MACE;IAAU;;;;;;EAKd,iBAAiB,oBAAoB,iBAAiB;;EAEtD,eAAe,cAAc,QAAQ;;EAErC,cAAc,gBAAgB,eAAe;;EAE7C,cAAc,cAAc;;KAoBzB,aAAa;;wBAGF,aACd;EACE;;EAEA,SAAS,KAAK,aAAa;IAE5B"}
@@ -1,4 +1,4 @@
1
- //#region src/aws/lambda-api.ts
1
+ // src/aws/lambda-api.ts
2
2
  const STATES = {
3
3
  RUNNING: "running",
4
4
  SUCCEEDED: "succeeded",
@@ -82,7 +82,6 @@ function sdkLambdaApi(options = {}) {
82
82
  }
83
83
  };
84
84
  }
85
- //#endregion
86
85
  export { sdkLambdaApi };
87
86
 
88
87
  //# sourceMappingURL=lambda-api.mjs.map
package/dist/client.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- //#region src/client.ts
2
+ // src/client.ts
3
3
  var JourneyClientError = class extends Error {
4
4
  path;
5
5
  status;
@@ -120,7 +120,6 @@ var JourneyClient = class {
120
120
  return await response.json();
121
121
  }
122
122
  };
123
- //#endregion
124
123
  exports.JourneyClient = JourneyClient;
125
124
  exports.JourneyClientError = JourneyClientError;
126
125
  exports.JourneyValidationError = JourneyValidationError;
package/dist/client.d.cts CHANGED
@@ -2,7 +2,6 @@ import { ProfileProps } from "./store/index.cjs";
2
2
  import { Contract, ContractIssue, ProfilePatch } from "./contract.cjs";
3
3
  import { DeployResult, IdentifyResult, IngestResult } from "./host/ingest.cjs";
4
4
  import * as core from "zod/v4/core";
5
- //#region src/client.d.ts
6
5
  /**
7
6
  * `@shware/workflow/client` — the producer side of the ingest API, for the
8
7
  * service that knows what users do (an api server, a webhook handler). Plain
@@ -104,6 +103,5 @@ export declare class JourneyClient<C extends Contract | undefined = undefined> {
104
103
  deploy(bundle: unknown): Promise<DeployResult>;
105
104
  private post;
106
105
  }
107
- //#endregion
108
106
  export {};
109
107
  //# sourceMappingURL=client.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.cts","names":[],"sources":["../src/client.ts"],"mappings":";;;;;;;;;;;iBAYiB,qBAAqB,UAAU;;;;;EAK9C,WAAW;;EAEX;;EAEA;;EAEA,eAAe;;qBAGJ,2BAA2B;WAE3B;WACA;WACA;EAHX,YACW,cACA,gBACA;;;qBAQA,+BAA+B;WAE/B;WACA;WACA,QAAQ;EAHnB,YACW,cACA,2BACA,QAAQ;;KAWhB,SAAS,KAAK,UAAU,eAAe,KAAK;;YAErC,gBAAgB,MAAM,wCAAwC,SAAS;KAC9E,UAAU,GAAG,MAAM,0BACnB,UAAU,yBAAyB,UAAU,gBAC9C,gBAAgB,SAAS,MACtB,SAAS,KAAK,MAAM,SAAS,GAAG,KAAK,UAAU;KAEjD,cAAc,MAAM,yBACrB,eACA,UAAU,SAAS,eAAe,KAAK,mBAAmB,KACxD,aAAa;iBAGF;;EAEf;;EAEA;;qBAGW,cAAc,UAAU;mBACN;EAA7B,YAA6B,SAAS,qBAAqB;;EAG3D,SAAS,gBAAgB,OAAO,cAAc,KAAK,QAAQ;;;;;;;EAgB3D,MAAM,UAAU,gBAAgB,IAC9B,gBACA,OAAO,MACJ,MAAM,UAAU,GAAG,KACrB,QAAQ;;;;;;EAsBX,eACE,gBACA;IAAU;IAAe;IAAqC;MAC7D;IAAU;IAAU;;;;;;EAcvB,cAAc,gBAAgB,oBAAoB;IAAU;IAAU;;;;;;;;EAUtE,WAAW,iBAAiB;IAAU;IAAU;IAAiB;;;EAKjE,aAAa,gBAAgB;IAAU;IAAU;;;EAKjD,aAAa,gBAAgB;IAAU;IAAU;;;EAKjD,OAAO,kBAAkB,QAAQ;UAInB"}
1
+ {"version":3,"file":"client.d.cts","names":[],"sources":["../src/client.ts"],"mappings":";;;;;;;;;;iBAYiB,qBAAqB,UAAU;;;;;EAK9C,WAAW;;EAEX;;EAEA;;EAEA,eAAe;;qBAGJ,2BAA2B;WAE3B;WACA;WACA;EAHX,YACW,cACA,gBACA;;;qBAQA,+BAA+B;WAE/B;WACA;WACA,QAAQ;EAHnB,YACW,cACA,2BACA,QAAQ;;KAWhB,SAAS,KAAK,UAAU,eAAe,KAAK;;YAErC,gBAAgB,MAAM,wCAAwC,SAAS;KAC9E,UAAU,GAAG,MAAM,0BACnB,UAAU,yBAAyB,UAAU,gBAC9C,gBAAgB,SAAS,MACtB,SAAS,KAAK,MAAM,SAAS,GAAG,KAAK,UAAU;KAEjD,cAAc,MAAM,yBACrB,eACA,UAAU,SAAS,eAAe,KAAK,mBAAmB,KACxD,aAAa;iBAGF;;EAEf;;EAEA;;qBAGW,cAAc,UAAU;mBACN;EAA7B,YAA6B,SAAS,qBAAqB;;EAG3D,SAAS,gBAAgB,OAAO,cAAc,KAAK,QAAQ;;;;;;;EAgB3D,MAAM,UAAU,gBAAgB,IAC9B,gBACA,OAAO,MACJ,MAAM,UAAU,GAAG,KACrB,QAAQ;;;;;;EAsBX,eACE,gBACA;IAAU;IAAe;IAAqC;MAC7D;IAAU;IAAU;;;;;;EAcvB,cAAc,gBAAgB,oBAAoB;IAAU;IAAU;;;;;;;;EAUtE,WAAW,iBAAiB;IAAU;IAAU;IAAiB;;;EAKjE,aAAa,gBAAgB;IAAU;IAAU;;;EAKjD,aAAa,gBAAgB;IAAU;IAAU;;;EAKjD,OAAO,kBAAkB,QAAQ;UAInB"}
package/dist/client.d.mts CHANGED
@@ -2,7 +2,6 @@ import { ProfileProps } from "./store/index.mjs";
2
2
  import { Contract, ContractIssue, ProfilePatch } from "./contract.mjs";
3
3
  import { DeployResult, IdentifyResult, IngestResult } from "./host/ingest.mjs";
4
4
  import * as core from "zod/v4/core";
5
- //#region src/client.d.ts
6
5
  /**
7
6
  * `@shware/workflow/client` — the producer side of the ingest API, for the
8
7
  * service that knows what users do (an api server, a webhook handler). Plain
@@ -104,6 +103,5 @@ export declare class JourneyClient<C extends Contract | undefined = undefined> {
104
103
  deploy(bundle: unknown): Promise<DeployResult>;
105
104
  private post;
106
105
  }
107
- //#endregion
108
106
  export {};
109
107
  //# sourceMappingURL=client.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.mts","names":[],"sources":["../src/client.ts"],"mappings":";;;;;;;;;;;iBAYiB,qBAAqB,UAAU;;;;;EAK9C,WAAW;;EAEX;;EAEA;;EAEA,eAAe;;qBAGJ,2BAA2B;WAE3B;WACA;WACA;EAHX,YACW,cACA,gBACA;;;qBAQA,+BAA+B;WAE/B;WACA;WACA,QAAQ;EAHnB,YACW,cACA,2BACA,QAAQ;;KAWhB,SAAS,KAAK,UAAU,eAAe,KAAK;;YAErC,gBAAgB,MAAM,wCAAwC,SAAS;KAC9E,UAAU,GAAG,MAAM,0BACnB,UAAU,yBAAyB,UAAU,gBAC9C,gBAAgB,SAAS,MACtB,SAAS,KAAK,MAAM,SAAS,GAAG,KAAK,UAAU;KAEjD,cAAc,MAAM,yBACrB,eACA,UAAU,SAAS,eAAe,KAAK,mBAAmB,KACxD,aAAa;iBAGF;;EAEf;;EAEA;;qBAGW,cAAc,UAAU;mBACN;EAA7B,YAA6B,SAAS,qBAAqB;;EAG3D,SAAS,gBAAgB,OAAO,cAAc,KAAK,QAAQ;;;;;;;EAgB3D,MAAM,UAAU,gBAAgB,IAC9B,gBACA,OAAO,MACJ,MAAM,UAAU,GAAG,KACrB,QAAQ;;;;;;EAsBX,eACE,gBACA;IAAU;IAAe;IAAqC;MAC7D;IAAU;IAAU;;;;;;EAcvB,cAAc,gBAAgB,oBAAoB;IAAU;IAAU;;;;;;;;EAUtE,WAAW,iBAAiB;IAAU;IAAU;IAAiB;;;EAKjE,aAAa,gBAAgB;IAAU;IAAU;;;EAKjD,aAAa,gBAAgB;IAAU;IAAU;;;EAKjD,OAAO,kBAAkB,QAAQ;UAInB"}
1
+ {"version":3,"file":"client.d.mts","names":[],"sources":["../src/client.ts"],"mappings":";;;;;;;;;;iBAYiB,qBAAqB,UAAU;;;;;EAK9C,WAAW;;EAEX;;EAEA;;EAEA,eAAe;;qBAGJ,2BAA2B;WAE3B;WACA;WACA;EAHX,YACW,cACA,gBACA;;;qBAQA,+BAA+B;WAE/B;WACA;WACA,QAAQ;EAHnB,YACW,cACA,2BACA,QAAQ;;KAWhB,SAAS,KAAK,UAAU,eAAe,KAAK;;YAErC,gBAAgB,MAAM,wCAAwC,SAAS;KAC9E,UAAU,GAAG,MAAM,0BACnB,UAAU,yBAAyB,UAAU,gBAC9C,gBAAgB,SAAS,MACtB,SAAS,KAAK,MAAM,SAAS,GAAG,KAAK,UAAU;KAEjD,cAAc,MAAM,yBACrB,eACA,UAAU,SAAS,eAAe,KAAK,mBAAmB,KACxD,aAAa;iBAGF;;EAEf;;EAEA;;qBAGW,cAAc,UAAU;mBACN;EAA7B,YAA6B,SAAS,qBAAqB;;EAG3D,SAAS,gBAAgB,OAAO,cAAc,KAAK,QAAQ;;;;;;;EAgB3D,MAAM,UAAU,gBAAgB,IAC9B,gBACA,OAAO,MACJ,MAAM,UAAU,GAAG,KACrB,QAAQ;;;;;;EAsBX,eACE,gBACA;IAAU;IAAe;IAAqC;MAC7D;IAAU;IAAU;;;;;;EAcvB,cAAc,gBAAgB,oBAAoB;IAAU;IAAU;;;;;;;;EAUtE,WAAW,iBAAiB;IAAU;IAAU;IAAiB;;;EAKjE,aAAa,gBAAgB;IAAU;IAAU;;;EAKjD,aAAa,gBAAgB;IAAU;IAAU;;;EAKjD,OAAO,kBAAkB,QAAQ;UAInB"}
package/dist/client.mjs CHANGED
@@ -1,4 +1,4 @@
1
- //#region src/client.ts
1
+ // src/client.ts
2
2
  var JourneyClientError = class extends Error {
3
3
  path;
4
4
  status;
@@ -119,7 +119,6 @@ var JourneyClient = class {
119
119
  return await response.json();
120
120
  }
121
121
  };
122
- //#endregion
123
122
  export { JourneyClient, JourneyClientError, JourneyValidationError };
124
123
 
125
124
  //# sourceMappingURL=client.mjs.map
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_host_platform = require("../host/platform.cjs");
3
- //#region src/cloudflare/bindings.ts
3
+ // src/cloudflare/bindings.ts
4
4
  /** How Cloudflare's `get` reports an unknown instance id. */
5
5
  const CF_NOT_FOUND = "instance.not_found";
6
6
  /**
@@ -42,7 +42,6 @@ const WAKE_TIMEOUT_TOLERANCE_MS = 5e3;
42
42
  function wakeExpired(deadlineMs, now) {
43
43
  return now >= deadlineMs - WAKE_TIMEOUT_TOLERANCE_MS;
44
44
  }
45
- //#endregion
46
45
  exports.WAKE_TIMEOUT_TOLERANCE_MS = WAKE_TIMEOUT_TOLERANCE_MS;
47
46
  exports.cloudflareJourneyBinding = cloudflareJourneyBinding;
48
47
  exports.wakeExpired = wakeExpired;