@lostgradient/weft 0.24.0 → 0.24.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. package/README.md +2 -2
  2. package/dist/cli/conformance.js +5 -2
  3. package/dist/cli/generated/operation-catalog.snapshot.json +95 -1
  4. package/dist/cli/generated/operation-client.generated.d.ts +28 -2
  5. package/dist/cli/generated/operation-client.generated.js +2 -0
  6. package/dist/cli/parse-schedule-arguments.js +15 -3
  7. package/dist/cli/schedule.js +2 -1
  8. package/dist/cli/types.d.ts +2 -1
  9. package/dist/client/http-client-requests.js +6 -9
  10. package/dist/client/start-body.js +1 -0
  11. package/dist/core/catalog/index.d.ts +2 -2
  12. package/dist/core/catalog/index.js +9 -2
  13. package/dist/core/catalog/reference-counts.d.ts +29 -14
  14. package/dist/core/catalog/removal.d.ts +63 -10
  15. package/dist/core/catalog/removal.js +18 -2
  16. package/dist/core/catalog/storage-io.d.ts +23 -0
  17. package/dist/core/catalog/storage-io.js +1 -1
  18. package/dist/core/engine/activity-resolution.js +17 -17
  19. package/dist/core/engine/bulk-operations-purge.d.ts +1 -1
  20. package/dist/core/engine/bulk-operations-purge.js +17 -22
  21. package/dist/core/engine/bulk-operations-retry.d.ts +24 -0
  22. package/dist/core/engine/bulk-operations-retry.js +190 -0
  23. package/dist/core/engine/bulk-operations-shared.d.ts +18 -0
  24. package/dist/core/engine/bulk-operations-shared.js +14 -0
  25. package/dist/core/engine/bulk-operations.d.ts +3 -2
  26. package/dist/core/engine/bulk-operations.js +10 -169
  27. package/dist/core/engine/callback-creators-bundles.js +5 -3
  28. package/dist/core/engine/callback-creators-core.js +9 -1
  29. package/dist/core/engine/callback-creators-schedule.js +2 -2
  30. package/dist/core/engine/catalog-readiness.js +2 -0
  31. package/dist/core/engine/catalog-removal.d.ts +107 -3
  32. package/dist/core/engine/catalog-removal.js +66 -13
  33. package/dist/core/engine/catalog-tombstone-recovery.d.ts +56 -0
  34. package/dist/core/engine/catalog-tombstone-recovery.js +39 -0
  35. package/dist/core/engine/child-workflow.d.ts +13 -1
  36. package/dist/core/engine/child-workflow.js +22 -4
  37. package/dist/core/engine/constraints.js +5 -1
  38. package/dist/core/engine/construction.d.ts +1 -1
  39. package/dist/core/engine/decode-revision.d.ts +32 -0
  40. package/dist/core/engine/decode-revision.js +9 -0
  41. package/dist/core/engine/disposal.d.ts +6 -2
  42. package/dist/core/engine/disposal.js +24 -10
  43. package/dist/core/engine/dynamic-source-errors.d.ts +81 -0
  44. package/dist/core/engine/dynamic-source-errors.js +25 -0
  45. package/dist/core/engine/dynamic-source-execution.d.ts +173 -0
  46. package/dist/core/engine/dynamic-source-execution.js +108 -0
  47. package/dist/core/engine/engine-internal-types.d.ts +16 -0
  48. package/dist/core/engine/engine-workflows-namespace.d.ts +10 -0
  49. package/dist/core/engine/engine-workflows-namespace.js +3 -1
  50. package/dist/core/engine/generation-codec.d.ts +22 -0
  51. package/dist/core/engine/generation-codec.js +2 -0
  52. package/dist/core/engine/index.d.ts +18 -10
  53. package/dist/core/engine/index.js +22 -11
  54. package/dist/core/engine/inline-launch-queue.js +1 -1
  55. package/dist/core/engine/internals.d.ts +26 -30
  56. package/dist/core/engine/lifecycle/checkpoint-launch.d.ts +29 -0
  57. package/dist/core/engine/lifecycle/checkpoint-launch.js +75 -0
  58. package/dist/core/engine/lifecycle/delayed-start-registration.d.ts +30 -0
  59. package/dist/core/engine/lifecycle/delayed-start-registration.js +11 -0
  60. package/dist/core/engine/lifecycle/fork-helpers.d.ts +33 -1
  61. package/dist/core/engine/lifecycle/fork-helpers.js +3 -1
  62. package/dist/core/engine/lifecycle/recovery-isolation.d.ts +20 -0
  63. package/dist/core/engine/lifecycle/recovery-isolation.js +26 -0
  64. package/dist/core/engine/lifecycle/recovery-revision-groups.d.ts +75 -0
  65. package/dist/core/engine/lifecycle/recovery-revision-groups.js +64 -0
  66. package/dist/core/engine/lifecycle/resume-body.d.ts +44 -0
  67. package/dist/core/engine/lifecycle/resume-body.js +211 -0
  68. package/dist/core/engine/lifecycle/resume-generation-guard.d.ts +58 -0
  69. package/dist/core/engine/lifecycle/resume-generation-guard.js +11 -0
  70. package/dist/core/engine/lifecycle/resume.d.ts +46 -3
  71. package/dist/core/engine/lifecycle/resume.js +21 -201
  72. package/dist/core/engine/lifecycle/shared.d.ts +43 -0
  73. package/dist/core/engine/lifecycle/standalone-claim-acquire.d.ts +80 -2
  74. package/dist/core/engine/lifecycle/standalone-claim-acquire.js +20 -4
  75. package/dist/core/engine/lifecycle/start-commit-errors.d.ts +12 -0
  76. package/dist/core/engine/lifecycle/start-commit-errors.js +6 -0
  77. package/dist/core/engine/lifecycle/start-commit.d.ts +24 -7
  78. package/dist/core/engine/lifecycle/start-commit.js +57 -15
  79. package/dist/core/engine/lifecycle/start-exec.d.ts +18 -2
  80. package/dist/core/engine/lifecycle/start-exec.js +7 -5
  81. package/dist/core/engine/lifecycle/start-or-signal-create.js +1 -3
  82. package/dist/core/engine/lifecycle/start-or-signal-resolution.d.ts +8 -2
  83. package/dist/core/engine/lifecycle/start-or-signal-resolution.js +11 -3
  84. package/dist/core/engine/lifecycle/start-or-signal.js +1 -1
  85. package/dist/core/engine/lifecycle/start-precondition-attribution.d.ts +55 -0
  86. package/dist/core/engine/lifecycle/start-precondition-attribution.js +13 -0
  87. package/dist/core/engine/lifecycle/start-revision-resolution.d.ts +34 -0
  88. package/dist/core/engine/lifecycle/start-revision-resolution.js +11 -0
  89. package/dist/core/engine/lifecycle/start-schedule-timing.d.ts +11 -0
  90. package/dist/core/engine/lifecycle/start-schedule-timing.js +21 -0
  91. package/dist/core/engine/lifecycle/start-state.d.ts +16 -0
  92. package/dist/core/engine/lifecycle/start-state.js +60 -0
  93. package/dist/core/engine/lifecycle/start-terminal-conflict-purge.d.ts +146 -4
  94. package/dist/core/engine/lifecycle/start-terminal-conflict-purge.js +33 -4
  95. package/dist/core/engine/lifecycle/start.d.ts +54 -7
  96. package/dist/core/engine/lifecycle/start.js +53 -90
  97. package/dist/core/engine/lifecycle/transition.d.ts +12 -4
  98. package/dist/core/engine/lifecycle/transition.js +40 -95
  99. package/dist/core/engine/lifecycle.d.ts +5 -2
  100. package/dist/core/engine/lifecycle.js +7 -6
  101. package/dist/core/engine/listing.js +15 -1
  102. package/dist/core/engine/memo-durable-activity.js +4 -1
  103. package/dist/core/engine/nonterminal-revision-count.d.ts +25 -0
  104. package/dist/core/engine/nonterminal-revision-count.js +16 -0
  105. package/dist/core/engine/operations-time.d.ts +5 -23
  106. package/dist/core/engine/operations-time.js +13 -11
  107. package/dist/core/engine/ownership-bootstrap.d.ts +1 -1
  108. package/dist/core/engine/pinned-schedule-revision-count.d.ts +26 -0
  109. package/dist/core/engine/pinned-schedule-revision-count.js +19 -0
  110. package/dist/core/engine/pinned-schedule-revision.d.ts +76 -0
  111. package/dist/core/engine/pinned-schedule-revision.js +53 -0
  112. package/dist/core/engine/registration.d.ts +30 -0
  113. package/dist/core/engine/registration.js +17 -2
  114. package/dist/core/engine/retention.js +9 -2
  115. package/dist/core/engine/revision-errors.d.ts +71 -0
  116. package/dist/core/engine/revision-errors.js +13 -0
  117. package/dist/core/engine/schedule-overlap.js +2 -1
  118. package/dist/core/engine/schedule-revision-fire.d.ts +17 -0
  119. package/dist/core/engine/schedule-revision-fire.js +3 -0
  120. package/dist/core/engine/schedule-run.d.ts +10 -0
  121. package/dist/core/engine/schedule-run.js +2 -1
  122. package/dist/core/engine/schedules.d.ts +11 -1
  123. package/dist/core/engine/schedules.js +28 -9
  124. package/dist/core/engine/source-diagnostics.d.ts +76 -0
  125. package/dist/core/engine/source-diagnostics.js +105 -0
  126. package/dist/core/engine/source-registration.js +4 -2
  127. package/dist/core/engine/source-resolution.d.ts +25 -9
  128. package/dist/core/engine/source-resolution.js +49 -14
  129. package/dist/core/engine/source-runtime-state.d.ts +92 -0
  130. package/dist/core/engine/source-runtime-state.js +36 -0
  131. package/dist/core/engine/storage-io.d.ts +19 -2
  132. package/dist/core/engine/storage-io.js +21 -2
  133. package/dist/core/engine/termination/complete.js +1 -1
  134. package/dist/core/engine/termination/finalizer-registration.d.ts +18 -0
  135. package/dist/core/engine/termination/finalizer-registration.js +21 -0
  136. package/dist/core/engine/termination/finalizer.d.ts +16 -19
  137. package/dist/core/engine/termination/finalizer.js +3 -3
  138. package/dist/core/engine/termination/suspend.js +3 -0
  139. package/dist/core/engine/time-operation-callbacks.d.ts +32 -0
  140. package/dist/core/engine/time-operation-callbacks.js +0 -0
  141. package/dist/core/engine/validation/schedule-cadence.d.ts +16 -0
  142. package/dist/core/engine/validation/schedule-cadence.js +20 -0
  143. package/dist/core/engine/validation/schedule-options.d.ts +4 -1
  144. package/dist/core/engine/validation/schedule-options.js +14 -0
  145. package/dist/core/engine/validation/schedule-revision.d.ts +24 -0
  146. package/dist/core/engine/validation/schedule-revision.js +21 -0
  147. package/dist/core/engine/validation/schedule-warnings.d.ts +11 -0
  148. package/dist/core/engine/validation/schedule-warnings.js +5 -0
  149. package/dist/core/engine/validation/schedule.d.ts +29 -4
  150. package/dist/core/engine/validation/schedule.js +19 -36
  151. package/dist/core/engine/validation.js +13 -17
  152. package/dist/core/engine/workflow-claim-reclaim-target.d.ts +1 -1
  153. package/dist/core/engine/workflow-claim-reclaim-target.js +22 -8
  154. package/dist/core/engine/workflow-claim-registry.d.ts +79 -75
  155. package/dist/core/engine/workflow-claim-registry.js +15 -2
  156. package/dist/core/engine/workflow-generation-fence.d.ts +74 -0
  157. package/dist/core/engine/workflow-generation-fence.js +19 -0
  158. package/dist/core/engine/workflow-retention-deadline.d.ts +16 -0
  159. package/dist/core/engine/workflow-retention-deadline.js +33 -0
  160. package/dist/core/events/event-map.d.ts +5 -0
  161. package/dist/core/events/index.d.ts +1 -0
  162. package/dist/core/events/index.js +1 -0
  163. package/dist/core/events/workflow-source-events.d.ts +102 -0
  164. package/dist/core/events/workflow-source-events.js +57 -0
  165. package/dist/core/execution-strategy.d.ts +7 -0
  166. package/dist/core/inline-execution-strategy.context-options.d.ts +1 -1
  167. package/dist/core/inline-execution-strategy.js +1 -1
  168. package/dist/core/start-workflow-validation.d.ts +15 -0
  169. package/dist/core/start-workflow-validation.js +11 -1
  170. package/dist/core/types/checkpoint.d.ts +14 -0
  171. package/dist/core/types/schedules.d.ts +52 -1
  172. package/dist/core/types/state.d.ts +16 -0
  173. package/dist/core/weft-error.d.ts +1 -1
  174. package/dist/core/weft-error.js +4 -1
  175. package/dist/core/worker-execution-strategy.d.ts +1 -0
  176. package/dist/core/worker-execution-strategy.js +13 -1
  177. package/dist/core/worker-fault-handling.d.ts +10 -0
  178. package/dist/core/worker-fault-handling.js +1 -0
  179. package/dist/core/worker-inbound-message.d.ts +1 -0
  180. package/dist/core/worker-inbound-message.js +1 -0
  181. package/dist/core/worker-protocol-guard.js +4 -0
  182. package/dist/core/worker-protocol.d.ts +7 -0
  183. package/dist/core/worker-protocol.js +2 -1
  184. package/dist/core/worker-turn-watchdog.d.ts +8 -1
  185. package/dist/core/worker-turn-watchdog.js +3 -2
  186. package/dist/core/workflow-identifiers.d.ts +37 -0
  187. package/dist/core/workflow-identifiers.js +19 -1
  188. package/dist/diagnostics/format.js +5 -0
  189. package/dist/diagnostics/types.d.ts +24 -0
  190. package/dist/diagnostics/version-check.js +8 -2
  191. package/dist/http.js +2 -2
  192. package/dist/index.d.ts +3 -3
  193. package/dist/index.js +7 -0
  194. package/dist/indexeddb.js +1 -1
  195. package/dist/json-schema.js +3 -3
  196. package/dist/server/fault-to-json-rpc.js +2 -1
  197. package/dist/server/fleet-event-feed.js +6 -6
  198. package/dist/server/index.d.ts +11 -0
  199. package/dist/server/operation-fault.d.ts +2 -0
  200. package/dist/server/operation-fault.js +2 -1
  201. package/dist/server/operations/create-schedule.d.ts +2 -0
  202. package/dist/server/operations/create-schedule.js +10 -6
  203. package/dist/server/operations/get-catalog-diagnostics.d.ts +28 -0
  204. package/dist/server/operations/get-catalog-diagnostics.js +10 -2
  205. package/dist/server/operations/get-task-detail-schema.d.ts +8 -0
  206. package/dist/server/operations/get-task-detail-schema.js +1 -0
  207. package/dist/server/operations/get-task-detail.d.ts +8 -0
  208. package/dist/server/operations/get-task-detail.js +1 -0
  209. package/dist/server/operations/get-task-diagnostics.d.ts +4 -4
  210. package/dist/server/operations/preload-workflow-revision.d.ts +28 -0
  211. package/dist/server/operations/preload-workflow-revision.js +60 -0
  212. package/dist/server/operations/schedule-faults.d.ts +1 -0
  213. package/dist/server/operations/schedule-faults.js +32 -4
  214. package/dist/server/operations/schedule-rest-body.d.ts +1 -0
  215. package/dist/server/operations/schedule-rest-body.js +2 -1
  216. package/dist/server/operations/static-registrations.js +6 -0
  217. package/dist/server/operations/update-schedule.d.ts +2 -0
  218. package/dist/server/operations/update-schedule.js +4 -2
  219. package/dist/server/operations/workflow-catalog-operation-helpers.js +27 -0
  220. package/dist/server/rest-binding.d.ts +11 -0
  221. package/dist/server/runtime/task-dispatch-envelope.d.ts +41 -0
  222. package/dist/server/runtime/task-dispatch-envelope.js +54 -0
  223. package/dist/server/runtime/task-dispatch-revision.d.ts +29 -0
  224. package/dist/server/runtime/task-dispatch-revision.js +13 -0
  225. package/dist/server/runtime/task-dispatch.d.ts +3 -1
  226. package/dist/server/runtime/task-dispatch.js +20 -44
  227. package/dist/server/runtime/task-ledger-recovery.js +1 -1
  228. package/dist/server/runtime/task-ledger-runtime.d.ts +14 -2
  229. package/dist/server/runtime/task-ledger-runtime.js +5 -3
  230. package/dist/server/runtime/task-polling.js +9 -3
  231. package/dist/server/runtime/task-reconciliation.js +2 -1
  232. package/dist/server/runtime/websocket-worker.js +9 -0
  233. package/dist/server/task-ledger-codec.d.ts +28 -0
  234. package/dist/server/task-ledger-codec.js +7 -1
  235. package/dist/server/task-ledger-transition-helpers.js +1 -0
  236. package/dist/server/task-ledger-types.d.ts +9 -0
  237. package/dist/server/task-ledger.d.ts +1 -1
  238. package/dist/server/task-ledger.js +3 -1
  239. package/dist/server/task-queue-types.d.ts +2 -0
  240. package/dist/storage/bun-sql.js +135 -100
  241. package/dist/storage/catalog-keys.d.ts +19 -0
  242. package/dist/storage/catalog-keys.js +3 -1
  243. package/dist/storage/compressed-storage.js +1 -1
  244. package/dist/storage/generation-keys.d.ts +52 -0
  245. package/dist/storage/generation-keys.js +4 -0
  246. package/dist/storage/index.d.ts +76 -63
  247. package/dist/storage/interface.d.ts +24 -230
  248. package/dist/storage/interface.js +1 -1
  249. package/dist/storage/key-prefixes.d.ts +1 -1
  250. package/dist/storage/key-prefixes.js +2 -0
  251. package/dist/storage/lease-keys.d.ts +48 -0
  252. package/dist/storage/lease-keys.js +8 -0
  253. package/dist/storage/lmdb.d.ts +30 -2
  254. package/dist/storage/lmdb.js +1 -1
  255. package/dist/storage/memory.js +1 -1
  256. package/dist/storage/neon.js +3 -3
  257. package/dist/storage/node-sqlite.js +135 -100
  258. package/dist/storage/postgres.js +3 -3
  259. package/dist/storage/resolve.js +1 -1
  260. package/dist/storage/scoped-storage.js +1 -1
  261. package/dist/storage/signal-keys.d.ts +23 -0
  262. package/dist/storage/signal-keys.js +9 -0
  263. package/dist/storage/testing.js +1 -1
  264. package/dist/storage/turso.js +2 -2
  265. package/dist/storage/workflow-lifecycle-keys.d.ts +128 -0
  266. package/dist/storage/workflow-lifecycle-keys.js +46 -0
  267. package/dist/storage/workflow-record-keys.d.ts +98 -0
  268. package/dist/storage/workflow-record-keys.js +47 -0
  269. package/dist/version.d.ts +1 -1
  270. package/dist/version.js +1 -1
  271. package/dist/web-extension.js +1 -1
  272. package/dist/worker/protocol-messages.d.ts +17 -0
  273. package/dist/worker/protocol-schemas.d.ts +32 -0
  274. package/dist/worker/protocol-schemas.js +7 -3
  275. package/dist/worker/protocol-task-result.js +35 -3
  276. package/dist/worker/protocol.js +1 -1
  277. package/dist/worker/registry/types.d.ts +2 -0
  278. package/dist/worker/registry.d.ts +1 -1
  279. package/dist/worker/registry.js +3 -1
  280. package/dist/workers/workflow-runner.d.ts +9 -0
  281. package/dist/workers/workflow-runner.js +9 -2
  282. package/dist/workers/workflow-worker-entry.js +9 -4
  283. package/package.json +2 -2
