@lostgradient/weft 0.24.0 → 0.24.2

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 (283) hide show
  1. package/README.md +2 -2
  2. package/dist/cli/conformance.js +5 -2
  3. package/dist/cli/generated/operation-catalog.snapshot.json +95 -1
  4. package/dist/cli/generated/operation-client.generated.d.ts +28 -2
  5. package/dist/cli/generated/operation-client.generated.js +2 -0
  6. package/dist/cli/parse-schedule-arguments.js +15 -3
  7. package/dist/cli/schedule.js +2 -1
  8. package/dist/cli/types.d.ts +2 -1
  9. package/dist/client/http-client-requests.js +6 -9
  10. package/dist/client/start-body.js +1 -0
  11. package/dist/core/catalog/index.d.ts +2 -2
  12. package/dist/core/catalog/index.js +9 -2
  13. package/dist/core/catalog/reference-counts.d.ts +29 -14
  14. package/dist/core/catalog/removal.d.ts +63 -10
  15. package/dist/core/catalog/removal.js +18 -2
  16. package/dist/core/catalog/storage-io.d.ts +23 -0
  17. package/dist/core/catalog/storage-io.js +1 -1
  18. package/dist/core/engine/activity-resolution.js +17 -17
  19. package/dist/core/engine/bulk-operations-purge.d.ts +1 -1
  20. package/dist/core/engine/bulk-operations-purge.js +17 -22
  21. package/dist/core/engine/bulk-operations-retry.d.ts +24 -0
  22. package/dist/core/engine/bulk-operations-retry.js +190 -0
  23. package/dist/core/engine/bulk-operations-shared.d.ts +18 -0
  24. package/dist/core/engine/bulk-operations-shared.js +14 -0
  25. package/dist/core/engine/bulk-operations.d.ts +3 -2
  26. package/dist/core/engine/bulk-operations.js +10 -169
  27. package/dist/core/engine/callback-creators-bundles.js +5 -3
  28. package/dist/core/engine/callback-creators-core.js +9 -1
  29. package/dist/core/engine/callback-creators-schedule.js +2 -2
  30. package/dist/core/engine/catalog-readiness.js +2 -0
  31. package/dist/core/engine/catalog-removal.d.ts +107 -3
  32. package/dist/core/engine/catalog-removal.js +66 -13
  33. package/dist/core/engine/catalog-tombstone-recovery.d.ts +56 -0
  34. package/dist/core/engine/catalog-tombstone-recovery.js +39 -0
  35. package/dist/core/engine/child-workflow.d.ts +13 -1
  36. package/dist/core/engine/child-workflow.js +22 -4
  37. package/dist/core/engine/constraints.js +5 -1
  38. package/dist/core/engine/construction.d.ts +1 -1
  39. package/dist/core/engine/decode-revision.d.ts +32 -0
  40. package/dist/core/engine/decode-revision.js +9 -0
  41. package/dist/core/engine/disposal.d.ts +6 -2
  42. package/dist/core/engine/disposal.js +24 -10
  43. package/dist/core/engine/dynamic-source-errors.d.ts +81 -0
  44. package/dist/core/engine/dynamic-source-errors.js +25 -0
  45. package/dist/core/engine/dynamic-source-execution.d.ts +173 -0
  46. package/dist/core/engine/dynamic-source-execution.js +108 -0
  47. package/dist/core/engine/engine-internal-types.d.ts +16 -0
  48. package/dist/core/engine/engine-workflows-namespace.d.ts +10 -0
  49. package/dist/core/engine/engine-workflows-namespace.js +3 -1
  50. package/dist/core/engine/generation-codec.d.ts +22 -0
  51. package/dist/core/engine/generation-codec.js +2 -0
  52. package/dist/core/engine/index.d.ts +18 -10
  53. package/dist/core/engine/index.js +22 -11
  54. package/dist/core/engine/inline-launch-queue.js +1 -1
  55. package/dist/core/engine/internals.d.ts +26 -30
  56. package/dist/core/engine/lifecycle/checkpoint-launch.d.ts +29 -0
  57. package/dist/core/engine/lifecycle/checkpoint-launch.js +75 -0
  58. package/dist/core/engine/lifecycle/delayed-start-registration.d.ts +30 -0
  59. package/dist/core/engine/lifecycle/delayed-start-registration.js +11 -0
  60. package/dist/core/engine/lifecycle/fork-helpers.d.ts +33 -1
  61. package/dist/core/engine/lifecycle/fork-helpers.js +3 -1
  62. package/dist/core/engine/lifecycle/recovery-isolation.d.ts +20 -0
  63. package/dist/core/engine/lifecycle/recovery-isolation.js +26 -0
  64. package/dist/core/engine/lifecycle/recovery-revision-groups.d.ts +75 -0
  65. package/dist/core/engine/lifecycle/recovery-revision-groups.js +64 -0
  66. package/dist/core/engine/lifecycle/resume-body.d.ts +44 -0
  67. package/dist/core/engine/lifecycle/resume-body.js +211 -0
  68. package/dist/core/engine/lifecycle/resume-generation-guard.d.ts +58 -0
  69. package/dist/core/engine/lifecycle/resume-generation-guard.js +11 -0
  70. package/dist/core/engine/lifecycle/resume.d.ts +46 -3
  71. package/dist/core/engine/lifecycle/resume.js +21 -201
  72. package/dist/core/engine/lifecycle/shared.d.ts +43 -0
  73. package/dist/core/engine/lifecycle/standalone-claim-acquire.d.ts +80 -2
  74. package/dist/core/engine/lifecycle/standalone-claim-acquire.js +20 -4
  75. package/dist/core/engine/lifecycle/start-commit-errors.d.ts +12 -0
  76. package/dist/core/engine/lifecycle/start-commit-errors.js +6 -0
  77. package/dist/core/engine/lifecycle/start-commit.d.ts +24 -7
  78. package/dist/core/engine/lifecycle/start-commit.js +57 -15
  79. package/dist/core/engine/lifecycle/start-exec.d.ts +18 -2
  80. package/dist/core/engine/lifecycle/start-exec.js +7 -5
  81. package/dist/core/engine/lifecycle/start-or-signal-create.js +1 -3
  82. package/dist/core/engine/lifecycle/start-or-signal-resolution.d.ts +8 -2
  83. package/dist/core/engine/lifecycle/start-or-signal-resolution.js +11 -3
  84. package/dist/core/engine/lifecycle/start-or-signal.js +1 -1
  85. package/dist/core/engine/lifecycle/start-precondition-attribution.d.ts +55 -0
  86. package/dist/core/engine/lifecycle/start-precondition-attribution.js +13 -0
  87. package/dist/core/engine/lifecycle/start-revision-resolution.d.ts +34 -0
  88. package/dist/core/engine/lifecycle/start-revision-resolution.js +11 -0
  89. package/dist/core/engine/lifecycle/start-schedule-timing.d.ts +11 -0
  90. package/dist/core/engine/lifecycle/start-schedule-timing.js +21 -0
  91. package/dist/core/engine/lifecycle/start-state.d.ts +16 -0
  92. package/dist/core/engine/lifecycle/start-state.js +60 -0
  93. package/dist/core/engine/lifecycle/start-terminal-conflict-purge.d.ts +146 -4
  94. package/dist/core/engine/lifecycle/start-terminal-conflict-purge.js +33 -4
  95. package/dist/core/engine/lifecycle/start.d.ts +54 -7
  96. package/dist/core/engine/lifecycle/start.js +53 -90
  97. package/dist/core/engine/lifecycle/transition.d.ts +12 -4
  98. package/dist/core/engine/lifecycle/transition.js +40 -95
  99. package/dist/core/engine/lifecycle.d.ts +5 -2
  100. package/dist/core/engine/lifecycle.js +7 -6
  101. package/dist/core/engine/listing.js +15 -1
  102. package/dist/core/engine/memo-durable-activity.js +4 -1
  103. package/dist/core/engine/nonterminal-revision-count.d.ts +25 -0
  104. package/dist/core/engine/nonterminal-revision-count.js +16 -0
  105. package/dist/core/engine/operations-time.d.ts +5 -23
  106. package/dist/core/engine/operations-time.js +13 -11
  107. package/dist/core/engine/ownership-bootstrap.d.ts +1 -1
  108. package/dist/core/engine/pinned-schedule-revision-count.d.ts +26 -0
  109. package/dist/core/engine/pinned-schedule-revision-count.js +19 -0
  110. package/dist/core/engine/pinned-schedule-revision.d.ts +76 -0
  111. package/dist/core/engine/pinned-schedule-revision.js +53 -0
  112. package/dist/core/engine/registration.d.ts +30 -0
  113. package/dist/core/engine/registration.js +17 -2
  114. package/dist/core/engine/retention.js +9 -2
  115. package/dist/core/engine/revision-errors.d.ts +71 -0
  116. package/dist/core/engine/revision-errors.js +13 -0
  117. package/dist/core/engine/schedule-overlap.js +2 -1
  118. package/dist/core/engine/schedule-revision-fire.d.ts +17 -0
  119. package/dist/core/engine/schedule-revision-fire.js +3 -0
  120. package/dist/core/engine/schedule-run.d.ts +10 -0
  121. package/dist/core/engine/schedule-run.js +2 -1
  122. package/dist/core/engine/schedules.d.ts +11 -1
  123. package/dist/core/engine/schedules.js +28 -9
  124. package/dist/core/engine/source-diagnostics.d.ts +76 -0
  125. package/dist/core/engine/source-diagnostics.js +105 -0
  126. package/dist/core/engine/source-registration.js +4 -2
  127. package/dist/core/engine/source-resolution.d.ts +25 -9
  128. package/dist/core/engine/source-resolution.js +49 -14
  129. package/dist/core/engine/source-runtime-state.d.ts +92 -0
  130. package/dist/core/engine/source-runtime-state.js +36 -0
  131. package/dist/core/engine/storage-io.d.ts +19 -2
  132. package/dist/core/engine/storage-io.js +21 -2
  133. package/dist/core/engine/termination/complete.js +1 -1
  134. package/dist/core/engine/termination/finalizer-registration.d.ts +18 -0
  135. package/dist/core/engine/termination/finalizer-registration.js +21 -0
  136. package/dist/core/engine/termination/finalizer.d.ts +16 -19
  137. package/dist/core/engine/termination/finalizer.js +3 -3
  138. package/dist/core/engine/termination/suspend.js +3 -0
  139. package/dist/core/engine/time-operation-callbacks.d.ts +32 -0
  140. package/dist/core/engine/time-operation-callbacks.js +0 -0
  141. package/dist/core/engine/validation/schedule-cadence.d.ts +16 -0
  142. package/dist/core/engine/validation/schedule-cadence.js +20 -0
  143. package/dist/core/engine/validation/schedule-options.d.ts +4 -1
  144. package/dist/core/engine/validation/schedule-options.js +14 -0
  145. package/dist/core/engine/validation/schedule-revision.d.ts +24 -0
  146. package/dist/core/engine/validation/schedule-revision.js +21 -0
  147. package/dist/core/engine/validation/schedule-warnings.d.ts +11 -0
  148. package/dist/core/engine/validation/schedule-warnings.js +5 -0
  149. package/dist/core/engine/validation/schedule.d.ts +29 -4
  150. package/dist/core/engine/validation/schedule.js +19 -36
  151. package/dist/core/engine/validation.js +13 -17
  152. package/dist/core/engine/workflow-claim-reclaim-target.d.ts +1 -1
  153. package/dist/core/engine/workflow-claim-reclaim-target.js +22 -8
  154. package/dist/core/engine/workflow-claim-registry.d.ts +79 -75
  155. package/dist/core/engine/workflow-claim-registry.js +15 -2
  156. package/dist/core/engine/workflow-generation-fence.d.ts +74 -0
  157. package/dist/core/engine/workflow-generation-fence.js +19 -0
  158. package/dist/core/engine/workflow-retention-deadline.d.ts +16 -0
  159. package/dist/core/engine/workflow-retention-deadline.js +33 -0
  160. package/dist/core/events/event-map.d.ts +5 -0
  161. package/dist/core/events/index.d.ts +1 -0
  162. package/dist/core/events/index.js +1 -0
  163. package/dist/core/events/workflow-source-events.d.ts +102 -0
  164. package/dist/core/events/workflow-source-events.js +57 -0
  165. package/dist/core/execution-strategy.d.ts +7 -0
  166. package/dist/core/inline-execution-strategy.context-options.d.ts +1 -1
  167. package/dist/core/inline-execution-strategy.js +1 -1
  168. package/dist/core/start-workflow-validation.d.ts +15 -0
  169. package/dist/core/start-workflow-validation.js +11 -1
  170. package/dist/core/types/checkpoint.d.ts +14 -0
  171. package/dist/core/types/schedules.d.ts +52 -1
  172. package/dist/core/types/state.d.ts +16 -0
  173. package/dist/core/weft-error.d.ts +1 -1
  174. package/dist/core/weft-error.js +4 -1
  175. package/dist/core/worker-execution-strategy.d.ts +1 -0
  176. package/dist/core/worker-execution-strategy.js +13 -1
  177. package/dist/core/worker-fault-handling.d.ts +10 -0
  178. package/dist/core/worker-fault-handling.js +1 -0
  179. package/dist/core/worker-inbound-message.d.ts +1 -0
  180. package/dist/core/worker-inbound-message.js +1 -0
  181. package/dist/core/worker-protocol-guard.js +4 -0
  182. package/dist/core/worker-protocol.d.ts +7 -0
  183. package/dist/core/worker-protocol.js +2 -1
  184. package/dist/core/worker-turn-watchdog.d.ts +8 -1
  185. package/dist/core/worker-turn-watchdog.js +3 -2
  186. package/dist/core/workflow-identifiers.d.ts +37 -0
  187. package/dist/core/workflow-identifiers.js +19 -1
  188. package/dist/diagnostics/format.js +5 -0
  189. package/dist/diagnostics/types.d.ts +24 -0
  190. package/dist/diagnostics/version-check.js +8 -2
  191. package/dist/http.js +2 -2
  192. package/dist/index.d.ts +3 -3
  193. package/dist/index.js +7 -0
  194. package/dist/indexeddb.js +1 -1
  195. package/dist/json-schema.js +3 -3
  196. package/dist/server/fault-to-json-rpc.js +2 -1
  197. package/dist/server/fleet-event-feed.js +6 -6
  198. package/dist/server/index.d.ts +11 -0
  199. package/dist/server/operation-fault.d.ts +2 -0
  200. package/dist/server/operation-fault.js +2 -1
  201. package/dist/server/operations/create-schedule.d.ts +2 -0
  202. package/dist/server/operations/create-schedule.js +10 -6
  203. package/dist/server/operations/get-catalog-diagnostics.d.ts +28 -0
  204. package/dist/server/operations/get-catalog-diagnostics.js +10 -2
  205. package/dist/server/operations/get-task-detail-schema.d.ts +8 -0
  206. package/dist/server/operations/get-task-detail-schema.js +1 -0
  207. package/dist/server/operations/get-task-detail.d.ts +8 -0
  208. package/dist/server/operations/get-task-detail.js +1 -0
  209. package/dist/server/operations/get-task-diagnostics.d.ts +4 -4
  210. package/dist/server/operations/preload-workflow-revision.d.ts +28 -0
  211. package/dist/server/operations/preload-workflow-revision.js +60 -0
  212. package/dist/server/operations/schedule-faults.d.ts +1 -0
  213. package/dist/server/operations/schedule-faults.js +32 -4
  214. package/dist/server/operations/schedule-rest-body.d.ts +1 -0
  215. package/dist/server/operations/schedule-rest-body.js +2 -1
  216. package/dist/server/operations/static-registrations.js +6 -0
  217. package/dist/server/operations/update-schedule.d.ts +2 -0
  218. package/dist/server/operations/update-schedule.js +4 -2
  219. package/dist/server/operations/workflow-catalog-operation-helpers.js +27 -0
  220. package/dist/server/rest-binding.d.ts +11 -0
  221. package/dist/server/runtime/task-dispatch-envelope.d.ts +41 -0
  222. package/dist/server/runtime/task-dispatch-envelope.js +54 -0
  223. package/dist/server/runtime/task-dispatch-revision.d.ts +29 -0
  224. package/dist/server/runtime/task-dispatch-revision.js +13 -0
  225. package/dist/server/runtime/task-dispatch.d.ts +3 -1
  226. package/dist/server/runtime/task-dispatch.js +20 -44
  227. package/dist/server/runtime/task-ledger-recovery.js +1 -1
  228. package/dist/server/runtime/task-ledger-runtime.d.ts +14 -2
  229. package/dist/server/runtime/task-ledger-runtime.js +5 -3
  230. package/dist/server/runtime/task-polling.js +9 -3
  231. package/dist/server/runtime/task-reconciliation.js +2 -1
  232. package/dist/server/runtime/websocket-worker.js +9 -0
  233. package/dist/server/task-ledger-codec.d.ts +28 -0
  234. package/dist/server/task-ledger-codec.js +7 -1
  235. package/dist/server/task-ledger-transition-helpers.js +1 -0
  236. package/dist/server/task-ledger-types.d.ts +9 -0
  237. package/dist/server/task-ledger.d.ts +1 -1
  238. package/dist/server/task-ledger.js +3 -1
  239. package/dist/server/task-queue-types.d.ts +2 -0
  240. package/dist/storage/bun-sql.js +135 -100
  241. package/dist/storage/catalog-keys.d.ts +19 -0
  242. package/dist/storage/catalog-keys.js +3 -1
  243. package/dist/storage/compressed-storage.js +1 -1
  244. package/dist/storage/generation-keys.d.ts +52 -0
  245. package/dist/storage/generation-keys.js +4 -0
  246. package/dist/storage/index.d.ts +76 -63
  247. package/dist/storage/interface.d.ts +24 -230
  248. package/dist/storage/interface.js +1 -1
  249. package/dist/storage/key-prefixes.d.ts +1 -1
  250. package/dist/storage/key-prefixes.js +2 -0
  251. package/dist/storage/lease-keys.d.ts +48 -0
  252. package/dist/storage/lease-keys.js +8 -0
  253. package/dist/storage/lmdb.d.ts +30 -2
  254. package/dist/storage/lmdb.js +1 -1
  255. package/dist/storage/memory.js +1 -1
  256. package/dist/storage/neon.js +3 -3
  257. package/dist/storage/node-sqlite.js +135 -100
  258. package/dist/storage/postgres.js +3 -3
  259. package/dist/storage/resolve.js +1 -1
  260. package/dist/storage/scoped-storage.js +1 -1
  261. package/dist/storage/signal-keys.d.ts +23 -0
  262. package/dist/storage/signal-keys.js +9 -0
  263. package/dist/storage/testing.js +1 -1
  264. package/dist/storage/turso.js +2 -2
  265. package/dist/storage/workflow-lifecycle-keys.d.ts +128 -0
  266. package/dist/storage/workflow-lifecycle-keys.js +46 -0
  267. package/dist/storage/workflow-record-keys.d.ts +98 -0
  268. package/dist/storage/workflow-record-keys.js +47 -0
  269. package/dist/version.d.ts +1 -1
  270. package/dist/version.js +1 -1
  271. package/dist/web-extension.js +1 -1
  272. package/dist/worker/protocol-messages.d.ts +17 -0
  273. package/dist/worker/protocol-schemas.d.ts +32 -0
  274. package/dist/worker/protocol-schemas.js +7 -3
  275. package/dist/worker/protocol-task-result.js +35 -3
  276. package/dist/worker/protocol.js +1 -1
  277. package/dist/worker/registry/types.d.ts +2 -0
  278. package/dist/worker/registry.d.ts +1 -1
  279. package/dist/worker/registry.js +3 -1
  280. package/dist/workers/workflow-runner.d.ts +9 -0
  281. package/dist/workers/workflow-runner.js +9 -2
  282. package/dist/workers/workflow-worker-entry.js +9 -4
  283. package/package.json +2 -2
