@lostgradient/weft 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (510) hide show
  1. package/README.md +79 -24
  2. package/dist/cli/conformance.js +7 -1
  3. package/dist/cli/generated/operation-client.generated.d.ts +28 -13
  4. package/dist/cli/generated/operation-client.generated.js +1 -0
  5. package/dist/cli/help-text.d.ts +1 -1
  6. package/dist/cli/help-text.js +1 -0
  7. package/dist/cli/operation-catalog-snapshot.d.ts +8 -0
  8. package/dist/cli/operation-catalog-snapshot.js +11 -0
  9. package/dist/cli/parse-schedule-arguments.js +3 -1
  10. package/dist/cli/schedule.js +2 -1
  11. package/dist/cli/types.d.ts +1 -0
  12. package/dist/cli-main.js +79 -78
  13. package/dist/client/handle-delegation.d.ts +3 -2
  14. package/dist/client/handle-delegation.js +3 -1
  15. package/dist/client/http-client-requests.d.ts +2 -1
  16. package/dist/client/http-client-requests.js +7 -0
  17. package/dist/client/http-client.d.ts +9 -6
  18. package/dist/client/http-client.js +10 -1
  19. package/dist/client/http-request.d.ts +11 -1
  20. package/dist/client/http-request.js +17 -7
  21. package/dist/client/index.d.ts +1 -1
  22. package/dist/client/interface.d.ts +61 -5
  23. package/dist/client/local-handles.d.ts +22 -0
  24. package/dist/client/local-handles.js +23 -0
  25. package/dist/client/local.d.ts +6 -3
  26. package/dist/client/local.js +12 -26
  27. package/dist/client/start-body.d.ts +4 -3
  28. package/dist/core/byte-arrays.d.ts +5 -0
  29. package/dist/core/byte-arrays.js +5 -0
  30. package/dist/core/checkpoint/lifecycle.d.ts +3 -0
  31. package/dist/core/checkpoint/lifecycle.js +9 -4
  32. package/dist/core/checkpoint/serialization.js +12 -5
  33. package/dist/core/codec/extension-codec.d.ts +16 -0
  34. package/dist/core/codec/extension-codec.js +100 -6
  35. package/dist/core/context/activity-retry-state.d.ts +38 -0
  36. package/dist/core/context/activity-retry-state.js +89 -0
  37. package/dist/core/context/activity-schedule-to-close.d.ts +159 -0
  38. package/dist/core/context/activity-schedule-to-close.js +69 -0
  39. package/dist/core/context/child-workflow-pipe.d.ts +5 -5
  40. package/dist/core/context/child-workflow-pipe.js +15 -2
  41. package/dist/core/context/context-presence.d.ts +19 -0
  42. package/dist/core/context/context-presence.js +13 -0
  43. package/dist/core/context/durable-operations.d.ts +25 -0
  44. package/dist/core/context/durable-operations.js +64 -0
  45. package/dist/core/context/index.d.ts +9 -5
  46. package/dist/core/context/index.js +17 -12
  47. package/dist/core/context/internals.d.ts +20 -0
  48. package/dist/core/context/internals.js +3 -1
  49. package/dist/core/context/operation-request.d.ts +35 -0
  50. package/dist/core/context/parallel-cache-entry.d.ts +14 -5
  51. package/dist/core/context/run-operation.d.ts +6 -1
  52. package/dist/core/context/run-operation.js +41 -87
  53. package/dist/core/context/session-state.js +7 -8
  54. package/dist/core/context/speculative-child.js +2 -0
  55. package/dist/core/context/types.d.ts +15 -0
  56. package/dist/core/context/version-patching.d.ts +8 -0
  57. package/dist/core/context/version-patching.js +40 -0
  58. package/dist/core/context/workflow-logger.d.ts +98 -0
  59. package/dist/core/context/workflow-logger.js +68 -0
  60. package/dist/core/engine/activity-heartbeat-tracking.d.ts +64 -0
  61. package/dist/core/engine/activity-heartbeat-tracking.js +42 -0
  62. package/dist/core/engine/activity-per-attempt-timeout.d.ts +46 -0
  63. package/dist/core/engine/activity-per-attempt-timeout.js +36 -0
  64. package/dist/core/engine/activity-reconciliation.d.ts +1 -0
  65. package/dist/core/engine/activity-reconciliation.js +12 -1
  66. package/dist/core/engine/activity-resolution.d.ts +23 -0
  67. package/dist/core/engine/activity-resolution.js +37 -0
  68. package/dist/core/engine/aggregate.js +66 -30
  69. package/dist/core/engine/async-activity-completion.d.ts +23 -6
  70. package/dist/core/engine/async-activity-completion.js +53 -12
  71. package/dist/core/engine/attributes-tags.js +9 -4
  72. package/dist/core/engine/bulk-operations-purge.d.ts +26 -0
  73. package/dist/core/engine/bulk-operations-purge.js +38 -3
  74. package/dist/core/engine/bulk-operations-shared.d.ts +2 -0
  75. package/dist/core/engine/bulk-operations-shared.js +8 -2
  76. package/dist/core/engine/bulk-operations.d.ts +4 -1
  77. package/dist/core/engine/bulk-operations.js +235 -24
  78. package/dist/core/engine/callback-creators-bundles.d.ts +9 -0
  79. package/dist/core/engine/callback-creators-bundles.js +30 -2
  80. package/dist/core/engine/callback-creators-core.js +6 -4
  81. package/dist/core/engine/callback-creators-router.js +10 -0
  82. package/dist/core/engine/callback-creators-schedule.d.ts +2 -2
  83. package/dist/core/engine/callback-creators-schedule.js +12 -8
  84. package/dist/core/engine/candidate-read-batching.d.ts +6 -0
  85. package/dist/core/engine/candidate-read-batching.js +1 -0
  86. package/dist/core/engine/checkpoint-io.js +61 -25
  87. package/dist/core/engine/checkpoint-reads.js +3 -2
  88. package/dist/core/engine/checkpoint-replay.d.ts +20 -0
  89. package/dist/core/engine/checkpoint-replay.js +242 -0
  90. package/dist/core/engine/checkpoint-side-effects.d.ts +23 -0
  91. package/dist/core/engine/checkpoint-side-effects.js +35 -0
  92. package/dist/core/engine/child-workflow-cancellation.d.ts +10 -0
  93. package/dist/core/engine/child-workflow-cancellation.js +40 -0
  94. package/dist/core/engine/child-workflow.js +27 -4
  95. package/dist/core/engine/condition-waiters.d.ts +14 -0
  96. package/dist/core/engine/condition-waiters.js +5 -0
  97. package/dist/core/engine/construction.d.ts +3 -0
  98. package/dist/core/engine/construction.js +21 -8
  99. package/dist/core/engine/coordination-branch-executors.d.ts +70 -0
  100. package/dist/core/engine/coordination-branch-executors.js +107 -0
  101. package/dist/core/engine/deferred-consume-envelope.d.ts +59 -0
  102. package/dist/core/engine/deferred-consume-envelope.js +14 -0
  103. package/dist/core/engine/disposal.js +13 -0
  104. package/dist/core/engine/engine-create-types.d.ts +14 -4
  105. package/dist/core/engine/engine-internal-types.d.ts +26 -3
  106. package/dist/core/engine/errors.d.ts +47 -0
  107. package/dist/core/engine/errors.js +20 -0
  108. package/dist/core/engine/event-log-compaction.d.ts +8 -0
  109. package/dist/core/engine/event-log-compaction.js +20 -2
  110. package/dist/core/engine/fenced-write.d.ts +65 -0
  111. package/dist/core/engine/fenced-write.js +71 -0
  112. package/dist/core/engine/finalizer-state.d.ts +28 -0
  113. package/dist/core/engine/finalizer-state.js +16 -0
  114. package/dist/core/engine/handles.d.ts +8 -0
  115. package/dist/core/engine/index.d.ts +34 -16
  116. package/dist/core/engine/index.js +136 -9
  117. package/dist/core/engine/inline-parking.js +3 -2
  118. package/dist/core/engine/internals.d.ts +107 -3
  119. package/dist/core/engine/lease-codec.d.ts +35 -0
  120. package/dist/core/engine/lease-codec.js +32 -0
  121. package/dist/core/engine/lease-deposition.d.ts +66 -0
  122. package/dist/core/engine/lease-deposition.js +10 -0
  123. package/dist/core/engine/lease-errors.d.ts +99 -0
  124. package/dist/core/engine/lease-errors.js +30 -0
  125. package/dist/core/engine/lease-manager.d.ts +114 -0
  126. package/dist/core/engine/lease-manager.js +135 -0
  127. package/dist/core/engine/lifecycle/persist.js +10 -32
  128. package/dist/core/engine/lifecycle/recovered-services.d.ts +8 -6
  129. package/dist/core/engine/lifecycle/recovered-services.js +18 -3
  130. package/dist/core/engine/lifecycle/resume.js +16 -9
  131. package/dist/core/engine/lifecycle/shared.d.ts +8 -1
  132. package/dist/core/engine/lifecycle/start-batch.d.ts +1 -1
  133. package/dist/core/engine/lifecycle/start-batch.js +2 -1
  134. package/dist/core/engine/lifecycle/start-commit.d.ts +9 -0
  135. package/dist/core/engine/lifecycle/start-commit.js +50 -8
  136. package/dist/core/engine/lifecycle/start-or-signal-create.d.ts +58 -0
  137. package/dist/core/engine/lifecycle/start-or-signal-create.js +95 -0
  138. package/dist/core/engine/lifecycle/start-or-signal.d.ts +3 -2
  139. package/dist/core/engine/lifecycle/start-or-signal.js +11 -81
  140. package/dist/core/engine/lifecycle/start-terminal-conflict-purge.d.ts +39 -0
  141. package/dist/core/engine/lifecycle/start-terminal-conflict-purge.js +28 -0
  142. package/dist/core/engine/lifecycle/start.d.ts +4 -4
  143. package/dist/core/engine/lifecycle/start.js +17 -9
  144. package/dist/core/engine/lifecycle/transition.js +17 -5
  145. package/dist/core/engine/lifecycle.d.ts +1 -1
  146. package/dist/core/engine/list-candidate-resolution.js +2 -2
  147. package/dist/core/engine/listing.js +9 -5
  148. package/dist/core/engine/operations-activity.d.ts +6 -13
  149. package/dist/core/engine/operations-activity.js +26 -53
  150. package/dist/core/engine/operations-coordination.d.ts +10 -0
  151. package/dist/core/engine/operations-coordination.js +44 -9
  152. package/dist/core/engine/operations-router.d.ts +6 -0
  153. package/dist/core/engine/operations-router.js +2 -0
  154. package/dist/core/engine/operations-speculate.js +6 -2
  155. package/dist/core/engine/operations-stream.js +12 -2
  156. package/dist/core/engine/operations-time.d.ts +4 -2
  157. package/dist/core/engine/operations-time.js +14 -2
  158. package/dist/core/engine/operations-wait-condition.d.ts +23 -0
  159. package/dist/core/engine/operations-wait-condition.js +62 -0
  160. package/dist/core/engine/ownership-options.d.ts +23 -0
  161. package/dist/core/engine/ownership-options.js +26 -0
  162. package/dist/core/engine/payload-size-policy.d.ts +3 -0
  163. package/dist/core/engine/payload-size-policy.js +4 -0
  164. package/dist/core/engine/pending-updates.d.ts +17 -0
  165. package/dist/core/engine/pending-updates.js +33 -11
  166. package/dist/core/engine/queries.js +1 -1
  167. package/dist/core/engine/registration.d.ts +1 -0
  168. package/dist/core/engine/registration.js +18 -3
  169. package/dist/core/engine/schedule-jitter.d.ts +5 -0
  170. package/dist/core/engine/schedule-jitter.js +10 -0
  171. package/dist/core/engine/schedule-run.d.ts +17 -0
  172. package/dist/core/engine/schedule-run.js +38 -0
  173. package/dist/core/engine/schedule-timer.js +81 -17
  174. package/dist/core/engine/schedules.d.ts +7 -4
  175. package/dist/core/engine/schedules.js +37 -16
  176. package/dist/core/engine/search-attribute-records.d.ts +4 -0
  177. package/dist/core/engine/search-attribute-records.js +17 -0
  178. package/dist/core/engine/signals.d.ts +18 -2
  179. package/dist/core/engine/signals.js +42 -21
  180. package/dist/core/engine/state-utilities.d.ts +49 -2
  181. package/dist/core/engine/state-utilities.js +114 -3
  182. package/dist/core/engine/storage-io.d.ts +16 -2
  183. package/dist/core/engine/storage-io.js +26 -5
  184. package/dist/core/engine/stream-chunk-loading.d.ts +2 -0
  185. package/dist/core/engine/stream-chunk-loading.js +24 -1
  186. package/dist/core/engine/sub-operation.js +25 -6
  187. package/dist/core/engine/termination/cleanup.d.ts +3 -1
  188. package/dist/core/engine/termination/cleanup.js +25 -1
  189. package/dist/core/engine/termination/complete.js +44 -6
  190. package/dist/core/engine/termination/finalizer-activity.d.ts +53 -0
  191. package/dist/core/engine/termination/finalizer-activity.js +30 -0
  192. package/dist/core/engine/termination/finalizer-claim.d.ts +110 -0
  193. package/dist/core/engine/termination/finalizer-claim.js +80 -0
  194. package/dist/core/engine/termination/finalizer.d.ts +48 -0
  195. package/dist/core/engine/termination/finalizer.js +159 -0
  196. package/dist/core/engine/termination/suspend.d.ts +3 -1
  197. package/dist/core/engine/termination.d.ts +1 -0
  198. package/dist/core/engine/termination.js +4 -0
  199. package/dist/core/engine/updates.js +5 -25
  200. package/dist/core/engine/validation/schedule.d.ts +2 -1
  201. package/dist/core/engine/validation/schedule.js +51 -2
  202. package/dist/core/engine/validation.js +32 -5
  203. package/dist/core/engine/waiting-update-response.d.ts +8 -0
  204. package/dist/core/engine/waiting-update-response.js +22 -0
  205. package/dist/core/engine/workflow-concurrency.d.ts +10 -0
  206. package/dist/core/engine/workflow-concurrency.js +136 -0
  207. package/dist/core/engine/workflow-feed.d.ts +4 -5
  208. package/dist/core/engine/workflow-feed.js +4 -1
  209. package/dist/core/engine/workflow-indexes.d.ts +9 -0
  210. package/dist/core/engine/workflow-indexes.js +10 -0
  211. package/dist/core/engine/workflow-state-stream.js +33 -13
  212. package/dist/core/engine/workflow-visibility-queries.d.ts +2 -2
  213. package/dist/core/engine-helpers.js +1 -0
  214. package/dist/core/events/activity-events.d.ts +43 -12
  215. package/dist/core/events/activity-events.js +28 -0
  216. package/dist/core/events/attribute-events.d.ts +2 -3
  217. package/dist/core/events/event-map.d.ts +18 -12
  218. package/dist/core/events/index.d.ts +1 -0
  219. package/dist/core/events/index.js +1 -0
  220. package/dist/core/events/schedule-events.d.ts +71 -0
  221. package/dist/core/events/schedule-events.js +29 -0
  222. package/dist/core/events/signal-events.d.ts +4 -6
  223. package/dist/core/events/system-events.d.ts +29 -19
  224. package/dist/core/events/system-events.js +26 -0
  225. package/dist/core/events/update-events.d.ts +6 -8
  226. package/dist/core/events/workflow-events.d.ts +88 -23
  227. package/dist/core/events/workflow-events.js +26 -0
  228. package/dist/core/failure-categories.js +5 -17
  229. package/dist/core/fault-code.d.ts +9 -3
  230. package/dist/core/fault-code.js +1 -0
  231. package/dist/core/inline-execution-strategy.context-options.d.ts +69 -0
  232. package/dist/core/inline-execution-strategy.context-options.js +56 -0
  233. package/dist/core/inline-execution-strategy.d.ts +31 -36
  234. package/dist/core/inline-execution-strategy.js +16 -27
  235. package/dist/core/list-filter-validation.d.ts +1 -1
  236. package/dist/core/payload-size.d.ts +1 -1
  237. package/dist/core/persisted-data-incompatible-error.d.ts +9 -7
  238. package/dist/core/review/events.d.ts +6 -8
  239. package/dist/core/scheduler/scheduler-class.d.ts +10 -1
  240. package/dist/core/scheduler/scheduler-class.js +38 -11
  241. package/dist/core/scheduler/timer-batch.js +9 -1
  242. package/dist/core/scheduler/timer-sources.d.ts +1 -0
  243. package/dist/core/scheduler/timer-sources.js +11 -5
  244. package/dist/core/session-state.d.ts +0 -1
  245. package/dist/core/session-state.js +2 -2
  246. package/dist/core/start-workflow-validation.d.ts +34 -0
  247. package/dist/core/start-workflow-validation.js +19 -0
  248. package/dist/core/types/activity-verification.d.ts +67 -0
  249. package/dist/core/types/activity-verification.js +0 -0
  250. package/dist/core/types/activity.d.ts +80 -61
  251. package/dist/core/types/bulk.d.ts +50 -9
  252. package/dist/core/types/checkpoint.d.ts +44 -8
  253. package/dist/core/types/list-options.d.ts +146 -0
  254. package/dist/core/types/list-options.js +0 -0
  255. package/dist/core/types/options.d.ts +121 -165
  256. package/dist/core/types/schedules.d.ts +39 -3
  257. package/dist/core/types/services-resolution.d.ts +2 -2
  258. package/dist/core/types/workflow-builder-runtime.d.ts +12 -3
  259. package/dist/core/types/workflow-builder-runtime.js +11 -2
  260. package/dist/core/types/workflow-builder.d.ts +42 -11
  261. package/dist/core/types/workflow-concurrency.d.ts +39 -0
  262. package/dist/core/types/workflow-concurrency.js +0 -0
  263. package/dist/core/types/workflow-context.d.ts +157 -14
  264. package/dist/core/types/workflow-definition.d.ts +53 -10
  265. package/dist/core/types/workflow-function.d.ts +84 -9
  266. package/dist/core/types/workflow-log.d.ts +98 -0
  267. package/dist/core/types/workflow-log.js +0 -0
  268. package/dist/core/types/workflow-registries.d.ts +14 -3
  269. package/dist/core/types/workflow-registry.d.ts +3 -0
  270. package/dist/core/types.d.ts +4 -0
  271. package/dist/core/types.js +4 -0
  272. package/dist/core/versioning.d.ts +9 -39
  273. package/dist/core/versioning.js +2 -12
  274. package/dist/core/weft-error.d.ts +44 -1
  275. package/dist/core/weft-error.js +16 -0
  276. package/dist/core/worker-execution-strategy-options.d.ts +26 -0
  277. package/dist/core/worker-execution-strategy.js +40 -36
  278. package/dist/core/worker-inbound-message.d.ts +38 -0
  279. package/dist/core/worker-inbound-message.js +37 -0
  280. package/dist/core/worker-log-abuse-counter.d.ts +175 -0
  281. package/dist/core/worker-log-abuse-counter.js +107 -0
  282. package/dist/core/worker-message-helpers.d.ts +47 -0
  283. package/dist/core/worker-message-helpers.js +26 -0
  284. package/dist/core/worker-protocol-guard.js +1 -1
  285. package/dist/core/worker-protocol-log.d.ts +56 -0
  286. package/dist/core/worker-protocol-log.js +18 -0
  287. package/dist/core/worker-protocol.d.ts +23 -0
  288. package/dist/core/worker-protocol.js +12 -2
  289. package/dist/core/workflow-version-tuple.d.ts +3 -9
  290. package/dist/core/workflow-version-tuple.js +2 -3
  291. package/dist/diagnostics/format.js +1 -6
  292. package/dist/diagnostics/types.d.ts +4 -5
  293. package/dist/diagnostics/validate.d.ts +0 -1
  294. package/dist/diagnostics/version-check.d.ts +1 -1
  295. package/dist/diagnostics/version-check.js +4 -9
  296. package/dist/index.d.ts +12 -10
  297. package/dist/index.js +29 -3
  298. package/dist/json-schema.js +3 -3
  299. package/dist/mcp/cli.js +19 -19
  300. package/dist/mcp/dispatcher.js +1 -1
  301. package/dist/mcp/http.js +16 -6
  302. package/dist/mcp/protocol.d.ts +2 -0
  303. package/dist/mcp/protocol.js +1 -1
  304. package/dist/mcp/session.d.ts +16 -0
  305. package/dist/mcp/session.js +59 -6
  306. package/dist/mcp/tools.js +73 -6
  307. package/dist/observability/index.js +2 -2
  308. package/dist/server/asyncapi-channels.js +5 -2
  309. package/dist/server/attribute-filters.d.ts +8 -3
  310. package/dist/server/attribute-filters.js +6 -1
  311. package/dist/server/authentication/api-key.d.ts +2 -1
  312. package/dist/server/authentication/api-key.js +5 -2
  313. package/dist/server/authentication/constant-time-api-key.d.ts +15 -0
  314. package/dist/server/authentication/constant-time-api-key.js +24 -0
  315. package/dist/server/authentication/index.d.ts +1 -1
  316. package/dist/server/authentication/index.js +7 -4
  317. package/dist/server/authentication/rotating-api-key-store.d.ts +5 -3
  318. package/dist/server/authentication/rotating-api-key-store.js +19 -11
  319. package/dist/server/engine-event-feed-backend.d.ts +4 -5
  320. package/dist/server/fault-to-http.js +8 -1
  321. package/dist/server/fault-to-json-rpc.js +1 -0
  322. package/dist/server/fleet-event-feed.d.ts +31 -0
  323. package/dist/server/fleet-event-feed.js +157 -0
  324. package/dist/server/handler/index.js +1 -1
  325. package/dist/server/handler/response-helpers.js +2 -1
  326. package/dist/server/handler/route-dispatch.d.ts +6 -3
  327. package/dist/server/handler/route-dispatch.js +2 -2
  328. package/dist/server/handler.js +23 -23
  329. package/dist/server/index.d.ts +32 -2
  330. package/dist/server/index.js +32 -32
  331. package/dist/server/json-rpc-transport-helpers.d.ts +1 -0
  332. package/dist/server/json-rpc-transport-helpers.js +2 -1
  333. package/dist/server/json-rpc-websocket-runtime.d.ts +11 -2
  334. package/dist/server/json-rpc-websocket-runtime.js +1 -0
  335. package/dist/server/json-rpc-websocket-subscriptions.d.ts +10 -0
  336. package/dist/server/json-rpc-websocket-subscriptions.js +29 -0
  337. package/dist/server/json-rpc-websocket-types.d.ts +22 -0
  338. package/dist/server/json-rpc-websocket-types.js +0 -0
  339. package/dist/server/json-rpc-websocket-validation.js +20 -4
  340. package/dist/server/json-rpc-websocket.d.ts +2 -43
  341. package/dist/server/json-rpc-websocket.js +57 -74
  342. package/dist/server/openapi.d.ts +2 -1
  343. package/dist/server/openapi.js +1 -3
  344. package/dist/server/openrpc-document-schema.d.ts +78 -0
  345. package/dist/server/openrpc-document-schema.js +27 -1
  346. package/dist/server/openrpc-errors.d.ts +3 -0
  347. package/dist/server/openrpc-errors.js +2 -1
  348. package/dist/server/openrpc.js +32 -0
  349. package/dist/server/operation-catalog/index.d.ts +1 -1
  350. package/dist/server/operation-catalog/pipeline-helpers.js +1 -0
  351. package/dist/server/operation-catalog/pipeline-stages.js +26 -12
  352. package/dist/server/operation-catalog/pipeline.js +8 -1
  353. package/dist/server/operation-catalog/registry.js +13 -0
  354. package/dist/server/operation-catalog/types.d.ts +20 -9
  355. package/dist/server/operation-fault.d.ts +10 -0
  356. package/dist/server/operation-fault.js +2 -0
  357. package/dist/server/operation-registry.d.ts +12 -11
  358. package/dist/server/operation-registry.js +12 -3
  359. package/dist/server/operations/aggregate-workflows.d.ts +15 -15
  360. package/dist/server/operations/async-activity.d.ts +2 -2
  361. package/dist/server/operations/async-activity.js +12 -7
  362. package/dist/server/operations/bulk-cancel-workflows.d.ts +1 -1
  363. package/dist/server/operations/bulk-cancel-workflows.js +2 -2
  364. package/dist/server/operations/bulk-delete-workflows.d.ts +1 -1
  365. package/dist/server/operations/bulk-delete-workflows.js +2 -2
  366. package/dist/server/operations/bulk-filter-helpers.d.ts +8 -6
  367. package/dist/server/operations/bulk-filter-helpers.js +54 -24
  368. package/dist/server/operations/bulk-mutate-workflow-tags.d.ts +11 -9
  369. package/dist/server/operations/bulk-mutate-workflow-tags.js +2 -2
  370. package/dist/server/operations/bulk-operation-helpers.d.ts +2 -2
  371. package/dist/server/operations/bulk-retry-failed-workflows.d.ts +7 -0
  372. package/dist/server/operations/bulk-retry-failed-workflows.js +64 -0
  373. package/dist/server/operations/bulk-signal-workflows.d.ts +11 -9
  374. package/dist/server/operations/bulk-signal-workflows.js +2 -2
  375. package/dist/server/operations/cancel-schedule.d.ts +1 -1
  376. package/dist/server/operations/create-schedule.d.ts +3 -1
  377. package/dist/server/operations/create-schedule.js +29 -11
  378. package/dist/server/operations/fleet-events-subscription.d.ts +54 -0
  379. package/dist/server/operations/fleet-events-subscription.js +99 -0
  380. package/dist/server/operations/fork-workflow.d.ts +1 -1
  381. package/dist/server/operations/fork-workflow.js +3 -2
  382. package/dist/server/operations/get-checkpoint-at.d.ts +1 -1
  383. package/dist/server/operations/get-registry.d.ts +1 -1
  384. package/dist/server/operations/get-retention-overview.d.ts +1 -1
  385. package/dist/server/operations/get-review.d.ts +1 -1
  386. package/dist/server/operations/get-schedule.d.ts +1 -1
  387. package/dist/server/operations/get-stream-chunks.d.ts +1 -1
  388. package/dist/server/operations/get-system-metrics.d.ts +2 -2
  389. package/dist/server/operations/get-task-diagnostics.d.ts +45 -6
  390. package/dist/server/operations/get-task-diagnostics.js +101 -7
  391. package/dist/server/operations/get-update-result.d.ts +1 -1
  392. package/dist/server/operations/get-workflow-attributes.d.ts +1 -1
  393. package/dist/server/operations/get-workflow-events.d.ts +1 -1
  394. package/dist/server/operations/get-workflow-result.d.ts +1 -1
  395. package/dist/server/operations/get-workflow-timeline.d.ts +1 -1
  396. package/dist/server/operations/get-workflow.d.ts +1 -1
  397. package/dist/server/operations/list-checkpoints.d.ts +1 -1
  398. package/dist/server/operations/list-reviews.d.ts +1 -1
  399. package/dist/server/operations/list-schedules.d.ts +1 -1
  400. package/dist/server/operations/list-task-queues.d.ts +2 -2
  401. package/dist/server/operations/list-workers.d.ts +2 -2
  402. package/dist/server/operations/list-workflows.d.ts +1 -1
  403. package/dist/server/operations/operation-helpers.d.ts +16 -1
  404. package/dist/server/operations/operation-helpers.js +15 -3
  405. package/dist/server/operations/pause-schedule.d.ts +1 -1
  406. package/dist/server/operations/purge-workflows.d.ts +5 -5
  407. package/dist/server/operations/purge-workflows.js +2 -2
  408. package/dist/server/operations/query-workflow.d.ts +1 -1
  409. package/dist/server/operations/query-workflow.js +3 -2
  410. package/dist/server/operations/recover-all.d.ts +1 -1
  411. package/dist/server/operations/replay-workflow.d.ts +1 -1
  412. package/dist/server/operations/resume-schedule.d.ts +1 -1
  413. package/dist/server/operations/set-workflow-attributes.d.ts +1 -1
  414. package/dist/server/operations/set-workflow-attributes.js +6 -3
  415. package/dist/server/operations/signal-workflow.js +8 -3
  416. package/dist/server/operations/single-workflow-tag-mutation.js +13 -3
  417. package/dist/server/operations/start-or-signal-workflow.d.ts +6 -1
  418. package/dist/server/operations/start-or-signal-workflow.js +14 -24
  419. package/dist/server/operations/start-workflow-options.d.ts +6 -0
  420. package/dist/server/operations/start-workflow-rest-input.d.ts +14 -0
  421. package/dist/server/operations/start-workflow-rest-input.js +31 -0
  422. package/dist/server/operations/start-workflow.d.ts +1 -1
  423. package/dist/server/operations/start-workflow.js +8 -23
  424. package/dist/server/operations/storage.d.ts +6 -6
  425. package/dist/server/operations/storage.js +24 -14
  426. package/dist/server/operations/stream-workflow-sse.d.ts +1 -1
  427. package/dist/server/operations/submit-review-decision.d.ts +1 -1
  428. package/dist/server/operations/submit-review-decision.js +6 -3
  429. package/dist/server/operations/update-schedule.d.ts +1 -1
  430. package/dist/server/operations/update-schedule.js +7 -4
  431. package/dist/server/operations/update-workflow.d.ts +1 -1
  432. package/dist/server/operations/update-workflow.js +7 -3
  433. package/dist/server/operations/worker-drain.d.ts +8 -8
  434. package/dist/server/operations/worker-drain.js +11 -8
  435. package/dist/server/operations/workflow-events-subscription.d.ts +7 -8
  436. package/dist/server/operations/workflow-events-subscription.js +43 -8
  437. package/dist/server/rest-binding.d.ts +3 -1
  438. package/dist/server/rest-bindings.js +12 -0
  439. package/dist/server/rest-body.d.ts +10 -0
  440. package/dist/server/rest-body.js +80 -0
  441. package/dist/server/runtime/authentication-bridge.d.ts +1 -0
  442. package/dist/server/runtime/authentication-bridge.js +33 -6
  443. package/dist/server/runtime/client-visible-events.d.ts +3 -0
  444. package/dist/server/runtime/client-visible-events.js +65 -0
  445. package/dist/server/runtime/context.d.ts +7 -0
  446. package/dist/server/runtime/event-broadcasting.d.ts +6 -0
  447. package/dist/server/runtime/event-broadcasting.js +72 -38
  448. package/dist/server/runtime/retry.d.ts +1 -0
  449. package/dist/server/runtime/retry.js +14 -0
  450. package/dist/server/runtime/shutdown.d.ts +7 -6
  451. package/dist/server/runtime/shutdown.js +6 -1
  452. package/dist/server/runtime/task-polling.js +61 -20
  453. package/dist/server/runtime/task-reconciliation.js +9 -1
  454. package/dist/server/runtime/task-result-resolution.d.ts +15 -0
  455. package/dist/server/runtime/task-result-resolution.js +81 -0
  456. package/dist/server/runtime/websocket-stream.d.ts +20 -1
  457. package/dist/server/runtime/websocket-stream.js +173 -7
  458. package/dist/server/runtime/websocket-upgrade.js +22 -3
  459. package/dist/server/runtime/websocket-worker.d.ts +1 -1
  460. package/dist/server/runtime/websocket-worker.js +38 -30
  461. package/dist/server/serve-internals.d.ts +3 -1
  462. package/dist/server/serve-internals.js +18 -2
  463. package/dist/server/task-state.d.ts +30 -0
  464. package/dist/server/task-state.js +28 -0
  465. package/dist/server/workflow-event-feed.d.ts +36 -115
  466. package/dist/server/workflow-event-feed.js +92 -27
  467. package/dist/service-worker/index.js +30 -30
  468. package/dist/storage/auto.js +1 -1
  469. package/dist/storage/bun-sql.js +24 -0
  470. package/dist/storage/compressed-storage.js +1 -1
  471. package/dist/storage/default-scope.d.ts +7 -4
  472. package/dist/storage/http.js +2 -2
  473. package/dist/storage/index.d.ts +76 -4
  474. package/dist/storage/indexeddb.js +1 -1
  475. package/dist/storage/interface.d.ts +163 -0
  476. package/dist/storage/interface.js +1 -1
  477. package/dist/storage/key-prefixes.d.ts +1 -1
  478. package/dist/storage/key-prefixes.js +10 -0
  479. package/dist/storage/lmdb.d.ts +4 -3
  480. package/dist/storage/lmdb.js +1 -1
  481. package/dist/storage/memory.js +1 -1
  482. package/dist/storage/neon-batch.d.ts +30 -0
  483. package/dist/storage/neon-batch.js +30 -0
  484. package/dist/storage/neon-value-mapping.d.ts +30 -3
  485. package/dist/storage/neon-value-mapping.js +12 -0
  486. package/dist/storage/neon.d.ts +16 -0
  487. package/dist/storage/neon.js +9 -4
  488. package/dist/storage/node-sqlite.js +23 -0
  489. package/dist/storage/postgres-key-value-queries.d.ts +69 -44
  490. package/dist/storage/postgres-key-value-queries.js +62 -24
  491. package/dist/storage/resolve.js +1 -1
  492. package/dist/storage/scoped-storage.js +1 -1
  493. package/dist/storage/testing.d.ts +168 -0
  494. package/dist/storage/testing.js +2 -0
  495. package/dist/storage/turso.d.ts +8 -0
  496. package/dist/storage/turso.js +2 -2
  497. package/dist/storage/typed-storage.js +1 -1
  498. package/dist/storage/web-extension.js +1 -1
  499. package/dist/testing/index.js +20 -20
  500. package/dist/version.d.ts +1 -1
  501. package/dist/version.js +1 -1
  502. package/dist/worker/protocol.js +1 -1
  503. package/dist/workers/worker-replay-state.d.ts +32 -0
  504. package/dist/workers/worker-replay-state.js +35 -0
  505. package/dist/workers/worker-state-namespace.d.ts +21 -0
  506. package/dist/workers/worker-state-namespace.js +13 -0
  507. package/dist/workers/workflow-runner.d.ts +19 -15
  508. package/dist/workers/workflow-runner.js +72 -60
  509. package/dist/workers/workflow-worker-entry.js +5 -2
  510. package/package.json +5 -1
