@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,236 @@
1
+ /**
2
+ * Reference accounting and removal for the durable workflow catalog
3
+ * (WFT-12): counts in-process references to a `(name, revision)`,
4
+ * decides whether removal is safe, and performs the removal itself —
5
+ * dispatching `WorkflowRevisionRemovedEvent` on success.
6
+ *
7
+ * Also owns the two `EngineInternals.inFlightStartsByRevision` accessors
8
+ * ({@link reserveInFlightStart}/{@link releaseInFlightStart}) that
9
+ * `lifecycle/start.ts` rides alongside its existing `pendingStarts`
10
+ * reservation try/finally, kept here rather than inline in `start.ts` to
11
+ * stay well under that file's line-count ceiling.
12
+ *
13
+ * @module core/engine/catalog-removal
14
+ */
15
+ import { type WorkflowRevisionReferenceCounts } from '../catalog/index.ts';
16
+ import type { Engine } from './index.ts';
17
+ import { type EngineInternals } from './internals.ts';
18
+ type RegistrationEntry = EngineInternals['registrations'] extends Map<string, infer Entry> ? Entry : never;
19
+ /**
20
+ * Reserve one in-flight-start slot against `type`'s currently active
21
+ * revision (if any), returning the revision reserved (or `undefined` when
22
+ * `type` has no active revision yet — a start under a still-warming
23
+ * catalog, which `Engine.start()`'s own `ensureWorkflowCatalogReady` await
24
+ * prevents in practice). Called once, synchronously, before
25
+ * `startWorkflow`'s `try` block; the returned value is captured by the
26
+ * caller and passed back to {@link releaseInFlightStart} in its `finally` —
27
+ * never re-resolved, so a concurrent activation moving the pointer
28
+ * mid-start cannot decrement a different revision than was incremented.
29
+ *
30
+ * `revisionOverride` (WFT-15/16) is the revision `resolveExecutableRegistration()`
31
+ * already resolved for a `registerSource()`-registered `type` — passed
32
+ * through instead of re-deriving via `catalog.resolveActive(type)`, which
33
+ * would read `undefined` for a dynamic source with no catalog active
34
+ * pointer set (a source can resolve and install without ever being
35
+ * `engine.workflows.activate()`-d), making `inFlightStarts` diagnostics
36
+ * silently miss a lazy run in flight. `undefined` (the default) preserves
37
+ * the eager-path behavior byte-for-byte.
38
+ */
39
+ export declare function reserveInFlightStart(internals: EngineInternals, type: string, revisionOverride?: string): string | undefined;
40
+ /**
41
+ * `startWorkflow`'s combined "resolve `type`, reserve an `inFlightStarts`
42
+ * slot for the resolved revision" step. Reserves EARLY — before the loader
43
+ * is awaited, via `resolve()`'s `onRevisionChosen` hook — for a lazy type,
44
+ * closing the window where a concurrent `removeWorkflowRevision()` could
45
+ * observe zero references against a revision this call's own source load
46
+ * is about to durably (re)install; reserves afterward for an eager type,
47
+ * exactly as before WFT-15/16 (that path never invokes the hook). If the
48
+ * loader then fails — `resolve()` rejects AFTER the hook already fired — the
49
+ * early reservation is released here before rethrowing: `startWorkflow`
50
+ * only assigns its own `inFlightRevision` on a successful return, so its
51
+ * `finally` releases nothing on this path and the increment would otherwise
52
+ * leak forever, permanently reporting the revision non-`removable`.
53
+ *
54
+ * `resolvedRevision` is the raw value `resolve()` itself returned —
55
+ * `undefined` for an eager registration, the resolved candidate for a
56
+ * dynamic source — distinct from `inFlightRevision`, which for an eager
57
+ * type falls back to the catalog's cached ACTIVE pointer (see
58
+ * {@link reserveInFlightStart}). A caller that needs "the exact revision of
59
+ * the code this process is about to run" (WFT-17's `WorkflowState.revision`)
60
+ * must use `resolvedRevision`, not `inFlightRevision` — the two intentionally
61
+ * diverge for an eager type under a multi-engine deployment where this
62
+ * process's own registration lags the durable active pointer.
63
+ */
64
+ export declare function resolveAndReserveExecutableRegistration(internals: EngineInternals, type: string, resolve: (type: string, onRevisionChosen?: (revision: string) => void) => Promise<{
65
+ entry: RegistrationEntry;
66
+ revision: string | undefined;
67
+ }>): Promise<{
68
+ registration: RegistrationEntry;
69
+ inFlightRevision: string | undefined;
70
+ resolvedRevision: string | undefined;
71
+ }>;
72
+ /** Release the slot {@link reserveInFlightStart} reserved; a no-op when `revision` is `undefined`. */
73
+ export declare function releaseInFlightStart(internals: EngineInternals, type: string, revision: string | undefined): void;
74
+ /**
75
+ * Count every in-process reference this batch wires to a real signal
76
+ * against `(name, revision)`. `registeredDefinitions` and `inFlightStarts`
77
+ * are in-memory, constant-time lookups; `nonTerminalRuns` (WFT-17 — see
78
+ * {@link countNonTerminalRunsForRevision}) is an UNBOUNDED, full `wf:`-prefix
79
+ * durable scan — the same shape `groupActiveWorkflowsByType` already uses
80
+ * elsewhere for this class of diagnostic, so it's consistent with how this
81
+ * codebase already pays for this, but it is O(n) in the total number of
82
+ * workflow records, not bounded by `(name, revision)`. `removeWorkflowRevision()`
83
+ * calls this TWICE per removal attempt (its own pre-check, and
84
+ * {@link finalizeRevisionRemoval}'s post-check) — worth knowing before
85
+ * wiring `removeWorkflowRevision()` into an automated cleanup path on a
86
+ * large durable store, rather than the operator-triggered use this batch
87
+ * assumes. `pinnedSchedules` is ALSO an unbounded, full `schedule:`-prefix
88
+ * durable scan (WFT-20 — see {@link countPinnedSchedulesForRevision}), so
89
+ * this function now pays for two bounded-but-unbounded-in-store-size scans
90
+ * per call. The remaining two fields of {@link WorkflowRevisionReferenceCounts}
91
+ * stay `0` — the dispatch ledger and execution realms are out of this
92
+ * batch's scope.
93
+ */
94
+ export declare function countWorkflowRevisionReferences(engine: Engine, name: string, revision: string): Promise<WorkflowRevisionReferenceCounts>;
95
+ /**
96
+ * Outcome of {@link removeWorkflowRevision}.
97
+ *
98
+ * @example
99
+ * ```ts
100
+ * import type { WorkflowCatalogRemovalResult } from '@lostgradient/weft';
101
+ *
102
+ * function describe(result: WorkflowCatalogRemovalResult): string {
103
+ * return result.removed ? 'removed' : `kept: ${result.reason}`;
104
+ * }
105
+ * void describe;
106
+ * ```
107
+ */
108
+ export type WorkflowCatalogRemovalResult = Readonly<{
109
+ removed: true;
110
+ }> | Readonly<{
111
+ removed: false;
112
+ reason: 'not-found';
113
+ }> | Readonly<{
114
+ removed: false;
115
+ reason: 'active';
116
+ activeRevision: string;
117
+ }> | Readonly<{
118
+ removed: false;
119
+ reason: 'referenced';
120
+ references: WorkflowRevisionReferenceCounts;
121
+ }> | Readonly<{
122
+ removed: false;
123
+ reason: 'conflict';
124
+ }>;
125
+ /**
126
+ * Remove `(name, revision)` from the durable workflow catalog. Refuses when
127
+ * the revision is not installed (`'not-found'`), is the currently active
128
+ * revision (`'active'`), or is referenced by any nonzero count in
129
+ * {@link countWorkflowRevisionReferences} (`'referenced'`, carrying the
130
+ * full breakdown so a caller can report exactly what is still holding the
131
+ * revision). Refuses with `'conflict'` when the durable delete's own
132
+ * compare-and-swap loses to a concurrent writer — the caller may re-read
133
+ * and retry. Dispatches `catalog:revision-removed` on success.
134
+ *
135
+ * Checks references BOTH before and after the durable delete (WFT-17,
136
+ * Codex review on PR #958). The pre-check above is an OPTIMIZATION — it
137
+ * refuses upfront in the common case, avoiding a needless delete-then-restore
138
+ * round trip — but is not, on its own, the guarantee: a concurrent
139
+ * `engine.start()` on a DIFFERENT process could read the entry as still
140
+ * installed, and commit a NEW run pinned to `revision`, in the narrow
141
+ * window between this function's pre-check scan and its own delete CAS
142
+ * landing; the pre-check's zero-references snapshot would then be stale
143
+ * by the time the delete actually commits. The POST-check closes this: it
144
+ * is safe to trust because `start-commit.ts`'s own start batch fences on
145
+ * this exact catalog entry's bytes (`buildCatalogEntryStartPrecondition`)
146
+ * — `conditionalBatch`'s precondition is evaluated against LIVE storage
147
+ * state at commit time, so ANY start whose commit lands after this
148
+ * function's delete necessarily loses its own CAS and never creates the
149
+ * reference at all. A nonzero post-delete count can therefore only be a
150
+ * run that committed BEFORE the delete — this function restores the entry
151
+ * and reports `'referenced'` rather than leaving a real, still-referenced
152
+ * run pinned to a revision the catalog no longer carries.
153
+ *
154
+ * `catalog.remove()`'s delete and `finalizeRevisionRemoval`'s restore-or-
155
+ * finalize used to be two SEPARATE commits (WFT-17/18, Codex review on PR
156
+ * #958): a process crash between them left the revision durably uninstalled
157
+ * with NO durable record of what was deleted, recoverable by no one. Both
158
+ * halves of `removeCatalogEntry` (the delete) now land in ONE
159
+ * `conditionalBatch` with a `catalog-tombstone:<name>:<revision>` record
160
+ * (the exact deleted bytes) — see `core/catalog/removal.ts`'s module doc —
161
+ * so this function's own restore-or-finalize below is itself a SECOND
162
+ * atomic operation (not a bare `install()`/no-op), and a crash between the
163
+ * two commits leaves a durable tombstone ANY process can resolve, not just
164
+ * this one. `catalog-tombstone-recovery.ts`'s boot-time sweep and this
165
+ * function's own targeted pre-check (below) both close that residual
166
+ * window; see that module's doc for the full mechanism.
167
+ *
168
+ * @example
169
+ * ```ts
170
+ * import { Engine, removeWorkflowRevision, workflow } from '@lostgradient/weft';
171
+ *
172
+ * const engine = new Engine();
173
+ * engine.register(workflow({ name: 'checkout', version: '1.0.0' }).execute(
174
+ * async function* () { return 'ok'; },
175
+ * ));
176
+ * const result = await removeWorkflowRevision(engine, 'checkout', 'some-old-revision');
177
+ * if (!result.removed) console.log('kept:', result.reason);
178
+ * ```
179
+ */
180
+ export declare function removeWorkflowRevision(engine: Engine, name: string, revision: string): Promise<WorkflowCatalogRemovalResult>;
181
+ /**
182
+ * Bounded diagnostics projection for one `(name, revision)`, backing
183
+ * `weft.catalog.diagnostics` and `removeWorkflowRevision`'s own pre-check.
184
+ *
185
+ * @example
186
+ * ```ts
187
+ * import type { WorkflowRevisionDiagnostics } from '@lostgradient/weft';
188
+ *
189
+ * function isSafeToRemove(diagnostics: WorkflowRevisionDiagnostics): boolean {
190
+ * return diagnostics.removable;
191
+ * }
192
+ * void isSafeToRemove;
193
+ * ```
194
+ */
195
+ export type WorkflowRevisionDiagnostics = Readonly<{
196
+ name: string;
197
+ revision: string;
198
+ installed: boolean;
199
+ active: boolean;
200
+ activeRevision?: string;
201
+ references: WorkflowRevisionReferenceCounts;
202
+ removable: boolean;
203
+ /**
204
+ * Dynamic-source load diagnostics (WFT-15/16), present only when `name`
205
+ * has an entry in `internals.sources.byName` — i.e. `name` has ever been
206
+ * `registerSource()`-registered on this engine. `undefined` for a purely
207
+ * eager name, or a dynamic source this process has never heard of.
208
+ */
209
+ source?: {
210
+ kind: import('../source/index.ts').WorkflowSourceKind;
211
+ requestedRevision: string;
212
+ state: import('./source-runtime-state.ts').SourceLoadState;
213
+ loadDurationMs?: number;
214
+ lastFailureCategory?: import('../types/identity.ts').FailureCategory;
215
+ waiterCount: number;
216
+ };
217
+ }>;
218
+ /**
219
+ * Bounded diagnostics for one `(name, revision)`: whether it is installed,
220
+ * whether it is the currently active revision (and what the active
221
+ * revision is, when different), its full reference-count breakdown, and
222
+ * whether {@link removeWorkflowRevision} would currently succeed against
223
+ * it (`removable`). Never returns raw manifest or contract content — only
224
+ * identity and counts.
225
+ *
226
+ * @example
227
+ * ```ts
228
+ * import { Engine, getWorkflowRevisionDiagnostics } from '@lostgradient/weft';
229
+ *
230
+ * const engine = new Engine();
231
+ * const diagnostics = await getWorkflowRevisionDiagnostics(engine, 'checkout', 'some-revision');
232
+ * console.log(diagnostics.installed, diagnostics.removable);
233
+ * ```
234
+ */
235
+ export declare function getWorkflowRevisionDiagnostics(engine: Engine, name: string, revision: string): Promise<WorkflowRevisionDiagnostics>;
236
+ export {};
@@ -0,0 +1,123 @@
1
+ import {
2
+ decrementNestedRevisionCount,
3
+ finalizeCatalogTombstone,
4
+ incrementNestedRevisionCount,
5
+ readNestedRevisionCount,
6
+ restoreCatalogEntryFromTombstone,
7
+ totalWorkflowRevisionReferences
8
+ } from "../catalog/index.js";
9
+ import { WorkflowRevisionRemovedEvent } from "../events/catalog-events.js";
10
+ import { ensureWorkflowCatalogReady, getWorkflowCatalog } from "./catalog-readiness.js";
11
+ import { resolveCatalogTombstoneIfPresent } from "./catalog-tombstone-recovery.js";
12
+ import { getInternals } from "./internals.js";
13
+ import { countNonTerminalRunsForRevision } from "./nonterminal-revision-count.js";
14
+ import { countPinnedSchedulesForRevision } from "./pinned-schedule-revision-count.js";
15
+ import { readSourceLoadDiagnostics, readSourceWaiterCount } from "./source-diagnostics.js";
16
+ export function reserveInFlightStart(internals, type, revisionOverride) {
17
+ const revision = revisionOverride ?? internals.workflowCatalog?.resolveActive(type)?.revision;
18
+ if (revision !== void 0)
19
+ incrementNestedRevisionCount(internals.inFlightStartsByRevision, type, revision);
20
+ return revision;
21
+ }
22
+ export async function resolveAndReserveExecutableRegistration(internals, type, resolve) {
23
+ let earlyReservation;
24
+ try {
25
+ const { entry: registration, revision } = await resolve(type, (chosen) => {
26
+ earlyReservation = reserveInFlightStart(internals, type, chosen);
27
+ }), inFlightRevision = earlyReservation !== void 0 ? earlyReservation : reserveInFlightStart(internals, type, revision);
28
+ return { registration, inFlightRevision, resolvedRevision: revision };
29
+ } catch (error) {
30
+ releaseInFlightStart(internals, type, earlyReservation);
31
+ throw error;
32
+ }
33
+ }
34
+ export function releaseInFlightStart(internals, type, revision) {
35
+ if (revision !== void 0)
36
+ decrementNestedRevisionCount(internals.inFlightStartsByRevision, type, revision);
37
+ }
38
+ export async function countWorkflowRevisionReferences(engine, name, revision) {
39
+ const internals = getInternals(engine), nonTerminalRuns = await countNonTerminalRunsForRevision(internals.storage, name, revision), pinnedSchedules = await countPinnedSchedulesForRevision(internals.storage, name, revision);
40
+ return {
41
+ registeredDefinitions: internals.registeredCatalogRevisions.get(name) === revision ? 1 : 0,
42
+ inFlightStarts: readNestedRevisionCount(internals.inFlightStartsByRevision, name, revision),
43
+ nonTerminalRuns,
44
+ pinnedSchedules,
45
+ pendingDispatches: 0,
46
+ activeExecutionRealms: 0,
47
+ retainedRecoveryRecords: 0
48
+ };
49
+ }
50
+ export async function removeWorkflowRevision(engine, name, revision) {
51
+ await ensureWorkflowCatalogReady(engine);
52
+ const catalog = getWorkflowCatalog(engine), internals = getInternals(engine);
53
+ await resolveCatalogTombstoneIfPresent(internals.storage, name, revision);
54
+ if (!await catalog.hasInstalled(name, revision))
55
+ return { removed: !1, reason: "not-found" };
56
+ const active = await catalog.resolveActiveDurable(name);
57
+ if (active !== void 0 && active.revision === revision)
58
+ return { removed: !1, reason: "active", activeRevision: active.revision };
59
+ const preReferences = await countWorkflowRevisionReferences(engine, name, revision);
60
+ if (totalWorkflowRevisionReferences(preReferences) > 0)
61
+ return { removed: !1, reason: "referenced", references: preReferences };
62
+ const result = await catalog.remove(name, revision);
63
+ switch (result.outcome) {
64
+ case "removed":
65
+ return finalizeRevisionRemoval(engine, name, revision, result.tombstoneBytes);
66
+ case "not-found":
67
+ return { removed: !1, reason: "not-found" };
68
+ case "active":
69
+ return { removed: !1, reason: "active", activeRevision: result.activeRevision };
70
+ case "conflict":
71
+ return { removed: !1, reason: "conflict" };
72
+ default:
73
+ throw Error(`Unknown workflow catalog removal outcome: ${String(result)}`);
74
+ }
75
+ }
76
+ async function finalizeRevisionRemoval(engine, name, revision, tombstoneBytes) {
77
+ const internals = getInternals(engine), postReferences = await countWorkflowRevisionReferences(engine, name, revision);
78
+ if (totalWorkflowRevisionReferences(postReferences) > 0) {
79
+ await restoreCatalogEntryFromTombstone(internals.storage, name, revision, tombstoneBytes);
80
+ return { removed: !1, reason: "referenced", references: postReferences };
81
+ }
82
+ await finalizeCatalogTombstone(internals.storage, name, revision, tombstoneBytes);
83
+ engine.dispatchEvent(new WorkflowRevisionRemovedEvent(name, revision));
84
+ return { removed: !0 };
85
+ }
86
+ export async function getWorkflowRevisionDiagnostics(engine, name, revision) {
87
+ await ensureWorkflowCatalogReady(engine);
88
+ const catalog = getWorkflowCatalog(engine), installed = await catalog.hasInstalled(name, revision), activePointer = await catalog.resolveActiveDurable(name), active = activePointer !== void 0 && activePointer.revision === revision, references = await countWorkflowRevisionReferences(engine, name, revision), removable = installed && !active && totalWorkflowRevisionReferences(references) === 0, source = buildSourceDiagnostics(getInternals(engine), name, revision);
89
+ return {
90
+ name,
91
+ revision,
92
+ installed,
93
+ active,
94
+ ...activePointer !== void 0 ? { activeRevision: activePointer.revision } : {},
95
+ references,
96
+ removable,
97
+ ...source !== void 0 ? { source } : {}
98
+ };
99
+ }
100
+ function resolveDiagnosticsSourceKind(diagnostics, registeredRevisions, revision) {
101
+ if (diagnostics !== void 0)
102
+ return diagnostics.kind;
103
+ const registered = registeredRevisions.get(revision);
104
+ return registered === void 0 ? "module" : registered.descriptor.kind;
105
+ }
106
+ function buildSourceDiagnostics(internals, name, revision) {
107
+ const registeredRevisions = internals.sources.byName.get(name);
108
+ if (registeredRevisions === void 0)
109
+ return;
110
+ const diagnostics = readSourceLoadDiagnostics(internals, name, revision);
111
+ return {
112
+ kind: resolveDiagnosticsSourceKind(diagnostics, registeredRevisions, revision),
113
+ requestedRevision: revision,
114
+ state: diagnostics === void 0 ? "idle" : diagnostics.state,
115
+ ...diagnostics?.loadDurationMs !== void 0 && {
116
+ loadDurationMs: diagnostics.loadDurationMs
117
+ },
118
+ ...diagnostics?.lastFailureCategory !== void 0 && {
119
+ lastFailureCategory: diagnostics.lastFailureCategory
120
+ },
121
+ waiterCount: readSourceWaiterCount(internals, name, revision)
122
+ };
123
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Resolves durable `catalog-tombstone:<name>:<revision>` records left
3
+ * behind by {@link import('../catalog/removal.ts').removeCatalogEntry}
4
+ * (WFT-17/18, Codex review on PR #958) — a tombstone exists only in the
5
+ * brief window between its delete-and-tombstone commit and the SAME call's
6
+ * own resolution (restore or finalize), normally sub-millisecond. A
7
+ * tombstone that outlives that window is an ORPHAN: the process that
8
+ * created it crashed (or otherwise failed) before resolving it. This
9
+ * module makes that recoverable by ANY process, not just the one that
10
+ * crashed — the exact gap the tombstone design closes (see
11
+ * `core/catalog/removal.ts`'s module doc for the full mechanism).
12
+ *
13
+ * Deliberately lives in `core/engine/`, not alongside the tombstone
14
+ * primitives in `core/catalog/`: resolving an orphan needs a FRESH
15
+ * reference count, and the only reference signal meaningful for a
16
+ * crashed peer's tombstone is the durable one —
17
+ * `nonterminal-revision-count.ts`'s `wf:`-prefix scan (in-process signals
18
+ * like `registeredDefinitions`/`inFlightStarts` are per-engine-instance and
19
+ * say nothing about what a DIFFERENT, crashed process was doing).
20
+ * `core/catalog/**` never imports from `core/engine/**` — a directional
21
+ * boundary `check-import-cycles.ts` enforces — so this orchestration has to
22
+ * live on the engine side of that line.
23
+ *
24
+ * Two call sites: `catalog-readiness.ts`'s boot-time sweep (every
25
+ * orphaned tombstone in the whole store, run once per engine instance
26
+ * before recovery or any new start can observe stale state) and
27
+ * `catalog-removal.ts`'s `removeWorkflowRevision` (a single, targeted
28
+ * check for the EXACT `(name, revision)` key it is about to act on, since
29
+ * a long-lived engine could observe a peer crash mid-lifetime, after its
30
+ * own boot sweep already ran).
31
+ *
32
+ * @module core/engine/catalog-tombstone-recovery
33
+ */
34
+ import { type Storage } from '../../storage/interface.ts';
35
+ /**
36
+ * Sweep every `catalog-tombstone:` record in `storage` and resolve each
37
+ * one. Bounded by the number of orphaned tombstones actually present —
38
+ * normally zero, so this is a cheap prefix scan that yields nothing to
39
+ * iterate; only non-trivial after a real crash left orphans behind. Called
40
+ * once per engine instance, at catalog-boot time
41
+ * (`catalog-readiness.ts`), before recovery's own preflight or any fresh
42
+ * start can observe a revision this sweep would otherwise still be
43
+ * resolving.
44
+ */
45
+ export declare function resolveOrphanedCatalogTombstones(storage: Storage): Promise<void>;
46
+ /**
47
+ * Targeted check for ONE `(name, revision)` tombstone — used by
48
+ * `removeWorkflowRevision` immediately before it acts, so a peer crash
49
+ * that happened after this engine's own boot-time sweep already ran (a
50
+ * long-lived engine) does not leave a stale tombstone permanently blocking
51
+ * every future removal attempt on that exact key (`removeCatalogEntry`'s
52
+ * own CAS requires the tombstone key absent). A no-op when no tombstone is
53
+ * present for this exact key — the overwhelmingly common case, costing one
54
+ * `storage.get`.
55
+ */
56
+ export declare function resolveCatalogTombstoneIfPresent(storage: Storage, name: string, revision: string): Promise<void>;
@@ -0,0 +1,39 @@
1
+ import { KEYS } from "../../storage/interface.js";
2
+ import { tryDecodeStorageKeyComponent } from "../../storage/key-encoding.js";
3
+ import {
4
+ decodeCatalogEntryRecord,
5
+ finalizeCatalogTombstone,
6
+ restoreCatalogEntryFromTombstone
7
+ } from "../catalog/index.js";
8
+ import { countNonTerminalRunsForRevision } from "./nonterminal-revision-count.js";
9
+ function splitCatalogTombstoneKey(key) {
10
+ const parts = key.split(":");
11
+ if (parts.length !== 3)
12
+ return null;
13
+ const name = tryDecodeStorageKeyComponent(parts[1] ?? ""), revision = tryDecodeStorageKeyComponent(parts[2] ?? "");
14
+ if (name === null || revision === null)
15
+ return null;
16
+ return { name, revision };
17
+ }
18
+ async function resolveCatalogTombstone(storage, name, revision, tombstoneBytes) {
19
+ if (await countNonTerminalRunsForRevision(storage, name, revision) > 0)
20
+ await restoreCatalogEntryFromTombstone(storage, name, revision, tombstoneBytes);
21
+ else
22
+ await finalizeCatalogTombstone(storage, name, revision, tombstoneBytes);
23
+ }
24
+ export async function resolveOrphanedCatalogTombstones(storage) {
25
+ for await (const [key, bytes] of storage.scan(KEYS.catalogTombstonePrefix())) {
26
+ const split = splitCatalogTombstoneKey(key);
27
+ if (split === null)
28
+ throw Error(`The store's catalog tombstone key ("${key}") does not match the expected catalog-tombstone:<name>:<revision> shape. Treating it as absent would risk silently abandoning an in-flight catalog removal, so this fails closed instead. Resolve by operator repair: inspect the stored bytes and, only if certain no removal is actually in flight, delete the key.`);
29
+ await decodeCatalogEntryRecord(key, bytes, split.name, split.revision);
30
+ await resolveCatalogTombstone(storage, split.name, split.revision, bytes);
31
+ }
32
+ }
33
+ export async function resolveCatalogTombstoneIfPresent(storage, name, revision) {
34
+ const tombstoneKey = KEYS.catalogTombstone(name, revision), tombstoneBytes = await storage.get(tombstoneKey);
35
+ if (tombstoneBytes === null)
36
+ return;
37
+ await decodeCatalogEntryRecord(tombstoneKey, tombstoneBytes, name, revision);
38
+ await resolveCatalogTombstone(storage, name, revision, tombstoneBytes);
39
+ }
@@ -1,9 +1,13 @@
1
1
  import { ConstraintViolatedEvent } from "../events.js";
