@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
@@ -3,6 +3,20 @@ import type { ConstraintDefinition } from '../constraint.ts';
3
3
  import type { ExecutionStrategy } from '../execution-strategy.ts';
4
4
  import type { InlineExecutionStrategy } from '../inline-execution-strategy.ts';
5
5
  import type { AnyActivityDefinition, ArchiveAdapter, Checkpoint, DefinitionSchema, EngineOptions, NormalizedHistoryPolicy, NormalizedPayloadSizePolicy, NormalizedRetentionPolicy, QueryDefinition, SearchAttributeSchema, SignalDefinition, UpdateDefinition, WorkflowConcurrencyOptions, WorkflowFunction, WorkflowTimelineEntry } from '../types.ts';
6
+ /**
7
+ * The identity a running workflow instance was launched under, cached by
8
+ * `EngineInternals.workflowTypeByWorkflowId` for the lifetime of its
9
+ * execution (WFT-19). `revision` is the exact `WorkflowState.revision` this
10
+ * instance is pinned to (WFT-17) — `undefined` for an eager registration or
11
+ * a legacy (pre-pinning) record — so a process-local lookup keyed by
12
+ * `workflowId` can resolve THIS instance's own dynamic-source revision
13
+ * rather than falling back to whichever revision this process resolved
14
+ * last.
15
+ */
16
+ export type WorkflowExecutionIdentity = {
17
+ type: string;
18
+ revision: string | undefined;
19
+ };
6
20
  export interface RegistrationEntry {
7
21
  handler: WorkflowFunction;
8
22
  version: string;
@@ -103,6 +117,8 @@ export type QueuedInlineWorkflowExecutionStart = {
103
117
  nestingDepth: number;
104
118
  executionDeadline: number | undefined;
105
119
  executionStateOwnerId: string;
120
+ /** The exact revision this queued start is pinned to (WFT-17/WFT-19). */
121
+ revision: string | undefined;
106
122
  /**
107
123
  * Liveness callback invoked once this queued start has actually begun
108
124
  * executing (its generator has been driven). Set only for `defer: false`
@@ -33,6 +33,7 @@ import { type WorkflowCatalogActivationResult, type WorkflowCatalogActivePointer
33
33
  import type { WorkflowCompatibilityPolicy } from '../contract/compatibility.ts';
34
34
  import type { WorkflowRevisionManifest } from '../contract/types.ts';
35
35
  import type { Engine } from './index.ts';
36
+ import { type ResolveWorkflowSourceOptions } from './source-resolution.ts';
36
37
  /**
37
38
  * Options accepted by {@link EngineWorkflowsNamespace.activate}.
38
39
  *
@@ -125,6 +126,15 @@ export interface EngineWorkflowsNamespace {
125
126
  getRevision(name: string, revision: string): Promise<WorkflowRevisionRecord | null>;
126
127
  /** Every installed revision of `name`, sorted deterministically by revision. */
127
128
  listRevisions(name: string): Promise<readonly WorkflowRevisionRecord[]>;
129
+ /**
130
+ * Load, validate, and install one dynamic workflow source revision
131
+ * previously recorded via `engine.registerSource()` (WFT-15/16). A thin,
132
+ * documented alias for `engine.resolveWorkflowSource()` — identical
133
+ * single-flight, cancellation, and error contract — offered here so
134
+ * deployment tooling that already reaches for `engine.workflows.*` for
135
+ * every other catalog operation does not need a second entry point.
136
+ */
137
+ preload(name: string, revision: string, options?: ResolveWorkflowSourceOptions): Promise<WorkflowRevisionRecord>;
128
138
  }
129
139
  /** Build the `engine.workflows` namespace object for `engine`. */
130
140
  export declare function createEngineWorkflowsNamespace(engine: Engine): EngineWorkflowsNamespace;
@@ -8,6 +8,7 @@ import {
8
8
  isWorkflowCatalogReady
9
9
  } from "./catalog-readiness.js";
10
10
  import { WorkflowNotRegisteredError } from "./errors.js";
11
+ import { resolveWorkflowSource } from "./source-resolution.js";
11
12
  async function ensureCatalogReady(engine) {
12
13
  if (!isWorkflowCatalogReady(engine))
13
14
  await ensureWorkflowCatalogReady(engine);
@@ -44,6 +45,7 @@ export function createEngineWorkflowsNamespace(engine) {
44
45
  activate: (name, revision, options) => activateWorkflowRevision(engine, name, revision, options),
45
46
  getActive: (name) => getActiveWorkflowRevision(engine, name),
46
47
  getRevision: (name, revision) => getInstalledWorkflowRevision(engine, name, revision),
47
- listRevisions: (name) => listInstalledWorkflowRevisions(engine, name)
48
+ listRevisions: (name) => listInstalledWorkflowRevisions(engine, name),
49
+ preload: (name, revision, options) => resolveWorkflowSource(engine, name, revision, options)
48
50
  };
49
51
  }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Pure codec for the durable per-workflow-id generation counter
3
+ * (`wf-gen:<id>`, WFT-153).
4
+ *
5
+ * Reuses `lease-codec.ts`'s `encodeEpoch`/`decodeEpoch` under
6
+ * generation-specific names rather than reimplementing them: both are
7
+ * permanently-retained monotonic uint64 counters minted the same way
8
+ * (`(observed ?? 0) + 1`, never a literal), so sharing one encoder/decoder
9
+ * keeps their on-disk representation byte-identical and their validity range
10
+ * ([1, MAX_SAFE_INTEGER)) — fail-closed on corruption — in lockstep by
11
+ * construction rather than by convention.
12
+ *
13
+ * @module core/engine/generation-codec
14
+ */
15
+ import { decodeEpoch, encodeEpoch } from './lease-codec.ts';
16
+ /** Encode an 8-byte big-endian uint64 generation. See `lease-codec.ts#encodeEpoch`. */
17
+ export declare const encodeGeneration: typeof encodeEpoch;
18
+ /**
19
+ * Decode an 8-byte big-endian uint64 generation, or `null` when the stored
20
+ * value is not a usable generation. See `lease-codec.ts#decodeEpoch`.
21
+ */
22
+ export declare const decodeGeneration: typeof decodeEpoch;
@@ -0,0 +1,2 @@
1
+ import { decodeEpoch, encodeEpoch } from "./lease-codec.js";
2
+ export const encodeGeneration = encodeEpoch, decodeGeneration = decodeEpoch;
@@ -30,6 +30,7 @@ export { ActivityReconciliationCapabilityError, ActivityReconciliationConflictEr
30
30
  export { AsyncActivityTokenNotFoundError } from './async-activity-completion.ts';
31
31
  export type { PendingAsyncActivity } from './async-activity-records.ts';
32
32
  export { getWorkflowRevisionDiagnostics, removeWorkflowRevision, type WorkflowCatalogRemovalResult, type WorkflowRevisionDiagnostics, } from './catalog-removal.ts';
33
+ export { DynamicWorkflowSourceUnavailableError, WorkflowSourceNotRegisteredError, } from './dynamic-source-errors.ts';
33
34
  export type { PendingTimelineEntry, RegistrationEntry, ResolvedOptions, TrackedWaiterKeys, WorkflowResultWaiter, } from './engine-internal-types.ts';
34
35
  export { ActivityResolutionError, BulkDeleteRequiresTerminalWorkflowsError, BulkOperationConfirmationError, EngineCreateNameMismatchError, EngineDisposalError, EngineDisposedError, IdempotencyKeyPurgedError, PersistedDataCorruptError, PersistedDataIncompatibleError, StartOrSignalConflictError, WorkflowAlreadyExistsError, WorkflowConcurrencyLimitExceededError, WorkflowNotFoundError, WorkflowNotRegisteredError, WorkflowSuspendNotSupportedError, WorkflowTeardownPendingError, WorkflowTypeNotRegisteredForRecoveryError, } from './errors.ts';
35
36
  export { HANDLE_RESULT_PROMISE, WorkflowHandle } from './handles.ts';
@@ -39,6 +40,7 @@ export type { WorkflowWakeKind } from './lease-deposition.ts';
39
40
  export { EngineLeaseAcquisitionTimeoutError, EngineLeaseCorruptedError, EngineLeaseNotHeldError, OwnershipModeMismatchError, WorkflowClaimUnavailableError, } from './lease-errors.ts';
40
41
  export type { EngineLeaseHealth, LeaseLostReason } from './lease-health.ts';
41
42
  export type { RecoverAllOptions, RecoveredWorkflowInfo } from './lifecycle.ts';
43
+ export { WorkflowRevisionUnavailableError } from './revision-errors.ts';
42
44
  export { ScheduleHandle } from './schedule-handle.ts';
43
45
  export type { ResolveWorkflowSourceOptions } from './source-resolution.ts';
44
46
  export type { WorkflowFeedListener, WorkflowFeedRecord, WorkflowFeedSelector, } from './workflow-feed.ts';
@@ -299,11 +301,15 @@ export declare class Engine<TWorkflows extends object = DefaultWorkflowRegistry,
299
301
  getActivityDefinition(name: string): ActivityMetadata | undefined;
300
302
  listActivityDefinitions(): ActivityMetadata[];
301
303
  /**
302
- * Resolve one activity's catalog metadata the same way dispatch resolves
303
- * it for a running workflow of this type: the workflow's per-workflow
304
- * `.activities({...})` registry first, falling back to the global registry
305
- * see `activity-resolution.ts`'s `resolveActivityViaRegistries`. Build
306
- * tooling (`buildWorkerManifestFromRegistry`) uses this so a workflow-scoped
304
+ * Resolve one activity's catalog metadata against the EAGER per-workflow
305
+ * `.activities({...})` registry only, falling back to the global registry
306
+ * never a `registerSource()`-registered type's dynamic-source revision,
307
+ * resolved or not (WFT-19: `internals.activityRegistriesByWorkflow` is
308
+ * eager-only as of this batch; a dynamic-source workflow's own activity
309
+ * dispatch resolves via the running instance's exact `(type, revision)`
310
+ * pin instead, in `activity-resolution.ts`, which this synchronous,
311
+ * type-only accessor has no instance to pin against). Build tooling
312
+ * (`buildWorkerManifestFromRegistry`) uses this so a workflow-scoped
307
313
  * activity's schema, not a same-named global activity's, feeds its
308
314
  * `contractHash` when both are registered.
309
315
  */
@@ -318,11 +324,13 @@ export declare class Engine<TWorkflows extends object = DefaultWorkflowRegistry,
318
324
  *
319
325
  * Companion to {@link getWorkflowActivityDefinition}: that resolves one
320
326
  * activity by name with the per-workflow-first, global-fallback dispatch
321
- * order; this enumerates only the names the per-workflow registry itself
322
- * declares — activities a workflow reaches solely through the global
323
- * registry are deliberately excluded, since those are not part of what
324
- * `.activities({...})` scoped to this workflow. Build tooling that needs a
325
- * workflow's full scoped-activity contract set (`buildRegistrySnapshot`,
327
+ * order; this enumerates only the names the EAGER per-workflow registry
328
+ * itself declares — activities a workflow reaches solely through the
329
+ * global registry are deliberately excluded, and so (as of WFT-19) is
330
+ * every `registerSource()`-registered type regardless of whether a
331
+ * revision has been resolved (see {@link getWorkflowActivityDefinition}'s
332
+ * doc). Build tooling that needs a workflow's full scoped-activity
333
+ * contract set (`buildRegistrySnapshot`,
326
334
  * `worker/manifest/registry-contract-builder.ts`) uses this instead of
327
335
  * reaching into engine internals directly.
328
336
  */
@@ -66,6 +66,10 @@ import {
66
66
  typedEngineView
67
67
  } from "./construction.js";
68
68
  import { disposeEngine } from "./disposal.js";
69
+ import {
70
+ canResolveRevisionLocally,
71
+ getResolvedDynamicRegistration
72
+ } from "./dynamic-source-execution.js";
69
73
  import {
70
74
  consumeNextEngineLeakWarningTokenForTesting,
71
75
  engineCleanupIntervalFinalizer
@@ -175,6 +179,7 @@ import { registerSource as registerWorkflowSource } from "./source-registration.
175
179
  import {
176
180
  resolveWorkflowSource as resolveWorkflowSourceImpl
177
181
  } from "./source-resolution.js";
182
+ import { createWorkflowSourceRuntimeState } from "./source-runtime-state.js";
178
183
  import {
179
184
  loadScheduleState,
180
185
  loadWorkflowState,
@@ -216,6 +221,10 @@ export {
216
221
  getWorkflowRevisionDiagnostics,
217
222
  removeWorkflowRevision
218
223
  } from "./catalog-removal.js";
224
+ export {
225
+ DynamicWorkflowSourceUnavailableError,
226
+ WorkflowSourceNotRegisteredError
227
+ } from "./dynamic-source-errors.js";
219
228
  export {
220
229
  ActivityResolutionError,
221
230
  BulkDeleteRequiresTerminalWorkflowsError,
@@ -250,6 +259,7 @@ export {
250
259
  OwnershipModeMismatchError,
251
260
  WorkflowClaimUnavailableError
252
261
  } from "./lease-errors.js";
262
+ export { WorkflowRevisionUnavailableError } from "./revision-errors.js";
253
263
  export { ScheduleHandle } from "./schedule-handle.js";
254
264
  export {
255
265
  clearEngineLeakWarningTokenForTesting,
@@ -270,7 +280,8 @@ function scheduleDefinitionFromInternals(internals, definition) {
270
280
  ...definition.description !== void 0 && { description: definition.description },
271
281
  ...definition.overlapPolicy !== void 0 && { overlap: definition.overlapPolicy },
272
282
  ...definition.backfill !== void 0 && { backfill: definition.backfill },
273
- ...definition.jitter !== void 0 && { jitter: definition.jitter }
283
+ ...definition.jitter !== void 0 && { jitter: definition.jitter },
284
+ ...definition.revisionPolicy !== void 0 && { revisionPolicy: definition.revisionPolicy }
274
285
  });
275
286
  }
276
287
 
@@ -318,8 +329,11 @@ export class Engine extends EventTarget {
318
329
  maxNestingDepth: resolvedOptions.maxNestingDepth,
319
330
  development: resolvedOptions.development,
320
331
  broadcastEvents: resolvedOptions.broadcastEvents,
321
- getRegistration: getInternals(this).registrations.get.bind(getInternals(this).registrations),
322
- listRegisteredWorkflowTypes: () => getInternals(this).registrations.keys(),
332
+ getRegistration: (workflowType, workflowId) => getResolvedDynamicRegistration(getInternals(this), workflowType, getInternals(this).workflowTypeByWorkflowId.get(workflowId)?.revision),
333
+ listRegisteredWorkflowTypes: () => new Set([
334
+ ...getInternals(this).registrations.keys(),
335
+ ...getInternals(this).sources.lastResolvedRevisionByName.keys()
336
+ ]).values(),
323
337
  getComposedWorkflowInterceptor: () => getComposedWorkflowInterceptor(getInternals(this)),
324
338
  resolveWorkflowType: this.#resolveWorkflowTypeTarget.bind(this),
325
339
  registerCancelHandler: (workflowId, handler) => registerCancelHandler(getInternals(this), workflowId, handler),
@@ -445,10 +459,7 @@ export class Engine extends EventTarget {
445
459
  getInternals(this).catalogDrainPromise = null;
446
460
  getInternals(this).registeredCatalogRevisions = new Map;
447
461
  getInternals(this).inFlightStartsByRevision = new Map;
448
- getInternals(this).workflowSourcesByName = new Map;
449
- getInternals(this).sourceResolutionsInFlight = new Map;
450
- getInternals(this).sourceResolutionWaiterControllers = new Set;
451
- getInternals(this).resolvedWorkflowSources = new Map;
462
+ getInternals(this).sources = createWorkflowSourceRuntimeState();
452
463
  this.#ensureRetentionSweepInterval();
453
464
  this.#startSecondInstanceDetection();
454
465
  }
@@ -539,7 +550,7 @@ export class Engine extends EventTarget {
539
550
  getNow: internals.options.getNow,
540
551
  claimTtlMs: internals.options.workflowClaimTtlMs,
541
552
  claimRenewIntervalMs: internals.options.workflowClaimRenewIntervalMs,
542
- isWorkflowTypeRegistered: (workflowType) => internals.workflowDefinitionsByName.has(workflowType),
553
+ isWorkflowTypeRegistered: (workflowType, revision) => canResolveRevisionLocally(internals, workflowType, revision),
543
554
  onWorkflowClaimReclaimed: async (workflowId) => {
544
555
  internals.inlineStrategy?.evictContextForReclaim(workflowId);
545
556
  internals.deliveredPendingUpdateIds.delete(workflowId);
@@ -836,7 +847,7 @@ export class Engine extends EventTarget {
836
847
  return cancelAllWorkflows(getInternals(this), filter, options);
837
848
  }
838
849
  async retryFailedAll(filter, options) {
839
- return retryFailedAllWorkflows(getInternals(this), filter, options);
850
+ return retryFailedAllWorkflows(getInternals(this), filter, options, this.#createLifecycleCallbacks());
840
851
  }
841
852
  async signalAll(filter, name, payloadOrOptions, options) {
842
853
  if (options === void 0)
@@ -1143,7 +1154,7 @@ export class Engine extends EventTarget {
1143
1154
  if (leaseManager !== null && leaseManager.currentEpochBytes() !== null)
1144
1155
  process.emitWarning("engine ownership lease disposed synchronously; lease release is fire-and-forget, so exiting before the release completes can make the next instance wait for leaseTtl. Use await engine.shutdown(), await using, or await engine[Symbol.asyncDispose]() for prompt rolling-deploy handoff.", ENGINE_LEASE_SYNCHRONOUS_DISPOSE_WARNING_NAME);
1145
1156
  const { registry: workflowClaimRegistry } = this.#detachWorkflowClaimOwnership();
1146
- disposeEngine(getInternals(this));
1157
+ disposeEngine(getInternals(this), (event) => this.dispatchEvent(event));
1147
1158
  if (this.#synchronousDisposeResult === null)
1148
1159
  this.#synchronousDisposeResult = leaseManager?.release() ?? Promise.resolve(!0);
1149
1160
  this.#synchronousDisposeResult;
@@ -1161,7 +1172,7 @@ export class Engine extends EventTarget {
1161
1172
  drainFailure = { error };
1162
1173
  } finally {
1163
1174
  const { registry: workflowClaimRegistry } = this.#detachWorkflowClaimOwnership();
1164
- disposeEngine(getInternals(this));
1175
+ disposeEngine(getInternals(this), (event) => this.dispatchEvent(event));
1165
1176
  await getInternals(this).inFlightLeaseAcquire?.catch(() => {});
1166
1177
  leaseReleased = await (this.#synchronousDisposeResult ?? leaseManager?.release() ?? Promise.resolve(!0));
1167
1178
  await this.#releaseWorkflowClaimsBestEffort(workflowClaimRegistry);
@@ -99,7 +99,7 @@ async function startQueuedInlineWorkflowExecution(internals, start, callbacks, o
99
99
  return;
100
100
  internals.queuedInlineWorkflowStartIds.delete(start.workflowId);
101
101
  internals.engine.dispatchEvent(new WorkflowStartedEvent(start.workflowId, start.workflowType, start.input));
102
- startWorkflowExecution(internals, start.workflowId, state.workflowExecutionToken, start.workflowType, start.input, start.checkpoint, start.nestingDepth, start.executionDeadline, start.executionStateOwnerId);
102
+ startWorkflowExecution(internals, start.workflowId, state.workflowExecutionToken, start.workflowType, state.revision, start.input, start.checkpoint, start.nestingDepth, start.executionDeadline, start.executionStateOwnerId);
103
103
  if (options?.abortStartedWorkflows === !0)
104
104
  internals.inlineStrategy?.abortWorkflowAdvanceForShutdown(start.workflowId);
105
105
  else
@@ -29,18 +29,19 @@ import type { InlineExecutionStrategy } from '../inline-execution-strategy.ts';
29
29
  import type { ComposedActivityInterceptor, ComposedWorkflowInterceptor, Interceptor } from '../interceptor.ts';
30
30
  import type { HumanReviewResult, ReviewCoordinator } from '../review/index.ts';
31
31
  import type { Scheduler } from '../scheduler.ts';
32
- import type { Checkpoint, StartWorkflowOptions, WorkflowDefinition } from '../types.ts';
32
+ import type { Checkpoint, StartWorkflowOptions } from '../types.ts';
33
33
  import type { UpdateCoordinator } from '../updates.ts';
34
34
  import type { WorkflowVersionTuple } from '../workflow-version-tuple.ts';
35
35
  import type { RecoveredWorkflowInfo } from './lifecycle/shared.ts';
36
36
  import type { ActivityHeartbeatKey } from './activity-heartbeat-tracking.ts';
37
- import type { PendingTimelineEntry, QueuedInlineWorkflowExecutionStart, RegistrationEntry, ResolvedOptions, TrackedWaiterKeys, WorkflowResultWaiter } from './engine-internal-types.ts';
37
+ import type { PendingTimelineEntry, QueuedInlineWorkflowExecutionStart, RegistrationEntry, ResolvedOptions, TrackedWaiterKeys, WorkflowExecutionIdentity, WorkflowResultWaiter } from './engine-internal-types.ts';
38
38
  import type { EngineCleanupIntervalDisposalTracker } from './engine-leak-warnings.ts';
39
39
  import type { WorkflowHandle, WorkflowHandleEngine } from './handles.ts';
40
40
  import type { WorkflowFeedListener } from './index.ts';
41
41
  import type { LeaseManager } from './lease-manager.ts';
42
42
  import type { ScheduleHandleEngine } from './schedule-handle.ts';
43
43
  import type { SecondInstanceDetector } from './second-instance-detector.ts';
44
+ import type { WorkflowSourceRuntimeState } from './source-runtime-state.ts';
44
45
  import type { WorkflowClaimMetricsRecorder } from './workflow-claim-metrics.ts';
45
46
  import type { WorkflowClaimRegistry } from './workflow-claim-registry.ts';
46
47
  import type { WorkflowClaimRenewalTask } from './workflow-claim-renewal-task.ts';
@@ -58,12 +59,6 @@ export type DurableInlineOperation = {
58
59
  type EngineRuntime = WorkflowHandleEngine & ScheduleHandleEngine & {
59
60
  start(type: string, input: unknown, options?: StartWorkflowOptions): Promise<WorkflowHandle>;
60
61
  };
61
- type SourceHandle = import('../source/index.ts').WorkflowSourceHandle;
62
- type CatalogRevisionRecord = import('../catalog/index.ts').WorkflowRevisionRecord;
63
- type ResolvedSource = {
64
- definition: WorkflowDefinition;
65
- activityRegistry: ActivityRegistry;
66
- };
67
62
  export interface EngineInternals {
68
63
  engine: EngineRuntime;
69
64
  storage: WeftStorage;
@@ -155,15 +150,15 @@ export interface EngineInternals {
155
150
  /**
156
151
  * Per-workflow activity registries built from
157
152
  * `workflow({ name }).activities({ ... }).execute(...)`, indexed by workflow
158
- * type. Activity lookup is per-activity: it consults the workflow's
159
- * `activityRegistriesByWorkflow.get(type)` registry first and, for any activity
160
- * that registry does not contain, falls back to the engine-wide
161
- * {@link EngineInternals.activityRegistry}. Both sources are first-class a
162
- * workflow can resolve some activities from its own `activities(...)` map and
163
- * others (shared/globally-registered) from the global registry, and a workflow
164
- * with no per-workflow map resolves entirely from the global one. Each
165
- * per-workflow registry is a defensive deep clone+freeze of the workflow's
166
- * `activities` map so post-registration mutation cannot reach the engine.
153
+ * type. Lookup consults `activityRegistriesByWorkflow.get(type)` first,
154
+ * falling back to {@link EngineInternals.activityRegistry} for any activity
155
+ * that registry lacks. Each entry is a defensive deep clone+freeze of the
156
+ * workflow's `activities` map. EAGER-ONLY as of WFT-19: only `registration.ts`
157
+ * writes here (never a `registerSource()` load), so a dynamic-source type's
158
+ * per-revision activities resolve instead via
159
+ * `internals.sources.resolved.get(type)?.get(revision)?.activityRegistry`
160
+ * (`activity-resolution.ts`), keyed by the running instance's own pin
161
+ * never this type-only map, which would clobber across revisions.
167
162
  */
168
163
  activityRegistriesByWorkflow: Map<string, ActivityRegistry>;
169
164
  /**
@@ -175,12 +170,13 @@ export interface EngineInternals {
175
170
  */
176
171
  workflowDefinitionsByName: Map<string, object>;
177
172
  /**
178
- * In-memory cache of `workflowId -> workflowType` populated when a workflow
179
- * starts executing (see lifecycle/start-exec.ts) and cleared on terminal
180
- * cleanup. Lets the activity-dispatch hot path resolve the correct
181
- * per-workflow registry synchronously without re-reading storage.
173
+ * In-memory cache of `workflowId -> {type, revision}`, populated whenever a
174
+ * workflow begins executing in THIS process (fresh start, delayed-start
175
+ * fire, resume, recovery, workflow-lease reclaim redrive WFT-19) and
176
+ * cleared on terminal cleanup. Lets the activity-dispatch hot path, and any
177
+ * other lookup needing an instance's own exact pin, resolve synchronously.
182
178
  */
183
- workflowTypeByWorkflowId: Map<string, string>;
179
+ workflowTypeByWorkflowId: Map<string, WorkflowExecutionIdentity>;
184
180
  activityWorkerDispatcher: ActivityWorkerDispatcher | null;
185
181
  checkpoints: Map<string, Checkpoint>;
186
182
  broadcastChannel: BroadcastChannel | null;
@@ -409,14 +405,14 @@ export interface EngineInternals {
409
405
  registeredCatalogRevisions: Map<string, string>;
410
406
  /** Name -> revision -> in-flight `startWorkflow` count (WFT-12, `lifecycle/start.ts`). Process-local, never persisted. */
411
407
  inFlightStartsByRevision: Map<string, Map<string, number>>;
412
- /** Dynamic workflow sources (WFT-13/14): `registerSource()` candidates, keyed name then revision. Registering never invokes the loader. Process-local, never persisted. */
413
- workflowSourcesByName: Map<string, Map<string, SourceHandle>>;
414
- /** In-flight `resolveWorkflowSource` single-flight load per `(name, revision)`. Self-removes on settle via a `catalogDrainPromise`-style identity guard. */
415
- sourceResolutionsInFlight: Map<string, Map<string, Promise<CatalogRevisionRecord>>>;
416
- /** Per-caller `AbortController`s from in-flight `resolveWorkflowSource()` calls; disposal aborts every waiter without touching the shared load (mirrors `pendingWebhooks`). */
417
- sourceResolutionWaiterControllers: Set<AbortController>;
418
- /** A successful `resolveWorkflowSource()`'s live definition, keyed name then revision. Unread this batch — WFT-15's job. */
419
- resolvedWorkflowSources: Map<string, Map<string, ResolvedSource>>;
408
+ /**
409
+ * Dynamic workflow sources (WFT-13/14, WFT-15/16): candidates, in-flight
410
+ * single-flight loads, per-caller waiter controllers, locally-resolved
411
+ * definitions, and bounded per-`(name, revision)` diagnostics — see
412
+ * {@link import('./source-runtime-state.ts').WorkflowSourceRuntimeState}
413
+ * for the full field-by-field breakdown. Process-local, never persisted.
414
+ */
415
+ sources: WorkflowSourceRuntimeState;
420
416
  }
421
417
  /**
422
418
  * Set up an empty `EngineInternals` skeleton in the WeakMap. The Engine
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Launch a workflow run from an already-built `WorkflowState`/`Checkpoint`
3
+ * pair — the shared tail `fork()` (`transition.ts`) drives after planting a
4
+ * new run's durable records. Split out of `transition.ts`, which has no
5
+ * headroom under the repository's 500-line implementation-file ceiling for
6
+ * this logic inline.
7
+ *
8
+ * @module core/engine/lifecycle/checkpoint-launch
9
+ */
10
+ import type { Checkpoint, WorkflowState } from '../../types.ts';
11
+ import { type WorkflowHandle } from '../handles.ts';
12
+ import type { EngineInternals } from '../internals.ts';
13
+ import { type LifecycleCallbacks, type RegistrationEntry } from './shared.ts';
14
+ export declare function launchWorkflowFromCheckpoint(internals: EngineInternals, workflowId: string, state: WorkflowState, checkpoint: Checkpoint, registration: RegistrationEntry,
15
+ /**
16
+ * The EXACT revision `registration` was resolved against — from the same
17
+ * `resolveExecutableRegistrationForRevision()` call that produced
18
+ * `registration`, threaded through explicitly rather than re-read off
19
+ * `state.revision` (WFT-19 review round 5, Codex, mirroring the identical
20
+ * fix in `lifecycle/resume.ts`). `fork()`'s own `forkState.revision` is
21
+ * now stamped with this same resolved value too (WFT-19 review round 6,
22
+ * Codex — `createForkedWorkflowState()`'s matching fix, so a legacy
23
+ * fork's durable pin agrees with this in-memory one), so `state.revision`
24
+ * and `resolvedRevision` coincide for every current caller; kept as an
25
+ * explicit parameter regardless, since this function's identity-cache
26
+ * write must never depend on that invariant holding at a future call
27
+ * site.
28
+ */
29
+ resolvedRevision: string | undefined, callbacks: LifecycleCallbacks): WorkflowHandle;
@@ -0,0 +1,75 @@
1
+ import { serializeCheckpoint } from "../../checkpoint.js";
2
+ import { Context, setContextWorkflowInterceptor } from "../../context.js";
3
+ import { WorkflowStartedEvent } from "../../events.js";
4
+ import { createCancelHandlerRegistration, resetCancelHandlers } from "../cancel-handlers.js";
5
+ import { getWorkflowExecutionStartedAt } from "../handles.js";
6
+ import { getComposedWorkflowInterceptor } from "../strategy-helpers.js";
7
+ import { createWorkflowVersionTuple } from "./persist.js";
8
+ import { createWorkflowHandle } from "./shared.js";
9
+ function launchInlineWorkflowFromCheckpoint(internals, workflowId, state, checkpoint, registration, callbacks) {
10
+ const inlineStrategy = internals.inlineStrategy;
11
+ if (!inlineStrategy)
12
+ throw Error("Inline workflow launch requested without an inline strategy.");
13
+ const accumulatedResults = new Map(checkpoint.accumulatedResults), workflowAbort = new AbortController;
14
+ resetCancelHandlers(internals, workflowId);
15
+ const context = new Context({
16
+ workflowId,
17
+ ...state.workflowExecutionToken !== void 0 && {
18
+ workflowExecutionToken: state.workflowExecutionToken
19
+ },
20
+ workflowType: state.type,
21
+ startedAt: getWorkflowExecutionStartedAt(state),
22
+ abortController: workflowAbort,
23
+ getNow: internals.options.getNow,
24
+ resolveWorkflowType: callbacks.resolveWorkflowTypeTarget,
25
+ executionStateOwnerId: state.executionStateOwnerId ?? workflowId,
26
+ accumulatedResults,
27
+ searchAttributes: checkpoint.searchAttributes,
28
+ registerCancelHandler: createCancelHandlerRegistration(internals, workflowId),
29
+ ...registration.searchAttributes && {
30
+ searchAttributeSchema: registration.searchAttributes
31
+ },
32
+ sleepReferenceTime: checkpoint.createdAt,
33
+ ...state.executionDeadline !== void 0 && { deadline: state.executionDeadline },
34
+ ...internals.options.onLog != null && { logSink: internals.options.onLog }
35
+ });
36
+ setContextWorkflowInterceptor(context, getComposedWorkflowInterceptor(internals));
37
+ if (internals.options.development)
38
+ context.explain(!0);
39
+ const generator = registration.handler(context, state.input);
40
+ inlineStrategy.adoptWorkflow(workflowId, generator, context, workflowAbort);
41
+ inlineStrategy.continueWorkflow(workflowId, void 0);
42
+ callbacks.swallowPromiseRejection(callbacks.processPendingUpdatesAfterInlineAdvance(workflowId));
43
+ }
44
+ function launchWorkerWorkflowFromCheckpoint(internals, workflowId, state, checkpoint) {
45
+ const serialized = serializeCheckpoint(checkpoint);
46
+ internals.strategy.startWorkflow({
47
+ workflowId,
48
+ ...state.workflowExecutionToken !== void 0 && {
49
+ workflowExecutionToken: state.workflowExecutionToken
50
+ },
51
+ workflowType: state.type,
52
+ input: state.input,
53
+ checkpoint: serialized,
54
+ executionStateOwnerId: state.executionStateOwnerId ?? workflowId,
55
+ ...state.executionDeadline !== void 0 && { deadline: state.executionDeadline },
56
+ ...internals.workflowHeaders.has(workflowId) && {
57
+ headers: [...internals.workflowHeaders.get(workflowId)]
58
+ }
59
+ });
60
+ }
61
+ export function launchWorkflowFromCheckpoint(internals, workflowId, state, checkpoint, registration, resolvedRevision, callbacks) {
62
+ internals.workflowTypeByWorkflowId.set(workflowId, {
63
+ type: state.type,
64
+ revision: resolvedRevision
65
+ });
66
+ internals.checkpoints.set(workflowId, checkpoint);
67
+ internals.workflowVersionTuples.set(workflowId, createWorkflowVersionTuple(internals, registration, callbacks));
68
+ const handle = createWorkflowHandle(internals, workflowId, callbacks);
69
+ callbacks.dispatchEvent(new WorkflowStartedEvent(workflowId, state.type, state.input));
70
+ if (internals.inlineStrategy)
71
+ launchInlineWorkflowFromCheckpoint(internals, workflowId, state, checkpoint, registration, callbacks);
72
+ else
73
+ launchWorkerWorkflowFromCheckpoint(internals, workflowId, state, checkpoint);
74
+ return handle;
75
+ }
@@ -0,0 +1,30 @@
1
+ import type { TimerEntry } from '../../types.ts';
2
+ import type { ExecutableRegistration } from '../dynamic-source-execution.ts';
3
+ import type { EngineInternals } from '../internals.ts';
4
+ import type { TimeOperationCallbacks } from '../operations-time.ts';
5
+ /**
6
+ * Resolve `type`'s registration for a delayed-start fire, failing the
7
+ * workflow (via `callbacks.failWorkflow`) and returning `null` on any
8
+ * resolution error instead of throwing. ADR 0002: acquires this workflow's
9
+ * claim standalone + hydrates cleanup tracking BEFORE failing — the
10
+ * happy-path pending→running fold later in `startDelayedWorkflow` would
11
+ * otherwise establish both.
12
+ *
13
+ * Resolved against `revision` — the pending run's own persisted
14
+ * `WorkflowState.revision` (WFT-17), `undefined` for a legacy record —
15
+ * never the catalog's active pointer, so a delayed-start fire honors the
16
+ * exact revision this run was created against, matching
17
+ * `resumeWorkflowFromStorage()`'s use of the same resolver.
18
+ *
19
+ * Returns the FULL `{ entry, revision }` pair, not just `entry` — mirroring
20
+ * `resolveExecutableRegistrationOrRenamedNotFound()`'s shape used by
21
+ * `resume.ts`/`transition.ts`. For a legacy, pre-revision-pinning pending
22
+ * record with exactly one registered `registerSource()` candidate, the
23
+ * resolver can unambiguously resolve that candidate even though the input
24
+ * `revision` was `undefined` — the caller MUST thread this returned
25
+ * `revision` (not the input `revision` or the persisted state's own,
26
+ * still-`undefined` `revision`) through the pending→running transition and
27
+ * into `beginWorkflowExecution`, or the per-instance identity cache ends up
28
+ * stamped with the wrong (missing) revision (WFT-19 review round 7).
29
+ */
30
+ export declare function resolveDelayedStartRegistrationOrFail(internals: EngineInternals, entry: TimerEntry, type: string, revision: string | undefined, callbacks: Pick<TimeOperationCallbacks, 'failWorkflow' | 'resolveExecutableRegistrationForRevision'>): Promise<ExecutableRegistration | null>;
@@ -0,0 +1,11 @@
1
+ import { ensureDelayedStartClaimAndCleanupBeforeFailure } from "./standalone-claim-acquire.js";
2
+ export async function resolveDelayedStartRegistrationOrFail(internals, entry, type, revision, callbacks) {
3
+ try {
4
+ return await callbacks.resolveExecutableRegistrationForRevision(type, revision);
5
+ } catch (error) {
6
+ await ensureDelayedStartClaimAndCleanupBeforeFailure(internals, entry.workflowId);
7
+ const asError = error instanceof Error ? error : Error(String(error));
8
+ await callbacks.failWorkflow(entry.workflowId, asError);
9
+ return null;
10
+ }
11
+ }
@@ -5,5 +5,37 @@ import type { EngineInternals } from '../internals.ts';
5
5
  import { type LifecycleCallbacks } from './shared.ts';
6
6
  export declare function createForkLineage(_internals: EngineInternals, sourceWorkflowId: string, checkpoint: Checkpoint, _callbacks: LifecycleCallbacks): ForkLineage;
7
7
  export declare function buildForkSearchAttributes(_internals: EngineInternals, checkpoint: Checkpoint, lineage: ForkLineage, _callbacks: LifecycleCallbacks): Record<string, SearchAttributeValue>;
8
- export declare function createForkedWorkflowState(_internals: EngineInternals, workflowId: string, sourceState: WorkflowState, versionTuple: WorkflowVersionTuple, lineage: ForkLineage, forkedAt: number, _callbacks: LifecycleCallbacks): WorkflowState;
8
+ export declare function createForkedWorkflowState(_internals: EngineInternals, workflowId: string, sourceState: WorkflowState, versionTuple: WorkflowVersionTuple, lineage: ForkLineage, forkedAt: number, _callbacks: LifecycleCallbacks,
9
+ /**
10
+ * `fork()`'s own resolver-returned revision — used to fill in the fork's
11
+ * persisted `revision` ONLY when `sourceState.revision` is itself
12
+ * `undefined` (WFT-19 review round 6, Codex, P1). Never overrides an
13
+ * already-defined `sourceState.revision`: `resolveExecutableRegistrationForRevision()`
14
+ * ALWAYS returns `revision: undefined` for an eager registration (eager
15
+ * has no ambiguity to resolve against — see `canResolveRevisionLocally`'s
16
+ * doc), even though the eager source run's own `sourceState.revision` is
17
+ * a real, independently-meaningful value (`resolveCachedStartRevision()`'s
18
+ * `registeredCatalogRevisions` fallback stamps it at ordinary start time,
19
+ * for every registration kind). Blindly preferring `resolvedRevision`
20
+ * here would have dropped that real value for every eager-type fork —
21
+ * caught by `tests/replay-fixtures/fork-from-checkpoint.json`'s golden
22
+ * byte comparison. For a legacy (pre-revision-pinning) source run on a
23
+ * dynamic-source type with exactly one registered candidate,
24
+ * `sourceState.revision` genuinely IS `undefined` even though the
25
+ * resolver resolved — and the fork launches against — that sole
26
+ * candidate's code; `sourceState.revision ?? resolvedRevision` falls
27
+ * through to the resolver's answer only in that case. Stamping the fork's
28
+ * persisted `revision` with the raw `undefined` legacy pin (as this
29
+ * function did before this fix existed) left the fork durably unpinned:
30
+ * it would run correctly until the next restart, but a fresh-process
31
+ * `recoverAll()` after a second candidate is later registered would
32
+ * classify the fork `legacy-ambiguous` and refuse to resume it, even
33
+ * though the fork's own resolver already knew exactly which revision it
34
+ * belonged to at creation time. Mirrors the identical fix already applied
35
+ * to the process-local identity cache in `checkpoint-launch.ts`'s
36
+ * `launchWorkflowFromCheckpoint()` (WFT-19 review round 5) — that fix
37
+ * closed the in-memory gap; this one closes the matching durable-state
38
+ * gap the same bug left behind, for the one case it actually applies to.
39
+ */
40
+ resolvedRevision: string | undefined): WorkflowState;
9
41
  export declare function buildForkBatchOperations(_internals: EngineInternals, workflowId: string, state: WorkflowState, checkpoint: Checkpoint, serializedCheckpoint: Uint8Array, workflowStartHeaders: Map<string, string> | undefined, _callbacks: LifecycleCallbacks): BatchOperation[];
@@ -16,7 +16,8 @@ export function buildForkSearchAttributes(_internals, checkpoint, lineage, _call
16
16
  [FORK_LINEAGE_ATTRIBUTE]: lineage.workflowId
17
17
  };
18
18
  }
19
- export function createForkedWorkflowState(_internals, workflowId, sourceState, versionTuple, lineage, forkedAt, _callbacks) {
19
+ export function createForkedWorkflowState(_internals, workflowId, sourceState, versionTuple, lineage, forkedAt, _callbacks, resolvedRevision) {
20
+ const forkRevision = sourceState.revision ?? resolvedRevision;
20
21
  return {
21
22
  id: workflowId,
22
23
  type: sourceState.type,
@@ -24,6 +25,7 @@ export function createForkedWorkflowState(_internals, workflowId, sourceState, v
24
25
  input: sourceState.input,
25
26
  workflowExecutionToken: crypto.randomUUID(),
26
27
  versionTuple,
28
+ ...forkRevision !== void 0 && { revision: forkRevision },
27
29
  executionStateOwnerId: workflowId,
28
30
  createdAt: forkedAt,
29
31
  startedAt: forkedAt,
@@ -0,0 +1,20 @@
1
+ /**
2
+ * `recoverAll()`'s per-entry error isolation — split out of `transition.ts`,
3
+ * which has no headroom under this repository's 500-line implementation-file
4
+ * ceiling for the WFT-134 claim-release wrapping `recoverEntryOrIsolateFailure`
5
+ * needed (mirrors `resume-body.ts`'s same split). This file's own job is just
6
+ * the branch-matching: given the error `resume()` rejected with, either
7
+ * isolate it to just this workflow (returning `null`) or rethrow it.
8
+ *
9
+ * @module core/engine/lifecycle/recovery-isolation
10
+ */
11
+ import type { WorkflowHandle } from '../handles.ts';
12
+ import type { LifecycleCallbacks, RecoverAllOptions } from './shared.ts';
13
+ /**
14
+ * Isolate one `recoverAll()` entry's failure to just this workflow when it
15
+ * matches a known-recoverable error, committing the matching `failWorkflowForXxx`
16
+ * fenced write; rethrows anything else, including an opted-in
17
+ * `VersionMismatchError` throw. See `transition.ts`'s `recoverEntryOrIsolateFailure`
18
+ * for the caller-side claim-release wrapping around this.
19
+ */
20
+ export declare function isolateRecoveryFailure(workflowId: string, callbacks: LifecycleCallbacks, options: RecoverAllOptions | undefined, error: unknown): Promise<WorkflowHandle | null>;