@@ -1,15 +1,17 @@
1
1
  import { WeftError } from './weft-error.ts';
2
2
  /**
3
3
  * Thrown by {@link Engine.create} (and other storage-opening entry points) when
4
- * a persisted Weft database carries a schema version older than the engine
5
- * understands. Pre-MVP Weft does not migrate persisted data bumping
6
- * {@link CURRENT_PERSISTED_DATA_SCHEMA_VERSION} intentionally invalidates older
7
- * databases so the failure surfaces deterministically at boot, before any
8
- * workflow attempts replay.
4
+ * a persisted Weft database's schema version does not match what the engine
5
+ * requires an older version, a newer one, an unparseable sentinel, or user
6
+ * data present with no sentinel at all. Weft loads persisted data only at the
7
+ * exact current schema version; it never reshapes a non-matching database in
8
+ * place. Bumping {@link CURRENT_PERSISTED_DATA_SCHEMA_VERSION} intentionally
9
+ * invalidates databases stamped with any other version so the failure surfaces
10
+ * deterministically at boot, before any workflow attempts replay.
9
11
  *
10
12
  * Inspect `foundVersion` to see what the storage advertised and `expectedVersion`
11
- * to see what this engine requires. Resolve by deleting the database (acceptable
12
- * pre-MVP) or by starting from fresh storage.
13
+ * to see what this engine requires. Resolve by deleting the database or by
14
+ * starting from fresh storage.
13
15
  *
14
16
  * @example
15
17
  * ```ts
@@ -6,12 +6,11 @@
6
6
  *
7
7
  * @example Route review notifications to a webhook
8
8
  * ```ts
9
- * import { ReviewRequestedEvent } from '@lostgradient/weft';
9
+ * import { ReviewRequestedEvent, type TypedEventTarget, type WeftReviewEventMap } from '@lostgradient/weft';
10
10
  *
11
- * const target = new EventTarget();
11
+ * declare const target: TypedEventTarget<WeftReviewEventMap>;
12
12
  *
13
- * target.addEventListener(ReviewRequestedEvent.type, (e) => {
14
- * const event = e as ReviewRequestedEvent;
13
+ * target.addEventListener(ReviewRequestedEvent.type, (event) => {
15
14
  * console.log(`Review ${event.reviewId} requested for workflow ${event.workflowId}`);
16
15
  * console.log('Reviewers:', event.reviewers);
17
16
  * });
@@ -33,12 +32,11 @@ export declare class ReviewRequestedEvent extends Event {
33
32
  *
34
33
  * @example Record review decisions in an audit log
35
34
  * ```ts
36
- * import { ReviewCompletedEvent } from '@lostgradient/weft';
35
+ * import { ReviewCompletedEvent, type TypedEventTarget, type WeftReviewEventMap } from '@lostgradient/weft';
37
36
  *
38
- * const target = new EventTarget();
37
+ * declare const target: TypedEventTarget<WeftReviewEventMap>;
39
38
  *
40
- * target.addEventListener(ReviewCompletedEvent.type, (e) => {
41
- * const event = e as ReviewCompletedEvent;
39
+ * target.addEventListener(ReviewCompletedEvent.type, (event) => {
42
40
  * console.log(`Review ${event.reviewId}: '${event.decision}' by ${event.reviewer} in ${event.duration}ms`);
43
41
  * });
44
42
  * ```
@@ -1,10 +1,19 @@
1
- import type { Storage } from '../../storage/interface.ts';
1
+ import type { BatchOperation, Storage } from '../../storage/interface.ts';
2
2
  import type { TimerEntry } from '../types.ts';
3
3
  export interface SchedulerOptions {
4
4
  storage: Storage;
5
5
  onTimerFired: (entry: TimerEntry) => void | Promise<void>;
6
6
  pollIntervalMs?: number;
7
7
  getNow?: () => number;
8
+ /**
9
+ * Commit the batch that deletes a fired timer's keys after its callback
10
+ * returns. Defaults to an unfenced `storage.batch`. The engine supplies a
11
+ * lease-fenced commit (#563) so the fired-timer delete and the callback's own
12
+ * follow-up writes share the same ownership fence — under deposition both are
13
+ * rejected and the timer survives for the successor to re-drive. With no lease
14
+ * held this commits exactly as the unfenced default would.
15
+ */
16
+ commitTimerCleanup?: (operations: BatchOperation[]) => Promise<void>;
8
17
  }
