@lostgradient/weft 0.7.0 → 0.9.0

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 (141) hide show
  1. package/README.md +9 -3
  2. package/dist/cli/generated/operation-client.generated.d.ts +1 -0
  3. package/dist/cli-main.js +78 -78
  4. package/dist/core/context/activity-retry-state.d.ts +6 -5
  5. package/dist/core/context/activity-retry-state.js +31 -21
  6. package/dist/core/context/durable-activity.d.ts +117 -0
  7. package/dist/core/context/durable-activity.js +79 -0
  8. package/dist/core/context/durable-operations.js +1 -1
  9. package/dist/core/context/index.d.ts +1 -0
  10. package/dist/core/context/index.js +2 -0
  11. package/dist/core/context/operation-request.d.ts +17 -0
  12. package/dist/core/context/parallel-operations.js +1 -0
  13. package/dist/core/context/run-operation-cached-request.d.ts +8 -0
  14. package/dist/core/context/run-operation-cached-request.js +59 -0
  15. package/dist/core/context/run-operation.d.ts +23 -5
  16. package/dist/core/context/run-operation.js +63 -47
  17. package/dist/core/context/speculative-child.js +1 -0
  18. package/dist/core/context/types.d.ts +1 -0
  19. package/dist/core/engine/activity-heartbeat-tracking.d.ts +8 -17
  20. package/dist/core/engine/activity-heartbeat-tracking.js +12 -2
  21. package/dist/core/engine/activity-reconciliation.d.ts +1 -0
  22. package/dist/core/engine/activity-reconciliation.js +7 -2
  23. package/dist/core/engine/anonymous-signal-sequence.js +6 -6
  24. package/dist/core/engine/async-activity-completion.d.ts +5 -7
  25. package/dist/core/engine/async-activity-completion.js +13 -9
  26. package/dist/core/engine/bulk-operations-purge.js +2 -1
  27. package/dist/core/engine/bulk-operations.js +18 -36
  28. package/dist/core/engine/callback-checkpoint-persistence.d.ts +3 -0
  29. package/dist/core/engine/callback-checkpoint-persistence.js +25 -0
  30. package/dist/core/engine/callback-creators-bundles.js +5 -2
  31. package/dist/core/engine/checkpoint-io.d.ts +4 -1
  32. package/dist/core/engine/checkpoint-io.js +19 -10
  33. package/dist/core/engine/completed-review-storage.d.ts +2 -1
  34. package/dist/core/engine/completed-review-storage.js +4 -3
  35. package/dist/core/engine/disposal.js +1 -0
  36. package/dist/core/engine/engine-internal-types.d.ts +1 -0
  37. package/dist/core/engine/index.d.ts +31 -0
  38. package/dist/core/engine/index.js +19 -10
  39. package/dist/core/engine/inline-launch-queue.js +1 -1
  40. package/dist/core/engine/internals.d.ts +25 -2
  41. package/dist/core/engine/lease-manager.js +2 -2
  42. package/dist/core/engine/lifecycle/fork-helpers.js +1 -0
  43. package/dist/core/engine/lifecycle/resume.js +6 -0
  44. package/dist/core/engine/lifecycle/start-exec.d.ts +2 -2
  45. package/dist/core/engine/lifecycle/start-exec.js +6 -4
  46. package/dist/core/engine/lifecycle/start.js +1 -0
  47. package/dist/core/engine/lifecycle/transition.js +6 -0
  48. package/dist/core/engine/memo-durable-activity.d.ts +11 -0
  49. package/dist/core/engine/memo-durable-activity.js +282 -0
  50. package/dist/core/engine/operations-activity.d.ts +6 -2
  51. package/dist/core/engine/operations-activity.js +24 -10
  52. package/dist/core/engine/operations-data.d.ts +4 -1
  53. package/dist/core/engine/operations-data.js +3 -3
  54. package/dist/core/engine/operations-time.d.ts +2 -2
  55. package/dist/core/engine/operations-time.js +40 -6
  56. package/dist/core/engine/reviews.js +7 -4
  57. package/dist/core/engine/schedule-timer.js +2 -0
  58. package/dist/core/engine/schedules.js +3 -0
  59. package/dist/core/engine/storage-io.js +1 -1
  60. package/dist/core/engine/termination/cleanup.js +15 -13
  61. package/dist/core/engine/termination/finalizer-activity.d.ts +1 -1
  62. package/dist/core/engine/termination/finalizer-activity.js +5 -1
  63. package/dist/core/engine/termination/finalizer.js +1 -1
  64. package/dist/core/engine/validation/schedule-options.d.ts +9 -0
  65. package/dist/core/engine/validation/schedule-options.js +59 -0
  66. package/dist/core/engine/validation/schedule.d.ts +3 -8
  67. package/dist/core/engine/validation/schedule.js +40 -56
  68. package/dist/core/engine/validation.js +1 -0
  69. package/dist/core/execution-strategy.d.ts +1 -0
  70. package/dist/core/inline-execution-strategy.context-options.d.ts +1 -0
  71. package/dist/core/inline-execution-strategy.context-options.js +3 -0
  72. package/dist/core/json.js +1 -1
  73. package/dist/core/types/activity.d.ts +11 -0
  74. package/dist/core/types/checkpoint.d.ts +1 -0
  75. package/dist/core/types/schedules.d.ts +10 -0
  76. package/dist/core/types/state.d.ts +6 -0
  77. package/dist/core/types/workflow-context.d.ts +13 -0
  78. package/dist/core/weft-error.d.ts +1 -1
  79. package/dist/core/weft-error.js +2 -0
  80. package/dist/core/worker-execution-strategy.d.ts +1 -0
  81. package/dist/core/worker-inbound-message.d.ts +1 -0
  82. package/dist/core/worker-inbound-message.js +3 -0
  83. package/dist/index.d.ts +2 -1
  84. package/dist/index.js +6 -0
  85. package/dist/json-schema.js +2 -2
  86. package/dist/mcp/cli.js +32 -32
  87. package/dist/observability/index.js +2 -2
  88. package/dist/runtime/portable.d.ts +1 -1
  89. package/dist/server/handler.js +27 -27
  90. package/dist/server/index.d.ts +2 -0
  91. package/dist/server/index.js +32 -32
  92. package/dist/server/operations/create-schedule.d.ts +2 -0
  93. package/dist/server/operations/create-schedule.js +13 -2
  94. package/dist/server/rest-binding.d.ts +1 -1
  95. package/dist/server/runtime/task-dispatch.js +6 -0
  96. package/dist/server/runtime/task-polling.js +9 -1
  97. package/dist/server/runtime/task-reconciliation.js +2 -1
  98. package/dist/server/runtime/websocket-worker.js +7 -2
  99. package/dist/server/serve-internals.d.ts +28 -0
  100. package/dist/server/serve-internals.js +4 -2
  101. package/dist/server/task-queue-types.d.ts +2 -0
  102. package/dist/server/task-state.d.ts +4 -0
  103. package/dist/service-worker/index.d.ts +15 -14
  104. package/dist/service-worker/index.js +28 -28
  105. package/dist/service-worker/scheduler.d.ts +41 -1
  106. package/dist/service-worker/setup.d.ts +18 -1
  107. package/dist/service-worker/setup.js +7 -4
  108. package/dist/storage/auto.d.ts +36 -18
  109. package/dist/storage/auto.js +1 -1
  110. package/dist/storage/compressed-storage.js +1 -1
  111. package/dist/storage/indexeddb.d.ts +6 -1
  112. package/dist/storage/indexeddb.js +1 -1
  113. package/dist/storage/interface.js +1 -1
  114. package/dist/storage/lmdb.js +1 -1
  115. package/dist/storage/memory.js +1 -1
  116. package/dist/storage/neon.js +1 -1
  117. package/dist/storage/resolve.js +1 -1
  118. package/dist/storage/scoped-storage.js +1 -1
  119. package/dist/storage/testing.js +1 -1
  120. package/dist/storage/turso.js +1 -1
  121. package/dist/storage/typed-storage.d.ts +1 -1
  122. package/dist/storage/typed-storage.js +1 -1
  123. package/dist/storage/web-extension.d.ts +1 -1
  124. package/dist/storage/web-extension.js +1 -1
  125. package/dist/testing/index.js +32 -32
  126. package/dist/version.d.ts +1 -1
  127. package/dist/version.js +1 -1
  128. package/dist/worker/execute-with-interceptors.d.ts +9 -3
  129. package/dist/worker/execute-with-interceptors.js +14 -2
  130. package/dist/worker/long-poll.d.ts +2 -1
  131. package/dist/worker/long-poll.js +1 -1
  132. package/dist/worker/protocol-messages.d.ts +2 -0
  133. package/dist/worker/protocol-schemas.d.ts +8 -0
  134. package/dist/worker/protocol-schemas.js +1 -0
  135. package/dist/worker/protocol.js +1 -1
  136. package/dist/worker/remote-activity-context.d.ts +2 -0
  137. package/dist/workers/activity-runner.d.ts +2 -0
  138. package/dist/workers/activity-runner.js +9 -1
  139. package/dist/workers/workflow-runner.d.ts +2 -1
  140. package/dist/workers/workflow-runner.js +1 -0
  141. package/package.json +1 -1
