@lostgradient/weft 0.23.1 → 0.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (469) hide show
  1. package/README.md +72 -4
  2. package/dist/cli/codegen-emit-dedup.d.ts +81 -0
  3. package/dist/cli/codegen-emit-dedup.js +45 -0
  4. package/dist/cli/codegen-emit-registry.d.ts +90 -0
  5. package/dist/cli/codegen-emit-registry.js +50 -0
  6. package/dist/cli/codegen-emit.d.ts +26 -39
  7. package/dist/cli/codegen-emit.js +4 -27
  8. package/dist/cli/codegen-validate.d.ts +49 -0
  9. package/dist/cli/codegen-validate.js +186 -0
  10. package/dist/cli/codegen.js +6 -87
  11. package/dist/cli/conformance.js +5 -2
  12. package/dist/cli/generated/operation-catalog.snapshot.json +381 -3
  13. package/dist/cli/generated/operation-client.generated.d.ts +350 -10
  14. package/dist/cli/generated/operation-client.generated.js +14 -0
  15. package/dist/cli/output.js +1 -1
  16. package/dist/cli/parse-schedule-arguments.js +15 -3
  17. package/dist/cli/schedule.js +2 -1
  18. package/dist/cli/storage-factory.js +2 -0
  19. package/dist/cli/types.d.ts +2 -1
  20. package/dist/cli/workflow-commands.js +2 -0
  21. package/dist/cli-main.js +1 -1
  22. package/dist/client/http-client-requests.js +6 -9
  23. package/dist/client/start-body.js +1 -0
  24. package/dist/core/application-payload-digest.d.ts +42 -0
  25. package/dist/core/application-payload-digest.js +76 -0
  26. package/dist/core/application-primitive-abort.d.ts +50 -0
  27. package/dist/core/application-primitive-abort.js +40 -0
  28. package/dist/core/application-primitive-attempt-registry.d.ts +74 -0
  29. package/dist/core/application-primitive-attempt-registry.js +73 -0
  30. package/dist/core/application-primitive-codec.d.ts +36 -0
  31. package/dist/core/application-primitive-codec.js +56 -0
  32. package/dist/core/application-primitive-commit.d.ts +67 -0
  33. package/dist/core/application-primitive-commit.js +66 -0
  34. package/dist/core/application-primitive-guards.d.ts +62 -0
  35. package/dist/core/application-primitive-guards.js +89 -0
  36. package/dist/core/application-primitive-payload.d.ts +29 -0
  37. package/dist/core/application-primitive-payload.js +65 -0
  38. package/dist/core/application-primitive-timing.d.ts +18 -0
  39. package/dist/core/application-primitive-timing.js +22 -0
  40. package/dist/core/atomic-state.js +2 -0
  41. package/dist/core/catalog/codec.d.ts +40 -0
  42. package/dist/core/catalog/codec.js +45 -0
  43. package/dist/core/catalog/errors.d.ts +104 -0
  44. package/dist/core/catalog/errors.js +41 -0
  45. package/dist/core/catalog/index.d.ts +25 -0
  46. package/dist/core/catalog/index.js +22 -0
  47. package/dist/core/catalog/reference-counts.d.ts +120 -0
  48. package/dist/core/catalog/reference-counts.js +28 -0
  49. package/dist/core/catalog/removal.d.ts +105 -0
  50. package/dist/core/catalog/removal.js +30 -0
  51. package/dist/core/catalog/storage-io.d.ts +101 -0
  52. package/dist/core/catalog/storage-io.js +106 -0
  53. package/dist/core/catalog/types.d.ts +108 -0
  54. package/dist/core/catalog/types.js +0 -0
  55. package/dist/core/catalog/workflow-catalog.d.ts +165 -0
  56. package/dist/core/catalog/workflow-catalog.js +198 -0
  57. package/dist/core/compare-codepoint.d.ts +13 -0
  58. package/dist/core/compare-codepoint.js +7 -0
  59. package/dist/core/compression.js +2 -0
  60. package/dist/core/context/attributes.d.ts +1 -1
  61. package/dist/core/context/durable-operations.d.ts +2 -2
  62. package/dist/core/context/index.js +5 -3
  63. package/dist/core/context/state-namespace.d.ts +1 -1
  64. package/dist/core/contract/build.d.ts +64 -0
  65. package/dist/core/contract/build.js +99 -0
  66. package/dist/core/contract/compatibility.d.ts +187 -0
  67. package/dist/core/contract/compatibility.js +37 -0
  68. package/dist/core/contract/failure.d.ts +64 -0
  69. package/dist/core/contract/failure.js +4 -0
  70. package/dist/core/contract/hash.d.ts +92 -0
  71. package/dist/core/contract/hash.js +34 -0
  72. package/dist/core/contract/index.d.ts +21 -0
  73. package/dist/core/contract/index.js +22 -0
  74. package/dist/core/contract/limits.d.ts +74 -0
  75. package/dist/core/contract/limits.js +1 -0
  76. package/dist/core/contract/manifest-parse-schema.d.ts +37 -0
  77. package/dist/core/contract/manifest-parse-schema.js +106 -0
  78. package/dist/core/contract/manifest-parse.d.ts +76 -0
  79. package/dist/core/contract/manifest-parse.js +189 -0
  80. package/dist/core/contract/manifest.d.ts +56 -0
  81. package/dist/core/contract/manifest.js +31 -0
  82. package/dist/core/contract/normalize.d.ts +97 -0
  83. package/dist/core/contract/normalize.js +127 -0
  84. package/dist/core/contract/revision.d.ts +29 -0
  85. package/dist/core/contract/revision.js +5 -0
  86. package/dist/core/contract/types.d.ts +274 -0
  87. package/dist/core/contract/types.js +1 -0
  88. package/dist/core/engine/activity-resolution.js +17 -17
  89. package/dist/core/engine/bulk-operations-purge.js +14 -20
  90. package/dist/core/engine/bulk-operations-retry.d.ts +9 -0
  91. package/dist/core/engine/bulk-operations-retry.js +177 -0
  92. package/dist/core/engine/bulk-operations-shared.d.ts +18 -0
  93. package/dist/core/engine/bulk-operations-shared.js +14 -0
  94. package/dist/core/engine/bulk-operations.js +8 -167
  95. package/dist/core/engine/callback-creators-bundles.js +4 -2
  96. package/dist/core/engine/callback-creators-core.js +9 -1
  97. package/dist/core/engine/callback-creators-schedule.js +2 -2
  98. package/dist/core/engine/catalog-activation.d.ts +40 -0
  99. package/dist/core/engine/catalog-activation.js +17 -0
  100. package/dist/core/engine/catalog-events.d.ts +36 -0
  101. package/dist/core/engine/catalog-events.js +15 -0
  102. package/dist/core/engine/catalog-readiness.d.ts +49 -0
  103. package/dist/core/engine/catalog-readiness.js +61 -0
  104. package/dist/core/engine/catalog-removal.d.ts +236 -0
  105. package/dist/core/engine/catalog-removal.js +123 -0
  106. package/dist/core/engine/catalog-tombstone-recovery.d.ts +56 -0
  107. package/dist/core/engine/catalog-tombstone-recovery.js +39 -0
  108. package/dist/core/engine/constraints.js +5 -1
  109. package/dist/core/engine/construction.d.ts +2 -2
  110. package/dist/core/engine/construction.js +4 -2
  111. package/dist/core/engine/decode-revision.d.ts +32 -0
  112. package/dist/core/engine/decode-revision.js +9 -0
  113. package/dist/core/engine/disposal.d.ts +6 -2
  114. package/dist/core/engine/disposal.js +26 -3
  115. package/dist/core/engine/dynamic-source-errors.d.ts +81 -0
  116. package/dist/core/engine/dynamic-source-errors.js +25 -0
  117. package/dist/core/engine/dynamic-source-execution.d.ts +173 -0
  118. package/dist/core/engine/dynamic-source-execution.js +108 -0
  119. package/dist/core/engine/engine-internal-types.d.ts +16 -0
  120. package/dist/core/engine/engine-workflows-namespace.d.ts +140 -0
  121. package/dist/core/engine/engine-workflows-namespace.js +51 -0
  122. package/dist/core/engine/finalizer-metadata.d.ts +22 -0
  123. package/dist/core/engine/finalizer-metadata.js +12 -0
  124. package/dist/core/engine/handle-result.js +2 -0
  125. package/dist/core/engine/index.d.ts +91 -0
  126. package/dist/core/engine/index.js +78 -6
  127. package/dist/core/engine/inline-launch-queue.js +1 -1
  128. package/dist/core/engine/internals.d.ts +54 -15
  129. package/dist/core/engine/internals.js +6 -0
  130. package/dist/core/engine/lifecycle/checkpoint-launch.d.ts +29 -0
  131. package/dist/core/engine/lifecycle/checkpoint-launch.js +75 -0
  132. package/dist/core/engine/lifecycle/delayed-start-registration.d.ts +30 -0
  133. package/dist/core/engine/lifecycle/delayed-start-registration.js +11 -0
  134. package/dist/core/engine/lifecycle/fork-helpers.d.ts +33 -1
  135. package/dist/core/engine/lifecycle/fork-helpers.js +3 -1
  136. package/dist/core/engine/lifecycle/recovery-revision-groups.d.ts +75 -0
  137. package/dist/core/engine/lifecycle/recovery-revision-groups.js +64 -0
  138. package/dist/core/engine/lifecycle/resume-generation-guard.d.ts +58 -0
  139. package/dist/core/engine/lifecycle/resume-generation-guard.js +11 -0
  140. package/dist/core/engine/lifecycle/resume.js +18 -9
  141. package/dist/core/engine/lifecycle/shared.d.ts +43 -0
  142. package/dist/core/engine/lifecycle/standalone-claim-acquire.d.ts +12 -0
  143. package/dist/core/engine/lifecycle/standalone-claim-acquire.js +6 -0
  144. package/dist/core/engine/lifecycle/start-commit-errors.d.ts +12 -0
  145. package/dist/core/engine/lifecycle/start-commit-errors.js +6 -0
  146. package/dist/core/engine/lifecycle/start-commit.d.ts +22 -7
  147. package/dist/core/engine/lifecycle/start-commit.js +49 -15
  148. package/dist/core/engine/lifecycle/start-exec.d.ts +18 -2
  149. package/dist/core/engine/lifecycle/start-exec.js +7 -5
  150. package/dist/core/engine/lifecycle/start-or-signal-create.js +1 -3
  151. package/dist/core/engine/lifecycle/start-or-signal.js +1 -1
  152. package/dist/core/engine/lifecycle/start-precondition-attribution.d.ts +49 -0
  153. package/dist/core/engine/lifecycle/start-precondition-attribution.js +13 -0
  154. package/dist/core/engine/lifecycle/start-revision-resolution.d.ts +34 -0
  155. package/dist/core/engine/lifecycle/start-revision-resolution.js +11 -0
  156. package/dist/core/engine/lifecycle/start-state.d.ts +16 -0
  157. package/dist/core/engine/lifecycle/start-state.js +60 -0
  158. package/dist/core/engine/lifecycle/start-terminal-conflict-purge.d.ts +66 -3
  159. package/dist/core/engine/lifecycle/start-terminal-conflict-purge.js +13 -3
  160. package/dist/core/engine/lifecycle/start.d.ts +16 -6
  161. package/dist/core/engine/lifecycle/start.js +39 -66
  162. package/dist/core/engine/lifecycle/transition.d.ts +3 -4
  163. package/dist/core/engine/lifecycle/transition.js +30 -80
  164. package/dist/core/engine/lifecycle.d.ts +4 -2
  165. package/dist/core/engine/lifecycle.js +6 -6
  166. package/dist/core/engine/listing.js +15 -1
  167. package/dist/core/engine/memo-durable-activity.js +4 -1
  168. package/dist/core/engine/nonterminal-revision-count.d.ts +25 -0
  169. package/dist/core/engine/nonterminal-revision-count.js +16 -0
  170. package/dist/core/engine/operations-time.d.ts +5 -23
  171. package/dist/core/engine/operations-time.js +13 -11
  172. package/dist/core/engine/ownership-bootstrap.d.ts +1 -1
  173. package/dist/core/engine/pinned-schedule-revision-count.d.ts +26 -0
  174. package/dist/core/engine/pinned-schedule-revision-count.js +19 -0
  175. package/dist/core/engine/pinned-schedule-revision.d.ts +76 -0
  176. package/dist/core/engine/pinned-schedule-revision.js +53 -0
  177. package/dist/core/engine/registration.d.ts +106 -0
  178. package/dist/core/engine/registration.js +28 -7
  179. package/dist/core/engine/retention.js +9 -2
  180. package/dist/core/engine/revision-errors.d.ts +71 -0
  181. package/dist/core/engine/revision-errors.js +13 -0
  182. package/dist/core/engine/schedule-revision-fire.d.ts +17 -0
  183. package/dist/core/engine/schedule-revision-fire.js +3 -0
  184. package/dist/core/engine/schedule-run.js +2 -1
  185. package/dist/core/engine/schedules.d.ts +2 -1
  186. package/dist/core/engine/schedules.js +28 -9
  187. package/dist/core/engine/source-diagnostics.d.ts +76 -0
  188. package/dist/core/engine/source-diagnostics.js +105 -0
  189. package/dist/core/engine/source-registration.d.ts +42 -0
  190. package/dist/core/engine/source-registration.js +38 -0
  191. package/dist/core/engine/source-resolution.d.ts +101 -0
  192. package/dist/core/engine/source-resolution.js +154 -0
  193. package/dist/core/engine/source-runtime-state.d.ts +92 -0
  194. package/dist/core/engine/source-runtime-state.js +36 -0
  195. package/dist/core/engine/storage-io.d.ts +19 -2
  196. package/dist/core/engine/storage-io.js +21 -2
  197. package/dist/core/engine/termination/finalizer-registration.d.ts +18 -0
  198. package/dist/core/engine/termination/finalizer-registration.js +21 -0
  199. package/dist/core/engine/termination/finalizer.d.ts +16 -19
  200. package/dist/core/engine/termination/finalizer.js +3 -3
  201. package/dist/core/engine/time-operation-callbacks.d.ts +32 -0
  202. package/dist/core/engine/time-operation-callbacks.js +0 -0
  203. package/dist/core/engine/validation/schedule-cadence.d.ts +16 -0
  204. package/dist/core/engine/validation/schedule-cadence.js +20 -0
  205. package/dist/core/engine/validation/schedule-options.d.ts +4 -1
  206. package/dist/core/engine/validation/schedule-options.js +14 -0
  207. package/dist/core/engine/validation/schedule-revision.d.ts +24 -0
  208. package/dist/core/engine/validation/schedule-revision.js +21 -0
  209. package/dist/core/engine/validation/schedule-warnings.d.ts +11 -0
  210. package/dist/core/engine/validation/schedule-warnings.js +5 -0
  211. package/dist/core/engine/validation/schedule.d.ts +4 -3
  212. package/dist/core/engine/validation/schedule.js +15 -26
  213. package/dist/core/engine/validation.js +5 -2
  214. package/dist/core/engine/workflow-claim-reclaim-target.d.ts +1 -1
  215. package/dist/core/engine/workflow-claim-reclaim-target.js +16 -2
  216. package/dist/core/engine/workflow-retention-deadline.d.ts +16 -0
  217. package/dist/core/engine/workflow-retention-deadline.js +33 -0
  218. package/dist/core/events/catalog-events.d.ts +117 -0
  219. package/dist/core/events/catalog-events.js +62 -0
  220. package/dist/core/events/event-map.d.ts +11 -0
  221. package/dist/core/events/index.d.ts +2 -0
  222. package/dist/core/events/index.js +2 -0
  223. package/dist/core/events/workflow-source-events.d.ts +102 -0
  224. package/dist/core/events/workflow-source-events.js +57 -0
  225. package/dist/core/execution-strategy.d.ts +7 -0
  226. package/dist/core/inline-execution-strategy.context-options.d.ts +1 -1
  227. package/dist/core/inline-execution-strategy.js +1 -1
  228. package/dist/core/mailbox-admission.d.ts +26 -0
  229. package/dist/core/mailbox-admission.js +130 -0
  230. package/dist/core/mailbox-claims.d.ts +251 -0
  231. package/dist/core/mailbox-claims.js +0 -0
  232. package/dist/core/mailbox-codec.d.ts +32 -0
  233. package/dist/core/mailbox-codec.js +221 -0
  234. package/dist/core/mailbox-contract.d.ts +290 -0
  235. package/dist/core/mailbox-contract.js +0 -0
  236. package/dist/core/mailbox-delivery.d.ts +37 -0
  237. package/dist/core/mailbox-delivery.js +193 -0
  238. package/dist/core/mailbox-guards.d.ts +78 -0
  239. package/dist/core/mailbox-guards.js +58 -0
  240. package/dist/core/mailbox-index-codec.d.ts +41 -0
  241. package/dist/core/mailbox-index-codec.js +71 -0
  242. package/dist/core/mailbox-internals.d.ts +156 -0
  243. package/dist/core/mailbox-internals.js +154 -0
  244. package/dist/core/mailbox-maintenance.d.ts +29 -0
  245. package/dist/core/mailbox-maintenance.js +196 -0
  246. package/dist/core/mailbox-settlement.d.ts +69 -0
  247. package/dist/core/mailbox-settlement.js +206 -0
  248. package/dist/core/mailbox-storage.d.ts +117 -0
  249. package/dist/core/mailbox-storage.js +115 -0
  250. package/dist/core/mailbox-transition-helpers.d.ts +70 -0
  251. package/dist/core/mailbox-transition-helpers.js +43 -0
  252. package/dist/core/mailbox-transitions-recovery.d.ts +28 -0
  253. package/dist/core/mailbox-transitions-recovery.js +64 -0
  254. package/dist/core/mailbox-transitions.d.ts +138 -0
  255. package/dist/core/mailbox-transitions.js +180 -0
  256. package/dist/core/mailbox-types.d.ts +406 -0
  257. package/dist/core/mailbox-types.js +16 -0
  258. package/dist/core/mailbox-validation.d.ts +65 -0
  259. package/dist/core/mailbox-validation.js +73 -0
  260. package/dist/core/mailbox-waits.d.ts +50 -0
  261. package/dist/core/mailbox-waits.js +97 -0
  262. package/dist/core/mailbox.d.ts +163 -0
  263. package/dist/core/mailbox.js +211 -0
  264. package/dist/core/outbox-claims.d.ts +307 -0
  265. package/dist/core/outbox-claims.js +0 -0
  266. package/dist/core/outbox-codec.d.ts +24 -0
  267. package/dist/core/outbox-codec.js +257 -0
  268. package/dist/core/outbox-contract.d.ts +346 -0
  269. package/dist/core/outbox-contract.js +0 -0
  270. package/dist/core/outbox-delivery.d.ts +34 -0
  271. package/dist/core/outbox-delivery.js +149 -0
  272. package/dist/core/outbox-drain.d.ts +29 -0
  273. package/dist/core/outbox-drain.js +158 -0
  274. package/dist/core/outbox-enqueue.d.ts +24 -0
  275. package/dist/core/outbox-enqueue.js +115 -0
  276. package/dist/core/outbox-guards.d.ts +76 -0
  277. package/dist/core/outbox-guards.js +60 -0
  278. package/dist/core/outbox-index-codec.d.ts +33 -0
  279. package/dist/core/outbox-index-codec.js +71 -0
  280. package/dist/core/outbox-internals.d.ts +99 -0
  281. package/dist/core/outbox-internals.js +159 -0
  282. package/dist/core/outbox-listing.d.ts +12 -0
  283. package/dist/core/outbox-listing.js +38 -0
  284. package/dist/core/outbox-maintenance.d.ts +28 -0
  285. package/dist/core/outbox-maintenance.js +191 -0
  286. package/dist/core/outbox-operations.d.ts +18 -0
  287. package/dist/core/outbox-operations.js +46 -0
  288. package/dist/core/outbox-runner.d.ts +30 -0
  289. package/dist/core/outbox-runner.js +217 -0
  290. package/dist/core/outbox-settlement.d.ts +57 -0
  291. package/dist/core/outbox-settlement.js +183 -0
  292. package/dist/core/outbox-storage.d.ts +107 -0
  293. package/dist/core/outbox-storage.js +127 -0
  294. package/dist/core/outbox-transition-helpers.d.ts +83 -0
  295. package/dist/core/outbox-transition-helpers.js +63 -0
  296. package/dist/core/outbox-transitions-recovery.d.ts +30 -0
  297. package/dist/core/outbox-transitions-recovery.js +42 -0
  298. package/dist/core/outbox-transitions.d.ts +145 -0
  299. package/dist/core/outbox-transitions.js +236 -0
  300. package/dist/core/outbox-types.d.ts +400 -0
  301. package/dist/core/outbox-types.js +20 -0
  302. package/dist/core/outbox-validation.d.ts +101 -0
  303. package/dist/core/outbox-validation.js +127 -0
  304. package/dist/core/outbox-waits.d.ts +39 -0
  305. package/dist/core/outbox-waits.js +88 -0
  306. package/dist/core/outbox.d.ts +156 -0
  307. package/dist/core/outbox.js +234 -0
  308. package/dist/core/registry-limits.d.ts +49 -0
  309. package/dist/core/registry-limits.js +10 -0
  310. package/dist/core/registry-schema-conversion.d.ts +20 -0
  311. package/dist/core/registry-schema-conversion.js +22 -0
  312. package/dist/core/registry-snapshot.d.ts +91 -42
  313. package/dist/core/registry-snapshot.js +39 -77
  314. package/dist/core/registry-workflow-contract-draft.d.ts +32 -0
  315. package/dist/core/registry-workflow-contract-draft.js +28 -0
  316. package/dist/core/registry-workflow-manifest.d.ts +122 -0
  317. package/dist/core/registry-workflow-manifest.js +92 -0
  318. package/dist/core/source/errors.d.ts +55 -0
  319. package/dist/core/source/errors.js +13 -0
  320. package/dist/core/source/index.d.ts +19 -0
  321. package/dist/core/source/index.js +4 -0
  322. package/dist/core/source/resolvers.d.ts +45 -0
  323. package/dist/core/source/resolvers.js +9 -0
  324. package/dist/core/source/types.d.ts +211 -0
  325. package/dist/core/source/types.js +0 -0
  326. package/dist/core/source/validate.d.ts +91 -0
  327. package/dist/core/source/validate.js +62 -0
  328. package/dist/core/source/workflow-source.d.ts +43 -0
  329. package/dist/core/source/workflow-source.js +16 -0
  330. package/dist/core/types/checkpoint.d.ts +14 -0
  331. package/dist/core/types/schedules.d.ts +52 -1
  332. package/dist/core/types/state.d.ts +16 -0
  333. package/dist/core/types/workflow-registries.d.ts +7 -0
  334. package/dist/core/types/workflow-registry.d.ts +12 -0
  335. package/dist/core/versioning.js +2 -0
  336. package/dist/core/weft-error.d.ts +1 -1
  337. package/dist/core/weft-error.js +12 -1
  338. package/dist/core/worker-execution-strategy.d.ts +1 -0
  339. package/dist/core/worker-execution-strategy.js +13 -1
  340. package/dist/core/worker-fault-handling.d.ts +10 -0
  341. package/dist/core/worker-fault-handling.js +1 -0
  342. package/dist/core/worker-inbound-message.d.ts +1 -0
  343. package/dist/core/worker-inbound-message.js +1 -0
  344. package/dist/core/worker-protocol-guard.js +4 -0
  345. package/dist/core/worker-protocol.d.ts +7 -0
  346. package/dist/core/worker-protocol.js +2 -1
  347. package/dist/core/worker-turn-watchdog.d.ts +8 -1
  348. package/dist/core/worker-turn-watchdog.js +3 -2
  349. package/dist/diagnostics/format.js +5 -0
  350. package/dist/diagnostics/types.d.ts +24 -0
  351. package/dist/diagnostics/version-check.js +8 -2
  352. package/dist/http.js +2 -2
  353. package/dist/index.d.ts +25 -4
  354. package/dist/index.js +57 -0
  355. package/dist/indexeddb.js +1 -1
  356. package/dist/json-schema.js +3 -3
  357. package/dist/mcp/resources.js +2 -0
  358. package/dist/runtime/portable.d.ts +9 -1
  359. package/dist/server/fault-to-json-rpc.js +4 -1
  360. package/dist/server/handler/auth-context-principal.js +4 -0
  361. package/dist/server/index.d.ts +11 -0
  362. package/dist/server/json-rpc-http.js +2 -0
  363. package/dist/server/json-rpc-websocket.js +6 -4
  364. package/dist/server/operation-catalog/index.d.ts +1 -1
  365. package/dist/server/operation-catalog/pipeline-helpers.js +2 -0
  366. package/dist/server/operation-catalog/types.d.ts +17 -0
  367. package/dist/server/operation-fault.d.ts +5 -0
  368. package/dist/server/operation-fault.js +4 -1
  369. package/dist/server/operations/activate-workflow-revision.d.ts +30 -0
  370. package/dist/server/operations/activate-workflow-revision.js +69 -0
  371. package/dist/server/operations/create-schedule.d.ts +2 -0
  372. package/dist/server/operations/create-schedule.js +10 -6
  373. package/dist/server/operations/fleet-events-subscription.js +1 -1
  374. package/dist/server/operations/fork-workflow.js +1 -1
  375. package/dist/server/operations/get-active-workflow-revision.d.ts +32 -0
  376. package/dist/server/operations/get-active-workflow-revision.js +46 -0
  377. package/dist/server/operations/get-catalog-diagnostics.d.ts +113 -0
  378. package/dist/server/operations/get-catalog-diagnostics.js +65 -0
  379. package/dist/server/operations/get-registry.js +17 -4
  380. package/dist/server/operations/get-task-detail-schema.d.ts +8 -0
  381. package/dist/server/operations/get-task-detail-schema.js +1 -0
  382. package/dist/server/operations/get-task-detail.d.ts +8 -0
  383. package/dist/server/operations/get-task-detail.js +1 -0
  384. package/dist/server/operations/get-task-diagnostics.d.ts +4 -4
  385. package/dist/server/operations/get-workflow-revision.d.ts +25 -0
  386. package/dist/server/operations/get-workflow-revision.js +50 -0
  387. package/dist/server/operations/install-workflow-revision.d.ts +27 -0
  388. package/dist/server/operations/install-workflow-revision.js +46 -0
  389. package/dist/server/operations/list-workflow-revisions.d.ts +20 -0
  390. package/dist/server/operations/list-workflow-revisions.js +40 -0
  391. package/dist/server/operations/preload-workflow-revision.d.ts +28 -0
  392. package/dist/server/operations/preload-workflow-revision.js +60 -0
  393. package/dist/server/operations/schedule-faults.d.ts +1 -0
  394. package/dist/server/operations/schedule-faults.js +32 -4
  395. package/dist/server/operations/schedule-rest-body.d.ts +1 -0
  396. package/dist/server/operations/schedule-rest-body.js +2 -1
  397. package/dist/server/operations/start-or-signal-workflow.js +1 -1
  398. package/dist/server/operations/start-workflow.js +1 -1
  399. package/dist/server/operations/static-registrations.js +42 -0
  400. package/dist/server/operations/storage.js +2 -2
  401. package/dist/server/operations/submit-review-decision.js +1 -1
  402. package/dist/server/operations/update-schedule.d.ts +2 -0
  403. package/dist/server/operations/update-schedule.js +4 -2
  404. package/dist/server/operations/workflow-catalog-operation-helpers.d.ts +59 -0
  405. package/dist/server/operations/workflow-catalog-operation-helpers.js +162 -0
  406. package/dist/server/runtime/task-dispatch-envelope.d.ts +14 -0
  407. package/dist/server/runtime/task-dispatch-envelope.js +32 -0
  408. package/dist/server/runtime/task-dispatch-revision.d.ts +29 -0
  409. package/dist/server/runtime/task-dispatch-revision.js +13 -0
  410. package/dist/server/runtime/task-dispatch.js +12 -37
  411. package/dist/server/runtime/task-ledger-recovery.js +1 -1
  412. package/dist/server/runtime/task-ledger-runtime.d.ts +14 -2
  413. package/dist/server/runtime/task-ledger-runtime.js +5 -3
  414. package/dist/server/runtime/task-polling.js +9 -3
  415. package/dist/server/runtime/task-reconciliation.js +2 -1
  416. package/dist/server/runtime/websocket-upgrade.js +2 -0
  417. package/dist/server/runtime/websocket-worker.js +9 -0
  418. package/dist/server/task-ledger-codec.d.ts +9 -0
  419. package/dist/server/task-ledger-codec.js +4 -1
  420. package/dist/server/task-ledger-transition-helpers.js +1 -0
  421. package/dist/server/task-ledger-types.d.ts +9 -0
  422. package/dist/server/task-ledger.d.ts +1 -1
  423. package/dist/server/task-ledger.js +2 -1
  424. package/dist/server/task-queue-types.d.ts +2 -0
  425. package/dist/storage/bun-sql.js +51 -6
  426. package/dist/storage/catalog-keys.d.ts +64 -0
  427. package/dist/storage/catalog-keys.js +8 -0
  428. package/dist/storage/compressed-storage.js +1 -1
  429. package/dist/storage/derived-operations.js +1 -1
  430. package/dist/storage/index.d.ts +28 -1
  431. package/dist/storage/interface.d.ts +28 -1
  432. package/dist/storage/interface.js +1 -1
  433. package/dist/storage/key-encoding.d.ts +15 -0
  434. package/dist/storage/key-encoding.js +3 -0
  435. package/dist/storage/key-prefixes.d.ts +1 -1
  436. package/dist/storage/key-prefixes.js +16 -0
  437. package/dist/storage/lmdb.d.ts +54 -1
  438. package/dist/storage/lmdb.js +1 -1
  439. package/dist/storage/mailbox-keys.d.ts +80 -0
  440. package/dist/storage/mailbox-keys.js +14 -0
  441. package/dist/storage/memory.js +1 -1
  442. package/dist/storage/neon.js +2 -2
  443. package/dist/storage/node-sqlite-loader.d.ts +1 -1
  444. package/dist/storage/node-sqlite.js +51 -6
  445. package/dist/storage/outbox-keys.d.ts +77 -0
  446. package/dist/storage/outbox-keys.js +14 -0
  447. package/dist/storage/postgres.js +2 -2
  448. package/dist/storage/resolve.js +1 -1
  449. package/dist/storage/scoped-storage.js +1 -1
  450. package/dist/storage/storage-configuration.d.ts +6 -0
  451. package/dist/storage/testing.js +1 -1
  452. package/dist/storage/turso.js +2 -2
  453. package/dist/version.d.ts +1 -1
  454. package/dist/version.js +1 -1
  455. package/dist/web-extension.js +1 -1
  456. package/dist/worker/manifest/registry-contract-builder.d.ts +21 -3
  457. package/dist/worker/manifest/registry-contract-builder.js +40 -31
  458. package/dist/worker/protocol-messages.d.ts +17 -0
  459. package/dist/worker/protocol-schemas.d.ts +32 -0
  460. package/dist/worker/protocol-schemas.js +7 -3
  461. package/dist/worker/protocol-task-result.js +35 -3
  462. package/dist/worker/protocol.js +1 -1
  463. package/dist/worker/registry/types.d.ts +2 -0
  464. package/dist/worker/registry.d.ts +1 -1
  465. package/dist/worker/registry.js +3 -1
  466. package/dist/workers/workflow-runner.d.ts +9 -0
  467. package/dist/workers/workflow-runner.js +9 -2
  468. package/dist/workers/workflow-worker-entry.js +9 -4
  469. package/package.json +2 -2
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Shared validation and fault mapping for the five `weft.workflows.revisions.*`
3
+ * / `weft.workflows.active.*` operations (WFT-11): `install-workflow-revision.ts`,
4
+ * `activate-workflow-revision.ts`, `get-workflow-revision.ts`,
5
+ * `list-workflow-revisions.ts`, `get-active-workflow-revision.ts`.
6
+ *
7
+ * @module server/operations/workflow-catalog-operation-helpers
8
+ */
9
+ import { type WorkflowCatalogActivationResult } from '../../core/catalog/index.ts';
10
+ import type { WorkflowCompatibilityPolicy } from '../../core/contract/compatibility.ts';
11
+ import type { WorkflowRevisionManifest } from '../../core/contract/types.ts';
12
+ import type { AccessPolicy } from '../authorization.ts';
13
+ import type { OperationFault } from '../operation-fault.ts';
14
+ import type { RestInputContext } from '../rest-binding.ts';
15
+ /** `workflows:admin` — required by `install` and `activate` (mutating). */
16
+ export declare const workflowsAdminAccess: AccessPolicy;
17
+ /** `workflows:read` — required by `get`/`list`/`active.get` (read-only). */
18
+ export declare const workflowsReadAccess: AccessPolicy;
19
+ /**
20
+ * Validate one `name` field per the wire-safe name grammar, raising the
21
+ * same `InvalidParams` fault both REST and JSON-RPC callers see for every
22
+ * other malformed identifier in this operation family. Bounded by
23
+ * `validateWorkflowOrActivityName` itself (`MAX_CONTRACT_IDENTIFIER_BYTES`).
24
+ */
25
+ export declare function validateWorkflowNameField(name: unknown): string;
26
+ /** Validate one `revision` field: a non-empty, bounded opaque string. */
27
+ export declare function validateWorkflowRevisionField(revision: unknown): string;
28
+ /** Validate an optional `expectedGeneration` field: a non-negative safe integer. */
29
+ export declare function validateExpectedGenerationField(value: unknown): number | undefined;
30
+ /** Validate an optional `policy` field against the one tunable compatibility axis. */
31
+ export declare function validatePolicyField(value: unknown): WorkflowCompatibilityPolicy | undefined;
32
+ /**
33
+ * Validate an untrusted `manifest` field via {@link parseWorkflowRevisionManifest} —
34
+ * the same hostile-input validation path (bounded sizes, recomputed
35
+ * `contractHash`) every other manifest consumer in this codebase uses.
36
+ */
37
+ export declare function validateManifestField(value: unknown): Promise<WorkflowRevisionManifest>;
38
+ /**
39
+ * Map one `applied: false` {@link WorkflowCatalogActivationResult} variant to
40
+ * the canonical `Conflict` fault. Exhaustive over all four refusal reasons —
41
+ * adding a fifth is a compile error here, forcing a deliberate wire mapping.
42
+ */
43
+ export declare function activationRefusalToFault(result: Extract<WorkflowCatalogActivationResult, {
44
+ applied: false;
45
+ }>): OperationFault;
46
+ /**
47
+ * Map an error thrown by `engine.workflows.install()`/`activate()` to the
48
+ * canonical operation fault, or rethrow unchanged when it is neither typed
49
+ * error this family can produce (letting the operation pipeline's generic
50
+ * `EngineFailure` wrapping handle anything else).
51
+ */
52
+ export declare function throwWorkflowCatalogOperationFault(error: unknown): never;
53
+ /**
54
+ * Read a REST request body as a JSON object, raising `InvalidParams` for
55
+ * malformed JSON or a non-object top-level value — shared by
56
+ * `install-workflow-revision.ts` (body-only) and
57
+ * `activate-workflow-revision.ts` (path `name` plus body fields).
58
+ */
59
+ export declare function readWorkflowCatalogRestBody(request: Request, context: RestInputContext): Promise<Record<string, unknown>>;
@@ -0,0 +1,162 @@
1
+ import { z } from "zod";
2
+ import {
3
+ WorkflowCatalogConflictError,
4
+ WorkflowRevisionNotInstalledError
5
+ } from "../../core/catalog/index.js";
6
+ import { MAX_CONTRACT_IDENTIFIER_BYTES } from "../../core/contract/limits.js";
7
+ import { parseWorkflowRevisionManifest } from "../../core/contract/manifest-parse.js";
8
+ import {
9
+ DynamicWorkflowSourceUnavailableError,
10
+ WorkflowSourceNotRegisteredError
11
+ } from "../../core/engine/dynamic-source-errors.js";
12
+ import { WorkflowNotRegisteredError } from "../../core/engine/errors.js";
13
+ import { WorkflowSourceValidationError } from "../../core/source/errors.js";
14
+ import { validateWorkflowOrActivityName } from "../../core/types/name-grammar.js";
15
+ import { readRestJsonBody } from "../rest-body.js";
16
+ import { invalidParamsFault, isOperationFault } from "./operation-helpers.js";
17
+ export const workflowsAdminAccess = {
18
+ kind: "scoped",
19
+ scopes: { kind: "anyOf", scopes: ["workflows:admin"] }
20
+ }, workflowsReadAccess = {
21
+ kind: "scoped",
22
+ scopes: { kind: "anyOf", scopes: ["workflows:read"] }
23
+ };
24
+ export function validateWorkflowNameField(name) {
25
+ if (typeof name !== "string" || name.length === 0)
26
+ throw invalidParamsFault('Field "name" must be a non-empty string');
27
+ try {
28
+ validateWorkflowOrActivityName(name, "workflow");
29
+ } catch (error) {
30
+ throw invalidParamsFault(error instanceof Error ? error.message : String(error));
31
+ }
32
+ return name;
33
+ }
34
+ export function validateWorkflowRevisionField(revision) {
35
+ if (typeof revision !== "string" || revision.length === 0)
36
+ throw invalidParamsFault('Field "revision" must be a non-empty string');
37
+ if (new TextEncoder().encode(revision).byteLength > MAX_CONTRACT_IDENTIFIER_BYTES)
38
+ throw invalidParamsFault(`Field "revision" exceeds the maximum identifier size of ${String(MAX_CONTRACT_IDENTIFIER_BYTES)} bytes`);
39
+ return revision;
40
+ }
41
+ export function validateExpectedGenerationField(value) {
42
+ if (value === void 0)
43
+ return;
44
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
45
+ throw invalidParamsFault('Field "expectedGeneration" must be a non-negative integer');
46
+ return value;
47
+ }
48
+ const compatibilityPolicyShape = z.object({ requireExactRevision: z.boolean().optional() }).strict();
49
+ export function validatePolicyField(value) {
50
+ if (value === void 0)
51
+ return;
52
+ const parsed = compatibilityPolicyShape.safeParse(value);
53
+ if (!parsed.success)
54
+ throw invalidParamsFault('Field "policy" must be an object with an optional boolean "requireExactRevision"');
55
+ return parsed.data.requireExactRevision === void 0 ? {} : { requireExactRevision: parsed.data.requireExactRevision };
56
+ }
57
+ export async function validateManifestField(value) {
58
+ const result = await parseWorkflowRevisionManifest(value);
59
+ if (!result.ok)
60
+ throw manifestValidationFailureFault(result);
61
+ return result.manifest;
62
+ }
63
+ function manifestValidationFailureFault(failure) {
64
+ return {
65
+ code: "InvalidParams",
66
+ message: failure.message,
67
+ data: {
68
+ issues: [
69
+ {
70
+ path: failure.path === void 0 ? [] : failure.path.split("."),
71
+ message: failure.message,
72
+ code: failure.reason
73
+ }
74
+ ]
75
+ }
76
+ };
77
+ }
78
+ export function activationRefusalToFault(result) {
79
+ switch (result.reason) {
80
+ case "incompatible": {
81
+ const { verdict } = result, reasons = verdict.compatible ? [] : verdict.reasons;
82
+ return {
83
+ code: "Conflict",
84
+ message: `Candidate revision is incompatible with the currently active revision: ${reasons.join(", ")}`,
85
+ data: { reason: result.reason, compatibilityReasons: reasons }
86
+ };
87
+ }
88
+ case "stale-generation":
89
+ return {
90
+ code: "Conflict",
91
+ message: `Stale expectedGeneration: the current durable generation is ${String(result.currentGeneration)}`,
92
+ data: { reason: result.reason, currentGeneration: result.currentGeneration }
93
+ };
94
+ case "expected-generation-required":
95
+ return {
96
+ code: "Conflict",
97
+ message: "expectedGeneration is required once a workflow has an active revision \u2014 current " + `generation is ${String(result.currentGeneration)}`,
98
+ data: { reason: result.reason, currentGeneration: result.currentGeneration }
99
+ };
100
+ case "conflict":
101
+ return {
102
+ code: "Conflict",
103
+ message: "Activation lost a concurrent write race; re-read the active pointer and retry",
104
+ data: { reason: result.reason }
105
+ };
106
+ default:
107
+ throw Error(`Unknown activation refusal reason: ${JSON.stringify(result)}`);
108
+ }
109
+ }
110
+ export function throwWorkflowCatalogOperationFault(error) {
111
+ if (error instanceof WorkflowRevisionNotInstalledError)
112
+ throw {
113
+ code: "NotFound",
114
+ message: error.message,
115
+ data: {
116
+ resource: "workflow-revision",
117
+ identifier: `${error.workflowName}:${error.revision}`,
118
+ weftCode: error.code
119
+ }
120
+ };
121
+ if (error instanceof WorkflowNotRegisteredError)
122
+ throw invalidParamsFault(error.message, error.code);
123
+ if (error instanceof WorkflowCatalogConflictError)
124
+ throw {
125
+ code: "Conflict",
126
+ message: error.message,
127
+ data: { reason: "catalog-conflict", weftCode: error.code }
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
+ };
151
+ throw error;
152
+ }
153
+ export async function readWorkflowCatalogRestBody(request, context) {
154
+ const body = await readRestJsonBody(request, context).catch((error) => {
155
+ if (isOperationFault(error))
156
+ throw error;
157
+ return null;
158
+ });
159
+ if (typeof body !== "object" || body === null || Array.isArray(body))
160
+ throw invalidParamsFault("Request body must be a JSON object.");
161
+ return body;
162
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Build the durable task-ledger envelope a fresh dispatch would create if no
3
+ * ledger record exists yet — split out of `task-dispatch.ts` purely to stay
4
+ * under this repository's 500-line-per-file ceiling, matching the existing
5
+ * `task-dispatch-revision.ts` precedent. There is no behavioral reason to
6
+ * import this module directly instead of `task-dispatch.ts`, which calls it
7
+ * from both `selectAndReserveWorker` and `enqueueTaskForLongPoll`.
8
+ *
9
+ * @module server/runtime/task-dispatch-envelope
10
+ */
11
+ import type { TaskDispatch } from '../index.ts';
12
+ import type { CreateQueuedInput } from '../task-ledger-transitions.ts';
13
+ /** The durable envelope every fresh dispatch would create if no ledger record exists yet. */
14
+ export declare function buildCreateQueuedInput(task: TaskDispatch, queue: string, visibilityTimeout: number): CreateQueuedInput;
@@ -0,0 +1,32 @@
1
+ import { isJSONValue } from "../../core/json.js";
2
+ import { isValidWorkflowRevision, REMOTE_TASK_RECORD_VERSION } from "../task-ledger.js";
3
+ function buildOptionalCreateQueuedFields(task) {
4
+ return {
5
+ ...task.workflowId !== void 0 ? { workflowId: task.workflowId } : {},
6
+ ...task.workflowExecutionToken !== void 0 ? { workflowExecutionToken: task.workflowExecutionToken } : {},
7
+ ...task.workflowRevision !== void 0 ? { workflowRevision: task.workflowRevision } : {},
8
+ ...task.priority !== void 0 ? { priority: task.priority } : {},
9
+ ...task.fairShareKey !== void 0 ? { fairShareKey: task.fairShareKey } : {},
10
+ ...task.sticky && task.workflowId !== void 0 ? { stickyWorkflowId: task.workflowId } : {},
11
+ ...task.retryPolicy !== void 0 ? { retryPolicy: task.retryPolicy } : {}
12
+ };
13
+ }
14
+ export function buildCreateQueuedInput(task, queue, visibilityTimeout) {
15
+ const input = task.input === void 0 ? null : task.input;
16
+ if (!isJSONValue(input))
17
+ throw Error(`TaskDispatch for operation "${task.operationId}" has a non-JSON-serializable "input" \u2014 the durable task ledger requires JSON-safe input.`);
18
+ if (task.workflowRevision !== void 0 && !isValidWorkflowRevision(task.workflowRevision))
19
+ throw Error(`TaskDispatch for operation "${task.operationId}" has an invalid "workflowRevision" \u2014 it must be a non-empty, bounded identifier.`);
20
+ return {
21
+ recordVersion: REMOTE_TASK_RECORD_VERSION,
22
+ operationId: task.operationId,
23
+ workflowType: task.workflowType,
24
+ activityName: task.activityName,
25
+ queue,
26
+ input,
27
+ headers: task.headers ?? {},
28
+ visibilityTimeoutMilliseconds: visibilityTimeout,
29
+ createdAt: Date.now(),
30
+ ...buildOptionalCreateQueuedFields(task)
31
+ };
32
+ }
@@ -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
+ }
@@ -1,4 +1,3 @@
1
- import { isJSONValue } from "../../core/json.js";
2
1
  import { buildWorkerExecutionIdentity } from "../../worker/manifest/execution-identity.js";