9
18
  /**
10
19
  * Scheduler manages durable timers and polls for expired deadlines.
@@ -4,16 +4,19 @@ import { buildTimerBatchOperations } from "./timer-batch.js";
4
4
  import {
5
5
  advanceTimerSource,
6
6
  readNextScannedTimerEntry,
7
+ readNextTeardownTimerEntry,
7
8
  readNextTerminalCleanupTimerEntry,
8
9
  selectNextTimerSource,
9
10
  shouldDeleteTimerIndexWithoutLookup
10
11
  } from "./timer-sources.js";
12
+ const EXPIRED_TIMER_SCAN_LIMIT_PER_SOURCE = 1000;
11
13
 
12
14
  export class Scheduler {
13
15
  #storage;
14
16
  #onTimerFired;
15
17
  #pollIntervalMs;
16
18
  #getNow;
19
+ #commitTimerCleanup;
17
20
  #intervalHandle = null;
18
21
  #stopped = !1;
19
22
  constructor(options) {
@@ -21,6 +24,7 @@ export class Scheduler {
21
24
  this.#onTimerFired = options.onTimerFired;
22
25
  this.#pollIntervalMs = options.pollIntervalMs ?? 1000;
23
26
  this.#getNow = options.getNow ?? Date.now;
27
+ this.#commitTimerCleanup = options.commitTimerCleanup ?? ((operations) => this.#storage.batch(operations));
24
28
  }
25
29
  start() {
26
30
  if (this.#intervalHandle !== null)
@@ -66,7 +70,7 @@ export class Scheduler {
66
70
  this.stop();
67
71
  }
68
72
  async#processExpiredTimers(now, { respectStopped }) {
69
- const currentTime = now ?? this.#getNow(), timerSources = this.#createTimerSources(this.#scanExpiredTimers(currentTime));
73
+ const currentTime = now ?? this.#getNow(), timerSources = this.#createTimerSources(this.#scanExpiredTimers(currentTime)), cleanupOperations = [];
70
74
  for (const timerSource of timerSources)
71
75
  await advanceTimerSource(timerSource, this.#storage);
72
76
  while (this.#hasPendingTimer(timerSources)) {
@@ -74,27 +78,36 @@ export class Scheduler {
74
78
  if (!nextEntry || !selectedSource)
75
79
  break;
76
80
  if (respectStopped && this.#stopped)
77
- return;
78
- if (await this.#processSelectedTimer(nextEntry) === "retry") {
81
+ break;
82
+ if (await this.#processSelectedTimer(nextEntry, cleanupOperations) === "retry") {
79
83
  await advanceTimerSource(selectedSource, this.#storage);
80
84
  continue;
81
85
  }
82
86
  await advanceTimerSource(selectedSource, this.#storage);
83
87
  }
88
+ await this.#deleteProcessedTimerKeys(cleanupOperations);
84
89
  }
85
90
  #scanExpiredTimers(currentTime) {
86
91
  return {
87
92
  deadline: this.#storage.scan("wf-deadline:", {
88
- lt: resolvePrefixRangeEnd(KEYS.deadline(currentTime, ""))
93
+ lt: resolvePrefixRangeEnd(KEYS.deadline(currentTime, "")),
94
+ limit: EXPIRED_TIMER_SCAN_LIMIT_PER_SOURCE
89
95
  }),
90
96
  delayedStart: this.#storage.scan("wf-delayed:", {
91
- lt: resolvePrefixRangeEnd(KEYS.delayedStart(currentTime, ""))
97
+ lt: resolvePrefixRangeEnd(KEYS.delayedStart(currentTime, "")),
98
+ limit: EXPIRED_TIMER_SCAN_LIMIT_PER_SOURCE
92
99
  }),
93
100
  schedule: this.#storage.scan("schedule-due:", {
94
- lt: resolvePrefixRangeEnd(KEYS.scheduleTick(currentTime, ""))
101
+ lt: resolvePrefixRangeEnd(KEYS.scheduleTick(currentTime, "")),
102
+ limit: EXPIRED_TIMER_SCAN_LIMIT_PER_SOURCE
95
103
  }),
96
104
  terminalCleanup: this.#storage.scan("wf-cleanup:", {
97
- lt: resolvePrefixRangeEnd(KEYS.terminalCleanup(currentTime, ""))
105
+ lt: resolvePrefixRangeEnd(KEYS.terminalCleanup(currentTime, "")),
106
+ limit: EXPIRED_TIMER_SCAN_LIMIT_PER_SOURCE
107
+ }),
108
+ teardown: this.#storage.scan("wf-teardown:", {
109
+ lt: resolvePrefixRangeEnd(KEYS.teardownTimer(currentTime, "")),
110
+ limit: EXPIRED_TIMER_SCAN_LIMIT_PER_SOURCE
98
111
  })
99
112
  };
100
113
  }
@@ -119,29 +132,43 @@ export class Scheduler {
119
132
  iterator: iterators.terminalCleanup[Symbol.asyncIterator](),
120
133
  next: null,
121
134
  readNext: readNextTerminalCleanupTimerEntry
135
+ },
136
+ {
137
+ iterator: iterators.teardown[Symbol.asyncIterator](),
138
+ next: null,
139
+ readNext: readNextTeardownTimerEntry
122
140
  }
123
141
  ];
124
142
  }
125
143
  #hasPendingTimer(timerSources) {
126
144
  return timerSources.some((timerSource) => timerSource.next !== null);
127
145
  }
128
- async#processSelectedTimer(nextEntry) {
146
+ async#processSelectedTimer(nextEntry, cleanupOperations) {
129
147
  try {
130
148
  await this.#onTimerFired(nextEntry.entry);
131
149
  } catch (error) {
132
150
  console.error(`Timer callback failed for timer ${nextEntry.entry.id}:`, error);
133
151
  return "retry";
134
152
  }
135
- await this.#deleteTimerKeysAfterCallback(nextEntry);
153
+ await this.#appendTimerCleanupOperationsAfterCallback(nextEntry, cleanupOperations);
136
154
  return "processed";
137
155
  }
138
- async#deleteTimerKeysAfterCallback(nextEntry) {
156
+ async#appendTimerCleanupOperationsAfterCallback(nextEntry, cleanupOperations) {
139
157
  try {
140
- await this.#storage.batch(await this.#buildTimerCleanupOperations(nextEntry));
158
+ cleanupOperations.push(...await this.#buildTimerCleanupOperations(nextEntry));
141
159
  } catch (deleteError) {
142
160
  console.error(`Failed to delete timer keys for ${nextEntry.entry.id}:`, deleteError);
143
161
  }
144
162
  }
163
+ async#deleteProcessedTimerKeys(cleanupOperations) {
164
+ if (cleanupOperations.length === 0)
165
+ return;
166
+ try {
167
+ await this.#commitTimerCleanup(cleanupOperations);
168
+ } catch (deleteError) {
169
+ console.error("Failed to delete timer keys for processed scheduler tick:", deleteError);
170
+ }
171
+ }
145
172
  async#buildTimerCleanupOperations(nextEntry) {
146
173
  const cleanupOperations = [{ type: "delete", key: nextEntry.key }], indexDeleteOperation = await this.#buildTimerIndexDeleteOperation(nextEntry);
147
174
  if (indexDeleteOperation)
@@ -2,7 +2,7 @@ import { KEYS } from "../../storage/interface.js";
2
2
  import { encode } from "../codec.js";
3
3
  import { normalizeStorageTimestamp } from "./duration.js";
4
4
  function isTimerEntryKind(value) {
5
- return value === "sleep" || value === "visibility-timeout" || value === "execution-deadline" || value === "delayed-start" || value === "schedule" || value === "terminal-cleanup";
5
+ return value === "sleep" || value === "visibility-timeout" || value === "execution-deadline" || value === "delayed-start" || value === "schedule" || value === "terminal-cleanup" || value === "teardown" || value === "wait-condition";
6
6
  }
7
7
  function isRecord(value) {
8
8
  return typeof value === "object" && value !== null;
@@ -30,6 +30,14 @@ export function buildTimerBatchOperations(entry) {
30
30
  value: encode(normalizedEntry.workflowId)
31
31
  }
32
32
  ];
33
+ if (normalizedEntry.kind === "teardown")
34
+ return [
35
+ {
36
+ type: "put",
37
+ key: KEYS.teardownTimer(normalizedEntry.fireAt, normalizedEntry.id),
38
+ value: encode(normalizedEntry.workflowId)
39
+ }
40
+ ];
33
41
  const deadlineKey = normalizedEntry.kind === "delayed-start" ? KEYS.delayedStart(normalizedEntry.fireAt, normalizedEntry.workflowId) : normalizedEntry.kind === "schedule" ? KEYS.scheduleTick(normalizedEntry.fireAt, normalizedEntry.workflowId) : KEYS.deadline(normalizedEntry.fireAt, normalizedEntry.id), operations = [
34
42
  { type: "put", key: deadlineKey, value: encode(normalizedEntry) }
35
43
  ];
@@ -12,6 +12,7 @@ export type TimerSource = {
12
12
  export declare function compareScannedTimerEntries(left: ScannedTimerEntry, right: ScannedTimerEntry): number;
13
13
  export declare function readNextScannedTimerEntry(iterator: AsyncIterator<[string, Uint8Array]>, storage: Storage): Promise<ScannedTimerEntry | null>;
14
14
  export declare function readNextTerminalCleanupTimerEntry(iterator: AsyncIterator<[string, Uint8Array]>, storage: Storage): Promise<ScannedTimerEntry | null>;
15
+ export declare function readNextTeardownTimerEntry(iterator: AsyncIterator<[string, Uint8Array]>, storage: Storage): Promise<ScannedTimerEntry | null>;
15
16
  export declare function advanceTimerSource(timerSource: TimerSource, storage: Storage): Promise<void>;
16
17
  export declare function selectNextTimerSource(timerSources: TimerSource[]): TimerSource | undefined;
17
18
  export declare function shouldDeleteTimerIndexWithoutLookup(entry: TimerEntry): boolean;
@@ -20,15 +20,15 @@ export async function readNextScannedTimerEntry(iterator, storage) {
20
20
  return { key, entry: decoded };
21
21
  }
22
22
  }
23
- export async function readNextTerminalCleanupTimerEntry(iterator, storage) {
24
- const prefix = "wf-cleanup:";
23
+ async function readNextWorkflowTimerEntry(iterator, storage, kind) {
24
+ const { diagnosticName, prefix } = kind === "terminal-cleanup" ? { diagnosticName: "terminal cleanup", prefix: "wf-cleanup:" } : { diagnosticName: "teardown timer", prefix: "wf-teardown:" };
25
25
  while (!0) {
26
26
  const next = await iterator.next();
27
27
  if (next.done)
28
28
  return null;
29
29
  const [key, value] = next.value, separatorIndex = key.indexOf(":", prefix.length), fireAtValue = separatorIndex === -1 ? Number.NaN : Number(key.slice(prefix.length, separatorIndex)), timerId = separatorIndex === -1 ? null : tryDecodeStorageKeyComponent(key.slice(separatorIndex + 1)), decodedWorkflowId = decode(value);
30
30
  if (!Number.isSafeInteger(fireAtValue) || fireAtValue < 0 || timerId === null || typeof decodedWorkflowId !== "string") {
31
- console.error(`Corrupted terminal cleanup entry at ${key}: removing`);
31
+ console.error(`Corrupted ${diagnosticName} entry at ${key}: removing`);
32
32
  await storage.delete(key);
33
33
  continue;
34
34
  }
@@ -38,11 +38,17 @@ export async function readNextTerminalCleanupTimerEntry(iterator, storage) {
38
38
  id: timerId,
39
39
  workflowId: decodedWorkflowId,
40
40
  fireAt: fireAtValue,
41
- kind: "terminal-cleanup"
41
+ kind
42
42
  }
43
43
  };
44
44
  }
45
45
  }
46
+ export async function readNextTerminalCleanupTimerEntry(iterator, storage) {
47
+ return readNextWorkflowTimerEntry(iterator, storage, "terminal-cleanup");
48
+ }
49
+ export async function readNextTeardownTimerEntry(iterator, storage) {
50
+ return readNextWorkflowTimerEntry(iterator, storage, "teardown");
51
+ }
46
52
  export async function advanceTimerSource(timerSource, storage) {
47
53
  timerSource.next = await timerSource.readNext(timerSource.iterator, storage);
48
54
  }
@@ -57,5 +63,5 @@ export function selectNextTimerSource(timerSources) {
57
63
  return selectedSource;
58
64
  }
59
65
  export function shouldDeleteTimerIndexWithoutLookup(entry) {
60
- return entry.kind !== "schedule" && entry.kind !== "terminal-cleanup";
66
+ return entry.kind !== "schedule" && entry.kind !== "terminal-cleanup" && entry.kind !== "teardown";
61
67
  }
@@ -1,6 +1,5 @@
1
1
  import { WeftError } from './weft-error.ts';
2
2
  export declare const SESSION_STATE_LOCAL_KEY = "stateSession";
3
- export declare const LEGACY_SESSION_STATE_LOCAL_KEY = "sessionState";
4
3
  export declare const MAX_SESSION_STATE_ENTRY_COUNT = 256;
5
4
  export declare const MAX_SESSION_STATE_KEY_LENGTH = 256;
6
5
  export declare const MAX_SESSION_STATE_SERIALIZED_BYTES: number;
@@ -1,6 +1,6 @@
1
1
  import { encode } from "./codec.js";
2
2
  import { WeftError } from "./weft-error.js";
3
- export const SESSION_STATE_LOCAL_KEY = "stateSession", LEGACY_SESSION_STATE_LOCAL_KEY = "sessionState", MAX_SESSION_STATE_ENTRY_COUNT = 256, MAX_SESSION_STATE_KEY_LENGTH = 256, MAX_SESSION_STATE_SERIALIZED_BYTES = 32768;
3
+ export const SESSION_STATE_LOCAL_KEY = "stateSession", MAX_SESSION_STATE_ENTRY_COUNT = 256, MAX_SESSION_STATE_KEY_LENGTH = 256, MAX_SESSION_STATE_SERIALIZED_BYTES = 32768;
4
4
  const RESERVED_SESSION_STATE_KEYS = new Set(["__proto__", "constructor", "prototype"]);
5
5
 
6
6
  export class SessionStateValidationError extends WeftError {
@@ -55,7 +55,7 @@ export function normalizeSessionStateRecord(value) {
55
55
  export function normalizeSessionStateLocals(locals) {
56
56
  if (!locals)
57
57
  return;
58
- return normalizeSessionStateRecord(locals[SESSION_STATE_LOCAL_KEY] ?? locals[LEGACY_SESSION_STATE_LOCAL_KEY]);
58
+ return normalizeSessionStateRecord(locals[SESSION_STATE_LOCAL_KEY]);
59
59
  }
60
60
  export function validateSessionStateStore(store) {
61
61
  const keys = Object.keys(store);
@@ -29,6 +29,40 @@ export declare const coerceStartWorkflowIdempotencyKey: (value: unknown, fieldNa
29
29
  * caller gets the same guarantees as an HTTP caller.
30
30
  */