@@ -0,0 +1,26 @@
1
+ import { RegExpExtensionDecodeError } from "../../codec/extension-codec.js";
2
+ import { VersionMismatchError } from "../../versioning.js";
3
+ import { DynamicWorkflowSourceUnavailableError } from "../dynamic-source-errors.js";
4
+ import { WorkflowClaimUnavailableError } from "../lease-errors.js";
5
+ import { WorkflowRevisionUnavailableError } from "../revision-errors.js";
6
+ export async function isolateRecoveryFailure(workflowId, callbacks, options, error) {
7
+ if (error instanceof RegExpExtensionDecodeError) {
8
+ await callbacks.failWorkflowForCheckpointDecodeError(workflowId, error);
9
+ return null;
10
+ }
11
+ if (error instanceof VersionMismatchError && options?.versionMismatchPolicy !== "throw") {
12
+ await callbacks.failWorkflowForVersionMismatch(workflowId, error);
13
+ return null;
14
+ }
15
+ if (error instanceof WorkflowClaimUnavailableError)
16
+ return null;
17
+ if (error instanceof WorkflowRevisionUnavailableError) {
18
+ await callbacks.failWorkflowForRevisionUnavailable(workflowId, error);
19
+ return null;
20
+ }
21
+ if (error instanceof DynamicWorkflowSourceUnavailableError) {
22
+ await callbacks.failWorkflowForUnavailableDynamicSource(workflowId, error);
23
+ return null;
24
+ }
25
+ throw error;
26
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * `recoverAll()`'s per-`(type, revision)` preload barrier (WFT-17/WFT-18),
3
+ * replacing the per-`type`-only barrier `recovery-dynamic-sources.ts` used
4
+ * to own. Split out of `transition.ts`, which has no headroom under the
5
+ * repository's 500-line implementation-file ceiling for this logic inline
6
+ * — the same reason `recovery-dynamic-sources.ts` was split out for
7
+ * WFT-15/16.
8
+ *
9
+ * Recovery scans non-terminal workflow states, groups them by their exact
10
+ * `(type, revision)` pin (a legacy record with no persisted `revision`
11
+ * groups under `undefined` for its type), and preloads/classifies every
12
+ * group BEFORE any group's runs advance — ready, or unavailable with the
13
+ * error every run in that group fails with. Grouping and classification use
14
+ * nested `Map<type, Map<revision, …>>` structures rather than a
15
+ * delimiter-joined composite key, so an arbitrary workflow `type` or
16
+ * `revision` string can never collide with a delimiter.
17
+ *
18
+ * @module core/engine/lifecycle/recovery-revision-groups
19
+ */
20
+ import { DynamicWorkflowSourceUnavailableError } from '../dynamic-source-errors.ts';
21
+ import type { EngineInternals } from '../internals.ts';
22
+ import { WorkflowRevisionUnavailableError } from '../revision-errors.ts';
23
+ import type { LifecycleCallbacks } from './shared.ts';
24
+ /** One preflight-recoverable entry's identity, as `transition.ts`'s preflight scan produces it. */
25
+ export type RecoverableRevisionEntry = {
26
+ readonly workflowId: string;
27
+ readonly type: string;
28
+ readonly revision: string | undefined;
29
+ };
30
+ /** One `(type, revision)` group: every non-terminal run pinned to that exact revision. */
31
+ export type RecoveryRevisionGroup = {
32
+ readonly type: string;
33
+ readonly revision: string | undefined;
34
+ readonly workflowIds: readonly string[];
35
+ };
36
+ /** `type -> revision -> group`. A legacy entry (no persisted `revision`) groups under the `undefined` key. */
37
+ export type RecoveryRevisionGroups = ReadonlyMap<string, ReadonlyMap<string | undefined, RecoveryRevisionGroup>>;
38
+ /**
39
+ * Group preflight-recoverable entries by their exact `(type, revision)` pin.
40
+ * Every non-terminal run pinned to the same revision of the same type lands
41
+ * in one group, regardless of scan order.
42
+ */
43
+ export declare function buildRecoveryRevisionGroups(entries: readonly RecoverableRevisionEntry[]): RecoveryRevisionGroups;
44
+ /** Outcome of classifying one `(type, revision)` group. */
45
+ export type RevisionGroupClassification = {
46
+ readonly status: 'ready';
47
+ } | {
48
+ readonly status: 'unavailable';
49
+ readonly error: WorkflowRevisionUnavailableError | DynamicWorkflowSourceUnavailableError;
50
+ };
51
+ /** `type -> revision -> classification`, mirroring {@link RecoveryRevisionGroups}'s shape. */
52
+ export type RevisionGroupClassifications = ReadonlyMap<string, ReadonlyMap<string | undefined, RevisionGroupClassification>>;
53
+ /**
54
+ * Resolve every `(type, revision)` group to `'ready'` or `'unavailable'`,
55
+ * concurrently, one `resolveExecutableRegistrationForRevision()` call per
56
+ * group — even when many non-terminal runs share the same pin. An eager
57
+ * type's groups are omitted from the result entirely (eager is always
58
+ * ready and needs no preload call); only dynamic-source groups are
59
+ * classified. A disposal mid-preload aborts the whole barrier by
60
+ * rethrowing, matching `recoverEntryOrIsolateFailure`'s own un-isolated
61
+ * treatment of {@link EngineDisposedError}.
62
+ */
63
+ export declare function classifyRevisionGroups(internals: EngineInternals, callbacks: LifecycleCallbacks, groups: RecoveryRevisionGroups): Promise<RevisionGroupClassifications>;
64
+ /**
65
+ * Wrap `callbacks` so `recoverAll()`'s own per-entry `resume()` calls below
66
+ * see a batch's cached `classifyRevisionGroups()` failure for the entry's
67
+ * `(type, revision)` group, WITHOUT touching any state shared with other
68
+ * callers. `classifications` is a plain, closure-local `Map` structure —
69
+ * nothing outside `recoverAll()` ever sees it, so a concurrent, unrelated
70
+ * `engine.start()`, `engine.resume()`, or a second concurrent `recoverAll()`
71
+ * batch for the SAME `(type, revision)` keeps using the real, un-wrapped
72
+ * `callbacks.resolveExecutableRegistrationForRevision` and can never observe
73
+ * (or race the reset of) this batch's classification.
74
+ */
75
+ export declare function createRecoveryScopedRevisionCallbacks(callbacks: LifecycleCallbacks, classifications: RevisionGroupClassifications): LifecycleCallbacks;
@@ -0,0 +1,64 @@
1
+ import { DynamicWorkflowSourceUnavailableError } from "../dynamic-source-errors.js";
2
+ import { EngineDisposedError } from "../errors.js";
3
+ import { WorkflowRevisionUnavailableError } from "../revision-errors.js";
4
+ export function buildRecoveryRevisionGroups(entries) {
5
+ const groups = new Map;
6
+ for (const entry of entries) {
7
+ let byRevision = groups.get(entry.type);
8
+ if (byRevision === void 0) {
9
+ byRevision = new Map;
10
+ groups.set(entry.type, byRevision);
11
+ }
12
+ const existing = byRevision.get(entry.revision);
13
+ if (existing === void 0)
14
+ byRevision.set(entry.revision, {
15
+ type: entry.type,
16
+ revision: entry.revision,
17
+ workflowIds: [entry.workflowId]
18
+ });
19
+ else
20
+ existing.workflowIds.push(entry.workflowId);
21
+ }
22
+ return groups;
23
+ }
24
+ export async function classifyRevisionGroups(internals, callbacks, groups) {
25
+ const dynamicGroups = [];
26
+ for (const [type, byRevision] of groups) {
27
+ if (internals.registrations.has(type))
28
+ continue;
29
+ dynamicGroups.push(...byRevision.values());
30
+ }
31
+ const results = new Map;
32
+ if (dynamicGroups.length === 0)
33
+ return results;
34
+ const settled = await Promise.allSettled(dynamicGroups.map((group) => callbacks.resolveExecutableRegistrationForRevision(group.type, group.revision)));
35
+ for (const [index, outcome] of settled.entries()) {
36
+ const group = dynamicGroups[index];
37
+ let byRevision = results.get(group.type);
38
+ if (byRevision === void 0) {
39
+ byRevision = new Map;
40
+ results.set(group.type, byRevision);
41
+ }
42
+ if (outcome.status === "fulfilled") {
43
+ byRevision.set(group.revision, { status: "ready" });
44
+ continue;
45
+ }
46
+ const reason = outcome.reason;
47
+ if (reason instanceof EngineDisposedError)
48
+ throw reason;
49
+ const error = reason instanceof WorkflowRevisionUnavailableError || reason instanceof DynamicWorkflowSourceUnavailableError ? reason : new DynamicWorkflowSourceUnavailableError(group.type, group.revision, "load-failed", reason);
50
+ byRevision.set(group.revision, { status: "unavailable", error });
51
+ }
52
+ return results;
53
+ }
54
+ export function createRecoveryScopedRevisionCallbacks(callbacks, classifications) {
55
+ return {
56
+ ...callbacks,
57
+ resolveExecutableRegistrationForRevision: (type, revision) => {
58
+ const classification = classifications.get(type)?.get(revision);
59
+ if (classification?.status === "unavailable")
60
+ return Promise.reject(classification.error);
61
+ return callbacks.resolveExecutableRegistrationForRevision(type, revision);
62
+ }
63
+ };
64
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * `resumeWorkflowFromStorage()`'s guts — split out of `resume.ts`, which has
3
+ * no headroom under the repository's 500-line implementation-file ceiling
4
+ * for the WFT-134 claim-release wrapping added around this logic (mirrors
5
+ * `resume-generation-guard.ts`'s same split). `resume.ts` itself is now just
6
+ * the public entry point: load/validate state, acquire a claim if needed,
7
+ * and call {@link performResumeAfterClaimAcquired} below inside the
8
+ * claim-release `try`/`catch`.
9
+ *
10
+ * @module core/engine/lifecycle/resume-body
11
+ */
12
+ import { type EventHeadRecord } from '../../event-log.ts';
13
+ import type { Checkpoint, WorkflowState } from '../../types.ts';
14
+ import { type WorkflowVersionTuple } from '../../workflow-version-tuple.ts';
15
+ import { type WorkflowHandle } from '../handles.ts';
16
+ import type { EngineInternals } from '../internals.ts';
17
+ import { deriveResumeGeneration } from './resume-generation-guard.ts';
18
+ import { type LifecycleCallbacks, type RecoverAllOptions, type RegistrationEntry } from './shared.ts';
19
+ export type SerializedResumeArgs = {
20
+ workflowId: string;
21
+ resumeCheckpoint: Checkpoint;
22
+ serializedCheckpoint: Uint8Array;
23
+ registeredVersionTuple: WorkflowVersionTuple;
24
+ restoredHead: EventHeadRecord;
25
+ workflowStartHeaders: Map<string, string> | undefined;
26
+ registration: RegistrationEntry;
27
+ /**
28
+ * The EXACT revision `registration` resolved against, NOT `state.revision`
29
+ * re-read independently (WFT-19 round 5): a legacy record with one registered
30
+ * candidate has `state.revision === undefined` even though the resolver
31
+ * resolved it — caching `state.revision` here would disable exact-revision lookup.
32
+ */
33
+ resolvedRevision: string | undefined;
34
+ expectedGeneration: ReturnType<typeof deriveResumeGeneration>;
35
+ callbacks: LifecycleCallbacks;
36
+ };
37
+ /**
38
+ * Everything `resumeWorkflowFromStorage` does once a claim (if any) is
39
+ * acquired: load tracking/checkpoint/registration state, prepare the resume,
40
+ * and either relaunch inline or in a worker. `resumeWorkflowFromStorage`
41
+ * itself just wraps a call to this in the WFT-134 claim-release
42
+ * `try`/`catch`.
43
+ */
44
+ export declare function performResumeAfterClaimAcquired(internals: EngineInternals, workflowId: string, state: WorkflowState, dispatchResumedEvent: boolean, callbacks: LifecycleCallbacks, onRecoveredWorkflow?: RecoverAllOptions['onRecoveredWorkflow']): Promise<WorkflowHandle>;
@@ -0,0 +1,211 @@
1
+ import { KEYS } from "../../../storage/interface.js";
2
+ import { deserializeCheckpoint, serializeCheckpoint } from "../../checkpoint.js";
3
+ import { encode } from "../../codec.js";
4
+ import { Context, setContextWorkflowInterceptor } from "../../context.js";
5
+ import { EventLog } from "../../event-log.js";
6
+ import { WorkflowResumedEvent } from "../../events.js";
7
+ import { buildTimerBatchOperations } from "../../scheduler.js";
8
+ import { createCancelHandlerRegistration, resetCancelHandlers } from "../cancel-handlers.js";
9
+ import { rememberCommittedCheckpointBytes } from "../checkpoint-commit-snapshots.js";
10
+ import { rehydrateChildCancellationHandlers } from "../child-workflow-cancellation.js";
11
+ import { resolveExecutableRegistrationOrRenamedNotFound } from "../dynamic-source-execution.js";
12
+ import { commitFencedEngineWrite } from "../fenced-write.js";
13
+ import { getWorkflowExecutionStartedAt } from "../handles.js";
14
+ import { loadWorkflowState } from "../storage-io.js";
15
+ import { getComposedWorkflowInterceptor } from "../strategy-helpers.js";
16
+ import { buildWorkflowVisibilityIndexTransition } from "../workflow-indexes.js";
17
+ import { prepareResumeState } from "./persist.js";
18
+ import {
19
+ reprovideRecoveredServices,
20
+ workflowServicesResolverInfoFromState
21
+ } from "./recovered-services.js";
22
+ import { assertSameGeneration, deriveResumeGeneration } from "./resume-generation-guard.js";
23
+ import {
24
+ enforceHistoryPolicyBeforeReplay,
25
+ loadTerminalCleanupTrackedState,
26
+ loadWorkflowStartHeaders,
27
+ setWorkflowStartHeaders
28
+ } from "./shared.js";
29
+ async function prepareRecoveredServicesOrFail(internals, state, callbacks, resolverInfo) {
30
+ return reprovideRecoveredServices(internals, state, callbacks.failWorkflowForUnavailableServices, callbacks.handleCleanupError, callbacks.dispatchEvent, resolverInfo);
31
+ }
32
+ async function runRecoveredWorkflowHookOrFail(internals, state, handle, resolverInfo, onRecoveredWorkflow, callbacks) {
33
+ const info = {
34
+ ...resolverInfo,
35
+ handle,
36
+ launchOptions: resolverInfo.launchOptions ?? { id: state.id },
37
+ services: internals.workflowServices.get(state.id)
38
+ };
39
+ try {
40
+ await onRecoveredWorkflow(info);
41
+ return !1;
42
+ } catch (error) {
43
+ const reason = error instanceof Error ? error.message : String(error), hookError = Error(`Recovery hook failed for workflow "${state.id}": ${reason}`);
44
+ try {
45
+ await callbacks.failWorkflowForRecoveryHook(state.id, hookError);
46
+ } catch (commitError) {
47
+ callbacks.handleCleanupError("onRecoveredWorkflow", commitError, state.id);
48
+ }
49
+ return !0;
50
+ }
51
+ }
52
+ async function prepareRecoveredWorkflowOrFail(internals, state, callbacks, onRecoveredWorkflow) {
53
+ const resolverInfo = onRecoveredWorkflow === void 0 ? void 0 : await workflowServicesResolverInfoFromState(internals, state), handle = callbacks.getHandle(state.id);
54
+ if (await prepareRecoveredServicesOrFail(internals, state, callbacks, resolverInfo))
55
+ return { handle, shouldStop: !0 };
56
+ if (onRecoveredWorkflow === void 0 || resolverInfo === void 0)
57
+ return { handle, shouldStop: !1 };
58
+ const shouldStop = await runRecoveredWorkflowHookOrFail(internals, state, handle, resolverInfo, onRecoveredWorkflow, callbacks);
59
+ return { handle, shouldStop };
60
+ }
61
+ function assertResumeNotTerminating(internals, workflowId) {
62
+ if (internals.terminalizingWorkflows.has(workflowId))
63
+ throw Error(`Cannot resume workflow "${workflowId}": termination is in progress`);
64
+ }
65
+ function commitSerializedResumeState(internals, args) {
66
+ const {
67
+ workflowId,
68
+ resumeCheckpoint,
69
+ serializedCheckpoint,
70
+ registeredVersionTuple,
71
+ restoredHead,
72
+ callbacks
73
+ } = args;
74
+ internals.checkpoints.set(workflowId, resumeCheckpoint);
75
+ rememberCommittedCheckpointBytes(internals, workflowId, serializedCheckpoint);
76
+ internals.workflowVersionTuples.set(workflowId, registeredVersionTuple);
77
+ internals.eventLogHeads.set(workflowId, restoredHead);
78
+ setWorkflowStartHeaders(internals, workflowId, args.workflowStartHeaders, callbacks);
79
+ internals.parkedInlineWorkflows.delete(workflowId);
80
+ }
81
+ async function relaunchInlineWorkflowAfterResume(internals, latestState, args) {
82
+ const { workflowId, resumeCheckpoint, registration, resolvedRevision, callbacks } = args, accumulatedResults = new Map(resumeCheckpoint.accumulatedResults), workflowAbort = new AbortController;
83
+ internals.workflowTypeByWorkflowId.set(workflowId, {
84
+ type: latestState.type,
85
+ revision: resolvedRevision
86
+ });
87
+ resetCancelHandlers(internals, workflowId);
88
+ await rehydrateChildCancellationHandlers(internals, workflowId, callbacks);
89
+ const context = new Context({
90
+ workflowId,
91
+ ...latestState.workflowExecutionToken !== void 0 && {
92
+ workflowExecutionToken: latestState.workflowExecutionToken
93
+ },
94
+ workflowType: latestState.type,
95
+ startedAt: getWorkflowExecutionStartedAt(latestState),
96
+ abortController: workflowAbort,
97
+ getNow: internals.options.getNow,
98
+ resolveWorkflowType: callbacks.resolveWorkflowTypeTarget,
99
+ executionStateOwnerId: latestState.executionStateOwnerId ?? workflowId,
100
+ accumulatedResults,
101
+ locals: resumeCheckpoint.locals,
102
+ searchAttributes: resumeCheckpoint.searchAttributes,
103
+ registerCancelHandler: createCancelHandlerRegistration(internals, workflowId),
104
+ ...registration.searchAttributes && {
105
+ searchAttributeSchema: registration.searchAttributes
106
+ },
107
+ sleepReferenceTime: resumeCheckpoint.createdAt,
108
+ ...latestState.executionDeadline !== void 0 && {
109
+ deadline: latestState.executionDeadline
110
+ },
111
+ services: internals.workflowServices.get(workflowId),
112
+ ...internals.options.onLog != null && { logSink: internals.options.onLog }
113
+ });
114
+ setContextWorkflowInterceptor(context, getComposedWorkflowInterceptor(internals));
115
+ if (internals.options.development)
116
+ context.explain(!0);
117
+ const generator = registration.handler(context, latestState.input), inlineStrategy = internals.inlineStrategy;
118
+ inlineStrategy.adoptWorkflow(workflowId, generator, context, workflowAbort);
119
+ inlineStrategy.continueWorkflow(workflowId, void 0);
120
+ }
121
+ async function relaunchWorkerWorkflowAfterResume(internals, latestState, args) {
122
+ const { workflowId, resumeCheckpoint, workflowStartHeaders, resolvedRevision, callbacks } = args;
123
+ internals.workflowTypeByWorkflowId.set(workflowId, {
124
+ type: latestState.type,
125
+ revision: resolvedRevision
126
+ });
127
+ resetCancelHandlers(internals, workflowId);
128
+ await rehydrateChildCancellationHandlers(internals, workflowId, callbacks);
129
+ const serialized = serializeCheckpoint(resumeCheckpoint);
130
+ internals.strategy.startWorkflow({
131
+ workflowId,
132
+ ...latestState.workflowExecutionToken !== void 0 && {
133
+ workflowExecutionToken: latestState.workflowExecutionToken
134
+ },
135
+ workflowType: latestState.type,
136
+ input: latestState.input,
137
+ checkpoint: serialized,
138
+ nestingDepth: internals.workflowNestingDepths.get(workflowId) ?? 0,
139
+ executionStateOwnerId: latestState.executionStateOwnerId ?? workflowId,
140
+ ...latestState.executionDeadline !== void 0 && {
141
+ deadline: latestState.executionDeadline
142
+ },
143
+ ...workflowStartHeaders !== void 0 && workflowStartHeaders.size > 0 && {
144
+ headers: [...workflowStartHeaders]
145
+ }
146
+ });
147
+ }
148
+ async function reactivateSuspendedWorkflowState(internals, state) {
149
+ if (state.status !== "suspended")
150
+ return;
151
+ const previousState = { ...state };
152
+ state.status = "running";
153
+ state.updatedAt = internals.options.getNow();
154
+ await commitFencedEngineWrite(internals, state.id, [
155
+ { type: "put", key: KEYS.workflow(state.id), value: encode(state) },
156
+ ...buildWorkflowVisibilityIndexTransition(state.id, previousState, state).batchOps,
157
+ ...state.executionDeadline !== void 0 ? buildTimerBatchOperations({
158
+ id: `deadline:${state.id}`,
159
+ workflowId: state.id,
160
+ fireAt: state.executionDeadline,
161
+ kind: "execution-deadline"
162
+ }) : []
163
+ ], [], () => Error(`Resume of workflow "${state.id}" lost its CAS race.`));
164
+ }
165
+ async function performSerializedResume(internals, args) {
166
+ const { workflowId } = args;
167
+ assertResumeNotTerminating(internals, workflowId);
168
+ const latestState = await loadWorkflowState(internals, workflowId);
169
+ assertResumeNotTerminating(internals, workflowId);
170
+ if (!latestState)
171
+ throw Error(`Workflow "${workflowId}" not found in storage`);
172
+ if (latestState.status !== "running" && latestState.status !== "suspended")
173
+ throw Error(`Cannot resume workflow "${workflowId}": status is "${latestState.status}", expected "running" or "suspended"`);
174
+ assertSameGeneration(workflowId, latestState, args.expectedGeneration);
175
+ await reactivateSuspendedWorkflowState(internals, latestState);
176
+ commitSerializedResumeState(internals, args);
177
+ if (internals.inlineStrategy) {
178
+ await relaunchInlineWorkflowAfterResume(internals, latestState, args);
179
+ return;
180
+ }
181
+ await relaunchWorkerWorkflowAfterResume(internals, latestState, args);
182
+ }
183
+ export async function performResumeAfterClaimAcquired(internals, workflowId, state, dispatchResumedEvent, callbacks, onRecoveredWorkflow) {
184
+ await loadTerminalCleanupTrackedState(internals, workflowId, callbacks);
185
+ const checkpointBytes = await internals.storage.get(KEYS.checkpoint(workflowId));
186
+ if (!checkpointBytes)
187
+ throw Error(`Checkpoint not found for workflow "${workflowId}"`);
188
+ const checkpoint = deserializeCheckpoint(checkpointBytes), { entry: registration, revision: resolvedRevision } = await resolveExecutableRegistrationOrRenamedNotFound((type) => callbacks.resolveExecutableRegistrationForRevision(type, state.revision), state.type, () => Error(`No workflow registered with name "${state.type}" (needed to resume "${workflowId}")`)), preparedResumeState = await prepareResumeState(internals, workflowId, state, checkpoint, checkpointBytes, registration, callbacks), resumeCheckpoint = preparedResumeState.checkpoint, registeredVersionTuple = preparedResumeState.versionTuple, restoredHead = await new EventLog(internals.storage, workflowId).loadHead();
189
+ if (await enforceHistoryPolicyBeforeReplay(internals, workflowId, restoredHead, callbacks))
190
+ return callbacks.getHandle(workflowId);
191
+ const workflowStartHeaders = await loadWorkflowStartHeaders(internals, workflowId, callbacks), { handle, shouldStop } = await prepareRecoveredWorkflowOrFail(internals, state, callbacks, onRecoveredWorkflow);
192
+ if (shouldStop)
193
+ return handle;
194
+ await callbacks.runSerializedWorkflowStateWrite(workflowId, () => performSerializedResume(internals, {
195
+ workflowId,
196
+ resumeCheckpoint,
197
+ serializedCheckpoint: preparedResumeState.serializedCheckpoint,
198
+ registeredVersionTuple,
199
+ restoredHead,
200
+ workflowStartHeaders,
201
+ registration,
202
+ resolvedRevision,
203
+ expectedGeneration: deriveResumeGeneration(state),
204
+ callbacks
205
+ }));
206
+ if (dispatchResumedEvent)
207
+ callbacks.dispatchEvent(new WorkflowResumedEvent(workflowId, resumeCheckpoint.step));
208
+ if (internals.inlineStrategy)
209
+ callbacks.swallowPromiseRejection(callbacks.processPendingUpdatesAfterInlineAdvance(workflowId));
210
+ return handle;
211
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * `resumeWorkflowFromStorage()`'s generation-identity re-check (WFT-19
3
+ * review round 7, chatgpt-codex-connector + stevekinney) — split out of
4
+ * `resume.ts`, which has no headroom under the repository's 500-line
5
+ * implementation-file ceiling for this doc-heavy addition.
6
+ *
7
+ * @module core/engine/lifecycle/resume-generation-guard
8
+ */
9
+ import type { WorkflowState } from '../../types.ts';
10
+ /**
11
+ * The generation a resume's `registration`/`resumeCheckpoint`/`resolvedRevision`
12
+ * were all resolved against — captured from the SAME `WorkflowState` decoded
13
+ * at the very top of `resumeWorkflowFromStorage()`, before
14
+ * `acquireStandaloneClaimBeforeResume`, the checkpoint load, and registration
15
+ * resolution all ran.
16
+ *
17
+ * `performSerializedResume()` re-reads workflow state fresh inside its
18
+ * serialized section but (before this guard existed) only re-checked
19
+ * `status` — never identity. An `onTerminalConflict: 'start-new'`
20
+ * replacement landing on this SAME `workflowId` between the top-of-function
21
+ * read and the serialized section's fresh read (e.g. a concurrent
22
+ * cancel/timeout terminalizes this run, then a fresh `start()` call replaces
23
+ * it) purges the old record and writes a brand-new one — new
24
+ * `type`/`revision` possibly, and ALWAYS a fresh `workflowExecutionToken`
25
+ * (`crypto.randomUUID()`, minted by every `start()` — see
26
+ * `start-state.ts`'s `buildInitialIdentitySlice`). Without
27
+ * {@link assertSameGeneration}, the stale `registration`/
28
+ * `resumeCheckpoint` a resume closure already built would replay against the
29
+ * replacement's fresh state: `commitSerializedResumeState` populates
30
+ * `internals.checkpoints` from the OLD checkpoint, and
31
+ * `relaunchInlineWorkflowAfterResume` drives the OLD handler — silently
32
+ * corrupting the replacement's run.
33
+ *
34
+ * A DIFFERENT engine's replacement is additionally caught earlier, by
35
+ * `acquireStandaloneClaimBeforeResume`'s durable `wakeOwnershipCheck`
36
+ * (workflow-lease mode only) — but that check compares only holder
37
+ * identity/epoch, never workflow identity, so a SAME-engine replacement
38
+ * (whose fold-acquire updates this engine's own already-held claim in
39
+ * place, leaving the epoch check trivially satisfied) is not caught there.
40
+ * This guard closes that gap for every ownership mode, not just
41
+ * workflow-lease.
42
+ */
43
+ export type ResumeGeneration = {
44
+ type: string;
45
+ revision: string | undefined;
46
+ workflowExecutionToken: string | undefined;
47
+ };
48
+ /** Captures {@link ResumeGeneration} off the `WorkflowState` a resume decoded at its top, before any `await`. */
49
+ export declare function deriveResumeGeneration(state: WorkflowState): ResumeGeneration;
50
+ /**
51
+ * Throws when `latestState` — freshly re-read inside `performSerializedResume()`'s
52
+ * serialized section — no longer belongs to the same generation `expected`
53
+ * names. See {@link ResumeGeneration}'s doc for the exact race this
54
+ * closes. All three fields are compared — `workflowExecutionToken` alone
55
+ * would miss a legacy record that carries `undefined` on both sides of the
56
+ * race.
57
+ */
58
+ export declare function assertSameGeneration(workflowId: string, latestState: WorkflowState, expected: ResumeGeneration): void;
@@ -0,0 +1,11 @@
1
+ export function deriveResumeGeneration(state) {
2
+ return {
3
+ type: state.type,
4
+ revision: state.revision,
5
+ workflowExecutionToken: state.workflowExecutionToken
6
+ };
7
+ }
8
+ export function assertSameGeneration(workflowId, latestState, expected) {
9
+ if (latestState.workflowExecutionToken !== expected.workflowExecutionToken || latestState.type !== expected.type || latestState.revision !== expected.revision)
10
+ throw Error(`Cannot resume workflow "${workflowId}": its persisted state changed generation (a replacement run landed at this same id) between resume's registration lookup ` + "and its serialized commit \u2014 retry against the new generation instead of replaying " + "stale state.");
11
+ }
@@ -1,4 +1,47 @@
1
- import { type WorkflowHandle } from '../handles.ts';
1
+ /**
2
+ * `engine.resume(id)` / `recoverAll()`'s standalone-replay-from-storage entry
3
+ * point. The actual work — load tracking/checkpoint/registration state,
4
+ * prepare the resume, and relaunch inline or in a worker — lives in
5
+ * `resume-body.ts`'s `performResumeAfterClaimAcquired` (split out to stay
6
+ * under this repository's 500-line implementation-file ceiling once the
7
+ * WFT-134 claim-release wrapping below was added). This file's own job is
8
+ * just: load and validate state, acquire a claim if this run doesn't already
9
+ * hold one, and release a claim it freshly acquired if the resume turns out
10
+ * not to succeed after all — UNLESS `options.deferClaimReleaseOnRejection`
11
+ * asks this call to leave that claim installed for its caller instead (see
12
+ * {@link ResumeFromStorageOptions}).
13
+ *
14
+ * @module core/engine/lifecycle/resume
15
+ */
16
+ import type { WorkflowHandle } from '../handles.ts';
2
17
  import type { EngineInternals } from '../internals.ts';
3
- import { type LifecycleCallbacks, type RecoverAllOptions } from './shared.ts';
4
- export declare function resumeWorkflowFromStorage(internals: EngineInternals, workflowId: string, dispatchResumedEvent: boolean, callbacks: LifecycleCallbacks, onRecoveredWorkflow?: RecoverAllOptions['onRecoveredWorkflow']): Promise<WorkflowHandle>;
18
+ import type { LifecycleCallbacks, RecoverAllOptions } from './shared.ts';
19
+ /**
20
+ * An out-parameter this call populates with the epoch of a claim it freshly
21
+ * acquired, so a caller using `deferClaimReleaseOnRejection` can release that
22
+ * EXACT generation itself once it is done using it (WFT-134 review round 2,
23
+ * issue D). Left at `{ epoch: null }` when no fresh acquisition happened —
24
+ * folding disabled, no registry, the cached claim matched, or acquisition
25
+ * itself threw `WorkflowClaimUnavailableError` before returning.
26
+ */
27
+ export type FreshResumeClaimTracker = {
28
+ epoch: number | null;
29
+ };
30
+ /** Options for {@link resumeWorkflowFromStorage}. */
31
+ export type ResumeFromStorageOptions = {
32
+ /**
33
+ * `true` for `recoverAll()`'s per-entry recovery loop (WFT-134 issue D):
34
+ * its own `recoverEntryOrIsolateFailure` isolates several errors into a
35
+ * fenced `failWorkflowForXxx()` commit that needs a freshly-acquired claim
36
+ * to still be installed, so this call must NOT release on rejection —
37
+ * instead it records the acquired epoch in `freshClaimTracker` and lets the
38
+ * caller release once its own isolated-failure handling is done. Default
39
+ * (`false`/omitted) is correct for an explicit `engine.resume()` caller,
40
+ * which has nothing further to do with the claim and must release
41
+ * immediately on any rejection.
42
+ */
43
+ deferClaimReleaseOnRejection?: boolean;
44
+ /** Populated with the freshly-acquired epoch, if any — see {@link FreshResumeClaimTracker}. */
45
+ freshClaimTracker?: FreshResumeClaimTracker;
46
+ };
47
+ export declare function resumeWorkflowFromStorage(internals: EngineInternals, workflowId: string, dispatchResumedEvent: boolean, callbacks: LifecycleCallbacks, onRecoveredWorkflow?: RecoverAllOptions['onRecoveredWorkflow'], options?: ResumeFromStorageOptions): Promise<WorkflowHandle>;