3
2
  import { evictOldestAffinityEntries } from "../runtime-helpers.js";
4
3
  import {
@@ -7,9 +6,10 @@ import {
7
6
  } from "../task-ledger-transitions.js";
8
7
  import {
9
8
  decodeRemoteTaskRecord,
10
- REMOTE_TASK_RECORD_VERSION,
11
9
  taskLedgerKey
12
10
  } from "../task-ledger.js";
11
+ import { buildCreateQueuedInput } from "./task-dispatch-envelope.js";
12
+ import { assertDispatchTargetsFreshRevision } from "./task-dispatch-revision.js";
13
13
  import { commitTaskLedgerTransition } from "./task-ledger-runtime.js";
14
14
  import {
15
15
  recordTaskBacklogMetric,
@@ -65,33 +65,6 @@ function recordDispatchOutcome(context, task, workerId) {
65
65
  operationIds.add(task.operationId);
66
66
  context.operationToWorkflow.set(task.operationId, task.workflowId);
67
67
  }
68
- function buildOptionalCreateQueuedFields(task) {
69
- return {
70
- ...task.workflowId !== void 0 ? { workflowId: task.workflowId } : {},
71
- ...task.workflowExecutionToken !== void 0 ? { workflowExecutionToken: task.workflowExecutionToken } : {},
72
- ...task.priority !== void 0 ? { priority: task.priority } : {},
73
- ...task.fairShareKey !== void 0 ? { fairShareKey: task.fairShareKey } : {},
74
- ...task.sticky && task.workflowId !== void 0 ? { stickyWorkflowId: task.workflowId } : {},
75
- ...task.retryPolicy !== void 0 ? { retryPolicy: task.retryPolicy } : {}
76
- };
77
- }
78
- function buildCreateQueuedInput(task, queue, visibilityTimeout) {
79
- const input = task.input === void 0 ? null : task.input;
80
- if (!isJSONValue(input))
81
- throw Error(`TaskDispatch for operation "${task.operationId}" has a non-JSON-serializable "input" \u2014 the durable task ledger requires JSON-safe input.`);
82
- return {
83
- recordVersion: REMOTE_TASK_RECORD_VERSION,
84
- operationId: task.operationId,
85
- workflowType: task.workflowType,
86
- activityName: task.activityName,
87
- queue,
88
- input,
89
- headers: task.headers ?? {},
90
- visibilityTimeoutMilliseconds: visibilityTimeout,
91
- createdAt: Date.now(),
92
- ...buildOptionalCreateQueuedFields(task)
93
- };
94
- }
95
68
  function buildCreateThenClaimTransition(createInput, claimInput) {
96
69
  return (current, now) => {
97
70
  let queuedRecord;
@@ -114,7 +87,7 @@ function bareActivityName(qualifiedActivityName) {
114
87
  const dotIndex = qualifiedActivityName.indexOf(".");
115
88
  return dotIndex === -1 ? qualifiedActivityName : qualifiedActivityName.slice(dotIndex + 1);
116
89
  }
117
- async function selectAndReserveWorker(context, options, task, queue, visibilityTimeout) {
90
+ async function selectAndReserveWorker(context, options, task, queue, visibilityTimeout, revisionFenceConditions) {
118
91
  const routingOptions = buildRoutingOptions(context, task, queue), worker = context.registry.findWorker(task.activityName, routingOptions);
119
92
  if (!worker)
120
93
  return !1;
@@ -128,7 +101,7 @@ async function selectAndReserveWorker(context, options, task, queue, visibilityT
128
101
  workflowType: task.workflowType,
129
102
  activityName: bareActivityName(task.activityName)
130
103
  });
131
- context.registry.assignTask(worker.id, task.operationId, visibilityTimeout, task.fairShareKey, attemptToken);
104
+ context.registry.assignTask(worker.id, task.operationId, visibilityTimeout, task.fairShareKey, attemptToken, task.workflowRevision);
132
105
  let result;
133
106
  try {
134
107
  result = await commitTaskLedgerTransition(options.engine.storage, task.operationId, buildCreateThenClaimTransition(createInput, {
@@ -136,7 +109,7 @@ async function selectAndReserveWorker(context, options, task, queue, visibilityT
136
109
  workerSessionId: worker.id,
137
110
  ...executionIdentity !== void 0 ? { executionIdentity } : {},
138
111
  leaseDurationMilliseconds: visibilityTimeout
139
- }), 1);
112
+ }), 1, revisionFenceConditions);
140
113
  } catch (error) {
141
114
  context.registry.releaseReservation(task.operationId);
142
115
  throw error;
@@ -159,6 +132,7 @@ async function selectAndReserveWorker(context, options, task, queue, visibilityT
159
132
  ...task.workflowExecutionToken !== void 0 && {
160
133
  workflowExecutionToken: task.workflowExecutionToken
161
134
  },
135
+ ...task.workflowRevision !== void 0 && { workflowRevision: task.workflowRevision },
162
136
  ...task.headers ? { headers: task.headers } : {}
163
137
  }));
164
138
  recordTaskQueueLatencyMetric(context.metricsCollector, {
@@ -169,11 +143,11 @@ async function selectAndReserveWorker(context, options, task, queue, visibilityT
169
143
  recordDispatchOutcome(context, task, worker.id);
170
144
  return !0;
171
145
  }
172
- async function enqueueTaskForLongPoll(context, options, task, queue, visibilityTimeout, resolvedPriority) {
146
+ async function enqueueTaskForLongPoll(context, options, task, queue, visibilityTimeout, resolvedPriority, revisionFenceConditions) {
173
147
  const storage = options.engine.storage, createInput = buildCreateQueuedInput(task, queue, visibilityTimeout), rawExisting = await storage.get(taskLedgerKey(task.operationId)), current = decodeRemoteTaskRecord(rawExisting);
174
148
  let queuedRecord;
175
149
  if (current === null) {
176
- const result = await commitTaskLedgerTransition(storage, task.operationId, (freshCurrent, now) => createQueued(freshCurrent, createInput, now), 1);
150
+ const result = await commitTaskLedgerTransition(storage, task.operationId, (freshCurrent, now) => createQueued(freshCurrent, createInput, now), 1, revisionFenceConditions);
177
151
  if (!result.ok) {
178
152
  const raced = decodeRemoteTaskRecord(await storage.get(taskLedgerKey(task.operationId)));
179
153
  if (raced === null || raced.state !== "queued")
@@ -194,6 +168,7 @@ async function enqueueTaskForLongPoll(context, options, task, queue, visibilityT
194
168
  visibilityTimeout,
195
169
  workflowId: task.workflowId,
196
170
  workflowExecutionToken: task.workflowExecutionToken,
171
+ workflowRevision: queuedRecord.workflowRevision,
197
172
  firstQueuedAt: queuedRecord.firstQueuedAt,
198
173
  lastQueuedAt: queuedRecord.lastQueuedAt,
199
174
  lastDispatchedAt: queuedRecord.lastDispatchedAt,
@@ -214,15 +189,15 @@ export async function dispatchTaskImpl(context, options, task) {
214
189
  }
215
190
  if (!task.workflowType)
216
191
  throw Error(`TaskDispatch for operation "${task.operationId}" is missing required field "workflowType".`);
217
- const dotIndex = task.activityName.indexOf(".");
192
+ const revisionFenceConditions = await assertDispatchTargetsFreshRevision(options, task), dotIndex = task.activityName.indexOf(".");
218
193
  if (dotIndex !== -1 && task.activityName.slice(0, dotIndex) !== task.workflowType)
219
194
  throw Error(`TaskDispatch for operation "${task.operationId}" has activityName "${task.activityName}" whose qualifier does not match workflowType "${task.workflowType}".`);
220
195
  const queue = task.queue ?? "default", visibilityTimeout = clampVisibilityTimeout(task.visibilityTimeout), resolvedPriority = resolveTaskPriority(context, options, task);
221
196
  if (!validateTaskEnvelope(context, task))
222
197
  return !1;
223
- if (await selectAndReserveWorker(context, options, task, queue, visibilityTimeout))
198
+ if (await selectAndReserveWorker(context, options, task, queue, visibilityTimeout, revisionFenceConditions))
224
199
  return !0;
225
- return enqueueTaskForLongPoll(context, options, task, queue, visibilityTimeout, resolvedPriority);
200
+ return enqueueTaskForLongPoll(context, options, task, queue, visibilityTimeout, resolvedPriority, revisionFenceConditions);
226
201
  }
227
202
  export function cancelTask(context, operationId) {
228
203
  const task = context.registry.getTask(operationId);
@@ -16,7 +16,7 @@ function rebuildWorkflowIndex(context, operationId, workflowId) {
16
16
  }
17
17
  function rehydrateWorkerOwnership(context, record, now) {
18
18
  const remaining = Math.max(0, record.leaseDeadline - now);
19
- context.registry.assignTask(record.workerSessionId, record.operationId, remaining, record.fairShareKey, record.attemptToken);
19
+ context.registry.assignTask(record.workerSessionId, record.operationId, remaining, record.fairShareKey, record.attemptToken, record.workflowRevision);
20
20
  const tracked = context.registry.getWorkerTasks(record.workerSessionId).find((task) => task.operationId === record.operationId);
21
21
  if (tracked)
22
22
  tracked.visibilityTimeout = record.visibilityTimeoutMilliseconds;
@@ -16,7 +16,7 @@
16
16
  *
17
17
  * @module server/runtime/task-ledger-runtime
18
18
  */
19
- import { type Storage } from '../../storage/interface.ts';
19
+ import { type ConditionalBatchCondition, type Storage } from '../../storage/interface.ts';
20
20
  import type { TaskLedgerPreconditionResult, TaskLedgerTransitionResult } from '../task-ledger-transitions.ts';
21
21
  import { type RemoteTaskRecord } from '../task-ledger.ts';
22
22
  export type TaskLedgerCommitResult<T extends RemoteTaskRecord> = Readonly<{
@@ -46,7 +46,19 @@ export type TaskLedgerDeleteResult = Readonly<{
46
46
  * reflects reality and re-attempting the identical transition cannot change
47
47
  * the outcome.
48
48
  */
49
- export declare function commitTaskLedgerTransition<T extends RemoteTaskRecord>(storage: Storage, operationId: string, transitionFn: (current: RemoteTaskRecord | null, now: number) => TaskLedgerTransitionResult<T>, maxAttempts?: number): Promise<TaskLedgerCommitResult<T>>;
49
+ export declare function commitTaskLedgerTransition<T extends RemoteTaskRecord>(storage: Storage, operationId: string, transitionFn: (current: RemoteTaskRecord | null, now: number) => TaskLedgerTransitionResult<T>, maxAttempts?: number,
50
+ /**
51
+ * Extra same-transaction preconditions to fence the commit on — for
52
+ * example, "the target workflow's persisted state is still exactly the
53
+ * bytes read at dispatch time" (WFT-20's revision-staleness gate). Checked
54
+ * in the SAME `conditionalBatch` call as the ledger key's own CAS, so a
55
+ * concurrent write to any of these keys between read and commit loses the
56
+ * whole batch atomically, closing the gap a standalone pre-check
57
+ * (read-then-later-write, with unrelated work in between) cannot close.
58
+ * Re-supplied by the caller on each retry attempt since the caller, not
59
+ * this loop, owns re-reading whatever these conditions guard.
60
+ */
61
+ additionalConditions?: readonly ConditionalBatchCondition[]): Promise<TaskLedgerCommitResult<T>>;
50
62
  /**
51
63
  * Read the current ledger record, check a delete-only precondition (WFT-24
52
64
  * retention: {@link canDeleteRetainedTerminalTask}), and conditionally delete
@@ -1,16 +1,18 @@
1
- import { storageConditionalBatch } from "../../storage/interface.js";
1
+ import {
2
+ storageConditionalBatch
3
+ } from "../../storage/interface.js";
2
4
  import {
3
5
  decodeRemoteTaskRecord,
4
6
  encodeRemoteTaskRecord,
5
7
  taskLedgerKey
6
8
  } from "../task-ledger.js";
7
- export async function commitTaskLedgerTransition(storage, operationId, transitionFn, maxAttempts = 1) {
9
+ export async function commitTaskLedgerTransition(storage, operationId, transitionFn, maxAttempts = 1, additionalConditions = []) {
8
10
  const key = taskLedgerKey(operationId);
9
11
  for (let attempt = 1;attempt <= maxAttempts; attempt++) {
10
12
  const rawExisting = await storage.get(key), current = decodeRemoteTaskRecord(rawExisting), result = transitionFn(current, Date.now());
11
13
  if (!result.ok)
12
14
  return result;
13
- if (await storageConditionalBatch(storage, [{ key, expectedValue: rawExisting }], [{ type: "put", key, value: encodeRemoteTaskRecord(result.nextRecord) }]))
15
+ if (await storageConditionalBatch(storage, [{ key, expectedValue: rawExisting }, ...additionalConditions], [{ type: "put", key, value: encodeRemoteTaskRecord(result.nextRecord) }]))
14
16
  return { ok: !0, record: result.nextRecord };
15
17
  }
16
18
  return {
@@ -58,7 +58,8 @@ function validateTaskResultBody(body) {
58
58
  workerId: typeof body.workerId === "string" ? body.workerId : void 0,
59
59
  value: body.value,
60
60
  error: typeof body.error === "string" ? body.error : void 0,
61
- attemptToken: rawAttemptToken
61
+ attemptToken: rawAttemptToken,
62
+ workflowRevision: typeof body.workflowRevision === "string" ? body.workflowRevision : void 0
62
63
  };
63
64
  }
64
65
  function isLongPollCompletionAuthorized(record, validated) {
@@ -68,7 +69,11 @@ function isLongPollCompletionAuthorized(record, validated) {
68
69
  return !1;
69
70
  if (validated.workerId === void 0 || record.workerSessionId !== validated.workerId)
70
71
  return !1;
71
- return validated.attemptToken === record.attemptToken;
72
+ if (validated.attemptToken !== record.attemptToken)
73
+ return !1;
74
+ if (record.workflowRevision !== void 0 && validated.workflowRevision !== record.workflowRevision)
75
+ return !1;
76
+ return !0;
72
77
  }
73
78
  async function applyTaskResult(context, options, result) {
74
79
  const { operationId, status, value, error } = result, committed = await commitTaskLedgerCompletion(options.engine.storage, {
@@ -155,7 +160,8 @@ export async function handleTaskPollRequest(context, options, request, url, prin
155
160
  attemptToken: claim.attemptToken,
156
161
  ...task.workflowExecutionToken !== void 0 && {
157
162
  workflowExecutionToken: task.workflowExecutionToken
158
- }
163
+ },
164
+ ...task.workflowRevision !== void 0 && { workflowRevision: task.workflowRevision }
159
165
  });
160
166
  }
161
167
  return new Response(null, { status: 204 });
@@ -65,7 +65,8 @@ export function taskDispatchFromLedgerRecord(record) {
65
65
  input: record.input,
66
66
  queue: record.queue,
67
67
  visibilityTimeout: record.visibilityTimeoutMilliseconds,
68
- workflowExecutionToken: record.workflowExecutionToken
68
+ workflowExecutionToken: record.workflowExecutionToken,
69
+ workflowRevision: record.workflowRevision
69
70
  };
70
71
  if (record.workflowId !== void 0)
71
72
  taskDispatch.workflowId = record.workflowId;
@@ -69,6 +69,8 @@ function upgradeScope(connectionType) {
69
69
  case "generic":
70
70
  case void 0:
71
71
  return null;
72
+ default:
73
+ throw Error(`Unknown WebSocket connection type: ${JSON.stringify(connectionType)}`);
72
74
  }
73
75
  }
74
76
  export function handleWebSocketUpgrade(server, context, options, request, url, authContext) {
@@ -47,6 +47,15 @@ function onTaskResultMessage(context, options, ws, message, cleanupWorkflowIndex
47
47
  });
48
48
  return;
49
49
  }
50
+ const inFlightTask = context.registry.getTask(operationId);
51
+ if (inFlightTask?.workflowRevision !== void 0 && message.workflowRevision !== inFlightTask.workflowRevision) {
52
+ sendWorkerProtocolMessage(ws, {
53
+ type: "protocolError",
54
+ code: "invalid_message",
55
+ message: `taskResult for operation "${operationId}" rejected \u2014 revision mismatch`
56
+ });
57
+ return;
58
+ }
50
59
  const resolvedStatus = resolveTaskResultStatus(message), payloadError = taskResultPayloadSizeError({
51
60
  status: resolvedStatus,
52
61
  ...message.status === "completed" ? { value: message.value } : { error: message.error }
@@ -15,6 +15,15 @@
15
15
  * @module server/task-ledger-codec
16
16
  */
17
17
  import type { RemoteTaskCancelling, RemoteTaskCompleting, RemoteTaskDeadLettered, RemoteTaskLeased, RemoteTaskQueued, RemoteTaskRecord, RemoteTaskTerminal, RemoteTaskTerminalCancelled, RemoteTaskTerminalResolved, RemoteTaskTerminalRetryExhausted } from './task-ledger-types.ts';
18
+ /**
19
+ * Whether `value` is a valid `workflowRevision` per the durable task
20
+ * ledger's non-empty, bounded identifier contract — the same contract
21
+ * `decodeRemoteTaskRecord` enforces on read. Exported so dispatch-time
22
+ * callers (`task-dispatch.ts`) can reject an invalid caller-supplied
23
+ * revision before it reaches a ledger write, instead of writing a record
24
+ * that later fails to decode.
25
+ */
26
+ export declare function isValidWorkflowRevision(value: unknown): value is string;
18
27
  /** Bounded header map: at most {@link MAX_TASK_HEADER_COUNT} entries, each key/value at most {@link MAX_TASK_HEADER_VALUE_BYTES}. */
19
28
  export declare function isValidTaskHeaders(value: unknown): value is Readonly<Record<string, string>>;
20
29
  export declare function isRemoteTaskQueued(value: unknown): value is RemoteTaskQueued;
@@ -14,6 +14,9 @@ function isRecord(value) {
14
14
  function isBoundedIdentifier(value, maxBytes = MAX_TASK_IDENTIFIER_BYTES) {
15
15
  return typeof value === "string" && value.length > 0 && utf8ByteLength(value) <= maxBytes;
16
16
  }
17
+ export function isValidWorkflowRevision(value) {
18
+ return isBoundedIdentifier(value);
19
+ }
17
20
  function isBoundedOptionalIdentifier(value, maxBytes = MAX_TASK_IDENTIFIER_BYTES) {
18
21
  return value === void 0 || isBoundedIdentifier(value, maxBytes);
19
22
  }
@@ -86,7 +89,7 @@ function isOptionalExecutionIdentity(value) {
86
89
  return value === void 0 || isValidExecutionIdentity(value);
87
90
  }
88
91
  function isValidTaskIdentityFields(value) {
89
- return value.recordVersion === 1 && isBoundedIdentifier(value.operationId) && isBoundedOptionalIdentifier(value.workflowId) && isBoundedIdentifier(value.workflowType) && isBoundedOptionalIdentifier(value.workflowExecutionToken) && isBoundedIdentifier(value.activityName) && isBoundedIdentifier(value.queue);
92
+ return value.recordVersion === 1 && isBoundedIdentifier(value.operationId) && isBoundedOptionalIdentifier(value.workflowId) && isBoundedIdentifier(value.workflowType) && isBoundedOptionalIdentifier(value.workflowExecutionToken) && isBoundedOptionalIdentifier(value.workflowRevision) && isBoundedIdentifier(value.activityName) && isBoundedIdentifier(value.queue);
90
93
  }
91
94
  function isValidTaskRoutingFields(value) {
92
95
  return isOptionalFiniteNumber(value.priority) && isBoundedOptionalIdentifier(value.fairShareKey) && isBoundedOptionalIdentifier(value.stickyWorkflowId) && isValidExecutionRequirement(value.executionRequirement);
@@ -5,6 +5,7 @@ export function pickBase(record) {
5
5
  ...record.workflowId !== void 0 ? { workflowId: record.workflowId } : {},
6
6
  workflowType: record.workflowType,
7
7
  ...record.workflowExecutionToken !== void 0 ? { workflowExecutionToken: record.workflowExecutionToken } : {},
8
+ ...record.workflowRevision !== void 0 ? { workflowRevision: record.workflowRevision } : {},
8
9
  activityName: record.activityName,
9
10
  queue: record.queue,
10
11
  input: record.input,
@@ -48,6 +48,15 @@ export type RemoteTaskBase = Readonly<{
48
48
  workflowId?: string;
49
49
  workflowType: string;
50
50
  workflowExecutionToken?: string;
51
+ /**
52
+ * The dispatching workflow run's persisted revision (WFT-20), when the
53
+ * `TaskDispatch` caller supplied one. Same optionality rationale as
54
+ * `workflowExecutionToken` above — NOT the same field as
55
+ * `executionRequirement.workflowRevision` (a client-declared routing
56
+ * constraint carried by `WorkerExecutionRequirementInput`, unrelated to
57
+ * this plain wire echo/validation field).
58
+ */
59
+ workflowRevision?: string;
51
60
  activityName: string;
52
61
  queue: string;
53
62
  input: JSONValue;
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * @module server/task-ledger
12
12
  */
13
- export { decodeRemoteTaskRecord, encodeRemoteTaskRecord, isRemoteTaskCancelling, isRemoteTaskCompleting, isRemoteTaskDeadLettered, isRemoteTaskLeased, isRemoteTaskQueued, isRemoteTaskRecord, isRemoteTaskTerminal, isRemoteTaskTerminalCancelled, isRemoteTaskTerminalResolved, isRemoteTaskTerminalRetryExhausted, isValidTaskHeaders, } from './task-ledger-codec.ts';
13
+ export { decodeRemoteTaskRecord, encodeRemoteTaskRecord, isRemoteTaskCancelling, isRemoteTaskCompleting, isRemoteTaskDeadLettered, isRemoteTaskLeased, isRemoteTaskQueued, isRemoteTaskRecord, isRemoteTaskTerminal, isRemoteTaskTerminalCancelled, isRemoteTaskTerminalResolved, isRemoteTaskTerminalRetryExhausted, isValidTaskHeaders, isValidWorkflowRevision, } from './task-ledger-codec.ts';
14
14
  export { taskLedgerKey } from './task-ledger-keys.ts';
15
15
  export { MAX_TASK_HEADER_COUNT, MAX_TASK_HEADER_VALUE_BYTES, MAX_TASK_IDENTIFIER_BYTES, MAX_TASK_REASON_BYTES, utf8ByteLength, } from './task-ledger-limits.ts';
16
16
  export { REMOTE_TASK_RECORD_VERSION } from './task-ledger-types.ts';