@@ -16,6 +16,7 @@ import {
16
16
  resolveActivityTimeout
17
17
  } from "./activity-schedule-to-close.js";
18
18
  import { getInternals, hasContextInternals } from "./internals.js";
19
+ import { getCachedRunActivityRequest } from "./run-operation-cached-request.js";
19
20
  import { isActivityCallOptions } from "./session-state.js";
20
21
  import { captureCallerStack } from "./validation.js";
21
22
  export function asConcreteContext(context) {
@@ -42,13 +43,27 @@ function parseRunArguments(activity, rest) {
42
43
  return { input: values[0], options };
43
44
  }
44
45
  export const readActivityRetryAttemptForTesting = readActivityRetryAttempt, readCompletedRetrySleepCountForTesting = readCompletedRetrySleepCount, completeActivityRetryAttemptForTesting = completeActivityRetryAttempt;
45
- function resolveScheduleToCloseBudget(internals, step, scheduleToCloseTimeout) {
46
+ const ACTIVITY_RETRY_SLEEP_DEADLINE_LOCAL_PREFIX = "__weftActivityRetrySleepDeadline:";
47
+ export function readOrInitActivityRetrySleepFireAt(context, operationId, duration) {
48
+ const internals = getInternals(context), localKey = `${ACTIVITY_RETRY_SLEEP_DEADLINE_LOCAL_PREFIX}${operationId}`, existing = internals.checkpointLocals[localKey];
49
+ if (typeof existing === "number" && Number.isFinite(existing))
50
+ return existing;
51
+ if (existing !== void 0)
52
+ throw Error(`Invalid checkpointed activity retry sleep deadline ${JSON.stringify(existing)} for "${operationId}".`);
53
+ const scheduledFireAt = internals.getNow() + duration;
54
+ internals.checkpointLocals = {
55
+ ...internals.checkpointLocals,
56
+ [localKey]: scheduledFireAt
57
+ };
58
+ return scheduledFireAt;
59
+ }
60
+ export function resolveScheduleToCloseBudget(internals, retryStateKey, scheduleToCloseTimeout) {
46
61
  const budgetMs = parseScheduleToCloseBudgetMs(scheduleToCloseTimeout);
47
62
  if (budgetMs === void 0)
48
63
  return;
49
64
  return {
50
65
  budgetMs,
51
- dispatchedAt: readOrInitActivityDispatchedAt(internals, step, internals.getNow())
66
+ dispatchedAt: readOrInitActivityDispatchedAt(internals, retryStateKey, internals.getNow())
52
67
  };
53
68
  }
54
69
  function getActivityName(activity, explicitName) {
@@ -59,39 +74,7 @@ function getActivityName(activity, explicitName) {
59
74
  function getActivityFunction(activity) {
60
75
  return typeof activity === "function" ? activity : void 0;
61
76
  }
62
- function getCachedRunActivityRequest(internals, step, activityName, input) {
63
- const hasCachedResult = internals.accumulatedResults?.has(step) ?? !1;
64
- if (hasCachedResult) {
65
- const cachedResult = internals.accumulatedResults?.get(step);
66
- internals.stepIndex += readCompletedRetrySleepCount(internals, step);
67
- if (internals.explainMode)
68
- console.log(`[weft] ctx.run(${activityName}) \u2192 Returning cached result from step ${step}`);
69
- return {
70
- request: { type: "activity", operationId: "", activityName, input },
71
- step,
72
- hasCachedResult,
73
- cachedResult,
74
- retryAttempt: 1
75
- };
76
- }
77
- const retryAttempt = readActivityRetryAttempt(internals, step);
78
- if (retryAttempt !== void 0) {
79
- internals.stepIndex += retryAttempt - 2;
80
- return {
81
- request: { type: "activity", operationId: "", activityName, input },
82
- step,
83
- hasCachedResult: !1,
84
- retryAttempt
85
- };
86
- }
87
- return {
88
- request: { type: "activity", operationId: "", activityName, input },
89
- step,
90
- hasCachedResult,
91
- retryAttempt: 1
92
- };
93
- }
94
- function createFreshRunActivityRequest(internals, step, activityName, activityFunction, input, options) {
77
+ function createFreshRunActivityRequest(internals, step, activityName, activityFunction, input, options, activityStateKey, workflowExecutionToken) {
95
78
  const queue = options?.queue ?? "default";
96
79
  if (internals.explainMode) {
97
80
  console.log(`[weft] ctx.run(${activityName}, ${JSON.stringify(input)})`);
@@ -103,6 +86,8 @@ function createFreshRunActivityRequest(internals, step, activityName, activityFu
103
86
  operationId: crypto.randomUUID(),
104
87
  activityName,
105
88
  step,
89
+ ...activityStateKey === void 0 ? {} : { activityStateKey },
90
+ ...workflowExecutionToken === void 0 ? {} : { workflowExecutionToken },
106
91
  ...activityFunction !== void 0 ? { fn: activityFunction } : {},
107
92
  input,
108
93
  callerStack: captureCallerStack(),
@@ -130,7 +115,7 @@ function isNonRetryableActivityError(error, policy) {
130
115
  export function shouldRetryActivityError(error, policy, attempt) {
131
116
  return policy !== void 0 && attempt < policy.maxAttempts && !isNonRetryableActivityError(error, policy);
132
117
  }
133
- function prepareActivityRetryRequest(request, attempt) {
118
+ export function prepareActivityRetryRequest(request, attempt) {
134
119
  if (attempt === 1)
135
120
  return request;
136
121
  return {
@@ -140,45 +125,76 @@ function prepareActivityRetryRequest(request, attempt) {
140
125
  };
141
126
  }
142
127
  export function createRunActivityRequest(context, activity, rest, explicitName) {
143
- const { input, options } = parseRunArguments(activity, rest), activityName = getActivityName(activity, explicitName), activityFunction = getActivityFunction(activity), internals = getInternals(context), step = internals.stepIndex++, cachedRequest = getCachedRunActivityRequest(internals, step, activityName, input);
128
+ parseRunArguments(activity, rest);
129
+ const internals = getInternals(context), step = internals.stepIndex++;
130
+ return createRunActivityRequestAtStep(context, activity, rest, step, {
131
+ ...explicitName === void 0 ? {} : { explicitName },
132
+ advanceStepIndexForCachedRetryState: !0,
133
+ retryStateKey: step,
134
+ cacheResultStep: step
135
+ });
136
+ }
137
+ export function createRunActivityRequestAtStep(context, activity, rest, step, configuration = {}) {
138
+ const { input, options } = parseRunArguments(activity, rest), activityName = getActivityName(activity, configuration.explicitName), activityFunction = getActivityFunction(activity), internals = getInternals(context), retryStateKey = configuration.retryStateKey ?? step, cacheResultStep = configuration.cacheResultStep === !1 ? void 0 : configuration.cacheResultStep ?? step, cachedRequest = getCachedRunActivityRequest(internals, step, retryStateKey, cacheResultStep, activityName, input, {
139
+ advanceStepIndexForCachedRetryState: configuration.advanceStepIndexForCachedRetryState ?? !1
140
+ });
144
141
  if (cachedRequest.hasCachedResult)
145
142
  return cachedRequest;
146
- const retryPolicy = resolveActivityRetryPolicy(activity, options), scheduleToCloseTimeout = resolveActivityScheduleToCloseTimeout(activity, options), effectiveTimeout = resolveActivityTimeout(activity, options), dispatchedOptions = effectiveTimeout === void 0 ? options : { ...options, timeout: effectiveTimeout };
143
+ const retryPolicy = resolveActivityRetryPolicy(activity, options), scheduleToCloseTimeout = resolveActivityScheduleToCloseTimeout(activity, options);
147
144
  return {
148
- request: createFreshRunActivityRequest(internals, step, activityName, activityFunction, input, dispatchedOptions),
145
+ request: createFreshRunActivityRequest(internals, step, activityName, activityFunction, input, resolveDispatchedActivityOptions(activity, options), configuration.activityStateKey, context.workflowExecutionToken),
149
146
  step,
147
+ retryStateKey,
148
+ ...cacheResultStep === void 0 ? {} : { cacheResultStep },
150
149
  hasCachedResult: !1,
151
150
  retryAttempt: cachedRequest.retryAttempt,
152
151
  ...retryPolicy === void 0 ? {} : { retryPolicy },
153
152
  ...scheduleToCloseTimeout === void 0 ? {} : { scheduleToCloseTimeout }
154
153
  };
155
154
  }
155
+ function resolveDispatchedActivityOptions(activity, options) {
156
+ const effectiveTimeout = resolveActivityTimeout(activity, options);
157
+ return effectiveTimeout === void 0 ? options : { ...options, timeout: effectiveTimeout };
158
+ }
156
159
  export function* runActivityWithRetry(context, activity, rest, explicitName) {
160
+ return yield* runPreparedActivityWithRetry(context, createRunActivityRequest(context, activity, rest, explicitName), defaultActivityRetrySleep(context));
161
+ }
162
+ export function* runActivityWithRetryAtStep(context, activity, rest, step, configuration = {}) {
163
+ return yield* runPreparedActivityWithRetry(context, createRunActivityRequestAtStep(context, activity, rest, step, configuration), configuration.retrySleep ?? defaultActivityRetrySleep(context));
164
+ }
165
+ function defaultActivityRetrySleep(context) {
166
+ return function* sleepForRetry(duration) {
167
+ yield* context.sleep(duration);
168
+ };
169
+ }
170
+ function* runPreparedActivityWithRetry(context, prepared, retrySleep) {
157
171
  const {
158
172
  request,
159
- step,
173
+ retryStateKey,
174
+ cacheResultStep,
160
175
  hasCachedResult,
161
176
  cachedResult,
162
177
  retryAttempt,
163
178
  retryPolicy,
164
179
  scheduleToCloseTimeout
165
- } = createRunActivityRequest(context, activity, rest, explicitName);
180
+ } = prepared;
166
181
  if (hasCachedResult)
167
182
  return cachedResult;
168
- const internals = getInternals(context), budget = retryPolicy === void 0 ? void 0 : resolveScheduleToCloseBudget(internals, step, scheduleToCloseTimeout);
183
+ const internals = getInternals(context), budget = retryPolicy === void 0 ? void 0 : resolveScheduleToCloseBudget(internals, retryStateKey, scheduleToCloseTimeout);
169
184
  let attempt = retryAttempt;
170
185
  if (attempt > 1) {
171
186
  if (retryPolicy === void 0)
172
187
  throw Error(`Missing activity retry policy for checkpointed retry attempt ${attempt}`);
173
- yield* context.sleep(calculateBackoff(attempt - 1, retryPolicy));
188
+ yield* retrySleep(calculateBackoff(attempt - 1, retryPolicy), attempt);
174
189
  }
175
190
  while (!0) {
176
191
  if (attempt > 1)
177
192
  assertScheduleToCloseBudgetNotExhausted(budget, request.activityName, internals.getNow());
178
193
  try {
179
194
  const result = yield prepareActivityRetryRequest(request, attempt);
180
- context.accumulatedResults.set(step, result);
181
- completeActivityRetryAttempt(internals, step, attempt - 1);
195
+ if (cacheResultStep !== void 0)
196
+ context.accumulatedResults.set(cacheResultStep, result);
197
+ completeActivityRetryAttempt(internals, retryStateKey, attempt - 1);
182
198
  return result;
183
199
  } catch (error) {
184
200
  if (!shouldRetryActivityError(error, retryPolicy, attempt))
@@ -186,8 +202,8 @@ export function* runActivityWithRetry(context, activity, rest, explicitName) {
186
202
  const backoff = calculateBackoff(attempt, retryPolicy), now = internals.getNow();
187
203
  assertScheduleToCloseBudgetNotExhausted(budget, request.activityName, now, now + backoff);
188
204
  const nextAttempt = attempt + 1;
189
- writeActivityRetryAttempt(internals, step, nextAttempt);
190
- yield* context.sleep(backoff);
205
+ writeActivityRetryAttempt(internals, retryStateKey, nextAttempt);
206
+ yield* retrySleep(backoff, nextAttempt);
191
207
  attempt = nextAttempt;
192
208
  }
193
209
  }
@@ -24,6 +24,7 @@ function assignOptionalContextOptions(options, internals) {
24
24
  function createSpeculativeChildOptions(parent, internals) {
25
25
  const options = {
26
26
  workflowId: parent.workflowId,
27
+ ...parent.workflowExecutionToken === void 0 ? {} : { workflowExecutionToken: parent.workflowExecutionToken },
27
28
  workflowType: parent.workflowType,
28
29
  startedAt: parent.startedAt,
29
30
  abortController: internals.abortController,
@@ -150,6 +150,7 @@ export interface StreamSink {
150
150
  */
151
151
  export interface ContextOptions {
152
152
  workflowId: string;
153
+ workflowExecutionToken?: string;
153
154
  workflowType: string;
154
155
  startedAt: number;
155
156
  abortController: AbortController;
@@ -1,19 +1,10 @@
1
1
  import type { ActivityContext } from '../types.ts';
2
2
  import type { EngineInternals } from './internals.ts';
3
- /**
4
- * Per-step heartbeat tracking for {@link ActivityContext.lastHeartbeatDetails}.
5
- *
6
- * The store is keyed `workflowId -> step` (not `workflowId` alone) so a retry of
7
- * an activity step reads the heartbeat ITS prior attempt recorded — and so a
8
- * later step's first attempt never inherits an earlier step's heartbeat, and
9
- * concurrent `ctx.all` activities never clobber one another. The step is stable
10
- * across retry attempts (assigned once at `stepIndex++`). Held only in engine
11
- * memory and cleared by workflowId (the outer key) on terminal cleanup and purge.
12
- */
13
- /** Record the heartbeat the current attempt of a step sent. */
14
- export declare function recordLastHeartbeatForStep(internals: EngineInternals, workflowId: string, step: number, details: unknown): void;
15
- /** Read the heartbeat a prior attempt of this step recorded, or `undefined`. */
16
- export declare function readLastHeartbeatForStep(internals: EngineInternals, workflowId: string, step: number): unknown;
3
+ export type ActivityHeartbeatKey = number | string;
4
+ /** Record the heartbeat the current attempt of an activity sent. */
5
+ export declare function recordLastHeartbeatForStep(internals: EngineInternals, workflowId: string, step: ActivityHeartbeatKey, details: unknown): void;
6
+ /** Read the heartbeat a prior attempt of this activity recorded, or `undefined`. */
7
+ export declare function readLastHeartbeatForStep(internals: EngineInternals, workflowId: string, step: ActivityHeartbeatKey): unknown;
17
8
  /**
18
9
  * Drop the heartbeat tracked for a single step once that step has completed
19
10
  * successfully — after inline verify, and (on the idempotency path) after the
@@ -26,7 +17,7 @@ export declare function readLastHeartbeatForStep(internals: EngineInternals, wor
26
17
  * resumable-batch heartbeat a retry depends on, so this is only ever called from
27
18
  * the non-speculative success path.
28
19
  */
29
- export declare function clearLastHeartbeatForStep(internals: EngineInternals, workflowId: string, step: number): void;
20
+ export declare function clearLastHeartbeatForStep(internals: EngineInternals, workflowId: string, step: ActivityHeartbeatKey): void;
30
21
  /**
31
22
  * #493: in development mode, emit a COARSE warning when an inline activity RETRY
32
23
  * (`attempt > 1`) starts with no `lastHeartbeatDetails` — the closest runtime
@@ -53,7 +44,7 @@ export declare function clearLastHeartbeatForStep(internals: EngineInternals, wo
53
44
  * routing model would need this gate to key on the resolved per-dispatch mode
54
45
  * instead.
55
46
  */
56
- export declare function warnIfRetryMissingHeartbeat(internals: EngineInternals, workflowId: string, step: number, attempt: number): void;
47
+ export declare function warnIfRetryMissingHeartbeat(internals: EngineInternals, workflowId: string, step: ActivityHeartbeatKey, attempt: number): void;
57
48
  /**
58
49
  * Build the {@link ActivityContext} handed to an inline activity function. The
59
50
  * signal comes from the per-workflow AbortController (so workflow cancellation
@@ -61,4 +52,4 @@ export declare function warnIfRetryMissingHeartbeat(internals: EngineInternals,
61
52
  * tracking above; `completeAsync` is supplied by the caller (it owns the
62
53
  * async-completion token machinery).
63
54
  */
64
- export declare function buildActivityContext(internals: EngineInternals, workflowId: string, step: number, signal: AbortSignal, completeAsync: () => never): ActivityContext;
55
+ export declare function buildActivityContext(internals: EngineInternals, workflowId: string, workflowExecutionToken: string | undefined, step: ActivityHeartbeatKey, attempt: number, signal: AbortSignal, completeAsync: () => never): ActivityContext;
@@ -1,4 +1,10 @@
1
1
  import { DevelopmentWarningEvent } from "../events.js";
2
+ function activityHeartbeatKeyLabel(key) {
3
+ return typeof key === "number" ? `step ${String(key)}` : `activity state key ${key}`;
4
+ }
5
+ function activityHeartbeatFieldPath(key) {
6
+ return typeof key === "number" ? `step.${String(key)}.lastHeartbeatDetails` : `activityStateKey.${key}.lastHeartbeatDetails`;
7
+ }
2
8
  export function recordLastHeartbeatForStep(internals, workflowId, step, details) {
3
9
  let byStep = internals.lastHeartbeatDetailsByStep.get(workflowId);
4
10
  if (byStep === void 0) {
@@ -27,11 +33,15 @@ export function warnIfRetryMissingHeartbeat(internals, workflowId, step, attempt
27
33
  return;
28
34
  if (readLastHeartbeatForStep(internals, workflowId, step) !== void 0)
29
35
  return;
30
- internals.engine.dispatchEvent(new DevelopmentWarningEvent(workflowId, `Activity retry (attempt ${attempt}) at step ${step} has no lastHeartbeatDetails. Either the previous attempt never recorded heartbeat details (it never called heartbeat(), or called it with no details), or the engine process restarted and discarded the in-memory heartbeat (it is not durable). The resumable-batch pattern only resumes across in-process retries; design the activity to restart cleanly when lastHeartbeatDetails is undefined.`, [`step.${step}.lastHeartbeatDetails`]));
36
+ internals.engine.dispatchEvent(new DevelopmentWarningEvent(workflowId, `Activity retry (attempt ${attempt}) at ${activityHeartbeatKeyLabel(step)} has no lastHeartbeatDetails. Either the previous attempt never recorded heartbeat details (it never called heartbeat(), or called it with no details), or the engine process restarted and discarded the in-memory heartbeat (it is not durable). The resumable-batch pattern only resumes across in-process retries; design the activity to restart cleanly when lastHeartbeatDetails is undefined.`, [activityHeartbeatFieldPath(step)]));
31
37
  }
32
- export function buildActivityContext(internals, workflowId, step, signal, completeAsync) {
38
+ export function buildActivityContext(internals, workflowId, workflowExecutionToken, step, attempt, signal, completeAsync) {
33
39
  return {
34
40
  signal,
41
+ ...workflowExecutionToken !== void 0 && {
42
+ workflowExecutionToken,
43
+ activityAttemptToken: `${workflowExecutionToken}:activity:${String(step)}:${String(attempt)}`
44
+ },
35
45
  lastHeartbeatDetails: readLastHeartbeatForStep(internals, workflowId, step),
36
46
  heartbeat: (details) => {
37
47
  internals.heartbeatDetails.set(workflowId, details);
@@ -102,6 +102,7 @@ export declare function resolveStartedActivityReconciliationRecord(internals: En
102
102
  }>;
103
103
  export declare function writeActivityReconciliationTransition(storage: Storage, reference: ActivityReconciliationReference, expectedRecord: ActivityReconciliationRecord, nextRecord: ActivityReconciliationRecord): Promise<void>;
104
104
  export declare function stageActivityReconciliationTransitionWithAtomicWorkflowCommit(internals: EngineInternals, workflowId: string, reference: ActivityReconciliationReference, expectedRecord: ActivityReconciliationRecord, nextRecord: ActivityReconciliationRecord): void;
105
+ export declare function commitActivityReconciliationTransitionWithFencedWrite(internals: EngineInternals, reference: ActivityReconciliationReference, expectedRecord: ActivityReconciliationRecord, nextRecord: ActivityReconciliationRecord): Promise<void>;
105
106
  export declare function normalizePreDispatchVerificationResult(result: ActivityVerificationResult): 'not-completed' | 'completed-result-unavailable' | 'indeterminate' | {
106
107
  result: unknown;
107
108
  };
@@ -7,6 +7,7 @@ import { decode, encode } from "../codec.js";
7
7
  import { assertPayloadWithinLimit } from "../payload-size.js";
8
8
  import { WeftError } from "../weft-error.js";
9
9
  import { stageAtomicWorkflowCommitSideEffects } from "./checkpoint-side-effects.js";
10
+ import { commitFencedEngineWrite } from "./fenced-write.js";
10
11
 
11
12
  export class ActivityReconciliationCapabilityError extends WeftError {
12
13
  constructor() {
@@ -83,7 +84,7 @@ export async function resolveStartedActivityReconciliationRecord(internals, work
83
84
  ownerId: crypto.randomUUID(),
84
85
  updatedAt: internals.options.getNow()
85
86
  };
86
- await writeActivityReconciliationTransition(internals.storage, reference, record, nextRecord);
87
+ await commitActivityReconciliationTransitionWithFencedWrite(internals, reference, record, nextRecord);
87
88
  return nextRecord;
88
89
  }
89
90
  if (normalized === "completed-result-unavailable")
@@ -92,7 +93,7 @@ export async function resolveStartedActivityReconciliationRecord(internals, work
92
93
  throw new ActivityReconciliationIndeterminateError(`Activity "${operation.activityName}" reconciliation is indeterminate.`);
93
94
  validateActivityResultForReconciliation(normalized.result, internals.options.payloadSizePolicy.maxBytes);
94
95
  const completedRecord = createCompletedActivityReconciliationRecord(record, normalized.result, internals.options.getNow());
95
- await writeActivityReconciliationTransition(internals.storage, reference, record, completedRecord);
96
+ await commitActivityReconciliationTransitionWithFencedWrite(internals, reference, record, completedRecord);
96
97
  return { completedResult: normalized.result };
97
98
  }
98
99
  export async function writeActivityReconciliationTransition(storage, reference, expectedRecord, nextRecord) {
@@ -103,6 +104,10 @@ export async function writeActivityReconciliationTransition(storage, reference,
103
104
  export function stageActivityReconciliationTransitionWithAtomicWorkflowCommit(internals, workflowId, reference, expectedRecord, nextRecord) {
104
105
  stageAtomicWorkflowCommitSideEffects(internals, workflowId, buildActivityReconciliationTransitionSideEffects(reference, expectedRecord, nextRecord));
105
106
  }
107
+ export async function commitActivityReconciliationTransitionWithFencedWrite(internals, reference, expectedRecord, nextRecord) {
108
+ const sideEffects = buildActivityReconciliationTransitionSideEffects(reference, expectedRecord, nextRecord);
109
+ await commitFencedEngineWrite(internals, sideEffects.operations, sideEffects.conditions, () => new ActivityReconciliationConflictError("Activity reconciliation completion lost compare-and-set ownership."));
110
+ }
106
111
  function buildActivityReconciliationTransitionSideEffects(reference, expectedRecord, nextRecord) {
107
112
  return {
108
113
  conditions: [{ key: reference.key, expectedValue: encode(expectedRecord) }],
@@ -79,21 +79,21 @@ async function scanNextAnonymousSignalSequence(internals, workflowId) {
79
79
  if (sequence !== null && sequence >= nextSequence)
80
80
  nextSequence = sequence + 1;
81
81
  }
82
+ if (!Number.isSafeInteger(nextSequence))
83
+ throw Error(`Anonymous signal sequence overflow for workflow "${workflowId}": computed ${nextSequence}`);
82
84
  return nextSequence;
83
85
  }
84
86
  function extractAnonymousSignalSequence(key) {
85
- const marker = ":anonymous%3A", markerIndex = key.lastIndexOf(marker);
86
- if (markerIndex === -1)
87
+ const idComponent = key.slice(key.lastIndexOf(":") + 1), marker = "anonymous%3A";
88
+ if (!idComponent.startsWith(marker))
87
89
  return null;
88
- const sequenceStart = markerIndex + marker.length, sequenceEnd = key.indexOf("%3A", sequenceStart);
90
+ const sequenceStart = marker.length, sequenceEnd = idComponent.indexOf("%3A", sequenceStart);
89
91
  if (sequenceEnd === -1)
90
92
  return null;
91
- const sequence = Number(key.slice(sequenceStart, sequenceEnd));
93
+ const sequence = Number(idComponent.slice(sequenceStart, sequenceEnd));
92
94
  return Number.isSafeInteger(sequence) && sequence >= 0 ? sequence : null;
93
95
  }
94
96
  function decodeSignalSequence(bytes) {
95
- if (bytes === null)
96
- return 0;
97
97
  const value = decode(bytes);
98
98
  if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
99
99
  throw Error("Stored anonymous signal sequence must be a non-negative safe integer");
@@ -26,9 +26,6 @@
26
26
  * arrives after token recovery but before replay has adopted the workflow
27
27
  * generator, the engine buffers the completion or failure outcome and drains it
28
28
  * when replay reaches the same deterministic token.
29
- *
30
- * Internal-only. Imported from `src/core/engine/**` and the `ActivityContext`
31
- * construction path.
32
29
  */
33
30
  import type { OperationOutcome } from '../types.ts';
34
31
  import { WeftError } from '../weft-error.ts';
@@ -101,13 +98,14 @@ export type PendingAsyncActivityResolution = {
101
98
  /**
102
99
  * Derive the durable, deterministic task token for an async activity.
103
100
  *
104
- * The token is anchored to the workflow id, the workflow step index, and the
101
+ * The token is anchored to the workflow id, the activity state key, and the
105
102
  * dispatch attempt — all of which are stable across replay — so a workflow that
106
103
  * crashes while parked on an async activity mints the identical token after
107
- * recovery. `operationId` is deliberately excluded because it is regenerated on
108
- * every yield and would change on replay.
104
+ * recovery. Plain `ctx.run()` uses the workflow step as the state key.
105
+ * `operationId` is deliberately excluded because it is regenerated on every
106
+ * yield and would change on replay.
109
107
  */
110
- export declare function deriveAsyncActivityToken(workflowId: string, step: number, attempt: number): string;
108
+ export declare function deriveAsyncActivityToken(workflowId: string, step: number | string, attempt: number): string;
111
109
  /**
112
110
  * Register a deferred activity: record it in memory and durably, then announce
113
111
  * the token via {@link ActivityAsyncPendingEvent}. Idempotent on `token`: if the
@@ -3,6 +3,8 @@ import { decode, encode } from "../codec.js";
3
3
  import { ActivityAsyncPendingEvent } from "../events.js";
4
4
  import { assertPayloadWithinLimit } from "../payload-size.js";
5
5
  import { WeftError } from "../weft-error.js";
6
+ import { stageAtomicWorkflowCommitSideEffects } from "./checkpoint-side-effects.js";
7
+ import { commitFencedEngineWrite } from "./fenced-write.js";
6
8
  const ASYNC_ACTIVITY_TOKEN_PREFIX = "async-act:v1", ASYNC_ACTIVITY_KEY_PREFIX = "async-act:v1:";
7
9
  export function asyncActivityWorkflowPrefix(workflowId) {
8
10
  return `${ASYNC_ACTIVITY_KEY_PREFIX}${encodeStorageKeyComponent(workflowId)}:`;
@@ -33,7 +35,7 @@ function isPersistedAsyncActivity(value) {
33
35
  export function deriveAsyncActivityToken(workflowId, step, attempt) {
34
36
  return `${ASYNC_ACTIVITY_TOKEN_PREFIX}:${workflowId}:${step}:${attempt}`;
35
37
  }
36
- function persistPendingAsyncActivity(storage, pending) {
38
+ function buildPersistPendingAsyncActivityOperation(pending) {
37
39
  const record = {
38
40
  version: 1,
39
41
  token: pending.token,
@@ -44,12 +46,16 @@ function persistPendingAsyncActivity(storage, pending) {
44
46
  attempt: pending.attempt,
45
47
  createdAt: pending.createdAt
46
48
  };
47
- return storage.put(KEYS.asyncActivity(pending.workflowId, pending.token), encode(record));
49
+ return {
50
+ type: "put",
51
+ key: KEYS.asyncActivity(pending.workflowId, pending.token),
52
+ value: encode(record)
53
+ };
48
54
  }
49
55
  export async function registerPendingAsyncActivity(internals, pending) {
50
56
  const alreadyRegistered = internals.pendingAsyncActivities.has(pending.token);
51
57
  internals.pendingAsyncActivities.set(pending.token, pending);
52
- await persistPendingAsyncActivity(internals.storage, pending);
58
+ await commitFencedEngineWrite(internals, [buildPersistPendingAsyncActivityOperation(pending)], [], () => Error(`Async activity registration for token "${pending.token}" lost its precondition.`));
53
59
  if (!alreadyRegistered)
54
60
  internals.engine.dispatchEvent(new ActivityAsyncPendingEvent(pending.token, pending.operationId, pending.workflowId, pending.activityName, pending.attempt));
55
61
  }
@@ -87,12 +93,10 @@ async function consumePendingAsyncActivity(internals, token) {
87
93
  if (!pending)
88
94
  throw new AsyncActivityTokenNotFoundError(token);
89
95
  internals.pendingAsyncActivities.delete(token);
90
- try {
91
- await internals.storage.delete(KEYS.asyncActivity(pending.workflowId, token));
92
- } catch (error) {
93
- internals.pendingAsyncActivities.set(token, pending);
94
- throw error;
95
- }
96
+ stageAtomicWorkflowCommitSideEffects(internals, pending.workflowId, {
97
+ conditions: [],
98
+ operations: [{ type: "delete", key: KEYS.asyncActivity(pending.workflowId, token) }]
99
+ });
96
100
  return pending;
97
101
  }
98
102
  function shouldBufferPendingAsyncActivityResolution(internals, workflowId) {
@@ -10,6 +10,7 @@ import { buildIndexOperations } from "../search-attributes.js";
10
10
  import { buildWorkflowTagIndexOperations, normalizeWorkflowTags } from "../workflow-tags.js";
11
11
  import { asyncActivityWorkflowPrefix } from "./async-activity-completion.js";
12
12
  import { forgetCommittedCheckpointBytes } from "./checkpoint-commit-snapshots.js";
13
+ import { commitFencedEngineWrite } from "./fenced-write.js";
13
14
  import { streamWorkflowStates } from "./listing.js";
14
15
  import { createTerminalCleanupTimerId } from "./state-utilities.js";
15
16
  import {
@@ -131,7 +132,7 @@ function getWorkflowRetentionDeadline(internals, state) {
131
132
  }
132
133
  export async function purgeWorkflow(internals, state, cleanupWaiters) {
133
134
  const deleteOperations = await collectWorkflowPurgeDeleteOperations(internals, state);
134
- await internals.storage.batch(deleteOperations);
135
+ await commitFencedEngineWrite(internals, deleteOperations, [], () => Error(`Purge commit for workflow "${state.id}" lost its precondition.`));
135
136
  clearPurgedWorkflowInMemoryState(internals, state.id, cleanupWaiters);
136
137
  }
137
138
  export async function collectWorkflowPurgeDeleteOperations(internals, state) {
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  KEYS,
3
3
  requireStorageCapability,
4
- storageConditionalBatch,
5
4
  storageHas
6
5
  } from "../../storage/interface.js";
7
6
  import { assertScopedBulkWorkflowFilter } from "../bulk-workflow-filter.js";
@@ -24,6 +23,10 @@ import {
24
23
  withBulkAuditEvent
25
24
  } from "./bulk-operations-shared.js";
26
25
  import { BulkDeleteRequiresTerminalWorkflowsError } from "./errors.js";
26
+ import {
27
+ assertLeaseHeldForEngineWork,
28
+ commitFencedEngineWriteAllowingPreconditionFailure
29
+ } from "./fenced-write.js";
27
30
  import { BULK_OPERATION_BATCH_SIZE } from "./listing.js";
28
31
  import { createTerminalCleanupTimerId } from "./state-utilities.js";
29
32
  import { loadWorkflowState, runSerializedWorkflowStateWrite } from "./storage-io.js";
@@ -59,20 +62,13 @@ async function runBulkCancellation(internals, filter, options = {}) {
59
62
  const workflowIdsToCancel = preparation.workflowIds, bulkConcurrency = resolveBulkOperationConcurrency(options);
60
63
  let cancelled = 0;
61
64
  const errors = [], cancellationResults = await runBulkWorkflowPool(workflowIdsToCancel, bulkConcurrency, async (workflowId) => {
62
- try {
63
- await internals.engine.cancel(workflowId);
64
- if ((await loadWorkflowState(internals, workflowId))?.status === "cancelled")
65
- return { status: "cancelled" };
66
- return {
67
- status: "failed",
68
- error: { id: workflowId, error: "Workflow no longer cancellable" }
69
- };
70
- } catch (error) {
71
- return {
72
- status: "failed",
73
- error: toBulkOperationError(internals, workflowId, error)
74
- };
75
- }
65
+ await internals.engine.cancel(workflowId);
66
+ if ((await loadWorkflowState(internals, workflowId))?.status === "cancelled")
67
+ return { status: "cancelled" };
68
+ return {
69
+ status: "failed",
70
+ error: { id: workflowId, error: "Workflow no longer cancellable" }
71
+ };
76
72
  });
77
73
  for (const cancellationResult of cancellationResults) {
78
74
  if (cancellationResult.status === "rejected") {
@@ -104,27 +100,15 @@ async function runBulkFailedWorkflowRetry(internals, filter, options = {}) {
104
100
  const bulkConcurrency = resolveBulkOperationConcurrency(options);
105
101
  let retried = 0;
106
102
  const errors = [], retryResults = await runBulkWorkflowPool(preparation.workflowIds, bulkConcurrency, async (workflowId) => {
107
- try {
108
- await retryFailedWorkflow(internals, workflowId);
109
- return { status: "retried" };
110
- } catch (error) {
111
- return {
112
- status: "failed",
113
- error: toBulkOperationError(internals, workflowId, error)
114
- };
115
- }
103
+ await retryFailedWorkflow(internals, workflowId);
104
+ return { status: "retried" };
116
105
  });
117
106
  for (const retryResult of retryResults) {
118
107
  if (retryResult.status === "rejected") {
119
108
  errors.push(toBulkOperationError(internals, retryResult.item, retryResult.reason));
120
109
  continue;
121
110
  }
122
- const { value } = retryResult;
123
- if (value.status === "retried") {
124
- retried += 1;
125
- continue;
126
- }
127
- errors.push(value.error);
111
+ retried += 1;
128
112
  }
129
113
  const result = { retried, failed: errors.length, errors };
130
114
  if (!shouldPersistBulkAudit(options))
@@ -132,6 +116,7 @@ async function runBulkFailedWorkflowRetry(internals, filter, options = {}) {
132
116
  return withBulkAuditEvent(internals, preparation, options, result, retried);
133
117
  }
134
118
  export async function retryFailedAll(internals, filter, options = {}) {
119
+ assertLeaseHeldForEngineWork(internals);
135
120
  return runBulkFailedWorkflowRetry(internals, filter, options);
136
121
  }
137
122
  async function retryFailedWorkflow(internals, workflowId) {
@@ -194,12 +179,9 @@ async function reactivateFailedWorkflowFromCheckpointSerialized(internals, workf
194
179
  throw Error(`Workflow concurrency admission for "${lastConcurrencyStateKey ?? workflowId}" changed too many times while retrying failed workflow "${workflowId}"`);
195
180
  }
196
181
  async function commitFailedWorkflowReactivation(internals, operations, conditions) {
197
- if (conditions.length === 0) {
198
- await internals.storage.batch(operations);
199
- return !0;
200
- }
201
- requireStorageCapability(internals.storage, "conditionalBatch", "retry failed workflow");
202
- return storageConditionalBatch(internals.storage, conditions, operations);
182
+ if (conditions.length > 0)
183
+ requireStorageCapability(internals.storage, "conditionalBatch", "retry failed workflow");
184
+ return commitFencedEngineWriteAllowingPreconditionFailure(internals, operations, conditions);
203
185
  }
204
186
  function buildReactivatedWorkflowState(internals, state) {
205
187
  const reactivatedState = {
@@ -0,0 +1,3 @@
1
+ import type { ContextOperationRequest } from '../context.ts';
2
+ import type { Engine } from './index.ts';
3
+ export declare function persistCheckpointForDataOperation<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>, workflowId: string, operation: ContextOperationRequest): Promise<void>;
@@ -0,0 +1,25 @@
1
+ import { HISTORY_CIRCUIT_BREAKER_REASON } from "../types.js";
2
+ import { validateAttributeValueSizes } from "./attributes-tags.js";
3
+ import { createTerminationCallbacks } from "./callback-creators-core.js";
4
+ import {
5
+ appendTimelineBatchOperations,
6
+ persistCheckpoint,
7
+ pruneCheckpointHistory
8
+ } from "./checkpoint-io.js";
9
+ import { getInternals } from "./internals.js";
10
+ import { swallowPromiseRejection } from "./strategy-helpers.js";
11
+ import { terminateWorkflow } from "./termination.js";
12
+ export function persistCheckpointForDataOperation(engine, workflowId, operation) {
13
+ return persistCheckpoint(getInternals(engine), workflowId, operation, void 0, {
14
+ appendTimelineBatchOperations: (id, checkpointOperation, step, timestamp, operations) => appendTimelineBatchOperations(getInternals(engine), id, checkpointOperation, step, timestamp, operations),
15
+ swallowPromiseRejection: (promise) => {
16
+ swallowPromiseRejection(promise);
17
+ },
18
+ validateAttributeValueSizes,
19
+ pruneCheckpointHistory: (id, step) => pruneCheckpointHistory(getInternals(engine), id, step),
20
+ dispatchEvent: (event) => {
21
+ engine.dispatchEvent(event);
22
+ },
23
+ enforceHistoryCircuitBreaker: (id) => terminateWorkflow(getInternals(engine), id, "timed-out", createTerminationCallbacks(engine), HISTORY_CIRCUIT_BREAKER_REASON)
24
+ }, { timeline: "preserve-pending" });
25
+ }
@@ -3,6 +3,7 @@ import {
3
3
  broadcast as broadcastFromInternals,
4
4
  dispatchPendingUpdateReceived as dispatchPendingUpdateReceivedFromBroadcast
5
5
  } from "./broadcast.js";
6
+ import { persistCheckpointForDataOperation } from "./callback-checkpoint-persistence.js";
6
7
  import {
7
8
  createBroadcastCallbacks,
8
9
  createGuardCallbacks,
@@ -97,7 +98,9 @@ export function createConditionOperationCallbacks(engine) {
97
98
  }
98
99
  export function createDataOperationCallbacks(engine) {
99
100
  return {
100
- runOperationWithResult: (workflowId, operation, execute) => runOperationWithResultForEngine(engine, workflowId, operation, execute)
101
+ runOperationWithResult: (workflowId, operation, execute) => runOperationWithResultForEngine(engine, workflowId, operation, execute),
102
+ persistCheckpoint: (workflowId, operation) => persistCheckpointForDataOperation(engine, workflowId, operation),
103
+ getActivityOperationCallbacks: () => createActivityOperationCallbacks(engine)
101
104
  };
102
105
  }
103
106
  export function createStateOperationCallbacks(engine) {
@@ -119,7 +122,7 @@ export function createTimeOperationCallbacks(engine) {
119
122
  loadWorkflowState: (workflowId) => loadWorkflowState(getInternals(engine), workflowId),
120
123
  failWorkflow: (workflowId, error) => failWorkflow(getInternals(engine), workflowId, error, createTerminationCallbacks(engine)),
121
124
  runSerializedWorkflowStateWrite: (workflowId, writeOperation) => runSerializedWorkflowStateWrite(getInternals(engine), workflowId, writeOperation),
122
- beginWorkflowExecution: (workflowId, workflowType, input, checkpoint, executionDeadline, executionStateOwnerId, registration) => beginWorkflowExecution(getInternals(engine), workflowId, workflowType, input, checkpoint, executionDeadline, executionStateOwnerId, registration, createLifecycleCallbacks(engine)),
125
+ beginWorkflowExecution: (workflowId, workflowExecutionToken, workflowType, input, checkpoint, executionDeadline, executionStateOwnerId, registration) => beginWorkflowExecution(getInternals(engine), workflowId, workflowExecutionToken, workflowType, input, checkpoint, executionDeadline, executionStateOwnerId, registration, createLifecycleCallbacks(engine)),
123
126
  workflowVersionTupleFromState: (state) => workflowVersionTupleFromState(getInternals(engine), state, createLifecycleCallbacks(engine)),
124
127
  setWorkflowStartHeaders: (workflowId, headers) => setWorkflowStartHeaders(getInternals(engine), workflowId, headers, createLifecycleCallbacks(engine)),
125
128
  loadWorkflowStartHeaders: (workflowId) => loadWorkflowStartHeaders(getInternals(engine), workflowId, createLifecycleCallbacks(engine)),