2
+ import { getResolvedDynamicRegistration } from "./dynamic-source-execution.js";
3
+ function resolveRunningInstanceRevision(internals, workflowId) {
4
+ return internals.workflowTypeByWorkflowId.get(workflowId)?.revision;
5
+ }
2
6
  export async function evaluateConstraints(internals, workflowId, callbacks) {
3
7
  const context = internals.inlineStrategy?.getContext(workflowId);
4
8
  if (!context)
5
9
  return !1;
6
- const constraints = internals.registrations.get(context.workflowType)?.constraints;
10
+ const revision = resolveRunningInstanceRevision(internals, workflowId), constraints = getResolvedDynamicRegistration(internals, context.workflowType, revision)?.constraints;
7
11
  if (!constraints || constraints.length === 0)
8
12
  return !1;
9
13
  const stateSnapshot = {
@@ -32,7 +32,7 @@ export type NormalizedWorkerExecutionConfiguration = {
32
32
  discardOnCancel: true;
33
33
  };
34
34
  export declare function definitionEntries<TDefinition extends object>(definitions: Record<string, TDefinition> | undefined): Array<[string, TDefinition]>;
35
- export declare function typedEngineView<TViewWorkflows extends object, TViewActivities extends object>(engine: object, _phantomTypes?: readonly [TViewWorkflows, TViewActivities]): never;
35
+ export declare function typedEngineView(engine: object): never;
36
36
  export declare function readEnvironmentVariableFromSources(name: string, sources: {
37
37
  bunEnv?: Record<string, string | undefined> | undefined;
38
38
  processEnv?: Record<string, string | undefined> | undefined;
@@ -50,7 +50,7 @@ export declare function createExecutionStrategyBundle(parameters: {
50
50
  maxNestingDepth: number;
51
51
  development: boolean;
52
52
  broadcastEvents: boolean;
53
- getRegistration: (workflowType: string) => RegistrationEntry | undefined;
53
+ getRegistration: (workflowType: string, workflowId: string) => RegistrationEntry | undefined;
54
54
  /** Live accessor for registered workflow type names (WFT-28); registrations are still empty here. */
55
55
  listRegisteredWorkflowTypes: () => Iterable<string>;
56
56
  getComposedWorkflowInterceptor?: () => ComposedWorkflowInterceptor | null;
@@ -15,6 +15,7 @@ import {
15
15
  DEFAULT_WORKER_TURN_TIMEOUT_MS,
16
16
  MIN_WORKER_PROTOCOL_MESSAGE_BYTES
17
17
  } from "../worker-protocol.js";
18
+ import { copyFinalizerMetadata } from "./finalizer-metadata.js";
18
19
  import { resolveBackgroundTaskMode, resolveOwnershipFields } from "./ownership-options.js";
19
20
  import {
20
21
  normalizeHistoryPolicy,
@@ -25,7 +26,7 @@ import {
25
26
  export function definitionEntries(definitions) {
26
27
  return Object.entries(definitions ?? {});
27
28
  }
28
- export function typedEngineView(engine, _phantomTypes) {
29
+ export function typedEngineView(engine) {
29
30
  return engine;
30
31
  }
31
32
  let didWarnOnMemoryStorageFallback = !1;
@@ -76,7 +77,8 @@ export function copyWorkflowDefinition(type, registration) {
76
77
  ...registration.updates === void 0 ? {} : { updates: { ...registration.updates } },
77
78
  ...registration.queries === void 0 ? {} : { queries: { ...registration.queries } },
78
79
  ...registration.searchAttributes === void 0 ? {} : { searchAttributes: registration.searchAttributes },
79
- ...registration.concurrency === void 0 ? {} : { concurrency: registration.concurrency }
80
+ ...registration.concurrency === void 0 ? {} : { concurrency: registration.concurrency },
81
+ ...copyFinalizerMetadata(registration.finalizer)
80
82
  };
81
83
  }
82
84
  function resolveRetentionFields(options) {
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Decoded-`revision` sanitization for {@link import('./validation.ts').decodeWorkflowState}.
3
+ * Split out of `validation.ts`, which has no headroom under the repository's
4
+ * 500-line implementation-file ceiling.
5
+ *
6
+ * @module core/engine/decode-revision
7
+ */
8
+ import type { WorkflowState } from '../types.ts';
9
+ /**
10
+ * Normalize a decoded `revision` that is present but not a non-empty,
11
+ * bounded string.
12
+ *
13
+ * Deliberately NEVER drops a present-but-malformed value to `undefined` —
14
+ * `revision` is engine-derived (never user-supplied at the API surface), so
15
+ * an invalid value here indicates storage corruption or tampering, and
16
+ * `undefined` is the SAME signal a genuinely missing `revision` carries
17
+ * (a legitimate pre-revision-pinning record). Recovery treats an
18
+ * `undefined` pin as unambiguous for an eager type or a dynamic source with
19
+ * at most one registered candidate — silently executing that sole
20
+ * candidate against a checkpoint whose true originating revision is
21
+ * actually unknown, rather than rejecting the damaged identity. Instead,
22
+ * a malformed value is replaced with a deterministic, distinctly-prefixed
23
+ * marker derived from the workflow id: still a valid, bounded `string`, but
24
+ * virtually guaranteed not to match any real registered candidate, so the
25
+ * ordinary `resolveExecutableRegistrationForRevision()` "not-registered"
26
+ * path rejects it explicitly (an `unavailable` recovery outcome, isolated
27
+ * to that one run) instead of silently downgrading it to "legacy."
28
+ *
29
+ * Only a genuinely absent `revision` (never persisted at all) returns
30
+ * early, unchanged, above.
31
+ */
32
+ export declare function sanitizeDecodedRevision(state: WorkflowState): void;
@@ -0,0 +1,9 @@
1
+ const MAX_WORKFLOW_REVISION_LENGTH = 512, CORRUPTED_WORKFLOW_REVISION_PREFIX = "weft:corrupted-revision:";
2
+ export function sanitizeDecodedRevision(state) {
3
+ if (state.revision === void 0)
4
+ return;
5
+ if (typeof state.revision === "string" && state.revision.length > 0 && state.revision.length <= MAX_WORKFLOW_REVISION_LENGTH)
6
+ return;
7
+ console.warn(`[weft] Decoded workflow state for "${state.id}" has a malformed revision field; replacing it with a corruption marker so recovery rejects it explicitly as an unavailable pin, rather than silently treating this run as pre-revision-pinning. This usually indicates corruption or tampering of the storage record.`);
8
+ state.revision = `${CORRUPTED_WORKFLOW_REVISION_PREFIX}${state.id}`.slice(0, MAX_WORKFLOW_REVISION_LENGTH);
9
+ }
@@ -4,6 +4,10 @@ import type { EngineInternals } from './internals.ts';
4
4
  * `Engine[Symbol.dispose]` — the operation order is correctness-sensitive
5
5
  * (abort before clearing waiters, dispose strategies before nulling them) and
6
6
  * is preserved exactly. `Engine[Symbol.dispose]` and `[Symbol.asyncDispose]`
7
- * both delegate here.
7
+ * both delegate here. `dispatchEvent` defaults to a no-op so every existing
8
+ * direct-internals test that calls this with one argument keeps compiling
9
+ * and running — only `Engine`'s own two call sites pass the real
10
+ * `engine.dispatchEvent` binding, which is what lets
11
+ * `disposeSourceResolutionState` fire `workflow-source:load-cancelled`.
8
12
  */
9
- export declare function disposeEngine(internals: EngineInternals): void;
13
+ export declare function disposeEngine(internals: EngineInternals, dispatchEvent?: (event: Event) => void): void;
@@ -1,3 +1,4 @@
1
+ import { WorkflowSourceLoadCancelledEvent } from "../events/workflow-source-events.js";
1
2
  import { disposeEngineCleanupInterval } from "./engine-runtime-helpers.js";
2
3
  import { EngineDisposedError } from "./errors.js";
3
4
  import { disposeQueuedInlineWorkflowStarts } from "./inline-launch-queue.js";
@@ -13,7 +14,29 @@ function clearPendingResultPollTimers(internals) {
13
14
  clearTimeout(timer);
14
15
  internals.pendingResultPollTimers.clear();
15
16
  }
16
- export function disposeEngine(internals) {
17
+ function rejectPendingResultResolvers(internals) {
18
+ for (const waiter of internals.resultResolvers.values())
19
+ waiter.reject(new EngineDisposedError);
20
+ }
21
+ function disposeSourceResolutionState(internals, dispatchEvent) {
22
+ for (const controller of internals.sources.waiterControllers)
23
+ controller.abort(new EngineDisposedError);
24
+ const stillLoading = [];
25
+ for (const [name, byRevision] of internals.sources.diagnostics)
26
+ for (const [revision, entry] of byRevision)
27
+ if (entry.state === "loading")
28
+ stillLoading.push({ name, revision, kind: entry.kind });
29
+ internals.sources.waiterControllers.clear();
30
+ internals.sources.resolutionsInFlight.clear();
31
+ internals.sources.byName.clear();
32
+ internals.sources.resolved.clear();
33
+ internals.sources.waitersByKey.clear();
34
+ internals.sources.lastResolvedRevisionByName.clear();
35
+ internals.sources.diagnostics.clear();
36
+ for (const { name, revision, kind } of stillLoading)
37
+ dispatchEvent(new WorkflowSourceLoadCancelledEvent(name, revision, kind));
38
+ }
39
+ export function disposeEngine(internals, dispatchEvent = () => {}) {
17
40
  internals.disposed = !0;
18
41
  internals.alertManager?.[Symbol.dispose]();
19
42
  internals.alertManager = null;
@@ -40,8 +63,7 @@ export function disposeEngine(internals) {
40
63
  disposeSecondInstanceDetection(internals);
41
64
  disposeLeaseManager(internals);
42
65
  internals.handleCache.clear();
43
- for (const waiter of internals.resultResolvers.values())
44
- waiter.reject(new EngineDisposedError);
66
+ rejectPendingResultResolvers(internals);
45
67
  rejectAllSleepTimerAcknowledgements(internals, new EngineDisposedError);
46
68
  internals.resultResolvers.clear();
47
69
  internals.updateWaiters.clear();
@@ -57,6 +79,7 @@ export function disposeEngine(internals) {
57
79
  for (const controller of internals.pendingWebhooks)
58
80
  controller.abort();
59
81
  internals.pendingWebhooks.clear();
82
+ disposeSourceResolutionState(internals, dispatchEvent);
60
83
  clearPendingResultPollTimers(internals);
61
84
  internals.sleepResolvers.clear();
62
85
  internals.sleepResolversByWorkflow.clear();