31
31
  export declare const assertValidIdempotencyKey: (value: string, fieldName: string) => string;
32
+ /**
33
+ * Validate the `onTerminalConflict` start policy against the rest of the start
34
+ * options. `'error'` (the default) and `'start-new'` are the only accepted
35
+ * values. `'start-new'` (Temporal's `ALLOW_DUPLICATE` for terminal runs) requires
36
+ * an explicit, caller-chosen `id` and is mutually exclusive with `idempotencyKey`:
37
+ * idempotency is a permanent at-most-once mapping that survives terminal state, so
38
+ * restarting under it would contradict that contract. A generated UUID is never a
39
+ * meaningful restart target, hence the explicit-`id` requirement.
40
+ */
41
+ export declare function assertValidOnTerminalConflict(options: {
42
+ onTerminalConflict?: unknown;
43
+ id?: unknown;
44
+ idempotencyKey?: unknown;
45
+ } | undefined): void;
46
+ /**
47
+ * `options.id` and `options.idempotencyKey` are mutually exclusive: idempotency
48
+ * assigns its own generated workflow id and dedups through the key, so pinning a
49
+ * caller id alongside it conflates "id already taken" with "lost the idempotency
50
+ * race". Reject the combination so each concern stays separable. Shared by the
51
+ * plain idempotent-start path and `startOrSignal` convergence validation.
52
+ */
53
+ export declare function assertIdAndIdempotencyKeyExclusive(options: {
54
+ id?: unknown;
55
+ idempotencyKey?: unknown;
56
+ }): void;
57
+ /**
58
+ * Reject `onTerminalConflict` on a start surface that does not support it
59
+ * (`engine.startOrSignal`). The option is type-absent from those surfaces, but a
60
+ * transport or untyped JS caller could still smuggle the field into the options
61
+ * object — this is the runtime backstop. `engine.startOrSignal`'s identity is the
62
+ * permanent at-most-once idempotency mapping, which `'start-new'` would violate,
63
+ * so the policy is `engine.start`-only (see follow-up issue #489).
64
+ */
65
+ export declare function assertOnTerminalConflictUnsupported(options: object | undefined, surface: string): void;
32
66
  export declare function coerceStartWorkflowTimestamp(value: unknown, fieldName: string): number;