@@ -60,6 +60,7 @@ export declare const getTaskDetailOperation: import("../operation-catalog.ts").O
60
60
  adoptedAt?: number | undefined;
61
61
  workflowId?: string | undefined;
62
62
  workflowExecutionToken?: string | undefined;
63
+ workflowRevision?: string | undefined;
63
64
  priority?: number | undefined;
64
65
  retryPolicy?: {
65
66
  maxAttempts: number;
@@ -95,6 +96,7 @@ export declare const getTaskDetailOperation: import("../operation-catalog.ts").O
95
96
  adoptedAt?: number | undefined;
96
97
  workflowId?: string | undefined;
97
98
  workflowExecutionToken?: string | undefined;
99
+ workflowRevision?: string | undefined;
98
100
  priority?: number | undefined;
99
101
  retryPolicy?: {
100
102
  maxAttempts: number;
@@ -130,6 +132,7 @@ export declare const getTaskDetailOperation: import("../operation-catalog.ts").O
130
132
  adoptedAt?: number | undefined;
131
133
  workflowId?: string | undefined;
132
134
  workflowExecutionToken?: string | undefined;
135
+ workflowRevision?: string | undefined;
133
136
  priority?: number | undefined;
134
137
  retryPolicy?: {
135
138
  maxAttempts: number;
@@ -168,6 +171,7 @@ export declare const getTaskDetailOperation: import("../operation-catalog.ts").O
168
171
  lastRequeueReason?: string | undefined;
169
172
  workflowId?: string | undefined;
170
173
  workflowExecutionToken?: string | undefined;
174
+ workflowRevision?: string | undefined;
171
175
  priority?: number | undefined;
172
176
  retryPolicy?: {
173
177
  maxAttempts: number;
@@ -206,6 +210,7 @@ export declare const getTaskDetailOperation: import("../operation-catalog.ts").O
206
210
  lastRequeueReason?: string | undefined;
207
211
  workflowId?: string | undefined;
208
212
  workflowExecutionToken?: string | undefined;
213
+ workflowRevision?: string | undefined;
209
214
  priority?: number | undefined;
210
215
  retryPolicy?: {
211
216
  maxAttempts: number;
@@ -246,6 +251,7 @@ export declare const getTaskDetailOperation: import("../operation-catalog.ts").O
246
251
  lastRequeueReason?: string | undefined;
247
252
  workflowId?: string | undefined;
248
253
  workflowExecutionToken?: string | undefined;
254
+ workflowRevision?: string | undefined;
249
255
  priority?: number | undefined;
250
256
  retryPolicy?: {
251
257
  maxAttempts: number;
@@ -286,6 +292,7 @@ export declare const getTaskDetailOperation: import("../operation-catalog.ts").O
286
292
  lastRequeueReason?: string | undefined;
287
293
  workflowId?: string | undefined;
288
294
  workflowExecutionToken?: string | undefined;
295
+ workflowRevision?: string | undefined;
289
296
  priority?: number | undefined;
290
297
  retryPolicy?: {
291
298
  maxAttempts: number;
@@ -324,6 +331,7 @@ export declare const getTaskDetailOperation: import("../operation-catalog.ts").O
324
331
  lastRequeueReason?: string | undefined;
325
332
  workflowId?: string | undefined;
326
333
  workflowExecutionToken?: string | undefined;
334
+ workflowRevision?: string | undefined;
327
335
  priority?: number | undefined;
328
336
  retryPolicy?: {
329
337
  maxAttempts: number;
@@ -38,6 +38,7 @@ function baseEnvelopeFields(record) {
38
38
  operationId: record.operationId,
39
39
  ...record.workflowId !== void 0 ? { workflowId: record.workflowId } : {},
40
40
  ...record.workflowExecutionToken !== void 0 ? { workflowExecutionToken: record.workflowExecutionToken } : {},
41
+ ...record.workflowRevision !== void 0 ? { workflowRevision: record.workflowRevision } : {},
41
42
  workflowType: record.workflowType,
42
43
  activityName: record.activityName,
43
44
  queue: record.queue,
@@ -60,8 +60,8 @@ declare const taskDiagnosticItemSchema: z.ZodUnion<readonly [z.ZodObject<{
60
60
  }>;
61
61
  state: z.ZodEnum<{
62
62
  "dead-lettered": "dead-lettered";
63
- queued: "queued";
64
63
  resolved: "resolved";
64
+ queued: "queued";
65
65
  inflight: "inflight";
66
66
  capacity: "capacity";
67
67
  }>;
@@ -122,8 +122,8 @@ declare const getTaskDiagnosticsOutput: z.ZodObject<{
122
122
  }>;
123
123
  state: z.ZodEnum<{
124
124
  "dead-lettered": "dead-lettered";
125
- queued: "queued";
126
125
  resolved: "resolved";
126
+ queued: "queued";
127
127
  inflight: "inflight";
128
128
  capacity: "capacity";
129
129
  }>;
@@ -217,7 +217,7 @@ export declare function createGetTaskDiagnosticsOperation(options?: GetTaskDiagn
217
217
  }, {
218
218
  items: ({
219
219
  kind: "dead-lettered" | "stuck-queued" | "stale-inflight" | "retry-storm" | "all-workers-at-capacity";
220
- state: "dead-lettered" | "queued" | "resolved" | "inflight" | "capacity";
220
+ state: "dead-lettered" | "resolved" | "queued" | "inflight" | "capacity";
221
221
  retryCount: number;
222
222
  requeueCount: number;
223
223
  evidence: string[];
@@ -279,7 +279,7 @@ export declare const getTaskDiagnosticsOperation: import("../operation-catalog.t
279
279
  }, {
280
280
  items: ({
281
281
  kind: "dead-lettered" | "stuck-queued" | "stale-inflight" | "retry-storm" | "all-workers-at-capacity";
282
- state: "dead-lettered" | "queued" | "resolved" | "inflight" | "capacity";
282
+ state: "dead-lettered" | "resolved" | "queued" | "inflight" | "capacity";
283
283
  retryCount: number;
284
284
  requeueCount: number;
285
285
  evidence: string[];
@@ -0,0 +1,28 @@
1
+ /**
2
+ * `weft.workflows.revisions.preload` operation + REST binding.
3
+ *
4
+ * Loads, validates, and installs one dynamic workflow source revision
5
+ * previously recorded via `engine.registerSource()` — a thin, documented
6
+ * exposure of `engine.workflows.preload()` (WFT-15/16). Modeled on
7
+ * `install-workflow-revision.ts` / `activate-workflow-revision.ts`.
8
+ *
9
+ * @module server/operations/preload-workflow-revision
10
+ */
11
+ import { z } from 'zod';
12
+ import type { WorkflowRevisionRecord } from '../../core/catalog/index.ts';
13
+ import type { UnknownRestBinding } from '../rest-bindings.ts';
14
+ declare const preloadWorkflowRevisionInput: z.ZodObject<{
15
+ name: z.ZodUnknown;
16
+ revision: z.ZodUnknown;
17
+ }, z.core.$strip>;
18
+ export type PreloadWorkflowRevisionInput = z.infer<typeof preloadWorkflowRevisionInput>;
19
+ export type PreloadWorkflowRevisionOutput = WorkflowRevisionRecord;
20
+ export declare const preloadWorkflowRevisionOperation: import("../operation-catalog.ts").OperationDefinition<{
21
+ name: unknown;
22
+ revision: unknown;
23
+ }, Readonly<{
24
+ manifest: import("../../index.ts").WorkflowRevisionManifest;
25
+ installedAt: number;
26
+ }>, unknown>;
27
+ export declare const preloadWorkflowRevisionRestBinding: UnknownRestBinding;
28
+ export {};
@@ -0,0 +1,60 @@
1
+ import { z } from "zod";
2
+ import { isWeftError } from "../../core/weft-error.js";
3
+ import { defineOperation } from "../operation-registry.js";
4
+ import {
5
+ readWorkflowCatalogRestBody,
6
+ throwWorkflowCatalogOperationFault,
7
+ validateWorkflowNameField,
8
+ validateWorkflowRevisionField,
9
+ workflowsAdminAccess
10
+ } from "./workflow-catalog-operation-helpers.js";
11
+ const preloadWorkflowRevisionInput = z.object({
12
+ name: z.unknown().describe("Workflow name. Runtime validation requires a wire-safe identifier."),
13
+ revision: z.unknown().describe("The registerSource()-registered revision to load, validate, and install. Runtime validation requires a non-empty string.")
14
+ }), preloadWorkflowRevisionOutput = z.unknown();
15
+ export const preloadWorkflowRevisionOperation = defineOperation({
16
+ name: "weft.workflows.revisions.preload",
17
+ mcpExposable: !1,
18
+ summary: "Load, validate, and install a registered dynamic workflow source revision",
19
+ description: "Load, validate, and install `(name, revision)` \u2014 previously recorded via " + "engine.registerSource() \u2014 durably into the workflow catalog. Faults NotFound when no " + "source was ever registered for this exact key, and Conflict when the load fails or the loaded module fails validation.",
20
+ destructive: !1,
21
+ tags: ["Workflow Catalog"],
22
+ inputSchema: preloadWorkflowRevisionInput,
23
+ outputSchema: preloadWorkflowRevisionOutput,
24
+ access: workflowsAdminAccess,
25
+ producibleFaults: ["InvalidParams", "NotFound", "Conflict"],
26
+ discoverable: !0,
27
+ transports: { http: !0, jsonRpcHttp: !0, jsonRpcWebSocket: !0, jsonRpcStdio: !0 },
28
+ unknownKeyPolicy: { http: "strip", jsonRpc: "reject" },
29
+ invoke: async ({ input, engine }) => {
30
+ const e = engine, name = validateWorkflowNameField(input.name), revision = validateWorkflowRevisionField(input.revision);
31
+ try {
32
+ return await e.workflows.preload(name, revision);
33
+ } catch (error) {
34
+ if (!isWeftError(error))
35
+ throw {
36
+ code: "Conflict",
37
+ message: `Dynamic workflow source "${name}" revision "${revision}" failed to load.`,
38
+ data: { reason: "load-failed" }
39
+ };
40
+ return throwWorkflowCatalogOperationFault(error);
41
+ }
42
+ }
43
+ }), preloadWorkflowRevisionRestBinding = {
44
+ method: "POST",
45
+ path: "/v1/registry/workflows/:name/preload",
46
+ pathParamNames: ["name"],
47
+ operationName: "weft.workflows.revisions.preload",
48
+ inputSources: {
49
+ name: { kind: "path", pathParam: "name" },
50
+ revision: { kind: "body-field", bodyField: "revision" }
51
+ },
52
+ extractInput: async (request, pathParams, context) => {
53
+ const body = await readWorkflowCatalogRestBody(request, context);
54
+ return {
55
+ name: pathParams.name ?? "",
56
+ revision: body.revision
57
+ };
58
+ },
59
+ success: { kind: "json", status: 200 }
60
+ };
@@ -6,6 +6,7 @@ export type ScheduleMutableOptionsInput = {
6
6
  overlap?: unknown;
7
7
  backfill?: unknown;
8
8
  jitter?: unknown;
9
+ revisionPolicy?: unknown;
9
10
  };
10
11
  /** Validate the mutable schedule options shared by create and update. */
11
12
  export declare function validateScheduleMutableOptions(input: ScheduleMutableOptionsInput): ScheduleUpdateOptions;
@@ -1,16 +1,19 @@
1
+ import { WorkflowRevisionUnavailableError } from "../../core/engine/revision-errors.js";
1
2
  import {
2
3
  isValidScheduleOverlapPolicy,
4
+ isValidScheduleRevisionPolicy,
3
5
  normalizeScheduleUpdateOptions
4
6
  } from "../../core/engine/validation/schedule.js";
5
7
  import { invalidParamsFault } from "./operation-helpers.js";
6
8
  export { isOperationFault } from "./operation-helpers.js";
7
9
  export function validateScheduleMutableOptions(input) {
8
- const description = validateScheduleDescription(input.description), overlap = validateScheduleOverlap(input.overlap), backfill = validateScheduleBackfill(input.backfill), jitter = validateScheduleJitter(input.jitter);
10
+ const description = validateScheduleDescription(input.description), overlap = validateScheduleOverlap(input.overlap), backfill = validateScheduleBackfill(input.backfill), jitter = validateScheduleJitter(input.jitter), revisionPolicy = validateScheduleRevisionPolicy(input.revisionPolicy);
9
11
  return {
10
12
  ...description !== void 0 ? { description } : {},
11
13
  ...overlap !== void 0 ? { overlap } : {},
12
14
  ...backfill !== void 0 ? { backfill } : {},
13
- ...jitter !== void 0 ? { jitter } : {}
15
+ ...jitter !== void 0 ? { jitter } : {},
16
+ ...revisionPolicy !== void 0 ? { revisionPolicy } : {}
14
17
  };
15
18
  }
16
19
  function validateScheduleDescription(value) {
@@ -27,6 +30,13 @@ function validateScheduleOverlap(value) {
27
30
  throw invalidParamsFault('Field "overlap" must be one of skip, queue, cancel-running, allow');
28
31
  return value;
29
32
  }
33
+ function validateScheduleRevisionPolicy(value) {
34
+ if (value === void 0)
35
+ return;
36
+ if (!isValidScheduleRevisionPolicy(value))
37
+ throw invalidParamsFault('Field "revisionPolicy" must be one of active-at-fire, pinned');
38
+ return value;
39
+ }
30
40
  function validateScheduleBackfill(value) {
31
41
  if (value === void 0)
32
42
  return;
@@ -51,7 +61,25 @@ function formatJitterValidationMessage(message) {
51
61
  const enginePrefix = "Invalid options.jitter: ", hasEnginePrefix = message.startsWith(enginePrefix), wireDetail = (hasEnginePrefix ? message.slice(enginePrefix.length) : message).replaceAll("options.jitter", 'Field "jitter"');
52
62
  return hasEnginePrefix ? `Field "jitter" is invalid: ${wireDetail}` : wireDetail;
53
63
  }
64
+ function mapRevisionUnavailableToFault(error) {
65
+ if (!(error instanceof WorkflowRevisionUnavailableError))
66
+ return;
67
+ return {
68
+ code: "Conflict",
69
+ message: error.message,
70
+ data: { reason: error.reason }
71
+ };
72
+ }
73
+ function isScheduleConflictMessage(normalizedMessage) {
74
+ return normalizedMessage.includes("already exists") || normalizedMessage.includes("cannot be resumed");
75
+ }
76
+ function isScheduleInvalidParamsMessage(message, normalizedMessage) {
77
+ return message.includes("Missing required field") || normalizedMessage.includes("must be") || normalizedMessage.includes("no workflow registered") || normalizedMessage.includes("cron") || normalizedMessage.includes("interval");
78
+ }
54
79
  export function mapScheduleErrorToFault(scheduleId, error) {
80
+ const revisionFault = mapRevisionUnavailableToFault(error);
81
+ if (revisionFault !== void 0)
82
+ return revisionFault;
55
83
  const message = error instanceof Error ? error.message : String(error), normalizedMessage = message.toLowerCase();
56
84
  if (normalizedMessage.includes("not found"))
57
85
  return {
@@ -59,13 +87,13 @@ export function mapScheduleErrorToFault(scheduleId, error) {
59
87
  message,
60
88
  data: { resource: "schedule", identifier: scheduleId }
61
89
  };
62
- if (normalizedMessage.includes("already exists") || normalizedMessage.includes("cannot be resumed"))
90
+ if (isScheduleConflictMessage(normalizedMessage))
63
91
  return {
64
92
  code: "Conflict",
65
93
  message,
66
94
  data: { reason: message }
67
95
  };
68
- if (message.includes("Missing required field") || normalizedMessage.includes("must be") || normalizedMessage.includes("no workflow registered") || normalizedMessage.includes("cron") || normalizedMessage.includes("interval"))
96
+ if (isScheduleInvalidParamsMessage(message, normalizedMessage))
69
97
  return {
70
98
  code: "InvalidParams",
71
99
  message,
@@ -6,6 +6,7 @@ export type SharedScheduleRestFields = {
6
6
  readonly overlap: unknown;
7
7
  readonly backfill: unknown;
8
8
  readonly jitter: unknown;
9
+ readonly revisionPolicy: unknown;
9
10
  };
10
11
  export declare function parseScheduleRestBodyRequestRecord(request: Request, context?: RestInputContext): Promise<Record<string, unknown>>;
11
12
  export declare function extractSharedScheduleRestFields(record: Record<string, unknown>): SharedScheduleRestFields;
@@ -23,6 +23,7 @@ export function extractSharedScheduleRestFields(record) {
23
23
  description: record.description,
24
24
  overlap: record.overlap,
25
25
  backfill: record.backfill,
26
- jitter: record.jitter
26
+ jitter: record.jitter,
27
+ revisionPolicy: record.revisionPolicy
27
28
  };
28
29
  }
@@ -90,6 +90,10 @@ import {
90
90
  } from "./list-workflow-revisions.js";
91
91
  import { listWorkflowsOperation, listWorkflowsRestBinding } from "./list-workflows.js";
92
92
  import { pauseScheduleOperation, pauseScheduleRestBinding } from "./pause-schedule.js";
93
+ import {
94
+ preloadWorkflowRevisionOperation,
95
+ preloadWorkflowRevisionRestBinding
96
+ } from "./preload-workflow-revision.js";
93
97
  import { purgeWorkflowsOperation, purgeWorkflowsRestBinding } from "./purge-workflows.js";
94
98
  import {
95
99
  queryWorkflowOperation,
@@ -178,6 +182,7 @@ export const STATIC_REST_BINDINGS = [
178
182
  getRegistryRestBinding,
179
183
  installWorkflowRevisionRestBinding,
180
184
  activateWorkflowRevisionRestBinding,
185
+ preloadWorkflowRevisionRestBinding,
181
186
  getWorkflowRevisionRestBinding,
182
187
  listWorkflowRevisionsRestBinding,
183
188
  getActiveWorkflowRevisionRestBinding,
@@ -247,6 +252,7 @@ export const STATIC_REST_BINDINGS = [
247
252
  getRegistryOperation,
248
253
  installWorkflowRevisionOperation,
249
254
  activateWorkflowRevisionOperation,
255
+ preloadWorkflowRevisionOperation,
250
256
  getWorkflowRevisionOperation,
251
257
  listWorkflowRevisionsOperation,
252
258
  getActiveWorkflowRevisionOperation,
@@ -8,6 +8,7 @@ declare const updateScheduleInput: z.ZodObject<{
8
8
  overlap: z.ZodOptional<z.ZodUnknown>;
9
9
  backfill: z.ZodOptional<z.ZodUnknown>;
10
10
  jitter: z.ZodOptional<z.ZodUnknown>;
11
+ revisionPolicy: z.ZodOptional<z.ZodUnknown>;
11
12
  }, z.core.$strip>;
12
13
  export type UpdateScheduleInput = z.infer<typeof updateScheduleInput>;
13
14
  export declare const updateScheduleOperation: import("../operation-catalog.ts").OperationDefinition<{
@@ -18,6 +19,7 @@ export declare const updateScheduleOperation: import("../operation-catalog.ts").
18
19
  overlap?: unknown;
19
20
  backfill?: unknown;
20
21
  jitter?: unknown;
22
+ revisionPolicy?: unknown;
21
23
  }, null, unknown>;
22
24
  export declare const updateScheduleRestBinding: UnknownRestBinding;
23
25
  export {};
@@ -16,7 +16,8 @@ const updateScheduleInput = z.object({
16
16
  description: z.unknown().optional().describe("Operator-facing schedule description. Runtime validation requires a string."),
17
17
  overlap: z.unknown().optional(),
18
18
  backfill: z.unknown().optional(),
19
- jitter: z.unknown().optional()
19
+ jitter: z.unknown().optional(),
20
+ revisionPolicy: z.unknown().optional().describe('Revision policy (WFT-20). Runtime validation requires "active-at-fire" or "pinned". Omitted preserves the current policy (and pin); "pinned" always re-resolves and re-captures the pin against the revision active right now.')
20
21
  });
21
22
  export const updateScheduleOperation = defineOperation({
22
23
  name: "weft.schedules.update",
@@ -52,7 +53,8 @@ export const updateScheduleOperation = defineOperation({
52
53
  description: { kind: "body-field", bodyField: "description" },
53
54
  overlap: { kind: "body-field", bodyField: "overlap" },
54
55
  backfill: { kind: "body-field", bodyField: "backfill" },
55
- jitter: { kind: "body-field", bodyField: "jitter" }
56
+ jitter: { kind: "body-field", bodyField: "jitter" },
57
+ revisionPolicy: { kind: "body-field", bodyField: "revisionPolicy" }
56
58
  },
57
59
  extractInput: async (request, pathParams, context) => {
58
60
  const record = await parseScheduleRestBodyRequestRecord(request, context);
@@ -5,7 +5,12 @@ import {
5
5
  } from "../../core/catalog/index.js";
6
6
  import { MAX_CONTRACT_IDENTIFIER_BYTES } from "../../core/contract/limits.js";
7
7
  import { parseWorkflowRevisionManifest } from "../../core/contract/manifest-parse.js";
8
+ import {
9
+ DynamicWorkflowSourceUnavailableError,
10
+ WorkflowSourceNotRegisteredError
11
+ } from "../../core/engine/dynamic-source-errors.js";
8
12
  import { WorkflowNotRegisteredError } from "../../core/engine/errors.js";
13
+ import { WorkflowSourceValidationError } from "../../core/source/errors.js";
9
14
  import { validateWorkflowOrActivityName } from "../../core/types/name-grammar.js";
10
15
  import { readRestJsonBody } from "../rest-body.js";
11
16
  import { invalidParamsFault, isOperationFault } from "./operation-helpers.js";
@@ -121,6 +126,28 @@ export function throwWorkflowCatalogOperationFault(error) {
121
126
  message: error.message,
122
127
  data: { reason: "catalog-conflict", weftCode: error.code }
123
128
  };
129
+ if (error instanceof WorkflowSourceNotRegisteredError)
130
+ throw {
131
+ code: "NotFound",
132
+ message: error.message,
133
+ data: { resource: "workflow-source", identifier: error.workflowType, weftCode: error.code }
134
+ };
135
+ if (error instanceof DynamicWorkflowSourceUnavailableError)
136
+ throw {
137
+ code: "Conflict",
138
+ message: error.reason === "load-failed" ? `Dynamic workflow source "${error.workflowType}"${error.revision === void 0 ? "" : ` revision "${error.revision}"`} failed to load.` : error.message,
139
+ data: { reason: error.reason, weftCode: error.code }
140
+ };
141
+ if (error instanceof WorkflowSourceValidationError)
142
+ throw {
143
+ code: "Conflict",
144
+ message: error.message,
145
+ data: {
146
+ reason: "validation-failed",
147
+ sourceValidationReasons: error.reasons,
148
+ weftCode: error.code
149
+ }
150
+ };
124
151
  throw error;
125
152
  }
126
153
  export async function readWorkflowCatalogRestBody(request, context) {
@@ -146,6 +146,17 @@ export type RestBinding<Input, Output> = {
146
146
  * path param would propagate to the engine as a confusingly-shaped
147
147
  * "missing" identifier, and surfacing the shape error at the router
148
148
  * (404) produces a cleaner wire response than a downstream 400.
149
+ *
150
+ * WHATWG URL path normalization collapses `.` and `..` path segments (and
151
+ * their percent-encoded forms) before `handleRequest()` ever sees
152
+ * `url.pathname` — this function never observes those segments as literal
153
+ * text, so a single trailing `:id`/`:operationId` segment can never match a
154
+ * resource whose id is literally `.` or `..`, no matter how it is encoded.
155
+ * This is no longer just a documented gap: `assertValidWorkflowId` (WFT-95)
156
+ * and `isValidOperationId` reject those exact strings at admission, so a
157
+ * caller-facing workflow or operation id can never legitimately be `.` or
158
+ * `..` in the first place — this URL-normalization quirk is closed by
159
+ * validation rather than left as something callers must work around.
149
160
  */
150
161
  export declare function bindingPathMatches(pattern: string, actualPath: string): Record<string, string> | null;
151
162
  /**
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Build the durable task-ledger envelope a fresh dispatch would create if no
3
+ * ledger record exists yet, and the fresh-dispatch admission checks
4
+ * `dispatchTaskImpl` runs before that — split out of `task-dispatch.ts`
5
+ * purely to stay under this repository's 500-line-per-file ceiling, matching
6
+ * the existing `task-dispatch-revision.ts` precedent. There is no behavioral
7
+ * reason to import this module directly instead of `task-dispatch.ts`, which
8
+ * calls `buildCreateQueuedInput` from both `selectAndReserveWorker` and
9
+ * `enqueueTaskForLongPoll`, and calls the admission helpers from
10
+ * `dispatchTaskImpl` itself.
11
+ *
12
+ * @module server/runtime/task-dispatch-envelope
13
+ */
14
+ import type { TaskDispatch } from '../index.ts';
15
+ import type { CreateQueuedInput } from '../task-ledger-transitions.ts';
16
+ import type { ServerContext } from './context.ts';
17
+ /**
18
+ * Wait for startup task-ledger recovery (WFT-23) — covers both the public
19
+ * `WeftServer.dispatchTask` entry point and `scheduleDelayedDispatch`'s timer
20
+ * callback, which also calls `dispatchTaskImpl` directly. A rejected gate
21
+ * means the recovery scan itself failed; propagate that failure loudly
22
+ * rather than silently returning false, which callers would read as an
23
+ * ordinary "no worker available" outcome.
24
+ */
25
+ export declare function awaitTaskLedgerRecoveryReady(context: ServerContext, task: TaskDispatch): Promise<void>;
26
+ /**
27
+ * Reject an invalid caller-supplied operationId before it reaches a ledger
28
+ * write (WFT-95). `dispatchTask()` is a public same-process API taking a
29
+ * caller-controlled operationId; an id equal to the exact string "." or
30
+ * ".." can never be addressed again over REST (a single trailing
31
+ * `:operationId` path segment is collapsed away by WHATWG URL path
32
+ * normalization before the route matcher ever sees it), so fresh-dispatch
33
+ * admission rejects it up front instead of writing a ledger record that
34
+ * becomes unreachable by id. Skipped for `redispatch` — reconstructing and
35
+ * redispatching an already-decoded, previously persisted ledger record
36
+ * (`scheduleDelayedDispatch`/`taskDispatchFromLedgerRecord`) must not
37
+ * re-apply an admission-only check to data that was valid when written.
38
+ */
39
+ export declare function assertFreshDispatchOperationIdAdmissible(task: TaskDispatch, redispatch: boolean): void;
40
+ /** The durable envelope every fresh dispatch would create if no ledger record exists yet. */
41
+ export declare function buildCreateQueuedInput(task: TaskDispatch, queue: string, visibilityTimeout: number): CreateQueuedInput;
@@ -0,0 +1,54 @@
1
+ import { isJSONValue } from "../../core/json.js";
2
+ import {
3
+ isValidOperationId,
4
+ isValidWorkflowRevision,
5
+ REMOTE_TASK_RECORD_VERSION
6
+ } from "../task-ledger.js";
7
+ export async function awaitTaskLedgerRecoveryReady(context, task) {
8
+ try {
9
+ await context.taskLedgerRecovery.ready;
10
+ } catch (error) {
11
+ throw Error(`Cannot dispatch task "${task.operationId}" \u2014 startup task-ledger recovery failed: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
12
+ }
13
+ }
14
+ export function assertFreshDispatchOperationIdAdmissible(task, redispatch) {
15
+ if (redispatch || isValidOperationId(task.operationId))
16
+ return;
17
+ let formattedOperationId;
18
+ try {
19
+ formattedOperationId = JSON.stringify(task.operationId) ?? String(task.operationId);
20
+ } catch {
21
+ formattedOperationId = `<${typeof task.operationId}>`;
22
+ }
23
+ throw Error(`TaskDispatch has an invalid "operationId" (${formattedOperationId}) \u2014 it must be a non-empty, bounded identifier other than "." or "..".`);
24
+ }
25
+ function buildOptionalCreateQueuedFields(task) {
26
+ return {
27
+ ...task.workflowId !== void 0 ? { workflowId: task.workflowId } : {},
28
+ ...task.workflowExecutionToken !== void 0 ? { workflowExecutionToken: task.workflowExecutionToken } : {},
29
+ ...task.workflowRevision !== void 0 ? { workflowRevision: task.workflowRevision } : {},
30
+ ...task.priority !== void 0 ? { priority: task.priority } : {},
31
+ ...task.fairShareKey !== void 0 ? { fairShareKey: task.fairShareKey } : {},
32
+ ...task.sticky && task.workflowId !== void 0 ? { stickyWorkflowId: task.workflowId } : {},
33
+ ...task.retryPolicy !== void 0 ? { retryPolicy: task.retryPolicy } : {}
34
+ };
35
+ }
36
+ export function buildCreateQueuedInput(task, queue, visibilityTimeout) {
37
+ const input = task.input === void 0 ? null : task.input;
38
+ if (!isJSONValue(input))
39
+ throw Error(`TaskDispatch for operation "${task.operationId}" has a non-JSON-serializable "input" \u2014 the durable task ledger requires JSON-safe input.`);
40
+ if (task.workflowRevision !== void 0 && !isValidWorkflowRevision(task.workflowRevision))
41
+ throw Error(`TaskDispatch for operation "${task.operationId}" has an invalid "workflowRevision" \u2014 it must be a non-empty, bounded identifier.`);
42
+ return {
43
+ recordVersion: REMOTE_TASK_RECORD_VERSION,
44
+ operationId: task.operationId,
45
+ workflowType: task.workflowType,
46
+ activityName: task.activityName,
47
+ queue,
48
+ input,
49
+ headers: task.headers ?? {},
50
+ visibilityTimeoutMilliseconds: visibilityTimeout,
51
+ createdAt: Date.now(),
52
+ ...buildOptionalCreateQueuedFields(task)
53
+ };
54
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Dispatch-time revision staleness gate (WFT-20) — split out of
3
+ * `task-dispatch.ts` purely to stay under this repository's 500-line-per-file
4
+ * ceiling; there is no behavioral reason to import this module directly
5
+ * instead of `task-dispatch.ts`, which calls it from `dispatchTaskImpl`.
6
+ *
7
+ * @module server/runtime/task-dispatch-revision
8
+ */
9
+ import { type ConditionalBatchCondition } from '../../storage/interface.ts';
10
+ import type { ServeOptions, TaskDispatch } from '../index.ts';
11
+ /**
12
+ * Reject a dispatch whose caller-supplied `workflowRevision` disagrees with
13
+ * `task.workflowId`'s persisted `WorkflowState.revision` — a bounded,
14
+ * structured failure BEFORE any worker reservation or ledger write. A no-op
15
+ * (never reads storage) unless BOTH `workflowId` and `workflowRevision` are
16
+ * supplied; a no-op when no persisted `WorkflowState` exists for `workflowId`
17
+ * yet (nothing to compare against — the caller opted into an extra read, not
18
+ * an extra existence requirement).
19
+ *
20
+ * Returns the `conditionalBatch` precondition(s) (empty when this check was a
21
+ * no-op) that fence the CALLER's own ledger commit on the exact workflow-state
22
+ * bytes just read here. This check alone is only a pre-commit read: a
23
+ * `start-new` restart could still displace the workflow to a different
24
+ * revision in the gap between this read and the caller's later ledger write.
25
+ * The caller MUST include the returned conditions in the SAME
26
+ * `conditionalBatch` call that commits the ledger record, so that gap closes
27
+ * atomically instead of merely being read-checked up front (WFT-20).
28
+ */
29
+ export declare function assertDispatchTargetsFreshRevision(options: ServeOptions, task: TaskDispatch): Promise<ConditionalBatchCondition[]>;
@@ -0,0 +1,13 @@
1
+ import { decodeWorkflowState } from "../../core/engine/validation.js";
2
+ import { KEYS } from "../../storage/interface.js";
3
+ export async function assertDispatchTargetsFreshRevision(options, task) {
4
+ if (task.workflowId === void 0 || task.workflowRevision === void 0)
5
+ return [];
6
+ const workflowKey = KEYS.workflow(task.workflowId), persistedBytes = await options.engine.storage.get(workflowKey);
7
+ if (persistedBytes === null)
8
+ return [];
9
+ const persistedRevision = decodeWorkflowState(persistedBytes).revision;
10
+ if (persistedRevision !== task.workflowRevision)
11
+ throw Error(`TaskDispatch for operation "${task.operationId}" targets workflow "${task.workflowId}" at revision "${task.workflowRevision}", but the persisted run is pinned to revision ${persistedRevision === void 0 ? "undefined (a legacy, pre-pinning record)" : `"${persistedRevision}"`} ` + "\u2014 this dispatch is stale.");
12
+ return [{ key: workflowKey, expectedValue: persistedBytes }];
13
+ }
@@ -9,6 +9,8 @@ import type { ServerContext } from './context.ts';
9
9
  */
10
10
  export declare function scheduleDelayedDispatch(context: ServerContext, options: ServeOptions, task: TaskDispatch, delay: number): void;
11
11
  export declare function resolveTaskPriority(_context: ServerContext, _options: ServeOptions, task: TaskDispatch): number | undefined;
12
- export declare function dispatchTaskImpl(context: ServerContext, options: ServeOptions, task: TaskDispatch): Promise<boolean>;
12
+ export declare function dispatchTaskImpl(context: ServerContext, options: ServeOptions, task: TaskDispatch, { redispatch }?: {
13
+ redispatch?: boolean;
14
+ }): Promise<boolean>;
13
15
  /** Send a cancel message to the worker handling a specific operation. */
14
16
  export declare function cancelTask(context: ServerContext, operationId: string): boolean;