@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,26 @@
1
+ /**
2
+ * Count schedules pinned to an exact `(type, revision)` (WFT-20). Wired into
3
+ * `catalog-removal.ts`'s `countWorkflowRevisionReferences()`, replacing the
4
+ * `pinnedSchedules: 0` stub WFT-12 left in place pending this batch (see
5
+ * that field's own doc comment: "always 0 until WFT-20").
6
+ *
7
+ * Mirrors `nonterminal-revision-count.ts`'s bounded-scan shape exactly: only
8
+ * top-level `schedule:{id}` records are schedule states — `schedule:{id}:*`
9
+ * suffix keys (timer index, run metadata) share the `schedule:` prefix but
10
+ * are not, the same skip `listSchedules`/`recoverOrphanedScheduleTimers`
11
+ * already apply.
12
+ *
13
+ * @module core/engine/pinned-schedule-revision-count
14
+ */
15
+ import type { Storage } from '../../storage/interface.ts';
16
+ /**
17
+ * Scan `storage` for schedules whose `workflowType` and `pinnedRevision`
18
+ * match exactly, returning the count. Only `revisionPolicy: 'pinned'`
19
+ * schedules ever count — an `'active-at-fire'` schedule against the same
20
+ * `(type, revision)` never blocks removal, since it resolves whatever is
21
+ * active at each future fire regardless of what is being removed now. A
22
+ * `'cancelled'` pinned schedule is excluded too: it will never fire again,
23
+ * so it must not block removal of the revision it once pinned. A `'paused'`
24
+ * pinned schedule still counts — it can be resumed and fire again later.
25
+ */
26
+ export declare function countPinnedSchedulesForRevision(storage: Storage, type: string, revision: string): Promise<number>;
@@ -0,0 +1,19 @@
1
+ import { decodeScheduleState } from "./validation/schedule.js";
2
+ export async function countPinnedSchedulesForRevision(storage, type, revision) {
3
+ let count = 0;
4
+ for await (const [key, bytes] of storage.scan("schedule:")) {
5
+ if (key.slice(9).includes(":"))
6
+ continue;
7
+ const state = decodeScheduleState(bytes);
8
+ if (!state)
9
+ continue;
10
+ if (state.workflowType !== type)
11
+ continue;
12
+ if (state.revisionPolicy !== "pinned" || state.pinnedRevision !== revision)
13
+ continue;
14
+ if (state.status === "cancelled")
15
+ continue;
16
+ count += 1;
17
+ }
18
+ return count;
19
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Revision resolution for a `revisionPolicy: 'pinned'` schedule (WFT-20):
3
+ * capture-time resolution (what revision would run right now, recorded on
4
+ * the schedule) and fire-time resolution (resolve and reserve EXACTLY the
5
+ * captured revision, enforcing a real, checkable commitment for an eager
6
+ * workflow type rather than silently degrading to active-at-fire behavior).
7
+ *
8
+ * Fire-time resolution deliberately does NOT reuse
9
+ * `resolveExecutableRegistrationForRevision()` unchanged for an eager type:
10
+ * that resolver's documented "eager ignores the pin" rule is correct for
11
+ * run RECOVERY (a process only ever runs the code it has loaded, so a stale
12
+ * pin on an eager type is harmless) but wrong for a schedule's
13
+ * forward-looking commitment — silently falling back to whatever is active
14
+ * would make a "pinned" schedule lie about what it guarantees, and would
15
+ * make `pinnedSchedules` reference-count accounting
16
+ * ({@link import('./pinned-schedule-revision-count.ts').countPinnedSchedulesForRevision})
17
+ * block removal of a revision nothing will ever actually run again.
18
+ *
19
+ * @module core/engine/pinned-schedule-revision
20
+ */
21
+ import type { ConditionalBatchCondition } from '../../storage/interface.ts';
22
+ import type { ScheduleRevisionPolicy } from '../types.ts';
23
+ import { type ExecutableRegistration } from './dynamic-source-execution.ts';
24
+ import type { Engine } from './index.ts';
25
+ import type { EngineInternals } from './internals.ts';
26
+ /**
27
+ * Capture-time resolution: the revision that would run RIGHT NOW for `type`,
28
+ * reusing the same resolver (and revision-selection rule) a fresh
29
+ * `engine.start()` call would use. Called by `schedule()`/`updateSchedule()`
30
+ * when a caller requests `revisionPolicy: 'pinned'`, so the captured
31
+ * {@link import('../types/schedules.ts').ScheduleMetadata.pinnedRevision} is
32
+ * exactly what would have run had the schedule fired at this instant. No
33
+ * `inFlightStartsByRevision` reservation here — this is not launching a
34
+ * workflow, only recording a decision; the write that persists the pin is
35
+ * separately fenced against a concurrent `removeWorkflowRevision()` via
36
+ * `buildCatalogEntryRevisionCondition` at the `writeScheduleState` call site.
37
+ */
38
+ export declare function resolveScheduleRevisionForPin(engine: Engine, internals: EngineInternals, type: string): Promise<string>;
39
+ /**
40
+ * `schedule()`'s create-time revision resolution — split out to keep that
41
+ * function under the complexity ceiling. For `revisionPolicy: 'pinned'`,
42
+ * captures and returns the current revision via
43
+ * {@link resolveScheduleRevisionForPin} (which already resolves, and for a
44
+ * lazy type loads, `type` internally). For `'active-at-fire'`, returns
45
+ * `undefined` and — for a lazy type not yet eagerly registered — resolves
46
+ * once here purely to trigger the loader at schedule-creation time, exactly
47
+ * as before this revision-policy field existed.
48
+ */
49
+ export declare function resolveScheduleCreationRevision(internals: EngineInternals, type: string, revisionPolicy: ScheduleRevisionPolicy): Promise<string | undefined>;
50
+ /**
51
+ * Fire-time resolve-and-reserve for a pinned schedule occurrence — the
52
+ * pinned-revision counterpart of
53
+ * `catalog-removal.ts`'s `resolveAndReserveExecutableRegistration`, reusing
54
+ * the identical early/late `inFlightStartsByRevision` reservation shape so a
55
+ * concurrent `removeWorkflowRevision()` sees an in-flight reference the same
56
+ * way it would for an ordinary start.
57
+ */
58
+ export declare function resolveAndReservePinnedExecutableRegistration(engine: Engine, internals: EngineInternals, type: string, revision: string): Promise<{
59
+ registration: ExecutableRegistration['entry'];
60
+ inFlightRevision: string | undefined;
61
+ resolvedRevision: string | undefined;
62
+ }>;
63
+ /**
64
+ * The `writeScheduleState` `extraConditions`/`onExtraConditionsLost` options
65
+ * that fence a pinned schedule's create/update write against a concurrent
66
+ * `removeWorkflowRevision()` landing between {@link resolveScheduleRevisionForPin}'s
67
+ * capture and this commit — see `storage-io.ts`'s `writeScheduleState` doc for
68
+ * why this is necessary (the scan-based `pinnedSchedules` reference count
69
+ * cannot see an uncommitted schedule write, so `removeWorkflowRevision()`'s
70
+ * own reference check cannot block it on its own). `undefined` (no fencing)
71
+ * when `pinnedRevision` is `undefined` — this write is not pinning.
72
+ */
73
+ export declare function buildPinnedRevisionWriteOptions(internals: EngineInternals, type: string, pinnedRevision: string | undefined): Promise<{
74
+ extraConditions: ConditionalBatchCondition[];
75
+ onExtraConditionsLost: () => Error;
76
+ } | undefined>;
@@ -0,0 +1,53 @@
1
+ import { releaseInFlightStart, reserveInFlightStart } from "./catalog-removal.js";
2
+ import {
3
+ resolveExecutableRegistration,
4
+ resolveExecutableRegistrationForRevision
5
+ } from "./dynamic-source-execution.js";
6
+ import { buildCatalogEntryRevisionCondition } from "./lifecycle/start-commit.js";
7
+ import {
8
+ resolveCachedStartRevision,
9
+ resolveStartRevisionUncached
10
+ } from "./lifecycle/start-revision-resolution.js";
11
+ import { WorkflowRevisionUnavailableError } from "./revision-errors.js";
12
+ export async function resolveScheduleRevisionForPin(engine, internals, type) {
13
+ const { revision: resolvedRevision } = await resolveExecutableRegistration(engine, internals, type);
14
+ return resolveCachedStartRevision(internals, type, resolvedRevision) ?? await resolveStartRevisionUncached(internals, type);
15
+ }
16
+ async function resolvePinnedExecutableRegistration(engine, internals, type, revision, onRevisionChosen) {
17
+ const eager = internals.registrations.get(type);
18
+ if (eager !== void 0) {
19
+ if (internals.registeredCatalogRevisions.get(type) !== revision)
20
+ throw new WorkflowRevisionUnavailableError(type, revision, "not-registered");
21
+ onRevisionChosen?.(revision);
22
+ return { entry: eager, revision: void 0 };
23
+ }
24
+ onRevisionChosen?.(revision);
25
+ return resolveExecutableRegistrationForRevision(engine, internals, type, revision);
26
+ }
27
+ export async function resolveScheduleCreationRevision(internals, type, revisionPolicy) {
28
+ if (revisionPolicy === "pinned")
29
+ return resolveScheduleRevisionForPin(internals.engine, internals, type);
30
+ if (!internals.registrations.has(type))
31
+ await resolveExecutableRegistration(internals.engine, internals, type);
32
+ return;
33
+ }
34
+ export async function resolveAndReservePinnedExecutableRegistration(engine, internals, type, revision) {
35
+ let earlyReservation;
36
+ try {
37
+ const { entry: registration, revision: resolvedRevision } = await resolvePinnedExecutableRegistration(engine, internals, type, revision, (chosen) => {
38
+ earlyReservation = reserveInFlightStart(internals, type, chosen);
39
+ }), inFlightRevision = earlyReservation !== void 0 ? earlyReservation : reserveInFlightStart(internals, type, resolvedRevision);
40
+ return { registration, inFlightRevision, resolvedRevision };
41
+ } catch (error) {
42
+ releaseInFlightStart(internals, type, earlyReservation);
43
+ throw error;
44
+ }
45
+ }
46
+ export async function buildPinnedRevisionWriteOptions(internals, type, pinnedRevision) {
47
+ if (pinnedRevision === void 0)
48
+ return;
49
+ return {
50
+ extraConditions: [await buildCatalogEntryRevisionCondition(internals, type, pinnedRevision)],
51
+ onExtraConditionsLost: () => new WorkflowRevisionUnavailableError(type, pinnedRevision, "not-installed")
52
+ };
53
+ }
@@ -1,7 +1,113 @@
1
+ import { ActivityRegistry } from '../activity-registry.ts';
2
+ import { type ActivityDefinition, type QueryDefinition, type SignalDefinition, type UpdateDefinition, type WorkflowDefinition } from '../types.ts';
3
+ import type { RegistrationEntry } from './engine-internal-types.ts';
1
4
  import type { EngineInternals } from './internals.ts';
2
5
  export type RegistrationCallbacks = {
3
6
  ensureRetentionSweepInterval: () => void;
4
7
  dispatchEvent: (event: Event) => void;
5
8
  };
9
+ /**
10
+ * Reject constraints on a workflow definition when the engine has no
11
+ * inline execution strategy. Exported so `dynamic-source-execution.ts`
12
+ * (WFT-15/16) can apply the identical guard to a dynamically-resolved
13
+ * definition — see that module's own call site.
14
+ */
15
+ export declare function assertConstraintsSupported(internals: EngineInternals, name: string, registration: WorkflowDefinition): void;
16
+ /**
17
+ * Build the `RegistrationEntry` `engine.register()` would store for
18
+ * `registration`, without committing anything — pure normalization
19
+ * (base fields, optional fields, and, for a builder-produced definition,
20
+ * signal/update/query name-collision checks). Exported so the dynamic
21
+ * workflow-source validation pipeline (`core/source/validate.ts`, WFT-13/14)
22
+ * can normalize a loaded module's exported definition through the identical
23
+ * path `engine.register()` uses, rather than re-deriving a
24
+ * `RegistrationEntry` independently and risking the two producers drifting
25
+ * apart.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * import { workflow } from '@lostgradient/weft';
30
+ *
31
+ * const greet = workflow({ name: 'greet' }).execute(async function* (_ctx, input: string) {
32
+ * return `hello ${input}`;
33
+ * });
34
+ * console.log(greet.name);
35
+ * ```
36
+ */
37
+ export declare function buildRegistrationEntry(name: string, registration: WorkflowDefinition): RegistrationEntry;
38
+ /**
39
+ * Visit every RESOLVED `registerSource()`-registered type's normalized
40
+ * retention policy (via {@link buildRegistrationEntry}) — the dynamic-source
41
+ * counterpart to walking `internals.registrations.values()` directly for an
42
+ * eager type. Used by `bulk-operations-purge.ts` so a dynamic workflow's own
43
+ * (possibly shorter) retention window narrows the purge sweep's scan bound
44
+ * the same way an eager registration's does.
45
+ */
46
+ export declare function forEachResolvedDynamicRetentionPolicy(internals: EngineInternals, visit: (policy: RegistrationEntry['retention']) => void): void;
47
+ /**
48
+ * True when at least one `registerSource()`-registered type has a
49
+ * registered candidate revision this process has NOT yet resolved — its
50
+ * retention policy (and everything else `buildRegistrationEntry` would
51
+ * derive) is genuinely unknown, so `getMinimumRetentionMs()`'s scan-bound
52
+ * optimization in `bulk-operations-purge.ts` cannot be trusted (WFT-19
53
+ * review round 1): it silently excluded exactly this class of workflow
54
+ * from the periodic retention sweep's scan bound, since an unresolved
55
+ * candidate's possibly-shorter-than-default retention window was invisible
56
+ * to the minimum computation. Used to fall back to an unbounded terminal
57
+ * scan while any such candidate remains unresolved — self-healing once
58
+ * `shouldPurgeWorkflowState`'s own per-run resolve installs it.
59
+ */
60
+ export declare function hasUnresolvedDynamicSourceCandidate(internals: EngineInternals): boolean;
61
+ /**
62
+ * Structural predicate for `BuiltWorkflowDefinition` — the runtime shape
63
+ * `workflow({ name }).execute(...)` returns. Exported so the dynamic
64
+ * workflow-source validation pipeline (`core/source/validate.ts`, WFT-13/14)
65
+ * can reject a loaded export that is a hand-rolled `{ name, handler }`
66
+ * literal rather than a builder-produced definition — the same "removed
67
+ * bare-handler shape" rejection `engine.register()` itself applies via
68
+ * {@link buildRegistrationEntry}.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * import { workflow } from '@lostgradient/weft';
73
+ *
74
+ * const greet = workflow({ name: 'greet' }).execute(async function* (_ctx, input: string) {
75
+ * return `hello ${input}`;
76
+ * });
77
+ * console.log(typeof greet.activities === 'object');
78
+ * ```
79
+ */
80
+ export declare function isBuilderWorkflowDefinition(value: unknown): value is WorkflowDefinition & {
81
+ readonly activities: Readonly<Record<string, Readonly<ActivityDefinition>>>;
82
+ readonly signals: Readonly<Record<string, Readonly<SignalDefinition<unknown>>>>;
83
+ readonly updates: Readonly<Record<string, Readonly<UpdateDefinition<unknown>>>>;
84
+ readonly queries: Readonly<Record<string, Readonly<QueryDefinition<unknown>>>>;
85
+ readonly searchAttributes: Readonly<Record<string, unknown>>;
86
+ };
87
+ /**
88
+ * Build a fresh per-workflow {@link ActivityRegistry} from a builder workflow's
89
+ * activities map. Each entry is defensively deep-cloned and then turned into a
90
+ * fresh `ActivityCallable` via {@link activity}, so the engine's registry holds
91
+ * its own callable references and the user's `BuiltWorkflowDefinition` cannot
92
+ * influence dispatch by post-registration mutation.
93
+ *
94
+ * Exported so the dynamic workflow-source validation pipeline
95
+ * (`core/source/validate.ts`, WFT-13/14) can build the same
96
+ * uncommitted-but-canonical per-workflow registry for a loaded module's
97
+ * export that `engine.register()` builds for an eagerly registered one —
98
+ * required so {@link import('../registry-workflow-manifest.ts').buildWorkflowManifestFromDefinition}
99
+ * produces byte-identical manifests for the two paths.
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * import { workflow } from '@lostgradient/weft';
104
+ *
105
+ * const greet = workflow({ name: 'greet' }).execute(async function* (_ctx, input: string) {
106
+ * return `hello ${input}`;
107
+ * });
108
+ * console.log(Object.keys(greet.activities).length);
109
+ * ```
110
+ */
111
+ export declare function buildPerWorkflowActivityRegistry(activities: Readonly<Record<string, Readonly<ActivityDefinition>>>): ActivityRegistry;
6
112
  export declare function register(internals: EngineInternals, definition: unknown, callbacks: RegistrationCallbacks): void;
7
113
  export declare function resolveWorkflowTypeTarget(internals: EngineInternals, target: string | Function, _callbacks: RegistrationCallbacks): string;
@@ -1,3 +1,4 @@
1
+ import { isRecord } from "../../worker/manifest/is-record.js";
1
2
  import { ActivityRegistry } from "../activity-registry.js";
2
3
  import { WorkflowDefinitionRegisteredEvent } from "../events.js";
3
4
  import {
@@ -6,14 +7,15 @@ import {
6
7
  } from "../types.js";
7
8
  import { clonePlain } from "../types/clone-plain.js";
8
9
  import { validateWorkflowOrActivityName } from "../types/name-grammar.js";
10
+ import { DEFAULT_WORKFLOW_VERSION } from "../versioning.js";
9
11
  import { normalizeRetentionPolicy } from "./validation.js";
10
12
  function copiedTags(tags) {
11
13
  return tags === void 0 ? void 0 : [...tags];
12
14
  }
13
15
  function isWorkflowDefinition(value) {
14
- return typeof value === "object" && value !== null && "name" in value && "handler" in value;
16
+ return typeof value === "object" && value !== null && "name" in value && "handler" in value && typeof value.handler === "function";
15
17
  }
16
- function assertConstraintsSupported(internals, name, registration) {
18
+ export function assertConstraintsSupported(internals, name, registration) {
17
19
  if (!registration.constraints || registration.constraints.length === 0)
18
20
  return;
19
21
  if (internals.inlineStrategy === null)
@@ -23,7 +25,7 @@ function buildBaseRegistrationEntry(name, registration) {
23
25
  const tags = copiedTags(registration.tags), normalizedRetention = normalizeRetentionPolicy(registration.retention, `registration("${name}").retention`);
24
26
  return {
25
27
  handler: registration.handler,
26
- version: registration.version ?? "1",
28
+ version: registration.version ?? DEFAULT_WORKFLOW_VERSION,
27
29
  ...registration.description === void 0 ? {} : { description: registration.description },
28
30
  ...tags === void 0 ? {} : { tags },
29
31
  ...registration.inputSchema === void 0 ? {} : {
@@ -56,7 +58,7 @@ function applyOptionalRegistrationFields(entry, registration) {
56
58
  if (registration.finalizer !== void 0)
57
59
  entry.finalizer = registration.finalizer;
58
60
  }
59
- function buildRegistrationEntry(name, registration) {
61
+ export function buildRegistrationEntry(name, registration) {
60
62
  const entry = buildBaseRegistrationEntry(name, registration);
61
63
  applyOptionalRegistrationFields(entry, registration);
62
64
  if (isBuilderWorkflowDefinition(registration)) {
@@ -66,6 +68,20 @@ function buildRegistrationEntry(name, registration) {
66
68
  }
67
69
  return entry;
68
70
  }
71
+ export function forEachResolvedDynamicRetentionPolicy(internals, visit) {
72
+ for (const [type, revisions] of internals.sources.resolved)
73
+ for (const resolved of revisions.values())
74
+ visit(buildRegistrationEntry(type, resolved.definition).retention);
75
+ }
76
+ export function hasUnresolvedDynamicSourceCandidate(internals) {
77
+ for (const [type, byRevision] of internals.sources.byName) {
78
+ const resolvedForType = internals.sources.resolved.get(type);
79
+ for (const revision of byRevision.keys())
80
+ if (resolvedForType?.has(revision) !== !0)
81
+ return !0;
82
+ }
83
+ return !1;
84
+ }
69
85
  function normalizeMessageDefinitions(workflowType, messageKind, definitions) {
70
86
  const normalized = Object.create(null), sortedDefinitions = Object.values(definitions).toSorted((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0);
71
87
  for (const definition of sortedDefinitions) {
@@ -78,25 +94,30 @@ function normalizeMessageDefinitions(workflowType, messageKind, definitions) {
78
94
  function commitWorkflowDefinition(internals, definition, callbacks) {
79
95
  const name = definition.name;
80
96
  validateWorkflowOrActivityName(name, "workflow");
97
+ if (internals.sources.byName.has(name))
98
+ throw Error(`Cannot register("${name}"): "${name}" is already registered as a dynamic workflow source via engine.registerSource(). A workflow name may not be both eagerly registered and a dynamic source.`);
81
99
  assertConstraintsSupported(internals, name, definition);
82
100
  const entry = buildRegistrationEntry(name, definition);
83
101
  internals.registrations.set(name, entry);
84
102
  callbacks.ensureRetentionSweepInterval();
85
103
  internals.workflowTypesByHandler.set(definition.handler, name);
104
+ internals.registeredCatalogRevisions.delete(name);
105
+ if (!internals.pendingCatalogInstalls.includes(name))
106
+ internals.pendingCatalogInstalls.push(name);
86
107
  callbacks.dispatchEvent(new WorkflowDefinitionRegisteredEvent(name));
87
108
  }
88
109
  function hasNonNullObjectField(value, key) {
89
110
  if (!(key in value))
90
111
  return !1;
91
112
  const fieldValue = value[key];
92
- return typeof fieldValue === "object" && fieldValue !== null;
113
+ return isRecord(fieldValue);
93
114
  }
94
- function isBuilderWorkflowDefinition(value) {
115
+ export function isBuilderWorkflowDefinition(value) {
95
116
  if (!isWorkflowDefinition(value))
96
117
  return !1;
97
118
  return hasNonNullObjectField(value, "activities") && hasNonNullObjectField(value, "signals") && hasNonNullObjectField(value, "updates") && hasNonNullObjectField(value, "queries") && hasNonNullObjectField(value, "searchAttributes");
98
119
  }
99
- function buildPerWorkflowActivityRegistry(activities) {
120
+ export function buildPerWorkflowActivityRegistry(activities) {
100
121
  const registry = new ActivityRegistry;
101
122
  for (const definition of Object.values(activities)) {
102
123
  const clonedDefinition = clonePlain(definition), callable = activity(clonedDefinition);
@@ -1,10 +1,15 @@
1
1
  import { purgeInternal } from "./bulk-operations.js";
2
+ import { resolveLastKnownDynamicRegistration } from "./dynamic-source-execution.js";
2
3
  export function hasConfiguredRetention(internals) {
3
4
  if (internals.options.retention !== null)
4
5
  return !0;
5
6
  for (const registration of internals.registrations.values())
6
7
  if (registration.retention !== void 0 && registration.retention !== null)
7
8
  return !0;
9
+ for (const revisions of internals.sources.resolved.values())
10
+ for (const resolved of revisions.values())
11
+ if (resolved.definition.retention !== void 0 && resolved.definition.retention !== null)
12
+ return !0;
8
13
  return !1;
9
14
  }
10
15
  export function setNextRetentionSweepAt(internals) {
@@ -49,7 +54,7 @@ export async function runRetentionSweep(internals, handleCleanupError, cleanupWa
49
54
  }
50
55
  }
51
56
  export function resolveWorkflowTypeRetention(internals, type) {
52
- const registration = internals.registrations.get(type);
57
+ const registration = resolveLastKnownDynamicRegistration(internals, type);
53
58
  if (registration?.retention)
54
59
  return {
55
60
  type,
@@ -69,7 +74,9 @@ export function resolveWorkflowTypeRetention(internals, type) {
69
74
  };
70
75
  }
71
76
  export function getRetentionOverview(internals, resolveRetentionForType = (type) => resolveWorkflowTypeRetention(internals, type)) {
72
- const workflowTypes = [...internals.registrations.keys()].toSorted().map((type) => resolveRetentionForType(type));
77
+ const workflowTypes = [
78
+ ...new Set([...internals.registrations.keys(), ...internals.sources.byName.keys()])
79
+ ].toSorted().map((type) => resolveRetentionForType(type));
73
80
  return {
74
81
  defaultRetention: internals.options.retention,
75
82
  sweepIntervalMs: internals.options.retentionSweepIntervalMs,
@@ -0,0 +1,71 @@
1
+ /**
2
+ * {@link WorkflowRevisionUnavailableError} (WFT-17/WFT-18) — thrown by
3
+ * {@link import('./dynamic-source-execution.ts').resolveExecutableRegistrationForRevision}
4
+ * when a resumed run's persisted, EXACT pinned `WorkflowState.revision` cannot
5
+ * be resolved in this process. Distinct from
6
+ * {@link import('./dynamic-source-errors.ts').DynamicWorkflowSourceUnavailableError},
7
+ * which covers a dynamic source whose ACTIVE revision is ambiguous or fails
8
+ * to load — this error instead covers "the run's own pin cannot be honored",
9
+ * which can also happen for a legacy (pre-revision-pinning) record on a
10
+ * dynamic source with two or more registered candidates, where there is no
11
+ * pin at all and the ambiguity cannot be resolved by falling back to
12
+ * whichever revision happens to be active (that fallback is exactly the bug
13
+ * this batch closes — see `documentation/guides/recovery-and-deploys.md`).
14
+ *
15
+ * @module core/engine/revision-errors
16
+ */
17
+ import { WeftError } from '../weft-error.ts';
18
+ /**
19
+ * Thrown when a workflow run's pinned {@link import('../types/state.ts').WorkflowState.revision}
20
+ * cannot be resolved to an executable registration in this process:
21
+ *
22
+ * - `reason: 'not-registered'` — the run pins a specific revision (a
23
+ * dynamic-source candidate this process has never `registerSource()`-registered,
24
+ * including the case where the pin no longer matches a dynamic source's sole
25
+ * remaining candidate).
26
+ * - `reason: 'legacy-ambiguous'` — the run predates revision pinning (no
27
+ * `revision` was ever persisted for it) and its type is a dynamic source
28
+ * with two or more registered candidates, so there is no way to tell which
29
+ * one it actually started against.
30
+ * - `reason: 'not-installed'` — thrown at commit-time ADMISSION, not
31
+ * recovery, for either a fresh `start()` or a checkpoint-backed failed-run
32
+ * `retryFailedAll()` reactivation (WFT-17/WFT-18 Codex review on PR #958):
33
+ * the resolved (or pinned) revision's durable catalog entry was
34
+ * concurrently removed — `removeWorkflowRevision()` racing a `start()` on
35
+ * a DIFFERENT process under a lease ownership mode, or racing a
36
+ * `retryFailedAll()` on ANY process/mode, since a failed run contributes no
37
+ * `inFlightStartsByRevision` reservation of its own — between this
38
+ * process resolving the revision and that commit batch actually landing.
39
+ * Fails the one call outright — never retried inside the engine — so the
40
+ * caller re-issues it, which re-resolves against whatever is actually
41
+ * still installed.
42
+ *
43
+ * `engine.recoverAll()` classifies the affected `(type, revision)` group
44
+ * `unavailable`: only the runs in that group fail (with this error as their
45
+ * `system` failure cause, delivered via `failWorkflow()`/`onRecoveredWorkflow`,
46
+ * never thrown to `recoverAll()`'s own caller); sibling groups — including
47
+ * OTHER revisions of the same dynamic-source type — continue recovering
48
+ * normally. A standalone `engine.resume(workflowId)` call has no such
49
+ * isolation to fall back on — there is only the one run — so it throws this
50
+ * error directly to its caller instead.
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * import { Engine, WorkflowRevisionUnavailableError } from '@lostgradient/weft';
55
+ *
56
+ * const engine = new Engine();
57
+ * try {
58
+ * await engine.resume('workflow-id');
59
+ * } catch (err) {
60
+ * if (err instanceof WorkflowRevisionUnavailableError) {
61
+ * console.error(err.workflowType, err.revision, err.reason);
62
+ * }
63
+ * }
64
+ * ```
65
+ */
66
+ export declare class WorkflowRevisionUnavailableError extends WeftError<'WorkflowRevisionUnavailableError'> {
67
+ readonly workflowType: string;
68
+ readonly revision: string | undefined;
69
+ readonly reason: 'not-registered' | 'legacy-ambiguous' | 'not-installed';
70
+ constructor(workflowType: string, revision: string | undefined, reason: 'not-registered' | 'legacy-ambiguous' | 'not-installed');
71
+ }
@@ -0,0 +1,13 @@
1
+ import { WeftError } from "../weft-error.js";
2
+
3
+ export class WorkflowRevisionUnavailableError extends WeftError {
4
+ workflowType;
5
+ revision;
6
+ reason;
7
+ constructor(workflowType, revision, reason) {
8
+ super("WorkflowRevisionUnavailableError", reason === "legacy-ambiguous" ? `Cannot recover workflow type "${workflowType}": this run predates revision pinning and the type is a dynamic source with multiple registered revisions, so which one it started against cannot be determined.` : reason === "not-installed" ? `Cannot admit workflow type "${workflowType}": revision${revision === void 0 ? "" : ` "${revision}"`} is no longer installed in the durable catalog (removed concurrently). Retry the operation.` : `Cannot recover workflow type "${workflowType}": its pinned revision${revision === void 0 ? "" : ` "${revision}"`} is not registered in this process. Register the exact revision this run started against before retrying.`);
9
+ this.workflowType = workflowType;
10
+ this.revision = revision;
11
+ this.reason = reason;
12
+ }
13
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * The pinned-vs-active-at-fire branch point for a scheduled occurrence
3
+ * (WFT-20), split into its own tiny module so `schedule-run.ts` — a
4
+ * deliberately small, purpose-built module — has one obvious call site
5
+ * instead of inlining the branch.
6
+ *
7
+ * @module core/engine/schedule-revision-fire
8
+ */
9
+ import type { ScheduleState } from '../types.ts';
10
+ /**
11
+ * The revision override `startScheduledRun` should pass to
12
+ * `ScheduleCallbacks.startWorkflow` for this occurrence: `state.pinnedRevision`
13
+ * when `state.revisionPolicy === 'pinned'`, else `undefined` (an
14
+ * `'active-at-fire'` schedule resolves whatever revision is active at fire
15
+ * time, unchanged from pre-WFT-20 behavior).
16
+ */
17
+ export declare function buildPinnedRevisionOverride(state: ScheduleState): string | undefined;
@@ -0,0 +1,3 @@
1
+ export function buildPinnedRevisionOverride(state) {
2
+ return state.revisionPolicy === "pinned" ? state.pinnedRevision : void 0;
3
+ }
@@ -3,6 +3,7 @@ import { encode } from "../codec.js";
3
3
  import { ScheduleFiredEvent } from "../events.js";
4
4
  import { unavailableServicesError } from "./lifecycle/recovered-services.js";
5
5
  import { EMPTY_STORAGE_VALUE } from "./lifecycle/shared.js";
6
+ import { buildPinnedRevisionOverride } from "./schedule-revision-fire.js";
6
7
  import { encodeScheduleRunMetadata } from "./schedule-run-metadata.js";
7
8
  export async function startScheduledRun(internals, state, callbacks, options = {}) {
8
9
  const workflowId = options.workflowId ?? crypto.randomUUID(), occurrence = options.occurrence, metadata = encodeScheduleRunMetadata(state.id, occurrence), scheduleRunOperations = [
@@ -49,7 +50,7 @@ export async function startScheduledRun(internals, state, callbacks, options = {
49
50
  internals.workflowServices.set(workflowId, resolution.services);
50
51
  }
51
52
  internals.workflowsNeedingTerminalCleanup.add(workflowId);
52
- await callbacks.startWorkflow(state.workflowType, state.input, { id: workflowId }, scheduleRunOperations);
53
+ await callbacks.startWorkflow(state.workflowType, state.input, { id: workflowId }, scheduleRunOperations, buildPinnedRevisionOverride(state));
53
54
  internals.engine.dispatchEvent(new ScheduleFiredEvent(state.id, workflowId, internals.options.getNow(), occurrence));
54
55
  if (resolution !== null && resolution.status === "unavailable") {
55
56
  const unavailableError = unavailableServicesError(workflowId, resolution.reason);
@@ -10,9 +10,10 @@ export type RefreshedScheduleState = {
10
10
  currentWorkflowState: WorkflowState | null;
11
11
  };
12
12
  export type ScheduleCallbacks = {
13
+ /** `revisionOverride` (WFT-20) is the exact revision a `revisionPolicy: 'pinned'` occurrence must resolve against; `undefined` for an `'active-at-fire'` schedule. */
13
14
  startWorkflow: (type: string, input: unknown, options: {
14
15
  id: string;
15
- }, additionalStartOperations?: BatchOperation[]) => Promise<void>;
16
+ }, additionalStartOperations?: BatchOperation[], revisionOverride?: string) => Promise<void>;
16
17
  loadWorkflowState: (workflowId: string) => Promise<WorkflowState | null | undefined>;
17
18
  cancelWorkflow: (workflowId: string) => Promise<void>;
18
19
  getWorkflowResult: (workflowId: string) => Promise<unknown>;
@@ -1,7 +1,11 @@
1
1
  import { KEYS } from "../../storage/interface.js";
2
2
  import { decode } from "../codec.js";
3
- import { WorkflowNotRegisteredError } from "./errors.js";
4
3
  import { commitFencedEngineWrite } from "./fenced-write.js";
4
+ import {
5
+ buildPinnedRevisionWriteOptions,
6
+ resolveScheduleCreationRevision,
7
+ resolveScheduleRevisionForPin
8
+ } from "./pinned-schedule-revision.js";
5
9
  import { ScheduleHandle } from "./schedule-handle.js";
6
10
  import { resolveEffectiveScheduleFireAt } from "./schedule-jitter.js";
7
11
  import { getNextScheduleOccurrence } from "./schedule-occurrence.js";
@@ -31,9 +35,7 @@ import {
31
35
  export { startScheduledRun } from "./schedule-run.js";
32
36
  export { handleScheduleTimer } from "./schedule-timer.js";
33
37
  export async function schedule(internals, type, input, spec, options) {
34
- if (!internals.registrations.has(type))
35
- throw new WorkflowNotRegisteredError(type);
36
- const normalizedSpec = normalizeScheduleSpec(spec), normalizedOptions = normalizeScheduleOptions(options), scheduleId = normalizedOptions.id ?? crypto.randomUUID();
38
+ const normalizedSpec = normalizeScheduleSpec(spec), normalizedOptions = normalizeScheduleOptions(options), scheduleId = normalizedOptions.id ?? crypto.randomUUID(), revisionPolicy = normalizedOptions.revisionPolicy ?? "active-at-fire", pinnedRevision = await resolveScheduleCreationRevision(internals, type, revisionPolicy);
37
39
  if (internals.pendingScheduleCreations.has(scheduleId))
38
40
  throw Error(`Schedule with id "${scheduleId}" already exists`);
39
41
  internals.pendingScheduleCreations.add(scheduleId);
@@ -52,13 +54,15 @@ export async function schedule(internals, type, input, spec, options) {
52
54
  overlap: normalizedOptions.overlap,
53
55
  backfill: normalizedOptions.backfill,
54
56
  ...normalizedOptions.jitterMs !== void 0 && { jitterMs: normalizedOptions.jitterMs },
57
+ revisionPolicy,
58
+ ...pinnedRevision !== void 0 && { pinnedRevision },
55
59
  createdAt: now,
56
60
  updatedAt: now,
57
61
  nextFireAt: getNextScheduleOccurrence({ ...cadenceFields, createdAt: now }, now),
58
62
  missedFireCount: 0,
59
63
  queuedRuns: []
60
64
  };
61
- await writeScheduleState(internals, state);
65
+ await writeScheduleState(internals, state, await buildPinnedRevisionWriteOptions(internals, type, pinnedRevision));
62
66
  return new ScheduleHandle(scheduleId, internals.engine);
63
67
  } finally {
64
68
  internals.pendingScheduleCreations.delete(scheduleId);
@@ -152,18 +156,33 @@ export async function updateSchedule(internals, scheduleId, newSpec, options) {
152
156
  const state = await requireScheduleState(internals, normalizedScheduleId), now = internals.options.getNow(), {
153
157
  cronExpression: _droppedCron,
154
158
  intervalMs: _droppedInterval,
155
- ...stateWithoutCadence
156
- } = state, cadenceFields = normalizedSpec.kind === "interval" ? { intervalMs: normalizedSpec.intervalMs } : { cronExpression: normalizedSpec.cronExpression }, anchorFields = normalizedSpec.kind === "interval" ? { createdAt: now } : {}, updatedState = {
157
- ...stateWithoutCadence,
159
+ pinnedRevision: _droppedPinnedRevision,
160
+ ...stateWithoutCadenceOrPin
161
+ } = state, cadenceFields = normalizedSpec.kind === "interval" ? { intervalMs: normalizedSpec.intervalMs } : { cronExpression: normalizedSpec.cronExpression }, anchorFields = normalizedSpec.kind === "interval" ? { createdAt: now } : {};
162
+ let pinnedRevision, revisionFields;
163
+ if (normalizedOptions.revisionPolicy === void 0)
164
+ revisionFields = {
165
+ revisionPolicy: state.revisionPolicy,
166
+ ...state.pinnedRevision !== void 0 && { pinnedRevision: state.pinnedRevision }
167
+ };
168
+ else if (normalizedOptions.revisionPolicy === "pinned") {
169
+ pinnedRevision = await resolveScheduleRevisionForPin(internals.engine, internals, state.workflowType);
170
+ revisionFields = { revisionPolicy: "pinned", pinnedRevision };
171
+ } else
172
+ revisionFields = { revisionPolicy: "active-at-fire" };
173
+ const updatedState = {
174
+ ...stateWithoutCadenceOrPin,
158
175
  ...normalizedOptions,
159
176
  ...cadenceFields,
160
177
  ...anchorFields,
178
+ ...revisionFields,
161
179
  updatedAt: now,
162
180
  nextFireAt: state.status === "cancelled" ? null : getNextScheduleOccurrence({ ...cadenceFields, createdAt: now }, now)
163
181
  };
164
182
  await writeScheduleState(internals, updatedState, {
165
183
  includeTimer: state.status === "active",
166
- replaceTimerFrom: state
184
+ replaceTimerFrom: state,
185
+ ...await buildPinnedRevisionWriteOptions(internals, state.workflowType, pinnedRevision)
167
186
  });
168
187
  });
169
188
  }