33
67
  export declare function parseStartWorkflowDuration(duration: Duration, fieldName: string): number;
34
68
  export declare function coerceStartWorkflowDuration(value: unknown, fieldName: string): Duration;
@@ -33,6 +33,25 @@ export const assertExclusiveStartWorkflowOptions = (startAt, startAfter) => {
33
33
  throw new StartWorkflowValidationError(`${fieldName} must be at most ${MAX_IDEMPOTENCY_KEY_BYTES} UTF-8 bytes`);
34
34
  return value;
35
35
  };
36
+ export function assertValidOnTerminalConflict(options) {
37
+ const onTerminalConflict = options?.onTerminalConflict;
38
+ if (onTerminalConflict === void 0 || onTerminalConflict === "error")
39
+ return;
40
+ if (onTerminalConflict !== "start-new")
41
+ throw new StartWorkflowValidationError("options.onTerminalConflict must be 'error' or 'start-new'");
42
+ if (options?.idempotencyKey !== void 0)
43
+ throw new StartWorkflowValidationError("options.onTerminalConflict: 'start-new' is mutually exclusive with options.idempotencyKey: idempotency is a permanent at-most-once mapping and cannot restart a terminal run");
44
+ if (options?.id === void 0)
45
+ throw new StartWorkflowValidationError("options.onTerminalConflict: 'start-new' requires an explicit options.id; a generated id is never a meaningful restart target");
46
+ }
47
+ export function assertIdAndIdempotencyKeyExclusive(options) {
48
+ if (options.id !== void 0 && options.idempotencyKey !== void 0)
49
+ throw new StartWorkflowValidationError("options.id and options.idempotencyKey are mutually exclusive: idempotency assigns its own workflow id and dedups through the idempotency key. Provide one or the other.");
50
+ }
51
+ export function assertOnTerminalConflictUnsupported(options, surface) {
52
+ if (options !== void 0 && "onTerminalConflict" in options && options.onTerminalConflict !== void 0)
53
+ throw new StartWorkflowValidationError(`${surface} does not support options.onTerminalConflict; it is available on engine.start only`);
54
+ }
36
55
  export function coerceStartWorkflowTimestamp(value, fieldName) {
37
56
  if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
38
57
  throw new StartWorkflowValidationError(`${fieldName} must be a non-negative integer millisecond timestamp`);
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Activity verification types: the two-phase verifier contract an activity can
3
+ * declare via {@link ActivityDefinition.verify}. Split out of `activity.ts` to
4
+ * keep that module under the per-file line ceiling; these types are re-exported
5
+ * through `../types.ts` so the public surface is unchanged.
6
+ */
7
+ /**
8
+ * Identifies whether an activity verifier is checking a fresh result or
9
+ * reconciling a prior keyed dispatch before redispatch.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import type { ActivityVerificationPhase } from '@lostgradient/weft';
14
+ *
15
+ * const phase: ActivityVerificationPhase = 'pre-dispatch-reconciliation';
16
+ * console.log(phase);
17
+ * ```
18
+ */
19
+ export type ActivityVerificationPhase = 'post-execution-validation' | 'pre-dispatch-reconciliation';
20
+ /**
21
+ * Metadata passed to a Tier-0 activity verifier.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * import type { ActivityVerificationContext } from '@lostgradient/weft';
26
+ *
27
+ * function shouldQueryExternalSystem(context: ActivityVerificationContext): boolean {
28
+ * return context.phase === 'pre-dispatch-reconciliation';
29
+ * }
30
+ * ```
31
+ */
32
+ export interface ActivityVerificationContext<TInput = unknown> {
33
+ phase: ActivityVerificationPhase;
34
+ workflowId: string;
35
+ activityName: string;
36
+ operationId: string;
37
+ input: TInput;
38
+ idempotencyKey?: string;
39
+ attempt: number;
40
+ }
41
+ /**
42
+ * Return value for activity verification. Post-execution validation uses a
43
+ * boolean; pre-dispatch reconciliation can report whether a prior keyed side
44
+ * effect completed, did not complete, or is indeterminate.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * import type { ActivityVerificationResult } from '@lostgradient/weft';
49
+ *
50
+ * const result: ActivityVerificationResult<string> = {
51
+ * status: 'completed-with-result',
52
+ * result: 'already-finished',
53
+ * };
54
+ * console.log(result.status);
55
+ * ```
56
+ */
57
+ export type ActivityVerificationResult<TOutput = unknown> = boolean | 'not-completed' | 'completed-result-unavailable' | 'indeterminate' | {
58
+ status: 'completed-with-result';
59
+ result: TOutput;
60
+ };
61
+ export type ActivityPostExecutionVerifier<TOutput = unknown> = {
62
+ bivarianceHack(result: TOutput): Promise<boolean> | boolean;
63
+ }['bivarianceHack'];
64
+ export type ActivityTier0Verifier<TInput = unknown, TOutput = unknown> = {
65
+ bivarianceHack(result: TOutput | undefined, context: ActivityVerificationContext<TInput>): Promise<ActivityVerificationResult<TOutput>> | ActivityVerificationResult<TOutput>;
66
+ }['bivarianceHack'];
67
+ export type ActivityVerifier<TInput = unknown, TOutput = unknown> = ActivityPostExecutionVerifier<TOutput> | ActivityTier0Verifier<TInput, TOutput>;
File without changes
@@ -1,3 +1,4 @@
1
+ import type { ActivityVerifier } from './activity-verification.ts';
1
2
  import type { DefinitionSchema, InferSchemaOutput } from './definition-schema.ts';
2
3
  import type { Duration, RetryPolicy } from './retry-retention.ts';
3
4
  /**
@@ -47,6 +48,53 @@ export type ActivityFunction<TInput = unknown, TOutput = unknown> = (input: TInp
47
48
  export interface ActivityContext {
48
49
  signal: AbortSignal;
49
50
  heartbeat(details?: unknown): void;
51
+ /**
52
+ * The heartbeat payload recorded by the PREVIOUS attempt of this activity, or
53
+ * `undefined` if there is none. This is the resumable-batch pattern: a
54
+ * long-running activity that calls `ctx.heartbeat({ done: n })` to record its
55
+ * progress can read `ctx.lastHeartbeatDetails` on a retry and skip the work it
56
+ * already finished, instead of re-running from the start and producing
57
+ * duplicate side effects.
58
+ *
59
+ * It is `undefined` on the first attempt, after an engine restart (the value is
60
+ * held in engine memory, never checkpointed), and for worker-executed
61
+ * activities (which run their function out of process and never observe this).
62
+ * Because it is non-durable, treat it as a best-effort optimization: a correct
63
+ * activity must still produce the right result when `lastHeartbeatDetails` is
64
+ * `undefined`. For a durability guarantee, persist progress in workflow state
65
+ * (e.g. one `ctx.run` per batch with an `idempotencyKey`) instead.
66
+ *
67
+ * Only top-level `ctx.run` activities retry, so this is only ever populated
68
+ * there. An activity called inside `ctx.all` / `ctx.race` does not retry, so its
69
+ * `lastHeartbeatDetails` is always `undefined`.
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * import { activity, type ActivityContext } from '@lostgradient/weft';
74
+ *
75
+ * function resumeFrom(details: unknown): number {
76
+ * return typeof details === 'object' && details !== null && 'done' in details &&
77
+ * typeof (details as { done: unknown }).done === 'number'
78
+ * ? (details as { done: number }).done
79
+ * : 0;
80
+ * }
81
+ *
82
+ * const postBatches = activity({
83
+ * name: 'postBatches',
84
+ * execute: async (batches: string[][], ctx?: ActivityContext) => {
85
+ * let done = resumeFrom(ctx?.lastHeartbeatDetails);
86
+ * for (; done < batches.length; done += 1) {
87
+ * await postBatch(batches[done]!);
88
+ * ctx?.heartbeat({ done: done + 1 });
89
+ * }
90
+ * return { posted: done };
91
+ * },
92
+ * });
93
+ * declare function postBatch(batch: string[]): Promise<void>;
94
+ * void postBatches;
95
+ * ```
96
+ */
97
+ lastHeartbeatDetails?: unknown;
50
98
  /**
51
99
  * Defer this activity to out-of-band completion. Calling `completeAsync()`
52
100
  * hands the work off to an external system — a webhook, a human callback, a
@@ -120,68 +168,30 @@ export interface ActivityCallOptions {
120
168
  sticky?: boolean;
121
169
  /** Override the default visibility timeout for this invocation. */
122
170
  visibilityTimeout?: Duration;
171
+ /**
172
+ * Total wall-clock budget for this activity across ALL retry attempts and the
173
+ * backoff waits between them — close to Temporal's `scheduleToCloseTimeout`.
174
+ * Unlike `timeout` (a per-attempt cap, reset on every attempt), this budget is
175
+ * measured from the first dispatch and is not reset between attempts. When the
176
+ * budget bars the next attempt, the activity fails with an
177
+ * {@link ActivityScheduleToCloseTimeoutError} (a `timeout` failure category).
178
+ *
179
+ * Enforcement is at the **retry decision point**, not by waiting out the clock:
180
+ * the activity fails when the next retry's backoff would start it at or after the
181
+ * deadline (or when an attempt has already overrun the budget), rather than
182
+ * parking for a backoff that is already doomed. So a retry whose backoff would
183
+ * overshoot the budget is skipped immediately even though the actual elapsed time
184
+ * is still under the budget — the error reports the actual elapsed time and the
185
+ * projected next-dispatch that triggered the decision.
186
+ *
187
+ * It has **no effect unless a retry policy is configured** — a non-retried
188
+ * activity fails on its first error before the budget is ever consulted. Use
189
+ * `timeout` to bound a single attempt. It also applies to top-level `ctx.run`
190
+ * activities only; an activity inside `ctx.all` / `ctx.race` does not retry, so
191
+ * this budget never engages there.
192
+ */
193
+ scheduleToCloseTimeout?: Duration;
123
194
  }
