@temelj/workflow 0.0.0-alpha.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 (393) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +38 -0
  3. package/dist/attributes.d.mts +15 -0
  4. package/dist/attributes.mjs +30 -0
  5. package/dist/client/create.d.mts +31 -0
  6. package/dist/client/create.mjs +67 -0
  7. package/dist/client/facades.d.mts +21 -0
  8. package/dist/client/facades.mjs +142 -0
  9. package/dist/client/mod.d.mts +2 -0
  10. package/dist/client/mod.mjs +2 -0
  11. package/dist/client/run-handle.d.mts +66 -0
  12. package/dist/client/run-handle.mjs +156 -0
  13. package/dist/client/worker-options.d.mts +17 -0
  14. package/dist/client/worker-options.mjs +25 -0
  15. package/dist/collection.d.mts +15 -0
  16. package/dist/collection.mjs +33 -0
  17. package/dist/compiled-function.d.mts +27 -0
  18. package/dist/compiled-function.mjs +54 -0
  19. package/dist/definition.d.mts +37 -0
  20. package/dist/definition.mjs +83 -0
  21. package/dist/engine/child-workflow.d.mts +10 -0
  22. package/dist/engine/child-workflow.mjs +333 -0
  23. package/dist/engine/command-identity.d.mts +9 -0
  24. package/dist/engine/command-identity.mjs +14 -0
  25. package/dist/engine/create.d.mts +106 -0
  26. package/dist/engine/create.mjs +402 -0
  27. package/dist/engine/deterministic.d.mts +12 -0
  28. package/dist/engine/deterministic.mjs +102 -0
  29. package/dist/engine/durable-command.d.mts +10 -0
  30. package/dist/engine/durable-command.mjs +17 -0
  31. package/dist/engine/execution-api.d.mts +29 -0
  32. package/dist/engine/execution-api.mjs +33 -0
  33. package/dist/engine/execution-service.d.mts +41 -0
  34. package/dist/engine/execution-service.mjs +288 -0
  35. package/dist/engine/hooks.d.mts +56 -0
  36. package/dist/engine/hooks.mjs +237 -0
  37. package/dist/engine/inspection-api.d.mts +34 -0
  38. package/dist/engine/inspection-api.mjs +77 -0
  39. package/dist/engine/inspection.d.mts +18 -0
  40. package/dist/engine/inspection.mjs +149 -0
  41. package/dist/engine/lifecycle.d.mts +18 -0
  42. package/dist/engine/lifecycle.mjs +38 -0
  43. package/dist/engine/lock-replay.d.mts +30 -0
  44. package/dist/engine/lock-replay.mjs +38 -0
  45. package/dist/engine/lock.d.mts +21 -0
  46. package/dist/engine/lock.mjs +197 -0
  47. package/dist/engine/message.d.mts +47 -0
  48. package/dist/engine/message.mjs +357 -0
  49. package/dist/engine/mod.d.mts +4 -0
  50. package/dist/engine/mod.mjs +2 -0
  51. package/dist/engine/observation.d.mts +35 -0
  52. package/dist/engine/observation.mjs +201 -0
  53. package/dist/engine/recovery.d.mts +26 -0
  54. package/dist/engine/recovery.mjs +92 -0
  55. package/dist/engine/replay.d.mts +41 -0
  56. package/dist/engine/replay.mjs +122 -0
  57. package/dist/engine/retry-policy.d.mts +4 -0
  58. package/dist/engine/retry-policy.mjs +4 -0
  59. package/dist/engine/retry.d.mts +23 -0
  60. package/dist/engine/retry.mjs +75 -0
  61. package/dist/engine/run-data.d.mts +9 -0
  62. package/dist/engine/run-data.mjs +74 -0
  63. package/dist/engine/run-service.d.mts +38 -0
  64. package/dist/engine/run-service.mjs +133 -0
  65. package/dist/engine/run-utils.d.mts +16 -0
  66. package/dist/engine/run-utils.mjs +83 -0
  67. package/dist/engine/schedule.d.mts +25 -0
  68. package/dist/engine/schedule.mjs +207 -0
  69. package/dist/engine/serialization.d.mts +9 -0
  70. package/dist/engine/serialization.mjs +85 -0
  71. package/dist/engine/start-api.d.mts +30 -0
  72. package/dist/engine/start-api.mjs +98 -0
  73. package/dist/engine/state.d.mts +77 -0
  74. package/dist/engine/state.mjs +464 -0
  75. package/dist/engine/step-api.d.mts +9 -0
  76. package/dist/engine/step-api.mjs +25 -0
  77. package/dist/engine/stream.d.mts +55 -0
  78. package/dist/engine/stream.mjs +333 -0
  79. package/dist/engine/summary/active-events.d.mts +34 -0
  80. package/dist/engine/summary/active-events.mjs +69 -0
  81. package/dist/engine/summary/child-workflow-runs.d.mts +24 -0
  82. package/dist/engine/summary/child-workflow-runs.mjs +138 -0
  83. package/dist/engine/summary/child-workflow-waits.d.mts +21 -0
  84. package/dist/engine/summary/child-workflow-waits.mjs +67 -0
  85. package/dist/engine/summary/recovery-child-workflow-waits.d.mts +11 -0
  86. package/dist/engine/summary/recovery-child-workflow-waits.mjs +89 -0
  87. package/dist/engine/summary/recovery-due-runs.d.mts +16 -0
  88. package/dist/engine/summary/recovery-due-runs.mjs +52 -0
  89. package/dist/engine/summary/recovery-failed-runs.d.mts +14 -0
  90. package/dist/engine/summary/recovery-failed-runs.mjs +33 -0
  91. package/dist/engine/summary/recovery-lease-runs.d.mts +16 -0
  92. package/dist/engine/summary/recovery-lease-runs.mjs +69 -0
  93. package/dist/engine/summary/recovery-locks.d.mts +18 -0
  94. package/dist/engine/summary/recovery-locks.mjs +100 -0
  95. package/dist/engine/summary/recovery-message-waits.d.mts +11 -0
  96. package/dist/engine/summary/recovery-message-waits.mjs +74 -0
  97. package/dist/engine/summary/recovery-retry-runs.d.mts +17 -0
  98. package/dist/engine/summary/recovery-retry-runs.mjs +65 -0
  99. package/dist/engine/summary/recovery-run-timestamps.d.mts +13 -0
  100. package/dist/engine/summary/recovery-run-timestamps.mjs +18 -0
  101. package/dist/engine/summary/recovery-runs.d.mts +23 -0
  102. package/dist/engine/summary/recovery-runs.mjs +54 -0
  103. package/dist/engine/summary/recovery-schedules.d.mts +10 -0
  104. package/dist/engine/summary/recovery-schedules.mjs +46 -0
  105. package/dist/engine/summary/recovery-sleep-waits.d.mts +10 -0
  106. package/dist/engine/summary/recovery-sleep-waits.mjs +53 -0
  107. package/dist/engine/summary/recovery-waits.d.mts +21 -0
  108. package/dist/engine/summary/recovery-waits.mjs +29 -0
  109. package/dist/engine/summary/run-availability.d.mts +13 -0
  110. package/dist/engine/summary/run-availability.mjs +37 -0
  111. package/dist/engine/summary/run-cleanup.d.mts +14 -0
  112. package/dist/engine/summary/run-cleanup.mjs +44 -0
  113. package/dist/engine/summary/run-failure.d.mts +14 -0
  114. package/dist/engine/summary/run-failure.mjs +62 -0
  115. package/dist/engine/summary/run-hooks.d.mts +14 -0
  116. package/dist/engine/summary/run-hooks.mjs +63 -0
  117. package/dist/engine/summary/run-lease.d.mts +11 -0
  118. package/dist/engine/summary/run-lease.mjs +64 -0
  119. package/dist/engine/summary/run-message-waits.d.mts +15 -0
  120. package/dist/engine/summary/run-message-waits.mjs +62 -0
  121. package/dist/engine/summary/run-metrics.d.mts +31 -0
  122. package/dist/engine/summary/run-metrics.mjs +93 -0
  123. package/dist/engine/summary/run-retry.d.mts +9 -0
  124. package/dist/engine/summary/run-retry.mjs +69 -0
  125. package/dist/engine/summary/run-sleeps.d.mts +15 -0
  126. package/dist/engine/summary/run-sleeps.mjs +61 -0
  127. package/dist/engine/summary/run-state.d.mts +26 -0
  128. package/dist/engine/summary/run-state.mjs +48 -0
  129. package/dist/engine/summary/run-status.d.mts +16 -0
  130. package/dist/engine/summary/run-status.mjs +35 -0
  131. package/dist/engine/summary/run-streams.d.mts +14 -0
  132. package/dist/engine/summary/run-streams.mjs +46 -0
  133. package/dist/engine/summary/run-transition.d.mts +9 -0
  134. package/dist/engine/summary/run-transition.mjs +39 -0
  135. package/dist/engine/summary/run-workflow.d.mts +9 -0
  136. package/dist/engine/summary/run-workflow.mjs +47 -0
  137. package/dist/engine/summary/step-attempt-active-child-workflows.d.mts +13 -0
  138. package/dist/engine/summary/step-attempt-active-child-workflows.mjs +55 -0
  139. package/dist/engine/summary/step-attempt-active-fields.d.mts +23 -0
  140. package/dist/engine/summary/step-attempt-active-fields.mjs +14 -0
  141. package/dist/engine/summary/step-attempt-active-message-waits.d.mts +12 -0
  142. package/dist/engine/summary/step-attempt-active-message-waits.mjs +47 -0
  143. package/dist/engine/summary/step-attempt-active-sleeps.d.mts +19 -0
  144. package/dist/engine/summary/step-attempt-active-sleeps.mjs +44 -0
  145. package/dist/engine/summary/step-attempt-buckets.d.mts +22 -0
  146. package/dist/engine/summary/step-attempt-buckets.mjs +152 -0
  147. package/dist/engine/summary/step-attempt-failure.d.mts +12 -0
  148. package/dist/engine/summary/step-attempt-failure.mjs +61 -0
  149. package/dist/engine/summary/step-attempt-lifecycle.d.mts +13 -0
  150. package/dist/engine/summary/step-attempt-lifecycle.mjs +19 -0
  151. package/dist/engine/summary/step-attempts.d.mts +11 -0
  152. package/dist/engine/summary/step-attempts.mjs +43 -0
  153. package/dist/engine/summary.d.mts +32 -0
  154. package/dist/engine/summary.mjs +37 -0
  155. package/dist/engine/task.d.mts +6 -0
  156. package/dist/engine/task.mjs +207 -0
  157. package/dist/errors/base.d.mts +99 -0
  158. package/dist/errors/base.mjs +426 -0
  159. package/dist/errors/capability.d.mts +11 -0
  160. package/dist/errors/capability.mjs +23 -0
  161. package/dist/errors/definition.d.mts +21 -0
  162. package/dist/errors/definition.mjs +51 -0
  163. package/dist/errors/details.d.mts +13 -0
  164. package/dist/errors/details.mjs +65 -0
  165. package/dist/errors/failures.d.mts +81 -0
  166. package/dist/errors/failures.mjs +168 -0
  167. package/dist/errors/hook.d.mts +14 -0
  168. package/dist/errors/hook.mjs +30 -0
  169. package/dist/errors/implementation.d.mts +11 -0
  170. package/dist/errors/implementation.mjs +25 -0
  171. package/dist/errors/lock.d.mts +28 -0
  172. package/dist/errors/lock.mjs +70 -0
  173. package/dist/errors/message.d.mts +106 -0
  174. package/dist/errors/message.mjs +122 -0
  175. package/dist/errors/mod.d.mts +17 -0
  176. package/dist/errors/mod.mjs +17 -0
  177. package/dist/errors/record-view.d.mts +11 -0
  178. package/dist/errors/record-view.mjs +24 -0
  179. package/dist/errors/records.d.mts +7 -0
  180. package/dist/errors/records.mjs +280 -0
  181. package/dist/errors/run.d.mts +116 -0
  182. package/dist/errors/run.mjs +232 -0
  183. package/dist/errors/runtime.d.mts +12 -0
  184. package/dist/errors/runtime.mjs +24 -0
  185. package/dist/errors/schedule.d.mts +27 -0
  186. package/dist/errors/schedule.mjs +65 -0
  187. package/dist/errors/step.d.mts +76 -0
  188. package/dist/errors/step.mjs +113 -0
  189. package/dist/errors/stream.d.mts +24 -0
  190. package/dist/errors/stream.mjs +64 -0
  191. package/dist/esbuild.d.mts +7 -0
  192. package/dist/esbuild.mjs +6 -0
  193. package/dist/events/descriptors.d.mts +245 -0
  194. package/dist/events/descriptors.mjs +405 -0
  195. package/dist/events/mod.d.mts +3 -0
  196. package/dist/events/mod.mjs +2 -0
  197. package/dist/history/attempt-key.d.mts +6 -0
  198. package/dist/history/attempt-key.mjs +7 -0
  199. package/dist/history/mod.d.mts +71 -0
  200. package/dist/history/mod.mjs +195 -0
  201. package/dist/history/projection.d.mts +8 -0
  202. package/dist/history/projection.mjs +259 -0
  203. package/dist/history/replay-projection.d.mts +88 -0
  204. package/dist/history/replay-projection.mjs +369 -0
  205. package/dist/history/sequencer.d.mts +16 -0
  206. package/dist/history/sequencer.mjs +78 -0
  207. package/dist/history/step-attempts.d.mts +9 -0
  208. package/dist/history/step-attempts.mjs +50 -0
  209. package/dist/history/timeline.d.mts +16 -0
  210. package/dist/history/timeline.mjs +272 -0
  211. package/dist/history/validator.d.mts +9 -0
  212. package/dist/history/validator.mjs +110 -0
  213. package/dist/inspection/mod.d.mts +5 -0
  214. package/dist/inspection/mod.mjs +3 -0
  215. package/dist/message-options.d.mts +8 -0
  216. package/dist/message-options.mjs +25 -0
  217. package/dist/mod.d.mts +52 -0
  218. package/dist/mod.mjs +26 -0
  219. package/dist/otel/support.d.mts +18 -0
  220. package/dist/otel/support.mjs +102 -0
  221. package/dist/otel.d.mts +30 -0
  222. package/dist/otel.mjs +588 -0
  223. package/dist/pagination.d.mts +25 -0
  224. package/dist/pagination.mjs +73 -0
  225. package/dist/registry.d.mts +20 -0
  226. package/dist/registry.mjs +48 -0
  227. package/dist/rolldown.d.mts +7 -0
  228. package/dist/rolldown.mjs +6 -0
  229. package/dist/rollup.d.mts +7 -0
  230. package/dist/rollup.mjs +6 -0
  231. package/dist/rspack.d.mts +7 -0
  232. package/dist/rspack.mjs +6 -0
  233. package/dist/runtime.d.mts +34 -0
  234. package/dist/runtime.mjs +194 -0
  235. package/dist/step-definition.d.mts +10 -0
  236. package/dist/step-definition.mjs +15 -0
  237. package/dist/store/append-projection.d.mts +15 -0
  238. package/dist/store/append-projection.mjs +26 -0
  239. package/dist/store/capabilities.d.mts +14 -0
  240. package/dist/store/capabilities.mjs +42 -0
  241. package/dist/store/cleanup.d.mts +18 -0
  242. package/dist/store/cleanup.mjs +338 -0
  243. package/dist/store/compaction.d.mts +5 -0
  244. package/dist/store/compaction.mjs +8 -0
  245. package/dist/store/create.d.mts +52 -0
  246. package/dist/store/create.mjs +159 -0
  247. package/dist/store/event-append-project.d.mts +15 -0
  248. package/dist/store/event-append-project.mjs +77 -0
  249. package/dist/store/event-append.d.mts +37 -0
  250. package/dist/store/event-append.mjs +80 -0
  251. package/dist/store/event-history.d.mts +22 -0
  252. package/dist/store/event-history.mjs +75 -0
  253. package/dist/store/event.d.mts +10 -0
  254. package/dist/store/event.mjs +28 -0
  255. package/dist/store/idempotency.d.mts +10 -0
  256. package/dist/store/idempotency.mjs +167 -0
  257. package/dist/store/instrumentation.d.mts +7 -0
  258. package/dist/store/instrumentation.mjs +123 -0
  259. package/dist/store/lock.d.mts +8 -0
  260. package/dist/store/lock.mjs +28 -0
  261. package/dist/store/materialization.d.mts +30 -0
  262. package/dist/store/materialization.mjs +127 -0
  263. package/dist/store/message-index.d.mts +21 -0
  264. package/dist/store/message-index.mjs +121 -0
  265. package/dist/store/mod.d.mts +5 -0
  266. package/dist/store/mod.mjs +4 -0
  267. package/dist/store/query.d.mts +24 -0
  268. package/dist/store/query.mjs +82 -0
  269. package/dist/store/revision.d.mts +4 -0
  270. package/dist/store/revision.mjs +7 -0
  271. package/dist/store/run.d.mts +49 -0
  272. package/dist/store/run.mjs +236 -0
  273. package/dist/store/schedule.d.mts +12 -0
  274. package/dist/store/schedule.mjs +41 -0
  275. package/dist/store/schema.d.mts +14 -0
  276. package/dist/store/schema.mjs +17 -0
  277. package/dist/store/step-attempt.d.mts +14 -0
  278. package/dist/store/step-attempt.mjs +23 -0
  279. package/dist/store/storage-value.d.mts +5 -0
  280. package/dist/store/storage-value.mjs +6 -0
  281. package/dist/store/validation.d.mts +35 -0
  282. package/dist/store/validation.mjs +77 -0
  283. package/dist/store-keys.d.mts +49 -0
  284. package/dist/store-keys.mjs +63 -0
  285. package/dist/telemetry.d.mts +132 -0
  286. package/dist/telemetry.mjs +172 -0
  287. package/dist/temporal.d.mts +23 -0
  288. package/dist/temporal.mjs +59 -0
  289. package/dist/timer.d.mts +12 -0
  290. package/dist/timer.mjs +28 -0
  291. package/dist/types/cleanup.d.mts +112 -0
  292. package/dist/types/cleanup.mjs +22 -0
  293. package/dist/types/client.d.mts +270 -0
  294. package/dist/types/client.mjs +1 -0
  295. package/dist/types/common.d.mts +19 -0
  296. package/dist/types/common.mjs +15 -0
  297. package/dist/types/definition.d.mts +92 -0
  298. package/dist/types/definition.mjs +1 -0
  299. package/dist/types/engine-options.d.mts +76 -0
  300. package/dist/types/engine-options.mjs +1 -0
  301. package/dist/types/engine.d.mts +309 -0
  302. package/dist/types/engine.mjs +1 -0
  303. package/dist/types/error-code.d.mts +256 -0
  304. package/dist/types/error-code.mjs +131 -0
  305. package/dist/types/error.d.mts +236 -0
  306. package/dist/types/error.mjs +48 -0
  307. package/dist/types/events.d.mts +2869 -0
  308. package/dist/types/events.mjs +283 -0
  309. package/dist/types/hook.d.mts +149 -0
  310. package/dist/types/hook.mjs +66 -0
  311. package/dist/types/lock.d.mts +63 -0
  312. package/dist/types/lock.mjs +18 -0
  313. package/dist/types/message-id.d.mts +7 -0
  314. package/dist/types/message-id.mjs +5 -0
  315. package/dist/types/message.d.mts +87 -0
  316. package/dist/types/message.mjs +1 -0
  317. package/dist/types/observation.d.mts +146 -0
  318. package/dist/types/observation.mjs +1 -0
  319. package/dist/types/pagination.d.mts +32 -0
  320. package/dist/types/pagination.mjs +13 -0
  321. package/dist/types/result.d.mts +62 -0
  322. package/dist/types/result.mjs +1 -0
  323. package/dist/types/retry.d.mts +48 -0
  324. package/dist/types/retry.mjs +1 -0
  325. package/dist/types/run-id.d.mts +7 -0
  326. package/dist/types/run-id.mjs +5 -0
  327. package/dist/types/run-list.d.mts +43 -0
  328. package/dist/types/run-list.mjs +1 -0
  329. package/dist/types/run-options.d.mts +86 -0
  330. package/dist/types/run-options.mjs +1 -0
  331. package/dist/types/run.d.mts +355 -0
  332. package/dist/types/run.mjs +207 -0
  333. package/dist/types/runtime.d.mts +143 -0
  334. package/dist/types/runtime.mjs +21 -0
  335. package/dist/types/schedule.d.mts +127 -0
  336. package/dist/types/schedule.mjs +48 -0
  337. package/dist/types/step-attempts.d.mts +326 -0
  338. package/dist/types/step-attempts.mjs +43 -0
  339. package/dist/types/step-id.d.mts +7 -0
  340. package/dist/types/step-id.mjs +5 -0
  341. package/dist/types/step.d.mts +183 -0
  342. package/dist/types/step.mjs +5 -0
  343. package/dist/types/store.d.mts +254 -0
  344. package/dist/types/store.mjs +1 -0
  345. package/dist/types/stream-id.d.mts +7 -0
  346. package/dist/types/stream-id.mjs +5 -0
  347. package/dist/types/stream.d.mts +126 -0
  348. package/dist/types/stream.mjs +1 -0
  349. package/dist/types/summary.d.mts +318 -0
  350. package/dist/types/summary.mjs +1 -0
  351. package/dist/types/telemetry.d.mts +74 -0
  352. package/dist/types/telemetry.mjs +9 -0
  353. package/dist/types/timeline.d.mts +237 -0
  354. package/dist/types/timeline.mjs +1 -0
  355. package/dist/types/vite.d.mts +65 -0
  356. package/dist/types/vite.mjs +1 -0
  357. package/dist/types/worker-id.d.mts +7 -0
  358. package/dist/types/worker-id.mjs +5 -0
  359. package/dist/types/worker.d.mts +94 -0
  360. package/dist/types/worker.mjs +1 -0
  361. package/dist/utility.d.mts +49 -0
  362. package/dist/utility.mjs +122 -0
  363. package/dist/vite/ast.d.mts +23 -0
  364. package/dist/vite/ast.mjs +73 -0
  365. package/dist/vite/error.d.mts +19 -0
  366. package/dist/vite/error.mjs +47 -0
  367. package/dist/vite/generated-name.d.mts +7 -0
  368. package/dist/vite/generated-name.mjs +9 -0
  369. package/dist/vite/manifest.d.mts +7 -0
  370. package/dist/vite/manifest.mjs +106 -0
  371. package/dist/vite/plugin.d.mts +7 -0
  372. package/dist/vite/plugin.mjs +190 -0
  373. package/dist/vite/safety.d.mts +12 -0
  374. package/dist/vite/safety.mjs +96 -0
  375. package/dist/vite/source-edit.d.mts +12 -0
  376. package/dist/vite/source-edit.mjs +44 -0
  377. package/dist/vite/source-map.d.mts +11 -0
  378. package/dist/vite/source-map.mjs +53 -0
  379. package/dist/vite/source.d.mts +7 -0
  380. package/dist/vite/source.mjs +14 -0
  381. package/dist/vite/transform.d.mts +7 -0
  382. package/dist/vite/transform.mjs +405 -0
  383. package/dist/vite.d.mts +6 -0
  384. package/dist/vite.mjs +5 -0
  385. package/dist/webhook.d.mts +16 -0
  386. package/dist/webhook.mjs +17 -0
  387. package/dist/webpack.d.mts +7 -0
  388. package/dist/webpack.mjs +6 -0
  389. package/dist/worker/error.d.mts +11 -0
  390. package/dist/worker/error.mjs +40 -0
  391. package/dist/worker.d.mts +18 -0
  392. package/dist/worker.mjs +427 -0
  393. package/package.json +144 -0