124
- /**
125
- * Identifies whether an activity verifier is checking a fresh result or
126
- * reconciling a prior keyed dispatch before redispatch.
127
- *
128
- * @example
129
- * ```ts
130
- * import type { ActivityVerificationPhase } from '@lostgradient/weft';
131
- *
132
- * const phase: ActivityVerificationPhase = 'pre-dispatch-reconciliation';
133
- * console.log(phase);
134
- * ```
135
- */
136
- export type ActivityVerificationPhase = 'post-execution-validation' | 'pre-dispatch-reconciliation';
137
- /**
138
- * Metadata passed to a Tier-0 activity verifier.
139
- *
140
- * @example
141
- * ```ts
142
- * import type { ActivityVerificationContext } from '@lostgradient/weft';
143
- *
144
- * function shouldQueryExternalSystem(context: ActivityVerificationContext): boolean {
145
- * return context.phase === 'pre-dispatch-reconciliation';
146
- * }
147
- * ```
148
- */
149
- export interface ActivityVerificationContext<TInput = unknown> {
150
- phase: ActivityVerificationPhase;
151
- workflowId: string;
152
- activityName: string;
153
- operationId: string;
154
- input: TInput;
155
- idempotencyKey?: string;
156
- attempt: number;
157
- }
158
- /**
159
- * Return value for activity verification. Post-execution validation uses a
160
- * boolean; pre-dispatch reconciliation can report whether a prior keyed side
161
- * effect completed, did not complete, or is indeterminate.
162
- *
163
- * @example
164
- * ```ts
165
- * import type { ActivityVerificationResult } from '@lostgradient/weft';
166
- *
167
- * const result: ActivityVerificationResult<string> = {
168
- * status: 'completed-with-result',
169
- * result: 'already-finished',
170
- * };
171
- * console.log(result.status);
172
- * ```
173
- */
174
- export type ActivityVerificationResult<TOutput = unknown> = boolean | 'not-completed' | 'completed-result-unavailable' | 'indeterminate' | {
175
- status: 'completed-with-result';
176
- result: TOutput;
177
- };
178
- export type ActivityPostExecutionVerifier<TOutput = unknown> = {
179
- bivarianceHack(result: TOutput): Promise<boolean> | boolean;
180
- }['bivarianceHack'];
181
- export type ActivityTier0Verifier<TInput = unknown, TOutput = unknown> = {
182
- bivarianceHack(result: TOutput | undefined, context: ActivityVerificationContext<TInput>): Promise<ActivityVerificationResult<TOutput>> | ActivityVerificationResult<TOutput>;
183
- }['bivarianceHack'];
184
- export type ActivityVerifier<TInput = unknown, TOutput = unknown> = ActivityPostExecutionVerifier<TOutput> | ActivityTier0Verifier<TInput, TOutput>;
185
195
  /**
186
196
  * Full metadata for an activity, combining the execute function with optional
187
197
  * retry policy, timeout, queue routing, compensation, and idempotency. Built
@@ -235,6 +245,15 @@ export interface ActivityDefinition<TInput = unknown, TOutput = unknown, TName e
235
245
  idempotent?: boolean;
236
246
  /** Visibility timeout for this activity. Defaults to 30 seconds. */
237
247
  visibilityTimeout?: Duration;
248
+ /**
249
+ * Total wall-clock budget across all retry attempts and their backoff waits,
250
+ * measured from the first dispatch. The per-call {@link ActivityCallOptions.scheduleToCloseTimeout}
251
+ * overrides this default. Enforced at the retry decision point (the activity
252
+ * fails when the next retry would start at or after the deadline, not by waiting
253
+ * out the clock), so it only engages for a retried, top-level `ctx.run` activity.
254
+ * See the per-call option for the full contract.
255
+ */
256
+ scheduleToCloseTimeout?: Duration;
238
257
  /**
239
258
  * Optional compensation function. When defined and a saga step that ran this
240
259
  * activity needs to be rolled back, the engine calls `compensate(input, output)`