@@ -0,0 +1,37 @@
1
+ import { RunId } from "../types/run-id.mjs";
2
+ import { WorkflowRunRecord } from "../types/run.mjs";
3
+ import { EventRecord } from "../types/events.mjs";
4
+ import { WorkflowStorage } from "../types/store.mjs";
5
+ import { StorageCompareAndSetManyItem, StorageValue } from "@temelj/storage";
6
+ //#region src/store/event-append.d.ts
7
+ type WorkflowEventAppendSuccessOutcome = {
8
+ readonly status: "appended";
9
+ readonly events: readonly EventRecord[];
10
+ readonly previousEventHistory?: StorageValue;
11
+ } | {
12
+ readonly status: "duplicate";
13
+ readonly events: readonly EventRecord[];
14
+ };
15
+ type WorkflowEventAppendOutcome = WorkflowEventAppendSuccessOutcome | {
16
+ readonly status: "staleRun";
17
+ };
18
+ type WorkflowEventAppendedOutcome = Extract<WorkflowEventAppendSuccessOutcome, {
19
+ readonly status: "appended";
20
+ }>;
21
+ interface WorkflowEventAppendAtomicProjectionPlan {
22
+ readonly item?: StorageCompareAndSetManyItem<StorageValue>;
23
+ }
24
+ type WorkflowEventAppendAtomicProjectionPlanner = (attempt: number) => Promise<WorkflowEventAppendAtomicProjectionPlan | undefined>;
25
+ type WorkflowEventAppendDuplicateDetector = (runId: RunId, events: readonly EventRecord[], event: EventRecord) => Extract<WorkflowEventAppendSuccessOutcome, {
26
+ readonly status: "duplicate";
27
+ }> | undefined;
28
+ interface EventAppendOptions {
29
+ readonly detectDuplicate?: WorkflowEventAppendDuplicateDetector;
30
+ readonly previousEventHistory?: StorageValue;
31
+ }
32
+ declare function makeStaleRunAppendOutcome(): WorkflowEventAppendOutcome;
33
+ declare function appendEventWithAtomicProjectionPlan(storage: WorkflowStorage, namespace: string, runId: RunId, event: EventRecord, planProjection?: WorkflowEventAppendAtomicProjectionPlanner, detectDuplicate?: WorkflowEventAppendDuplicateDetector): Promise<WorkflowEventAppendSuccessOutcome>;
34
+ declare function appendEventIfRunRevisionCurrentAtomically(storage: WorkflowStorage, namespace: string, currentRun: WorkflowRunRecord, event: EventRecord, detectDuplicate?: WorkflowEventAppendDuplicateDetector): Promise<WorkflowEventAppendOutcome>;
35
+ declare function appendEventIfCurrent(storage: WorkflowStorage, namespace: string, runId: RunId, event: EventRecord, options?: EventAppendOptions): Promise<WorkflowEventAppendSuccessOutcome>;
36
+ //#endregion
37
+ export { WorkflowEventAppendAtomicProjectionPlanner, WorkflowEventAppendDuplicateDetector, WorkflowEventAppendOutcome, WorkflowEventAppendSuccessOutcome, WorkflowEventAppendedOutcome, appendEventIfCurrent, appendEventIfRunRevisionCurrentAtomically, appendEventWithAtomicProjectionPlan, makeStaleRunAppendOutcome };
@@ -0,0 +1,80 @@
1
+ import { WorkflowStateError } from "../errors/base.mjs";
2
+ import "../errors/mod.mjs";
3
+ import { supportsWorkflowAtomicBatchWrite, supportsWorkflowConditionalWrite } from "./capabilities.mjs";
4
+ import { makeEventsKey, makeRunKey } from "../store-keys.mjs";
5
+ import { toStorageValue } from "./storage-value.mjs";
6
+ import { createRunRevisionGuardedEventHistoryCompareAndSetItems, createWorkflowEventHistoryCompareAndSetItem, getStoredEventHistory } from "./event-history.mjs";
7
+ //#region src/store/event-append.ts
8
+ const MAX_APPEND_EVENT_ATTEMPTS = 16;
9
+ function makeAppendedEventOutcome(events, previousEventHistory) {
10
+ return {
11
+ status: "appended",
12
+ events,
13
+ ...previousEventHistory === void 0 ? {} : { previousEventHistory }
14
+ };
15
+ }
16
+ function makeStaleRunAppendOutcome() {
17
+ return { status: "staleRun" };
18
+ }
19
+ async function appendEventWithAtomicProjectionPlan(storage, namespace, runId, event, planProjection, detectDuplicate) {
20
+ if (!supportsWorkflowAtomicBatchWrite(storage)) return await appendEventIfCurrent(storage, namespace, runId, event, {
21
+ detectDuplicate,
22
+ previousEventHistory: await storage.get(makeEventsKey(namespace, runId))
23
+ });
24
+ const eventsStorageKey = makeEventsKey(namespace, runId);
25
+ for (let attempt = 0; attempt < MAX_APPEND_EVENT_ATTEMPTS; attempt++) {
26
+ const appendState = await readWorkflowEventAppendState(storage, eventsStorageKey, runId, event, detectDuplicate);
27
+ const duplicate = appendState.duplicate;
28
+ if (duplicate !== void 0) return duplicate;
29
+ const projectionPlan = await planProjection?.(attempt);
30
+ const items = [createWorkflowEventHistoryCompareAndSetItem(eventsStorageKey, appendState.raw, appendState.nextEvents), ...projectionPlan?.item === void 0 ? [] : [projectionPlan.item]];
31
+ if (await storage.compareAndSetMany(items)) return makeAppendedEventOutcome(appendState.nextEvents, appendState.raw);
32
+ }
33
+ WorkflowStateError.failedWorkflowEventAppend(runId, MAX_APPEND_EVENT_ATTEMPTS);
34
+ }
35
+ async function appendEventIfRunRevisionCurrentAtomically(storage, namespace, currentRun, event, detectDuplicate) {
36
+ const runId = currentRun.id;
37
+ const runStorageKey = makeRunKey(namespace, runId);
38
+ const eventsStorageKey = makeEventsKey(namespace, runId);
39
+ for (let attempt = 0; attempt < MAX_APPEND_EVENT_ATTEMPTS; attempt++) {
40
+ const appendState = await readWorkflowEventAppendState(storage, eventsStorageKey, runId, event, detectDuplicate);
41
+ const duplicate = appendState.duplicate;
42
+ if (duplicate !== void 0) {
43
+ if (await storage.compareAndSetMany(createRunRevisionGuardedEventHistoryCompareAndSetItems(runStorageKey, currentRun, eventsStorageKey, appendState.raw, appendState.currentEvents))) return duplicate;
44
+ continue;
45
+ }
46
+ if (await storage.compareAndSetMany(createRunRevisionGuardedEventHistoryCompareAndSetItems(runStorageKey, currentRun, eventsStorageKey, appendState.raw, appendState.nextEvents))) return makeAppendedEventOutcome(appendState.nextEvents, appendState.raw);
47
+ if (event.kind === "message_sent") return makeStaleRunAppendOutcome();
48
+ }
49
+ return makeStaleRunAppendOutcome();
50
+ }
51
+ async function appendEventIfCurrent(storage, namespace, runId, event, options = {}) {
52
+ const key = makeEventsKey(namespace, runId);
53
+ if (!supportsWorkflowConditionalWrite(storage)) {
54
+ const current = (await getStoredEventHistory(storage, key)).events;
55
+ const duplicate = options.detectDuplicate?.(runId, current, event);
56
+ if (duplicate !== void 0) return duplicate;
57
+ const events = [...current, event];
58
+ await storage.set(key, toStorageValue(events));
59
+ return makeAppendedEventOutcome(events, options.previousEventHistory);
60
+ }
61
+ for (let attempt = 0; attempt < MAX_APPEND_EVENT_ATTEMPTS; attempt++) {
62
+ const appendState = await readWorkflowEventAppendState(storage, key, runId, event, options.detectDuplicate);
63
+ const duplicate = appendState.duplicate;
64
+ if (duplicate !== void 0) return duplicate;
65
+ if (await storage.compareAndSet(key, appendState.raw, toStorageValue(appendState.nextEvents))) return makeAppendedEventOutcome(appendState.nextEvents, appendState.raw);
66
+ }
67
+ WorkflowStateError.failedWorkflowEventAppend(runId, MAX_APPEND_EVENT_ATTEMPTS);
68
+ }
69
+ async function readWorkflowEventAppendState(storage, eventsStorageKey, runId, event, detectDuplicate) {
70
+ const { raw, events: currentEvents } = await getStoredEventHistory(storage, eventsStorageKey);
71
+ const duplicate = detectDuplicate?.(runId, currentEvents, event);
72
+ return {
73
+ raw,
74
+ currentEvents,
75
+ ...duplicate === void 0 ? {} : { duplicate },
76
+ nextEvents: duplicate === void 0 ? [...currentEvents, event] : currentEvents
77
+ };
78
+ }
79
+ //#endregion
80
+ export { appendEventIfCurrent, appendEventIfRunRevisionCurrentAtomically, appendEventWithAtomicProjectionPlan, makeStaleRunAppendOutcome };
@@ -0,0 +1,22 @@
1
+ import { RunId } from "../types/run-id.mjs";
2
+ import { WorkflowRunRecord } from "../types/run.mjs";
3
+ import { EventRecord } from "../types/events.mjs";
4
+ import { WorkflowStorage } from "../types/store.mjs";
5
+ import { StorageCompareAndSetManyItem, StorageValue } from "@temelj/storage";
6
+ //#region src/store/event-history.d.ts
7
+ type WorkflowEventHistoryCompareAndSetItem = StorageCompareAndSetManyItem<StorageValue>;
8
+ type WorkflowRunRevisionCompareAndSetItem = StorageCompareAndSetManyItem<StorageValue>;
9
+ declare function getStoredEventHistory(storage: WorkflowStorage, key: string): Promise<{
10
+ readonly raw: StorageValue | undefined;
11
+ readonly events: readonly EventRecord[];
12
+ }>;
13
+ declare function getStoredCleanupEventHistory(storage: WorkflowStorage, key: string): Promise<{
14
+ readonly raw: StorageValue | undefined;
15
+ readonly events: readonly EventRecord[];
16
+ }>;
17
+ declare function isSameWorkflowEventIdentity(left: EventRecord, right: EventRecord): boolean;
18
+ declare function rollbackAppendedEventIfCurrent(storage: WorkflowStorage, namespace: string, runId: RunId, expectedEvents: readonly EventRecord[], previousEventHistory?: StorageValue): Promise<boolean>;
19
+ declare function createWorkflowEventHistoryCompareAndSetItem(eventsStorageKey: string, expected: StorageValue | undefined, events: readonly EventRecord[]): WorkflowEventHistoryCompareAndSetItem;
20
+ declare function createRunRevisionGuardedEventHistoryCompareAndSetItems(runStorageKey: string, currentRun: WorkflowRunRecord, eventsStorageKey: string, expectedEvents: StorageValue | undefined, events: readonly EventRecord[]): readonly [WorkflowRunRevisionCompareAndSetItem, WorkflowEventHistoryCompareAndSetItem];
21
+ //#endregion
22
+ export { createRunRevisionGuardedEventHistoryCompareAndSetItems, createWorkflowEventHistoryCompareAndSetItem, getStoredCleanupEventHistory, getStoredEventHistory, isSameWorkflowEventIdentity, rollbackAppendedEventIfCurrent };
@@ -0,0 +1,75 @@
1
+ import { getEventDescriptor, isCleanupEventRecord } from "../events/descriptors.mjs";
2
+ import { supportsWorkflowConditionalWrite } from "./capabilities.mjs";
3
+ import { makeEventsKey } from "../store-keys.mjs";
4
+ import { isSameWorkflowStorageValue } from "./revision.mjs";
5
+ import { toStorageValue } from "./storage-value.mjs";
6
+ import { isReadableEventRecord } from "./validation.mjs";
7
+ //#region src/store/event-history.ts
8
+ async function getStoredEventHistory(storage, key) {
9
+ const raw = await storage.get(key);
10
+ return {
11
+ raw,
12
+ events: Array.isArray(raw) ? raw.filter(isReadableEventRecord) : []
13
+ };
14
+ }
15
+ async function getStoredCleanupEventHistory(storage, key) {
16
+ const history = await getStoredEventHistory(storage, key);
17
+ return {
18
+ raw: history.raw,
19
+ events: history.events.filter(isCleanupEventRecord)
20
+ };
21
+ }
22
+ function isSameWorkflowEventIdentity(left, right) {
23
+ if (left.kind !== right.kind || Temporal.Instant.compare(left.timestamp, right.timestamp) !== 0) return false;
24
+ const descriptor = getEventDescriptor(left.kind);
25
+ return isSameWorkflowEventFields(left, right, descriptor.identityFields) && isSameWorkflowEventValueFields(left, right, descriptor.valueIdentityFields) && isSameWorkflowEventStringListFields(left, right, descriptor.stringListIdentityFields);
26
+ }
27
+ function isSameWorkflowEventFields(left, right, fields = []) {
28
+ return fields.every((field) => Reflect.get(left, field) === Reflect.get(right, field));
29
+ }
30
+ function isSameWorkflowEventValueFields(left, right, fields = []) {
31
+ return fields.every((field) => isSameWorkflowStorageValue(Reflect.get(left, field), Reflect.get(right, field)));
32
+ }
33
+ function isSameWorkflowEventStringListFields(left, right, fields = []) {
34
+ return fields.every((field) => {
35
+ const leftValue = Reflect.get(left, field);
36
+ const rightValue = Reflect.get(right, field);
37
+ const leftValues = Array.isArray(leftValue) && leftValue.every((item) => typeof item === "string" && item.trim() !== "") ? leftValue : void 0;
38
+ const rightValues = Array.isArray(rightValue) && rightValue.every((item) => typeof item === "string" && item.trim() !== "") ? rightValue : void 0;
39
+ if (leftValues === void 0 || rightValues === void 0) return leftValues === rightValues;
40
+ if (leftValues.length !== rightValues.length) return false;
41
+ return leftValues.every((value, index) => value === rightValues[index]);
42
+ });
43
+ }
44
+ async function rollbackAppendedEventIfCurrent(storage, namespace, runId, expectedEvents, previousEventHistory) {
45
+ if (expectedEvents.length === 0) return false;
46
+ const key = makeEventsKey(namespace, runId);
47
+ const rolledBackEvents = expectedEvents.slice(0, -1);
48
+ if (supportsWorkflowConditionalWrite(storage)) return await storage.compareAndSet(key, toStorageValue(expectedEvents), previousEventHistory ?? toStorageValue(rolledBackEvents));
49
+ const current = (await getStoredEventHistory(storage, key)).events;
50
+ const expectedLast = expectedEvents.at(-1);
51
+ const currentLast = current.at(-1);
52
+ if (current.length !== expectedEvents.length || expectedLast === void 0 || currentLast === void 0 || !isSameWorkflowEventIdentity(currentLast, expectedLast)) return false;
53
+ await storage.set(key, previousEventHistory ?? toStorageValue(rolledBackEvents));
54
+ return true;
55
+ }
56
+ function createWorkflowEventHistoryCompareAndSetItem(eventsStorageKey, expected, events) {
57
+ return {
58
+ key: eventsStorageKey,
59
+ expected,
60
+ value: toStorageValue(events)
61
+ };
62
+ }
63
+ function createWorkflowRunRevisionCompareAndSetItem(runStorageKey, currentRun) {
64
+ const value = toStorageValue(currentRun);
65
+ return {
66
+ key: runStorageKey,
67
+ expected: value,
68
+ value
69
+ };
70
+ }
71
+ function createRunRevisionGuardedEventHistoryCompareAndSetItems(runStorageKey, currentRun, eventsStorageKey, expectedEvents, events) {
72
+ return [createWorkflowRunRevisionCompareAndSetItem(runStorageKey, currentRun), createWorkflowEventHistoryCompareAndSetItem(eventsStorageKey, expectedEvents, events)];
73
+ }
74
+ //#endregion
75
+ export { createRunRevisionGuardedEventHistoryCompareAndSetItems, createWorkflowEventHistoryCompareAndSetItem, getStoredCleanupEventHistory, getStoredEventHistory, isSameWorkflowEventIdentity, rollbackAppendedEventIfCurrent };
@@ -0,0 +1,10 @@
1
+ import { RunId } from "../types/run-id.mjs";
2
+ import { WorkflowRunRecord } from "../types/run.mjs";
3
+ import { EventRecord } from "../types/events.mjs";
4
+ import { WorkflowStorage } from "../types/store.mjs";
5
+ //#region src/store/event.d.ts
6
+ declare function appendWorkflowEvent(storage: WorkflowStorage, namespace: string, runId: RunId, event: EventRecord): Promise<readonly EventRecord[]>;
7
+ declare function appendWorkflowEventIfRunCurrent(storage: WorkflowStorage, namespace: string, current: WorkflowRunRecord, event: EventRecord): Promise<readonly EventRecord[] | undefined>;
8
+ declare function getWorkflowEvents(storage: WorkflowStorage, namespace: string, runId: RunId): Promise<readonly EventRecord[]>;
9
+ //#endregion
10
+ export { appendWorkflowEvent, appendWorkflowEventIfRunCurrent, getWorkflowEvents };
@@ -0,0 +1,28 @@
1
+ import { WorkflowStateError } from "../errors/base.mjs";
2
+ import { makeEventsKey } from "../store-keys.mjs";
3
+ import { requireReadableStoreRun } from "./validation.mjs";
4
+ import { getStoredEventHistory } from "./event-history.mjs";
5
+ import { requireReadableStoredWorkflowRun } from "./run.mjs";
6
+ import { createWorkflowAppendProjectionPipeline } from "./append-projection.mjs";
7
+ import { appendEventWithProjectionPipelineIfRunCurrent, appendEventWithProjections } from "./event-append-project.mjs";
8
+ //#region src/store/event.ts
9
+ async function finalizeWorkflowAppendOutcome(outcome, projectionPipeline) {
10
+ if (outcome.status === "staleRun") return;
11
+ if (projectionPipeline === void 0) WorkflowStateError.appendProjectionPipelineMissing();
12
+ return await projectionPipeline.finalize(outcome);
13
+ }
14
+ async function appendWorkflowEvent(storage, namespace, runId, event) {
15
+ await requireReadableStoredWorkflowRun(storage, namespace, runId);
16
+ const projectionPipeline = await createWorkflowAppendProjectionPipeline(storage, namespace, runId, event);
17
+ return await finalizeWorkflowAppendOutcome(await appendEventWithProjections(storage, namespace, runId, event, projectionPipeline), projectionPipeline);
18
+ }
19
+ async function appendWorkflowEventIfRunCurrent(storage, namespace, current, event) {
20
+ requireReadableStoreRun(current, namespace);
21
+ const appendOutcome = await appendEventWithProjectionPipelineIfRunCurrent(storage, namespace, current, event);
22
+ return await finalizeWorkflowAppendOutcome(appendOutcome.outcome, appendOutcome.projectionPipeline);
23
+ }
24
+ async function getWorkflowEvents(storage, namespace, runId) {
25
+ return (await getStoredEventHistory(storage, makeEventsKey(namespace, runId))).events;
26
+ }
27
+ //#endregion
28
+ export { appendWorkflowEvent, appendWorkflowEventIfRunCurrent, getWorkflowEvents };
@@ -0,0 +1,10 @@
1
+ import { WorkflowRunRecord } from "../types/run.mjs";
2
+ import { WorkflowIdempotencyKeyOptions, WorkflowStorage } from "../types/store.mjs";
3
+ //#region src/store/idempotency.d.ts
4
+ interface WorkflowIdempotencyRunReader {
5
+ getRun(runId: string): Promise<WorkflowRunRecord | undefined>;
6
+ }
7
+ declare function createRunWithIdempotency(storage: WorkflowStorage, namespace: string, store: WorkflowIdempotencyRunReader, run: WorkflowRunRecord): Promise<WorkflowRunRecord>;
8
+ declare function getRunByIdempotencyKey(storage: WorkflowStorage, namespace: string, store: WorkflowIdempotencyRunReader, options: WorkflowIdempotencyKeyOptions): Promise<WorkflowRunRecord | undefined>;
9
+ //#endregion
10
+ export { createRunWithIdempotency, getRunByIdempotencyKey };
@@ -0,0 +1,167 @@
1
+ import { WorkflowStateError } from "../errors/base.mjs";
2
+ import "../errors/mod.mjs";
3
+ import { supportsWorkflowAtomicBatchWrite, supportsWorkflowConditionalWrite } from "./capabilities.mjs";
4
+ import { makeEventsKey, makeIdempotencyKey, makeRunKey } from "../store-keys.mjs";
5
+ import { toStorageValue } from "./storage-value.mjs";
6
+ import { isReadableWorkflowRunRecord } from "./validation.mjs";
7
+ //#region src/store/idempotency.ts
8
+ const MAX_IDEMPOTENT_CREATE_WAIT_ATTEMPTS = 16;
9
+ async function createRunWithIdempotency(storage, namespace, store, run) {
10
+ if (run.namespace !== namespace) throw WorkflowStateError.runNamespaceMismatch(String(run.namespace), namespace);
11
+ const keyOptions = idempotencyKeyOptionsForRun(run);
12
+ if (supportsWorkflowAtomicBatchWrite(storage)) return await createRunAtomicallyWithIdempotency(storage, namespace, store, run, keyOptions);
13
+ const idempotencyClaim = keyOptions === void 0 ? void 0 : await claimWorkflowIdempotencyIndex(storage, namespace, store, run, keyOptions);
14
+ if (idempotencyClaim?.status === "existing") return idempotencyClaim.run;
15
+ if (keyOptions !== void 0) assertWorkflowIdempotencyClaimed(run.id, idempotencyClaim);
16
+ try {
17
+ await createRunRecordAndEventHistory(storage, namespace, run);
18
+ return run;
19
+ } catch (error) {
20
+ await rollbackWorkflowIdempotencyClaim(storage, idempotencyClaim);
21
+ throw error;
22
+ }
23
+ }
24
+ async function createRunRecordAndEventHistory(storage, namespace, run) {
25
+ const runKey = makeRunKey(namespace, run.id);
26
+ const eventsKey = makeEventsKey(namespace, run.id);
27
+ let claim = {};
28
+ try {
29
+ if (!supportsWorkflowConditionalWrite(storage)) {
30
+ if (await storage.get(runKey) !== void 0) WorkflowStateError.runIdAlreadyExists(run.id);
31
+ if (await storage.get(eventsKey) !== void 0) WorkflowStateError.eventHistoryAlreadyExists(run.id);
32
+ await storage.set(runKey, toStorageValue(run));
33
+ claim = { runKey };
34
+ await storage.set(eventsKey, toStorageValue([]));
35
+ return {
36
+ ...claim,
37
+ eventsKey
38
+ };
39
+ }
40
+ if (!await storage.compareAndSet(runKey, void 0, toStorageValue(run))) WorkflowStateError.runIdAlreadyExists(run.id);
41
+ claim = { runKey };
42
+ if (!await storage.compareAndSet(eventsKey, void 0, toStorageValue([]))) WorkflowStateError.eventHistoryAlreadyExists(run.id);
43
+ return {
44
+ ...claim,
45
+ eventsKey
46
+ };
47
+ } catch (error) {
48
+ await rollbackRunCreationClaim(storage, claim);
49
+ throw error;
50
+ }
51
+ }
52
+ async function rollbackRunCreationClaim(storage, claim) {
53
+ await storage.deleteMany([...claim.runKey === void 0 ? [] : [claim.runKey], ...claim.eventsKey === void 0 ? [] : [claim.eventsKey]]);
54
+ }
55
+ async function rollbackWorkflowIdempotencyClaim(storage, claim) {
56
+ if (claim?.status !== "claimed") return;
57
+ if (!supportsWorkflowConditionalWrite(storage)) {
58
+ await storage.delete(claim.key);
59
+ return;
60
+ }
61
+ await storage.compareAndSet(claim.key, claim.value, void 0);
62
+ }
63
+ async function claimWorkflowIdempotencyIndex(storage, namespace, store, run, keyOptions) {
64
+ const key = makeIdempotencyKey(namespace, keyOptions);
65
+ const value = toStorageValue(run.id);
66
+ if (!supportsWorkflowConditionalWrite(storage)) {
67
+ const existingRun = await getRunByIdempotencyKey(storage, namespace, store, keyOptions);
68
+ if (existingRun !== void 0) return {
69
+ status: "existing",
70
+ run: existingRun
71
+ };
72
+ await storage.set(key, value);
73
+ return {
74
+ status: "claimed",
75
+ key,
76
+ value
77
+ };
78
+ }
79
+ if (await storage.compareAndSet(key, void 0, value)) return {
80
+ status: "claimed",
81
+ key,
82
+ value
83
+ };
84
+ const existingRun = await waitForRunByIdempotencyKey(storage, namespace, store, keyOptions);
85
+ if (existingRun !== void 0) return {
86
+ status: "existing",
87
+ run: existingRun
88
+ };
89
+ if (!await releaseStaleWorkflowIdempotencyIndex(storage, namespace, store, keyOptions)) WorkflowStateError.idempotencyKeyClaimedWithoutRun(run.id);
90
+ if (await storage.compareAndSet(key, void 0, value)) return {
91
+ status: "claimed",
92
+ key,
93
+ value
94
+ };
95
+ const reclaimedExistingRun = await waitForRunByIdempotencyKey(storage, namespace, store, keyOptions);
96
+ if (reclaimedExistingRun !== void 0) return {
97
+ status: "existing",
98
+ run: reclaimedExistingRun
99
+ };
100
+ WorkflowStateError.idempotencyKeyClaimedWithoutRun(run.id);
101
+ }
102
+ function assertWorkflowIdempotencyClaimed(runId, claim) {
103
+ if (claim?.status !== "claimed") WorkflowStateError.idempotencyKeyClaimedWithoutRun(runId);
104
+ }
105
+ async function createRunAtomicallyWithIdempotency(storage, namespace, store, run, keyOptions) {
106
+ for (let attempt = 0; attempt < 2; attempt++) {
107
+ if (await storage.compareAndSetMany([
108
+ ...atomicIdempotencyClaimItems(namespace, run, keyOptions),
109
+ {
110
+ key: makeRunKey(namespace, run.id),
111
+ expected: void 0,
112
+ value: toStorageValue(run)
113
+ },
114
+ {
115
+ key: makeEventsKey(namespace, run.id),
116
+ expected: void 0,
117
+ value: toStorageValue([])
118
+ }
119
+ ])) return run;
120
+ if (keyOptions === void 0) WorkflowStateError.runIdAlreadyExists(run.id);
121
+ const existingRun = await waitForRunByIdempotencyKey(storage, namespace, store, keyOptions);
122
+ if (existingRun !== void 0) return existingRun;
123
+ if (attempt === 0 && await releaseStaleWorkflowIdempotencyIndex(storage, namespace, store, keyOptions)) continue;
124
+ WorkflowStateError.idempotencyKeyClaimedWithoutRun(run.id);
125
+ }
126
+ throw WorkflowStateError.runIdAlreadyExists(run.id);
127
+ }
128
+ function atomicIdempotencyClaimItems(namespace, run, keyOptions) {
129
+ return keyOptions === void 0 ? [] : [{
130
+ key: makeIdempotencyKey(namespace, keyOptions),
131
+ expected: void 0,
132
+ value: toStorageValue(run.id)
133
+ }];
134
+ }
135
+ async function getRunByIdempotencyKey(storage, namespace, store, options) {
136
+ const runId = await storage.get(makeIdempotencyKey(namespace, options));
137
+ if (!(typeof runId === "string" && runId.trim() !== "")) return;
138
+ const run = await store.getRun(runId);
139
+ return run !== void 0 && isReadableWorkflowRunRecord(run, run.namespace) && run.workflowName === options.workflowName && run.workflowVersion === options.workflowVersion && run.idempotencyKey === options.idempotencyKey ? run : void 0;
140
+ }
141
+ function idempotencyKeyOptionsForRun(run) {
142
+ return run.idempotencyKey === void 0 ? void 0 : {
143
+ workflowName: run.workflowName,
144
+ ...run.workflowVersion === void 0 ? {} : { workflowVersion: run.workflowVersion },
145
+ idempotencyKey: run.idempotencyKey
146
+ };
147
+ }
148
+ async function waitForRunByIdempotencyKey(storage, namespace, store, options) {
149
+ for (let attempt = 0; attempt < MAX_IDEMPOTENT_CREATE_WAIT_ATTEMPTS; attempt++) {
150
+ const run = await getRunByIdempotencyKey(storage, namespace, store, options);
151
+ if (run !== void 0) return run;
152
+ await Promise.resolve();
153
+ }
154
+ }
155
+ async function releaseStaleWorkflowIdempotencyIndex(storage, namespace, store, options) {
156
+ if (!supportsWorkflowConditionalWrite(storage)) return false;
157
+ const key = makeIdempotencyKey(namespace, options);
158
+ const value = await storage.get(key);
159
+ if (value === void 0) return false;
160
+ if (typeof value === "string" && value.trim() !== "") {
161
+ const run = await store.getRun(value);
162
+ if (run !== void 0 && isReadableWorkflowRunRecord(run, run.namespace) && run.workflowName === options.workflowName && run.workflowVersion === options.workflowVersion && run.idempotencyKey === options.idempotencyKey) return false;
163
+ }
164
+ return await storage.compareAndSet(key, value, void 0);
165
+ }
166
+ //#endregion
167
+ export { createRunWithIdempotency, getRunByIdempotencyKey };
@@ -0,0 +1,7 @@
1
+ import { Telemetry } from "../types/telemetry.mjs";
2
+ import { WorkflowStorage } from "../types/store.mjs";
3
+ //#region src/store/instrumentation.d.ts
4
+ /** Wraps workflow storage operations with telemetry. */
5
+ declare function instrumentWorkflowStorage(storage: WorkflowStorage, telemetry: Telemetry | undefined): WorkflowStorage;
6
+ //#endregion
7
+ export { instrumentWorkflowStorage };
@@ -0,0 +1,123 @@
1
+ import { withStorageTelemetry } from "../telemetry.mjs";
2
+ //#region src/store/instrumentation.ts
3
+ /** Wraps workflow storage operations with telemetry. */
4
+ function instrumentWorkflowStorage(storage, telemetry) {
5
+ if (telemetry?.withStorageOperation === void 0) return storage;
6
+ const backend = storage.engine.name;
7
+ const run = async (operation, callback) => await withStorageTelemetry(telemetry, {
8
+ operation,
9
+ backend
10
+ }, callback);
11
+ const instrumented = {
12
+ engine: storage.engine,
13
+ capabilities: storage.capabilities,
14
+ on(pattern, handler) {
15
+ return storage.on(pattern, handler);
16
+ },
17
+ once(pattern, handler) {
18
+ return storage.once(pattern, handler);
19
+ },
20
+ off(pattern, handler) {
21
+ storage.off(pattern, handler);
22
+ },
23
+ listeners(pattern) {
24
+ return pattern === void 0 ? storage.listeners() : storage.listeners(pattern);
25
+ },
26
+ clearListeners(pattern) {
27
+ storage.clearListeners(pattern);
28
+ },
29
+ listenerCount(pattern) {
30
+ return storage.listenerCount(pattern);
31
+ },
32
+ async watch(callback) {
33
+ return await run("watch", async () => await storage.watch(callback));
34
+ },
35
+ async unwatch() {
36
+ await run("unwatch", async () => await storage.unwatch());
37
+ },
38
+ async get(key) {
39
+ return await run("get", async () => await storage.get(key));
40
+ },
41
+ async tryGet(key) {
42
+ return await run("tryGet", async () => await storage.tryGet(key));
43
+ },
44
+ async set(key, value, options) {
45
+ await run("set", async () => await storage.set(key, value, options));
46
+ },
47
+ async trySet(key, value, options) {
48
+ return await run("trySet", async () => await storage.trySet(key, value, options));
49
+ },
50
+ async compareAndSet(key, expected, value, options) {
51
+ return await run("compareAndSet", async () => await storage.compareAndSet(key, expected, value, options));
52
+ },
53
+ async tryCompareAndSet(key, expected, value, options) {
54
+ return await run("tryCompareAndSet", async () => await storage.tryCompareAndSet(key, expected, value, options));
55
+ },
56
+ async compareAndSetMany(items) {
57
+ return await run("compareAndSetMany", async () => await storage.compareAndSetMany(items));
58
+ },
59
+ async tryCompareAndSetMany(items) {
60
+ return await run("tryCompareAndSetMany", async () => await storage.tryCompareAndSetMany(items));
61
+ },
62
+ async has(key) {
63
+ return await run("has", async () => await storage.has(key));
64
+ },
65
+ async tryHas(key) {
66
+ return await run("tryHas", async () => await storage.tryHas(key));
67
+ },
68
+ async delete(key) {
69
+ return await run("delete", async () => await storage.delete(key));
70
+ },
71
+ async tryDelete(key) {
72
+ return await run("tryDelete", async () => await storage.tryDelete(key));
73
+ },
74
+ async getMany(keys) {
75
+ return await run("getMany", async () => await storage.getMany(keys));
76
+ },
77
+ async tryGetMany(keys) {
78
+ return await run("tryGetMany", async () => await storage.tryGetMany(keys));
79
+ },
80
+ async setMany(items) {
81
+ await run("setMany", async () => await storage.setMany(items));
82
+ },
83
+ async trySetMany(items) {
84
+ return await run("trySetMany", async () => await storage.trySetMany(items));
85
+ },
86
+ async deleteMany(keys) {
87
+ return await run("deleteMany", async () => await storage.deleteMany(keys));
88
+ },
89
+ async tryDeleteMany(keys) {
90
+ return await run("tryDeleteMany", async () => await storage.tryDeleteMany(keys));
91
+ },
92
+ async keys(options) {
93
+ return await run("keys", async () => await storage.keys(options));
94
+ },
95
+ async tryKeys(options) {
96
+ return await run("tryKeys", async () => await storage.tryKeys(options));
97
+ },
98
+ async entries(options) {
99
+ return await run("entries", async () => await storage.entries(options));
100
+ },
101
+ async tryEntries(options) {
102
+ return await run("tryEntries", async () => await storage.tryEntries(options));
103
+ },
104
+ async clear(options) {
105
+ await run("clear", async () => await storage.clear(options));
106
+ },
107
+ async tryClear(options) {
108
+ return await run("tryClear", async () => await storage.tryClear(options));
109
+ },
110
+ async dispose() {
111
+ await run("dispose", async () => await storage.dispose());
112
+ },
113
+ async [Symbol.asyncDispose]() {
114
+ await instrumented.dispose();
115
+ },
116
+ async tryDispose() {
117
+ return await run("tryDispose", async () => await storage.tryDispose());
118
+ }
119
+ };
120
+ return instrumented;
121
+ }
122
+ //#endregion
123
+ export { instrumentWorkflowStorage };
@@ -0,0 +1,8 @@
1
+ import { LockRecord } from "../types/lock.mjs";
2
+ import { WorkflowStorage } from "../types/store.mjs";
3
+ //#region src/store/lock.d.ts
4
+ declare function getReadableLock(storage: WorkflowStorage, namespace: string, key: string): Promise<LockRecord | undefined>;
5
+ declare function listReadableLocks(storage: WorkflowStorage, namespace: string): Promise<readonly LockRecord[]>;
6
+ declare function updateLockIfCurrent(storage: WorkflowStorage, namespace: string, current: LockRecord | undefined, next: LockRecord): Promise<LockRecord | undefined>;
7
+ //#endregion
8
+ export { getReadableLock, listReadableLocks, updateLockIfCurrent };
@@ -0,0 +1,28 @@
1
+ import { WorkflowLockStateError } from "../errors/lock.mjs";
2
+ import "../errors/mod.mjs";
3
+ import { makeLockKey, makeLockKeyPrefix } from "../store-keys.mjs";
4
+ import { toStorageValue } from "./storage-value.mjs";
5
+ import { isReadableLockRecord } from "./validation.mjs";
6
+ import { compactWorkflowStoreRecord } from "./compaction.mjs";
7
+ //#region src/store/lock.ts
8
+ async function getReadableLock(storage, namespace, key) {
9
+ const lock = await storage.get(makeLockKey(namespace, key));
10
+ return isReadableLockRecord(lock, namespace) ? lock : void 0;
11
+ }
12
+ async function listReadableLocks(storage, namespace) {
13
+ return (await storage.entries({ prefix: makeLockKeyPrefix(namespace) })).map((entry) => entry.value).filter((lock) => isReadableLockRecord(lock, namespace)).sort((a, b) => a.key.localeCompare(b.key)).filter(isFirstLockRecordForKey);
14
+ }
15
+ async function updateLockIfCurrent(storage, namespace, current, next) {
16
+ if (next.namespace !== namespace) WorkflowLockStateError.namespaceMismatch(String(next.namespace), namespace);
17
+ if (current !== void 0) {
18
+ if (current.namespace !== namespace) WorkflowLockStateError.namespaceMismatch(String(current.namespace), namespace);
19
+ if (current.key !== next.key) WorkflowLockStateError.keyChangeRejected();
20
+ }
21
+ const compact = compactWorkflowStoreRecord(next);
22
+ return await storage.compareAndSet(makeLockKey(namespace, next.key), current === void 0 ? void 0 : toStorageValue(current), toStorageValue(compact)) ? compact : void 0;
23
+ }
24
+ function isFirstLockRecordForKey(lock, index, locks) {
25
+ return locks.findIndex((entry) => entry.key === lock.key) === index;
26
+ }
27
+ //#endregion
28
+ export { getReadableLock, listReadableLocks, updateLockIfCurrent };
@@ -0,0 +1,30 @@
1
+ import { RunId } from "../types/run-id.mjs";
2
+ import { WorkflowStepAttemptRecord } from "../types/step-attempts.mjs";
3
+ import "../types/run.mjs";
4
+ import { EventRecord } from "../types/events.mjs";
5
+ import { WorkflowStorage } from "../types/store.mjs";
6
+ import { StorageCompareAndSetManyItem, StorageValue } from "@temelj/storage";
7
+ //#region src/store/materialization.d.ts
8
+ interface WorkflowStepAttemptMaterializationStoragePlan {
9
+ readonly materializes: boolean;
10
+ readonly storageKey?: string;
11
+ readonly current?: WorkflowStepAttemptRecord;
12
+ readonly item?: StorageCompareAndSetManyItem<StorageValue>;
13
+ }
14
+ interface WorkflowStepAttemptAppendMaterializationOutcome {
15
+ readonly status: "appended" | "duplicate";
16
+ readonly events: readonly EventRecord[];
17
+ readonly previousEventHistory?: StorageValue;
18
+ }
19
+ declare function materializeStepAttemptForAppendOutcome(storage: WorkflowStorage, namespace: string, runId: RunId, event: EventRecord, outcome: WorkflowStepAttemptAppendMaterializationOutcome): Promise<void>;
20
+ declare function createWorkflowStepAttemptMaterializationStoragePlan(storage: WorkflowStorage, namespace: string, runId: RunId, event: EventRecord): Promise<WorkflowStepAttemptMaterializationStoragePlan>;
21
+ declare function reconcileStepAttempts(storage: WorkflowStorage, namespace: string, runId: RunId, events: readonly EventRecord[]): Promise<readonly WorkflowStepAttemptRecord[]>;
22
+ declare function materializeStepAttemptIfCurrent(storage: WorkflowStorage, runId: RunId, storageKey: string, createNext: (current: WorkflowStepAttemptRecord | undefined) => WorkflowStepAttemptRecord | undefined, options?: {
23
+ readonly repairStatusMismatch?: boolean;
24
+ }): Promise<void>;
25
+ declare function shouldStoreStepAttempt(current: WorkflowStepAttemptRecord | undefined, next: WorkflowStepAttemptRecord, options?: {
26
+ readonly repairStatusMismatch?: boolean;
27
+ }): boolean;
28
+ declare function isSameStepAttemptIdentity(current: WorkflowStepAttemptRecord, next: WorkflowStepAttemptRecord): boolean;
29
+ //#endregion
30
+ export { WorkflowStepAttemptAppendMaterializationOutcome, WorkflowStepAttemptMaterializationStoragePlan, createWorkflowStepAttemptMaterializationStoragePlan, isSameStepAttemptIdentity, materializeStepAttemptForAppendOutcome, materializeStepAttemptIfCurrent, reconcileStepAttempts, shouldStoreStepAttempt };