@fluidgrids/workflows 2026.1028.2 → 2026.1030.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/README.md +181 -11
  2. package/dist/{activation-BBh1p82z.d.cts → activation-DqUfpHzk.d.cts} +1 -1
  3. package/dist/{activation-DnhG7SmF.d.ts → activation-xpx1oWuo.d.ts} +1 -1
  4. package/dist/{chunk-VRHHBPT6.js → chunk-2D3MYIIF.js} +1212 -128
  5. package/dist/chunk-3U2NU7YC.cjs +124 -0
  6. package/dist/{chunk-NEIUQASE.cjs → chunk-4QKB4ARC.cjs} +3 -3
  7. package/dist/{chunk-GBQ33SIZ.cjs → chunk-54FLQNUM.cjs} +12 -1
  8. package/dist/chunk-5HIVIV53.js +330 -0
  9. package/dist/chunk-5MFVJM76.js +1222 -0
  10. package/dist/{chunk-JD2VQIDZ.cjs → chunk-672KMMBK.cjs} +2 -2
  11. package/dist/{chunk-C5OLWZ42.js → chunk-6A2FGSUS.js} +22 -14
  12. package/dist/{chunk-XKJA7KX3.js → chunk-6OLN6BMB.js} +52 -3
  13. package/dist/{chunk-6FSHT5IL.js → chunk-7EZIANC7.js} +1 -1
  14. package/dist/{chunk-2J6TF7YI.cjs → chunk-A5SXCA62.cjs} +10 -3
  15. package/dist/{chunk-BO6OVILK.js → chunk-AC6ZEXVR.js} +10 -4
  16. package/dist/{chunk-ABFZWYHT.js → chunk-AE5Q6ZAJ.js} +315 -50
  17. package/dist/chunk-C4F5KJTI.js +293 -0
  18. package/dist/{chunk-IISBRUWJ.js → chunk-G5H32GIG.js} +1 -1
  19. package/dist/chunk-GEQDGUGB.cjs +2719 -0
  20. package/dist/{chunk-XHXIDVEC.js → chunk-HCM7ZC7Q.js} +1 -1
  21. package/dist/chunk-HMZUGSMU.cjs +1554 -0
  22. package/dist/{chunk-SAOBPYYJ.cjs → chunk-IQPXHQQQ.cjs} +8 -4
  23. package/dist/{chunk-P6TA5EZT.cjs → chunk-ISOIA7NV.cjs} +335 -58
  24. package/dist/chunk-JSC75O5C.cjs +167 -0
  25. package/dist/chunk-M272AHEX.js +25 -0
  26. package/dist/{chunk-BD7ZPG53.js → chunk-NWQ5WRLE.js} +10 -2
  27. package/dist/chunk-ODZ2IAR2.cjs +1247 -0
  28. package/dist/chunk-Q4MWQNJK.cjs +28 -0
  29. package/dist/{chunk-HWJZVOG7.js → chunk-SR7TR5KX.js} +6 -2
  30. package/dist/{chunk-FEW3JBYA.cjs → chunk-TCTE7DX5.cjs} +3 -3
  31. package/dist/{chunk-623FVQSN.cjs → chunk-TYF56RGB.cjs} +123 -0
  32. package/dist/chunk-VA4OFR72.cjs +324 -0
  33. package/dist/chunk-VU5S5A7V.js +150 -0
  34. package/dist/chunk-YEHR4NNE.js +1522 -0
  35. package/dist/{chunk-FMSW2HDF.cjs → chunk-ZCGKGDCL.cjs} +23 -15
  36. package/dist/codegen/index.d.cts +2 -2
  37. package/dist/codegen/index.d.ts +2 -2
  38. package/dist/collect-6NIEufHd.d.ts +103 -0
  39. package/dist/collect-CcTCKqx6.d.cts +103 -0
  40. package/dist/{file-BOoHZgoQ.d.cts → file-BxYpwjRQ.d.cts} +1007 -21
  41. package/dist/{file-yuPCFU5b.d.ts → file-CFdPQJI9.d.ts} +1007 -21
  42. package/dist/history/index.cjs +375 -86
  43. package/dist/history/index.d.cts +590 -12
  44. package/dist/history/index.d.ts +590 -12
  45. package/dist/history/index.js +50 -4
  46. package/dist/index.cjs +156 -50
  47. package/dist/index.d.cts +38 -58
  48. package/dist/index.d.ts +38 -58
  49. package/dist/index.js +6 -4
  50. package/dist/interceptors-CNcr2dlk.d.ts +159 -0
  51. package/dist/interceptors-CqkNZVfI.d.cts +159 -0
  52. package/dist/ir/index.cjs +362 -38
  53. package/dist/ir/index.d.cts +282 -7
  54. package/dist/ir/index.d.ts +282 -7
  55. package/dist/ir/index.js +329 -23
  56. package/dist/{lower-BzmUz0sq.d.cts → lower-BtRfIW2A.d.cts} +56 -8
  57. package/dist/{lower-_-iT4HYs.d.ts → lower-CpsMFOFX.d.ts} +56 -8
  58. package/dist/{manifest-C8N6HDYl.d.ts → manifest-D-I_twys.d.ts} +1 -1
  59. package/dist/{manifest-0OLw0i7k.d.cts → manifest-DahBQVM8.d.cts} +1 -1
  60. package/dist/node-evaluator-DGQDPSPI.cjs +24 -0
  61. package/dist/node-evaluator-LEEVD7H7.js +14 -0
  62. package/dist/payload-fields-BVRQn2yH.d.cts +122 -0
  63. package/dist/payload-fields-oOBWxDiG.d.ts +122 -0
  64. package/dist/quickjs/index.cjs +28 -27
  65. package/dist/quickjs/index.d.cts +6 -6
  66. package/dist/quickjs/index.d.ts +6 -6
  67. package/dist/quickjs/index.js +10 -9
  68. package/dist/roundtrip/index.cjs +259 -51
  69. package/dist/roundtrip/index.d.cts +100 -9
  70. package/dist/roundtrip/index.d.ts +100 -9
  71. package/dist/roundtrip/index.js +177 -11
  72. package/dist/runtime/index.cjs +21 -20
  73. package/dist/runtime/index.d.cts +184 -15
  74. package/dist/runtime/index.d.ts +184 -15
  75. package/dist/runtime/index.js +8 -7
  76. package/dist/testing/index.cjs +1122 -115
  77. package/dist/testing/index.d.cts +294 -13
  78. package/dist/testing/index.d.ts +294 -13
  79. package/dist/testing/index.js +1086 -84
  80. package/dist/{types-DV-HX_Gt.d.ts → types-Bv2i4cBX.d.cts} +244 -33
  81. package/dist/{types-CpBBjaGX.d.cts → types-DGx-b9eq.d.ts} +244 -33
  82. package/dist/{types-BGoPzgcl.d.ts → types-V7jEEUaL.d.cts} +20 -1
  83. package/dist/{types-BGoPzgcl.d.cts → types-V7jEEUaL.d.ts} +20 -1
  84. package/dist/{workflow-Bpr3vnA_.d.ts → workflow-B18OeF7g.d.ts} +2 -2
  85. package/dist/workflow-BGnv8SS6.d.ts +803 -0
  86. package/dist/{workflow-FXUkpIBc.d.cts → workflow-BJPFv3cp.d.cts} +2 -2
  87. package/dist/workflow-DS32Gtws.d.cts +803 -0
  88. package/fixtures/histories/activity-options-updated.history.json +159 -0
  89. package/fixtures/histories/activity-paused-unpaused.history.json +160 -0
  90. package/fixtures/histories/auto-upgrade-patched.history.json +276 -0
  91. package/fixtures/histories/benign-failure.history.json +146 -0
  92. package/fixtures/histories/cancel-activity-try-cancel.history.json +150 -0
  93. package/fixtures/histories/child-cancel-wait-requested.history.json +217 -0
  94. package/fixtures/histories/child-options-roundtrip.history.json +192 -0
  95. package/fixtures/histories/codec-opaque.history.json +229 -0
  96. package/fixtures/histories/continue-as-new-last-result.history.json +86 -0
  97. package/fixtures/histories/continue-as-new-options.history.json +99 -0
  98. package/fixtures/histories/continue-as-new-r1-long-task-queue.history.json +78 -0
  99. package/fixtures/histories/continue-as-new-r1-retry-options.history.json +83 -0
  100. package/fixtures/histories/dynamic-workflow.history.json +150 -0
  101. package/fixtures/histories/execution-timeout-chain.history.json +98 -0
  102. package/fixtures/histories/external-cancel-resolved.history.json +123 -0
  103. package/fixtures/histories/external-cancel-unknown-target.history.json +127 -0
  104. package/fixtures/histories/failure-error-types-fails-run.history.json +144 -0
  105. package/fixtures/histories/handler-drain-warn.history.json +222 -0
  106. package/fixtures/histories/heartbeat-details-on-retry.history.json +145 -0
  107. package/fixtures/histories/interceptor-headers.history.json +339 -0
  108. package/fixtures/histories/local-activity-abandoned-at-completion.history.json +73 -0
  109. package/fixtures/histories/local-activity-cancelled-in-scope.history.json +118 -0
  110. package/fixtures/histories/local-activity-completed.history.json +157 -0
  111. package/fixtures/histories/local-activity-failed.history.json +93 -0
  112. package/fixtures/histories/local-activity-retry-in-task.history.json +88 -0
  113. package/fixtures/histories/query-custom.history.json +213 -0
  114. package/fixtures/histories/query-default-handler.history.json +120 -0
  115. package/fixtures/histories/reset-forked-reapplied-signals.history.json +239 -0
  116. package/fixtures/histories/reset-reapplied-update-admitted.history.json +228 -0
  117. package/fixtures/histories/run-retry-last-failure.history.json +90 -0
  118. package/fixtures/histories/run-timeout.history.json +159 -0
  119. package/fixtures/histories/schedule-to-start-timeout.history.json +132 -0
  120. package/fixtures/histories/search-attributes-upserted.history.json +177 -0
  121. package/fixtures/histories/start-delay-signal-ends-delay.history.json +155 -0
  122. package/fixtures/histories/typeerror-task-retry-100.history.json +137 -0
  123. package/fixtures/histories/update-accepted-completed.history.json +45 -30
  124. package/fixtures/histories/update-default-handler.history.json +246 -0
  125. package/fixtures/histories/update-handler-awaits-activity.history.json +196 -0
  126. package/fixtures/histories/update-not-handled.history.json +138 -0
  127. package/fixtures/histories/update-rejected-no-event.history.json +190 -0
  128. package/fixtures/histories/update-with-start-admitted.history.json +150 -0
  129. package/fixtures/histories/user-activity-cancel.history.json +149 -0
  130. package/fixtures/histories/user-activity-retry.history.json +143 -0
  131. package/fixtures/histories/user-activity.history.json +149 -0
  132. package/package.json +1 -1
  133. package/schema/bridge-v2.schema.json +1062 -0
  134. package/schema/history-file.schema.json +538 -83
  135. package/schema/ir-v2.schema.json +290 -0
  136. package/schema/payload-fields.json +162 -0
  137. package/schema/run-event.schema.json +503 -82
  138. package/schema/workflow-command.schema.json +372 -69
  139. package/schema/workflow-task.schema.json +924 -171
  140. package/dist/assemble-BLqQ8lSu.d.cts +0 -39
  141. package/dist/assemble-DWgaXHd-.d.ts +0 -39
  142. package/dist/chunk-DHTLALBL.cjs +0 -80
  143. package/dist/chunk-DJYMDLV5.js +0 -227
  144. package/dist/chunk-I5LR3D2K.js +0 -869
  145. package/dist/chunk-M4BBAERY.cjs +0 -1635
  146. package/dist/chunk-N23SKIG4.js +0 -73
  147. package/dist/chunk-PZCVF76Q.cjs +0 -868
  148. package/dist/chunk-QQ6ULXHI.cjs +0 -885
  149. package/dist/chunk-UK3WM7YZ.cjs +0 -75
  150. package/dist/chunk-VOKMAAJP.js +0 -848
  151. package/dist/node-evaluator-4MSDKWOG.cjs +0 -22
  152. package/dist/node-evaluator-SX4LEYQC.js +0 -12
  153. package/dist/workflow-C2a05WUJ.d.ts +0 -444
  154. package/dist/workflow-J-yYixny.d.cts +0 -444
@@ -1,22 +1,24 @@
1
1
  'use strict';
2
2
 
3
- var chunkJD2VQIDZ_cjs = require('../chunk-JD2VQIDZ.cjs');
4
- var chunkSAOBPYYJ_cjs = require('../chunk-SAOBPYYJ.cjs');
5
- var chunkGBQ33SIZ_cjs = require('../chunk-GBQ33SIZ.cjs');
3
+ var chunk672KMMBK_cjs = require('../chunk-672KMMBK.cjs');
4
+ var chunkIQPXHQQQ_cjs = require('../chunk-IQPXHQQQ.cjs');
5
+ var chunk54FLQNUM_cjs = require('../chunk-54FLQNUM.cjs');
6
6
  require('../chunk-G4UEPUGO.cjs');
7
7
  require('../chunk-GVTZMA5C.cjs');
8
8
  require('../chunk-QKZL3ONM.cjs');
9
9
  require('../chunk-TBDXTV22.cjs');
10
- var chunkPZCVF76Q_cjs = require('../chunk-PZCVF76Q.cjs');
10
+ var chunkHMZUGSMU_cjs = require('../chunk-HMZUGSMU.cjs');
11
+ require('../chunk-JSC75O5C.cjs');
11
12
  var chunkSAENRNBJ_cjs = require('../chunk-SAENRNBJ.cjs');
12
- var chunkM4BBAERY_cjs = require('../chunk-M4BBAERY.cjs');
13
- var chunkFMSW2HDF_cjs = require('../chunk-FMSW2HDF.cjs');
14
- require('../chunk-FR7KYWRO.cjs');
13
+ var chunkGEQDGUGB_cjs = require('../chunk-GEQDGUGB.cjs');
14
+ var chunkZCGKGDCL_cjs = require('../chunk-ZCGKGDCL.cjs');
15
+ require('../chunk-Q4MWQNJK.cjs');
15
16
  var chunkL24YIZY7_cjs = require('../chunk-L24YIZY7.cjs');
16
- var chunkDHTLALBL_cjs = require('../chunk-DHTLALBL.cjs');
17
- var chunkP6TA5EZT_cjs = require('../chunk-P6TA5EZT.cjs');
18
- var chunk623FVQSN_cjs = require('../chunk-623FVQSN.cjs');
19
- require('../chunk-2J6TF7YI.cjs');
17
+ var chunkVA4OFR72_cjs = require('../chunk-VA4OFR72.cjs');
18
+ require('../chunk-FR7KYWRO.cjs');
19
+ var chunkISOIA7NV_cjs = require('../chunk-ISOIA7NV.cjs');
20
+ require('../chunk-A5SXCA62.cjs');
21
+ var chunkTYF56RGB_cjs = require('../chunk-TYF56RGB.cjs');
20
22
  require('../chunk-Z2Y65YOY.cjs');
21
23
  var vm = require('vm');
22
24
 
@@ -24,8 +26,10 @@ var vm = require('vm');
24
26
  function drainJobs() {
25
27
  return new Promise((resolve) => setImmediate(resolve));
26
28
  }
27
- function registryOf(workflows) {
28
- return chunkM4BBAERY_cjs.buildWorkflowRegistry([["in-process", { ...workflows }]]);
29
+ function registryOf(workflows, interceptors) {
30
+ return chunkGEQDGUGB_cjs.buildWorkflowRegistry([
31
+ ["in-process", { ...workflows, ...interceptors !== void 0 ? { interceptors } : {} }]
32
+ ]);
29
33
  }
30
34
  async function hostLoop(abi, requestJson) {
31
35
  abi.start(requestJson);
@@ -35,19 +39,71 @@ async function hostLoop(abi, requestJson) {
35
39
  return abi.complete();
36
40
  }
37
41
  async function runWorkflowTaskInProcess(registry, request) {
38
- const abi = chunkM4BBAERY_cjs.createWorkflowRuntime(registry);
42
+ const abi = chunkGEQDGUGB_cjs.createWorkflowRuntime(registry);
39
43
  const json = await hostLoop(abi, JSON.stringify(request));
40
44
  return JSON.parse(json);
41
45
  }
42
46
 
43
47
  // src/testing/environment.ts
48
+ var QueryRejectedError = class extends Error {
49
+ constructor(runId, queryName, message) {
50
+ super(message);
51
+ this.runId = runId;
52
+ this.queryName = queryName;
53
+ this.name = "QueryRejectedError";
54
+ }
55
+ runId;
56
+ queryName;
57
+ };
58
+ var QueryFailedError = class extends Error {
59
+ constructor(runId, queryName, message) {
60
+ super(message);
61
+ this.runId = runId;
62
+ this.queryName = queryName;
63
+ this.name = "QueryFailedError";
64
+ }
65
+ runId;
66
+ queryName;
67
+ };
68
+ var UpdateRefusedError = class extends Error {
69
+ constructor(message) {
70
+ super(message);
71
+ this.name = "UpdateRefusedError";
72
+ }
73
+ };
74
+ var WorkflowAlreadyStartedError = class extends Error {
75
+ constructor(workflowKey, workflowId, existingRunId) {
76
+ super(
77
+ `Workflow ${workflowKey} already has a run with workflow id "${workflowId}" (${existingRunId})`
78
+ );
79
+ this.workflowKey = workflowKey;
80
+ this.workflowId = workflowId;
81
+ this.existingRunId = existingRunId;
82
+ this.name = "WorkflowAlreadyStartedError";
83
+ }
84
+ workflowKey;
85
+ workflowId;
86
+ existingRunId;
87
+ };
88
+ var UnfinishedHandlersError = class extends Error {
89
+ constructor(runId, handlers) {
90
+ super(
91
+ `Run ${runId} finished while handlers were still running: ${handlers.map((handler) => `${handler.kind} ${handler.name} x${handler.count}`).join(", ")} (await ctx.allHandlersFinished(), or set unfinishedPolicy: 'ABANDON')`
92
+ );
93
+ this.runId = runId;
94
+ this.handlers = handlers;
95
+ this.name = "UnfinishedHandlersError";
96
+ }
97
+ runId;
98
+ handlers;
99
+ };
44
100
  var WorkflowFailedError = class extends Error {
45
101
  constructor(runId, failure) {
46
102
  super(`Run ${runId} failed: ${failure.message}`);
47
103
  this.runId = runId;
48
104
  this.failure = failure;
49
105
  this.name = "WorkflowFailedError";
50
- Object.defineProperty(this, "cause", { value: chunkFMSW2HDF_cjs.failureToError(failure), enumerable: false });
106
+ Object.defineProperty(this, "cause", { value: chunkZCGKGDCL_cjs.failureToError(failure), enumerable: false });
51
107
  }
52
108
  runId;
53
109
  failure;
@@ -72,7 +128,7 @@ var RunBlockedError = class extends Error {
72
128
  }
73
129
  runId;
74
130
  };
75
- var TestRunHandle = class {
131
+ var TestRunHandle = class _TestRunHandle {
76
132
  constructor(env, runId) {
77
133
  this.env = env;
78
134
  this.runId = runId;
@@ -89,7 +145,7 @@ var TestRunHandle = class {
89
145
  }
90
146
  /** Deliver a signal and run until idle (without skipping time). */
91
147
  async signal(signal, payload) {
92
- this.env.deliverSignal(this.runId, chunkFMSW2HDF_cjs.signalName(signal), payload);
148
+ this.env.deliverSignal(this.runId, chunkZCGKGDCL_cjs.signalName(signal), payload);
93
149
  await this.env.runUntilIdle(false);
94
150
  }
95
151
  /** Request cancellation and run until idle (without skipping time). */
@@ -102,6 +158,22 @@ var TestRunHandle = class {
102
158
  this.env.terminate(this.runId, reason);
103
159
  await this.env.runUntilIdle(false);
104
160
  }
161
+ /** Send an update and run until idle (Phase C). */
162
+ update(update, args, options = {}) {
163
+ return this.env.update(this.runId, update, args, options);
164
+ }
165
+ /** Answer a query from the run's history (Phase C custom queries and the built-ins). */
166
+ query(query, args) {
167
+ return this.env.query(this.runId, query, args);
168
+ }
169
+ /** Reset the run (11 §2.7): a new run forked at a completed task; this one is terminated. */
170
+ async reset(options = {}) {
171
+ return new _TestRunHandle(this.env, await this.env.reset(this.runId, options));
172
+ }
173
+ /** Sink calls the run's tasks made (Phase C). */
174
+ sinkCalls() {
175
+ return this.env.sinkCallsOf(this.runId);
176
+ }
105
177
  /** Run until this run (or the last run of its continue-as-new chain) ends; its output. */
106
178
  async result() {
107
179
  return this.env.resultOf(this.runId);
@@ -116,6 +188,23 @@ function toDate(value) {
116
188
  if (value instanceof Date) return value.getTime();
117
189
  return typeof value === "number" ? value : Date.parse(value);
118
190
  }
191
+ function optionalDuration(value, what) {
192
+ return value === void 0 ? void 0 : chunkVA4OFR72_cjs.toMs(value, what);
193
+ }
194
+ var FAILED_STATUSES = /* @__PURE__ */ new Set([
195
+ "FAILED",
196
+ "CANCELLED",
197
+ "TERMINATED",
198
+ "TIMED_OUT"
199
+ ]);
200
+ function admittedPayload(update) {
201
+ return {
202
+ updateId: update.updateId,
203
+ name: update.name,
204
+ args: update.args,
205
+ ...update.headers !== void 0 ? { headers: { ...update.headers } } : {}
206
+ };
207
+ }
119
208
  function toJsonValue(value) {
120
209
  if (value === void 0) return null;
121
210
  const text = JSON.stringify(value);
@@ -125,6 +214,12 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
125
214
  clock;
126
215
  timeSkipping;
127
216
  enabled;
217
+ /** The bundle features the gate's flags enable, sent with every task (`request.features`). */
218
+ codeFeatures;
219
+ failOnUnfinishedHandlers;
220
+ historyRelease;
221
+ dues = [];
222
+ held = /* @__PURE__ */ new Set();
128
223
  workspaceId;
129
224
  runs = /* @__PURE__ */ new Map();
130
225
  runOrder = [];
@@ -136,17 +231,65 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
136
231
  timers = [];
137
232
  mockedChildren = [];
138
233
  runCounter = 0;
234
+ updateCounter = 0;
139
235
  executor;
140
236
  workflowKeys;
237
+ interceptors;
238
+ activityImpls;
239
+ activityInterceptors;
240
+ connections;
241
+ sinks;
242
+ /** Attempts that handed their completion to an outside system (`completeAsync`), by token. */
243
+ asyncAttempts = /* @__PURE__ */ new Map();
141
244
  constructor(options) {
142
245
  this.clock = toDate(options.startTime);
143
246
  this.timeSkipping = options.timeSkipping !== false;
144
- this.enabled = options.enabled ?? "parity";
247
+ this.enabled = options.enabled ?? new Set(chunkISOIA7NV_cjs.COMMAND_FEATURES);
248
+ this.codeFeatures = chunkISOIA7NV_cjs.codeFeaturesEnabledBy(this.enabled);
249
+ this.failOnUnfinishedHandlers = options.failOnUnfinishedHandlers !== false;
250
+ this.historyRelease = options.historyRelease ?? chunkTYF56RGB_cjs.RUNTIME_RELEASE;
145
251
  this.workspaceId = options.workspaceId ?? "test-workspace";
146
252
  this.workflows = { ...options.workflows ?? {} };
147
- this.registry = registryOf(this.workflows);
253
+ this.interceptors = options.interceptors;
254
+ this.registry = registryOf(this.workflows, this.interceptors);
148
255
  this.executor = options.taskExecutor;
149
256
  this.workflowKeys = { ...options.workflowKeys ?? {} };
257
+ this.activityImpls = [...options.activities ?? []];
258
+ for (const impl of this.activityImpls)
259
+ if (!chunkVA4OFR72_cjs.isActivityImplementation(impl))
260
+ throw new TypeError("activities must be implementActivity() or defineActivity() values");
261
+ this.activityInterceptors = [...options.activityInterceptors ?? []];
262
+ this.connections = { ...options.connections ?? {} };
263
+ this.sinks = { ...options.sinks ?? {} };
264
+ }
265
+ /** Register a user-activity implementation (Phase C). A later one replaces an earlier of the same name. */
266
+ registerActivity(implementation) {
267
+ if (!chunkVA4OFR72_cjs.isActivityImplementation(implementation))
268
+ throw new TypeError(
269
+ "registerActivity needs an implementActivity() or defineActivity() value"
270
+ );
271
+ const index = this.activityImpls.findIndex(
272
+ (impl) => impl.name === implementation.name && impl.dynamic === implementation.dynamic
273
+ );
274
+ if (index >= 0) this.activityImpls.splice(index, 1);
275
+ this.activityImpls.push(implementation);
276
+ }
277
+ /** Mock a user activity by name or declaration (Phase C). */
278
+ mockActivity(activity, fn) {
279
+ const name = typeof activity === "string" ? activity : activity.name;
280
+ if (typeof activity !== "string" && !chunkVA4OFR72_cjs.isActivityDefinition(activity))
281
+ throw new TypeError("mockActivity needs an activity name or a declareActivity() value");
282
+ this.registerActivity(
283
+ Object.freeze({
284
+ __fluidgrids: chunkVA4OFR72_cjs.ACTIVITY_MARKER,
285
+ name,
286
+ options: typeof activity === "string" ? {} : activity.options,
287
+ implementation: chunkVA4OFR72_cjs.ACTIVITY_IMPL_MARKER,
288
+ // The mock receives the activity's JSON args, typed by the declaration.
289
+ fn: (ctx, args) => fn(args, ctx),
290
+ dynamic: false
291
+ })
292
+ );
150
293
  }
151
294
  /** Create an environment. */
152
295
  static async create(options = {}) {
@@ -165,6 +308,26 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
165
308
  impl
166
309
  );
167
310
  }
311
+ /**
312
+ * Hold the activity queue of a node type (every node type when omitted):
313
+ * attempts wait instead of starting, and a `scheduleToStartTimeout` expires
314
+ * (`ACTIVITY_TIMED_OUT { timeoutType: SCHEDULE_TO_START }`, not retried).
315
+ */
316
+ holdActivities(nodeType = "*") {
317
+ this.held.add(nodeType);
318
+ }
319
+ /** Release held activity queues (all when no node type is given). */
320
+ releaseActivities(nodeType) {
321
+ if (nodeType === void 0) this.held.clear();
322
+ else this.held.delete(nodeType);
323
+ }
324
+ /** The hold key of an attempt: its node type, or the task queue of a user activity. */
325
+ holdKeyOf(entry) {
326
+ return entry.kind === "user" ? entry.taskQueue ?? "" : entry.nodeType;
327
+ }
328
+ isHeld(nodeType) {
329
+ return this.held.has("*") || this.held.has(nodeType);
330
+ }
168
331
  /** Mock a child workflow started by key (graph or durable). */
169
332
  mockChild(workflowKey, impl) {
170
333
  this.childMocks.set(workflowKey, impl);
@@ -175,20 +338,330 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
175
338
  // A declared workflow is stored by its declaration; its input type is the caller's.
176
339
  this.ensureRegistered(definition)
177
340
  );
341
+ const declared = this.workflows[workflowFn]?.options ?? {};
342
+ const workflowKey = options.workflowKey ?? (typeof definition === "string" ? this.workflows[workflowFn]?.name ?? workflowFn : definition.name);
343
+ if (options.update !== void 0 && options.startDelay !== void 0)
344
+ throw new UpdateRefusedError(
345
+ "Update-with-start cannot be combined with a start delay (11 \xA72.6)"
346
+ );
347
+ if (options.workflowId !== void 0) {
348
+ const existing = this.useExisting(workflowKey, options);
349
+ if (existing !== void 0) {
350
+ for (const signal of options.signals ?? [])
351
+ this.deliverSignal(existing, signal.name, signal.payload);
352
+ if (options.update !== void 0)
353
+ this.addUpdate(this.run(existing), options.update, "PENDING");
354
+ await this.runUntilIdle(false);
355
+ return new TestRunHandle(this, existing);
356
+ }
357
+ }
358
+ const executionTimeoutMs = optionalDuration(
359
+ options.executionTimeout ?? declared.executionTimeout,
360
+ "executionTimeout"
361
+ );
362
+ const retry = options.retry ?? declared.retry;
363
+ const config = {
364
+ workflowKey,
365
+ runAttempt: 1,
366
+ ...options.workflowId !== void 0 ? { businessId: options.workflowId } : {},
367
+ ...executionTimeoutMs !== void 0 ? { executionTimeoutMs, executionDeadline: this.clock + executionTimeoutMs } : {},
368
+ ...this.durationConfig(options.runTimeout ?? declared.runTimeout, "runTimeoutMs"),
369
+ ...this.durationConfig(
370
+ options.workflowTaskTimeout ?? declared.workflowTaskTimeout,
371
+ "workflowTaskTimeoutMs"
372
+ ),
373
+ ...this.durationConfig(options.startDelay, "startDelayMs"),
374
+ ...retry !== void 0 ? { retry: chunkVA4OFR72_cjs.runRetryPolicyOf(retry) } : {},
375
+ ...options.summary !== void 0 ? { summary: options.summary } : {},
376
+ ...options.details !== void 0 ? { details: options.details } : {},
377
+ ...options.memo !== void 0 ? { memo: toJsonValue(options.memo) } : {},
378
+ ...(options.versioningBehavior ?? declared.versioningBehavior) !== void 0 ? { versioningBehavior: options.versioningBehavior ?? declared.versioningBehavior } : {},
379
+ ...options.headers !== void 0 ? { headers: { ...options.headers } } : {},
380
+ ...options.searchAttributes !== void 0 ? { searchAttributes: toJsonValue(options.searchAttributes) } : {},
381
+ ...options.fairnessKey !== void 0 ? { fairnessKey: options.fairnessKey } : {},
382
+ ...options.fairnessWeight !== void 0 ? { fairnessWeight: options.fairnessWeight } : {}
383
+ };
178
384
  const runId = this.createRun(
179
385
  workflowFn,
180
386
  toJsonValue(options.input),
181
387
  { ...options.info, ...options.runId !== void 0 ? { runId: options.runId } : {} },
182
- void 0
388
+ void 0,
389
+ {},
390
+ config,
391
+ options.update !== void 0 ? [this.newUpdate(options.update, "ADMITTED")] : []
183
392
  );
184
393
  for (const signal of options.signals ?? [])
185
394
  this.deliverSignal(runId, signal.name, signal.payload);
186
395
  await this.runUntilIdle(false);
187
396
  return new TestRunHandle(this, runId);
188
397
  }
398
+ /**
399
+ * Update-with-start (11 §2.6): start the run (or, with
400
+ * `idConflictPolicy: USE_EXISTING`, reach the open one) and deliver the
401
+ * update before any other task runs.
402
+ */
403
+ async startWithUpdate(definition, options) {
404
+ const updateId = options.update.updateId ?? this.nextUpdateId();
405
+ const handle = await this.start(definition, {
406
+ ...options,
407
+ update: { ...options.update, updateId }
408
+ });
409
+ return { handle, update: this.updateResultOf(handle.runId, updateId) };
410
+ }
411
+ nextUpdateId() {
412
+ this.updateCounter += 1;
413
+ return `u${this.updateCounter}`;
414
+ }
415
+ /** A new update row (not attached to a run yet). */
416
+ newUpdate(update, status) {
417
+ return {
418
+ updateId: update.updateId ?? this.nextUpdateId(),
419
+ name: update.name,
420
+ args: toJsonValue(update.args),
421
+ ...update.headers !== void 0 ? { headers: { ...update.headers } } : {},
422
+ status
423
+ };
424
+ }
425
+ /** Record an update on a run: pending (delivered by the next task) or admitted into history. */
426
+ addUpdate(run, update, status) {
427
+ const existing = update.updateId !== void 0 ? run.updates.get(update.updateId) : void 0;
428
+ if (existing) return existing;
429
+ const entry = this.newUpdate(update, status);
430
+ run.updates.set(entry.updateId, entry);
431
+ if (status === "ADMITTED")
432
+ this.append(run, { type: "UPDATE_ADMITTED", payload: admittedPayload(entry) });
433
+ else {
434
+ if (run.delayedUntil !== void 0) this.endDelay(run);
435
+ else this.scheduleTask(run);
436
+ }
437
+ return entry;
438
+ }
439
+ /** Schedule a workflow task for a run that has none (an update needs no input event). */
440
+ scheduleTask(run) {
441
+ if (run.state.status !== "RUNNING" || run.state.task.state !== "NONE") return;
442
+ if (run.delayedUntil !== void 0) return;
443
+ run.taskCounter += 1;
444
+ const taskId = `${run.runId}-task-${run.taskCounter}`;
445
+ const scheduled = {
446
+ seq: run.history.length + 1,
447
+ type: "WORKFLOW_TASK_SCHEDULED",
448
+ payload: { taskId },
449
+ createdAt: new Date(this.clock).toISOString()
450
+ };
451
+ chunkISOIA7NV_cjs.applyEvent(run.state, scheduled);
452
+ run.history.push(scheduled);
453
+ }
454
+ /**
455
+ * Send an update to a run and run until idle (Phase C, 05 §6). The result
456
+ * is `REJECTED` (the validator refused it or no handler took it; nothing is
457
+ * written to history), `COMPLETED`, or `ACCEPTED` while its handler still
458
+ * waits (for a timer without time skipping, or with `waitFor: ACCEPTED`).
459
+ */
460
+ async update(runId, update, args, options = {}) {
461
+ const run = this.run(runId);
462
+ const name = typeof update === "string" ? update : update.name;
463
+ if (options.updateId !== void 0 && run.updates.has(options.updateId))
464
+ return this.updateResultOf(runId, options.updateId);
465
+ if (run.state.status !== "RUNNING")
466
+ throw new UpdateRefusedError(`Run ${runId} is ${run.state.status}; it takes no updates`);
467
+ const entry = this.addUpdate(
468
+ run,
469
+ {
470
+ name,
471
+ args,
472
+ ...options.updateId !== void 0 ? { updateId: options.updateId } : {},
473
+ ...options.headers !== void 0 ? { headers: options.headers } : {}
474
+ },
475
+ "PENDING"
476
+ );
477
+ await this.runUntilIdle(false);
478
+ return this.updateResultOf(runId, entry.updateId);
479
+ }
480
+ /** The current result of an update. */
481
+ updateResultOf(runId, updateId) {
482
+ const entry = this.run(runId).updates.get(updateId);
483
+ if (!entry) throw new Error(`Run ${runId} has no update ${updateId}`);
484
+ return {
485
+ updateId,
486
+ status: entry.status === "ADMITTED" ? "PENDING" : entry.status,
487
+ ...entry.result !== void 0 ? { result: entry.result } : {},
488
+ ...entry.failure !== void 0 ? { failure: entry.failure } : {}
489
+ };
490
+ }
491
+ /** Answer a query from the run's history (a replay-only `query` task). */
492
+ async query(runId, query, args) {
493
+ const run = this.run(runId);
494
+ const name = typeof query === "string" ? query : query.name;
495
+ const request = {
496
+ protocol: chunkTYF56RGB_cjs.HISTORY_PROTOCOL,
497
+ kind: "query",
498
+ workflowFn: run.workflowFn,
499
+ info: run.info,
500
+ history: run.history,
501
+ nowMs: this.clock,
502
+ queries: [{ queryId: "q1", name, args: toJsonValue(args) }]
503
+ };
504
+ const result = await this.execute(request);
505
+ const answer = result.queryResults?.[0];
506
+ if (answer?.rejected === true)
507
+ throw new QueryRejectedError(runId, name, answer.error ?? `No handler for query ${name}`);
508
+ if (answer === void 0 || answer.error !== void 0)
509
+ throw new QueryFailedError(
510
+ runId,
511
+ name,
512
+ answer?.error ?? result.failure?.message ?? "The query was not answered"
513
+ );
514
+ return answer.value ?? null;
515
+ }
516
+ /** Sink calls the run's tasks made. */
517
+ sinkCallsOf(runId) {
518
+ return this.run(runId).sinkCalls.map((call) => ({ ...call, args: [...call.args] }));
519
+ }
520
+ /**
521
+ * Reset a run (11 §2.7): a new run whose history is the original's up to
522
+ * and including the chosen completed workflow task (with its commands),
523
+ * then `WORKFLOW_RESET`, then the signals (and, as `UPDATE_ADMITTED`, the
524
+ * accepted updates) received after that point. The original is terminated
525
+ * with reason `RESET`; children it started before the point follow the new
526
+ * run, the others get their parent-close policy. Returns the new run id.
527
+ */
528
+ async reset(runId, options = {}) {
529
+ const original = this.run(runId);
530
+ const history = original.history;
531
+ const points = [];
532
+ for (const event of history) {
533
+ if (event.type !== "WORKFLOW_TASK_COMPLETED") continue;
534
+ const taskId = typeof event.payload["taskId"] === "string" ? event.payload["taskId"] : "";
535
+ let end = event.seq;
536
+ let closes = false;
537
+ while (end < history.length) {
538
+ const next = history[end];
539
+ if (!next || !chunkTYF56RGB_cjs.isCommandEvent(next) || next.taskId !== taskId) break;
540
+ if (chunkTYF56RGB_cjs.TERMINAL_EVENTS.has(next.type)) closes = true;
541
+ end += 1;
542
+ }
543
+ if (!closes) points.push({ seq: event.seq, cut: end });
544
+ }
545
+ const point = options.toSeq !== void 0 ? [...points].reverse().find((entry) => entry.seq <= (options.toSeq ?? 0)) : options.to === "FIRST_TASK" ? points[0] : points[points.length - 1];
546
+ if (!point) throw new Error(`Run ${runId} has no completed workflow task to reset to`);
547
+ const cut = point.cut;
548
+ const copied = history.slice(0, cut).map((event) => ({ ...event, payload: { ...event.payload } }));
549
+ const later = history.slice(cut);
550
+ const reapplySignals = options.reapplySignals !== false;
551
+ const reapplyUpdates = options.reapplyUpdates !== false;
552
+ const keptChildren = new Set(
553
+ copied.filter((event) => event.type === "CHILD_RUN_INITIATED").map((event) => String(event.payload["childId"]))
554
+ );
555
+ this.runCounter += 1;
556
+ const newRunId = `run-${this.runCounter}`;
557
+ if (original.state.status === "RUNNING") {
558
+ original.resetTo = newRunId;
559
+ this.append(original, { type: "WORKFLOW_TERMINATED", payload: { reason: "RESET" } });
560
+ this.onClosed(original, keptChildren);
561
+ } else original.resetTo = newRunId;
562
+ const fork = {
563
+ runId: newRunId,
564
+ workflowFn: original.workflowFn,
565
+ history: copied,
566
+ state: chunkISOIA7NV_cjs.projectRunState(copied),
567
+ taskCounter: copied.filter((event) => event.type === "WORKFLOW_TASK_SCHEDULED").length,
568
+ info: { ...original.info, runId: newRunId },
569
+ children: new Map([...original.children].filter(([childId]) => keptChildren.has(childId))),
570
+ config: { ...original.config },
571
+ ...original.parent ? { parent: original.parent } : {},
572
+ updates: /* @__PURE__ */ new Map(),
573
+ sinkCalls: []
574
+ };
575
+ this.runs.set(newRunId, fork);
576
+ this.runOrder.push(newRunId);
577
+ for (const [childId, childRunId] of fork.children) {
578
+ const child = childRunId !== void 0 ? this.runs.get(childRunId) : void 0;
579
+ if (child) child.parent = { runId: newRunId, childId };
580
+ }
581
+ this.append(fork, {
582
+ type: "WORKFLOW_RESET",
583
+ payload: {
584
+ fromRunId: runId,
585
+ toSeq: cut,
586
+ reapplySignals,
587
+ reapplyUpdates,
588
+ ...options.reason !== void 0 ? { reason: options.reason } : {}
589
+ }
590
+ });
591
+ for (const [activityId, activity] of Object.entries(fork.state.activities)) {
592
+ if (!chunkISOIA7NV_cjs.isActivityOpen(activity)) continue;
593
+ const scheduled = copied[activity.scheduledSeq - 1];
594
+ if (scheduled?.type !== "ACTIVITY_SCHEDULED") continue;
595
+ this.afterCommand(fork, {
596
+ // The run-event schema checked the payload; it is the command that scheduled it.
597
+ ...scheduled.payload,
598
+ type: "SCHEDULE_ACTIVITY",
599
+ activityId
600
+ });
601
+ }
602
+ for (const [timerId, timer] of Object.entries(fork.state.timers))
603
+ if (timer.status === "PENDING")
604
+ this.timers.push({ runId: newRunId, timerId, fireAt: Date.parse(timer.fireAt) });
605
+ for (const event of later) {
606
+ if (event.type === "SIGNAL_RECEIVED" && reapplySignals)
607
+ this.append(fork, { type: "SIGNAL_RECEIVED", payload: { ...event.payload } });
608
+ if (reapplyUpdates && (event.type === "UPDATE_ACCEPTED" || event.type === "UPDATE_ADMITTED") && !fork.updates.has(String(event.payload["updateId"])) && fork.state.updates[String(event.payload["updateId"])] === void 0) {
609
+ const headers = event.payload["headers"];
610
+ this.addUpdate(
611
+ fork,
612
+ {
613
+ updateId: String(event.payload["updateId"]),
614
+ name: String(event.payload["name"]),
615
+ args: event.payload["args"] ?? null,
616
+ ...typeof headers === "object" && headers !== null && !Array.isArray(headers) ? (
617
+ // The run-event schema checked the headers map.
618
+ { headers }
619
+ ) : {}
620
+ },
621
+ "ADMITTED"
622
+ );
623
+ }
624
+ }
625
+ if (chunkISOIA7NV_cjs.hasUnprocessedInput(fork.history)) this.scheduleTask(fork);
626
+ await this.runUntilIdle(false);
627
+ return newRunId;
628
+ }
629
+ durationConfig(value, key) {
630
+ const ms = optionalDuration(value, key);
631
+ if (ms === void 0) return {};
632
+ const out = {};
633
+ out[key] = ms;
634
+ return out;
635
+ }
636
+ /**
637
+ * The workflow-id policies of a start (11 §2.1): the open run to use, or
638
+ * undefined to start a new run (after terminating the open one for
639
+ * `TERMINATE_EXISTING`). Throws {@link WorkflowAlreadyStartedError}.
640
+ */
641
+ useExisting(workflowKey, options) {
642
+ const workflowId = options.workflowId ?? "";
643
+ const runs = this.runOrder.map((id) => this.run(id)).filter(
644
+ (run) => run.config.workflowKey === workflowKey && run.config.businessId === workflowId
645
+ );
646
+ const open = runs.find((run) => run.state.status === "RUNNING");
647
+ if (open) {
648
+ const conflict = options.idConflictPolicy ?? "FAIL";
649
+ if (conflict === "USE_EXISTING") return open.runId;
650
+ if (conflict === "FAIL")
651
+ throw new WorkflowAlreadyStartedError(workflowKey, workflowId, open.runId);
652
+ this.terminate(open.runId, "ID_CONFLICT");
653
+ return void 0;
654
+ }
655
+ const last = runs[runs.length - 1];
656
+ if (!last) return void 0;
657
+ const reuse = options.idReusePolicy ?? "ALLOW_DUPLICATE";
658
+ if (reuse === "REJECT_DUPLICATE" || reuse === "ALLOW_DUPLICATE_FAILED_ONLY" && !FAILED_STATUSES.has(last.state.status))
659
+ throw new WorkflowAlreadyStartedError(workflowKey, workflowId, last.runId);
660
+ return void 0;
661
+ }
189
662
  /** Advance the clock by `duration`, firing timers and running work as it comes due. */
190
663
  async sleep(duration) {
191
- const until = this.clock + chunkFMSW2HDF_cjs.toMs(duration, "sleep duration");
664
+ const until = this.clock + chunkVA4OFR72_cjs.toMs(duration, "sleep duration");
192
665
  await this.runUntilIdle(false);
193
666
  for (; ; ) {
194
667
  const next = this.nextDue();
@@ -210,7 +683,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
210
683
  }
211
684
  historyFileOf(runId, extra = {}) {
212
685
  const run = this.run(runId);
213
- return chunkPZCVF76Q_cjs.createHistoryFile(run.workflowFn, this.historyOf(runId), {
686
+ return chunkHMZUGSMU_cjs.createHistoryFile(run.workflowFn, this.historyOf(runId), {
214
687
  info: { ...run.info },
215
688
  ...extra
216
689
  });
@@ -228,7 +701,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
228
701
  if (value === definition) return name2;
229
702
  const name = Object.hasOwn(this.workflows, definition.name) ? `${definition.name}#${this.runCounter}` : definition.name;
230
703
  this.workflows[name] = definition;
231
- this.registry = registryOf(this.workflows);
704
+ this.registry = registryOf(this.workflows, this.interceptors);
232
705
  return name;
233
706
  }
234
707
  run(runId) {
@@ -236,7 +709,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
236
709
  if (!run) throw new Error(`Unknown run ${runId}`);
237
710
  return run;
238
711
  }
239
- createRun(workflowFn, input, info, parent, extraStarted = {}) {
712
+ createRun(workflowFn, input, info, parent, extraStarted = {}, config = { workflowKey: workflowFn, runAttempt: 1 }, admitted = []) {
240
713
  this.runCounter += 1;
241
714
  const runId = info.runId ?? `run-${this.runCounter}`;
242
715
  const snapshot = {
@@ -253,23 +726,84 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
253
726
  runId,
254
727
  workflowFn,
255
728
  history: [],
256
- state: chunkP6TA5EZT_cjs.initialRunState(),
729
+ state: chunkISOIA7NV_cjs.initialRunState(),
257
730
  taskCounter: 0,
258
731
  info: snapshot,
259
732
  children: /* @__PURE__ */ new Map(),
260
- ...parent ? { parent } : {}
733
+ config,
734
+ ...parent ? { parent } : {},
735
+ updates: /* @__PURE__ */ new Map(),
736
+ sinkCalls: []
261
737
  };
738
+ const firstTaskDelay = config.startDelayMs ?? config.firstTaskDelayMs;
739
+ if (firstTaskDelay !== void 0 && firstTaskDelay > 0) {
740
+ run.delayedUntil = this.clock + firstTaskDelay;
741
+ this.dues.push({ runId, kind: "start", at: run.delayedUntil });
742
+ }
743
+ if (config.runTimeoutMs !== void 0)
744
+ this.dues.push({ runId, kind: "runTimeout", at: this.clock + config.runTimeoutMs });
745
+ if (config.executionDeadline !== void 0)
746
+ this.dues.push({ runId, kind: "executionTimeout", at: config.executionDeadline });
262
747
  this.runs.set(runId, run);
263
748
  this.runOrder.push(runId);
264
- this.append(run, {
265
- type: "WORKFLOW_STARTED",
266
- // The service writes the seed of ctx.random()/ctx.uuid() into the start
267
- // event so the history replays on its own; it uses the run id.
268
- payload: { workflowFn, input, taskQueue: "managed", randomnessSeed: runId, ...extraStarted }
269
- });
749
+ this.append(
750
+ run,
751
+ {
752
+ type: "WORKFLOW_STARTED",
753
+ // The service writes the seed of ctx.random()/ctx.uuid() into the start
754
+ // event so the history replays on its own; it uses the run id.
755
+ payload: {
756
+ workflowFn,
757
+ input,
758
+ taskQueue: config.taskQueue ?? "managed",
759
+ randomnessSeed: runId,
760
+ ...extraStarted,
761
+ ...this.startedFields(config)
762
+ }
763
+ },
764
+ admitted.length === 0
765
+ );
766
+ if (admitted.length > 0) {
767
+ for (const update of admitted) {
768
+ run.updates.set(update.updateId, update);
769
+ this.append(run, { type: "UPDATE_ADMITTED", payload: admittedPayload(update) }, false);
770
+ }
771
+ this.scheduleTask(run);
772
+ }
270
773
  return runId;
271
774
  }
272
- append(run, draft) {
775
+ /** The R2 fields of `WORKFLOW_STARTED`, each written only when it is set. */
776
+ startedFields(config) {
777
+ const out = {};
778
+ if (config.businessId !== void 0) {
779
+ out["businessId"] = config.businessId;
780
+ out["workflowId"] = config.businessId;
781
+ }
782
+ if (config.startDelayMs !== void 0) out["startDelayMs"] = config.startDelayMs;
783
+ if (config.retry !== void 0 || config.runAttempt > 1) out["runAttempt"] = config.runAttempt;
784
+ if (config.summary !== void 0) out["summary"] = config.summary;
785
+ if (config.details !== void 0) out["details"] = config.details;
786
+ if (config.memo !== void 0) out["context"] = config.memo;
787
+ const timeouts = {};
788
+ if (config.executionTimeoutMs !== void 0)
789
+ timeouts["executionTimeout"] = config.executionTimeoutMs;
790
+ if (config.runTimeoutMs !== void 0) timeouts["runTimeout"] = config.runTimeoutMs;
791
+ if (config.workflowTaskTimeoutMs !== void 0)
792
+ timeouts["workflowTaskTimeout"] = config.workflowTaskTimeoutMs;
793
+ if (Object.keys(timeouts).length > 0) out["timeouts"] = timeouts;
794
+ if (config.retry !== void 0) out["retry"] = toJsonValue(config.retry);
795
+ if (config.versioningBehavior !== void 0)
796
+ out["versioningBehavior"] = config.versioningBehavior;
797
+ if (config.lastCompletionResult !== void 0 && this.historyRelease >= 2)
798
+ out["lastCompletionResult"] = config.lastCompletionResult;
799
+ if (config.lastFailure !== void 0) out["lastFailure"] = toJsonValue(config.lastFailure);
800
+ if (config.headers !== void 0) out["headers"] = { ...config.headers };
801
+ if (config.searchAttributes !== void 0) out["searchAttributes"] = config.searchAttributes;
802
+ if (config.fairnessKey !== void 0) out["fairnessKey"] = config.fairnessKey;
803
+ if (config.fairnessWeight !== void 0) out["fairnessWeight"] = config.fairnessWeight;
804
+ return out;
805
+ }
806
+ append(run, draft, schedule = true) {
273
807
  const event = {
274
808
  seq: run.history.length + 1,
275
809
  type: draft.type,
@@ -277,9 +811,10 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
277
811
  createdAt: new Date(this.clock).toISOString(),
278
812
  ...draft.taskId !== void 0 ? { taskId: draft.taskId } : {}
279
813
  };
280
- chunkP6TA5EZT_cjs.applyEvent(run.state, event);
814
+ chunkISOIA7NV_cjs.applyEvent(run.state, event);
281
815
  run.history.push(event);
282
- if (chunk623FVQSN_cjs.isInputEvent(event) && run.state.status === "RUNNING" && run.state.task.state === "NONE") {
816
+ if (run.delayedUntil !== void 0 && event.type === "SIGNAL_RECEIVED") this.endDelay(run);
817
+ if (schedule && run.delayedUntil === void 0 && chunkTYF56RGB_cjs.isInputEvent(event) && run.state.status === "RUNNING" && run.state.task.state === "NONE") {
283
818
  run.taskCounter += 1;
284
819
  const taskId = `${run.runId}-task-${run.taskCounter}`;
285
820
  const scheduled = {
@@ -288,12 +823,18 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
288
823
  payload: { taskId },
289
824
  createdAt: event.createdAt
290
825
  };
291
- chunkP6TA5EZT_cjs.applyEvent(run.state, scheduled);
826
+ chunkISOIA7NV_cjs.applyEvent(run.state, scheduled);
292
827
  run.history.push(scheduled);
293
828
  }
294
829
  return event;
295
830
  }
296
- deliverSignal(runId, name, payload) {
831
+ /** End a start delay: the first workflow task is scheduled now. */
832
+ endDelay(run) {
833
+ run.delayedUntil = void 0;
834
+ this.dues = this.dues.filter((due) => !(due.runId === run.runId && due.kind === "start"));
835
+ this.scheduleTask(run);
836
+ }
837
+ deliverSignal(runId, name, payload, headers) {
297
838
  const run = this.runs.get(runId);
298
839
  if (!run || run.state.status !== "RUNNING") return false;
299
840
  this.append(run, {
@@ -301,7 +842,8 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
301
842
  payload: {
302
843
  name,
303
844
  payload: toJsonValue(payload),
304
- receivedAt: new Date(this.clock).toISOString()
845
+ receivedAt: new Date(this.clock).toISOString(),
846
+ ...headers !== void 0 ? { headers: { ...headers } } : {}
305
847
  }
306
848
  });
307
849
  return true;
@@ -314,6 +856,11 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
314
856
  type: "WORKFLOW_CANCEL_REQUESTED",
315
857
  payload: reason !== void 0 ? { reason } : {}
316
858
  });
859
+ if (run.delayedUntil !== void 0) {
860
+ run.delayedUntil = void 0;
861
+ this.append(run, { type: "WORKFLOW_CANCELLED", payload: {} });
862
+ this.onClosed(run);
863
+ }
317
864
  return true;
318
865
  }
319
866
  terminate(runId, reason) {
@@ -333,7 +880,9 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
333
880
  await this.runTask(task);
334
881
  continue;
335
882
  }
336
- const attempt = this.attempts.find((entry) => entry.dueAt <= this.clock);
883
+ const attempt = this.attempts.find(
884
+ (entry) => entry.dueAt <= this.clock && !this.isHeld(this.holdKeyOf(entry))
885
+ );
337
886
  if (attempt) {
338
887
  this.attempts = this.attempts.filter((entry) => entry !== attempt);
339
888
  await this.runAttempt(attempt);
@@ -352,16 +901,78 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
352
901
  }
353
902
  throw new Error("The test environment did not settle after 100000 steps");
354
903
  }
904
+ /** When a held attempt's schedule-to-start timeout expires, if it has one. */
905
+ heldDeadline(entry) {
906
+ return this.isHeld(this.holdKeyOf(entry)) && entry.scheduleToStart !== void 0 ? entry.dueAt + entry.scheduleToStart : void 0;
907
+ }
355
908
  nextDue() {
356
- const due = [
357
- ...this.timers.map((timer) => timer.fireAt),
358
- ...this.attempts.map((entry) => entry.dueAt)
359
- ];
909
+ const due = [...this.timers.map((timer) => timer.fireAt)];
910
+ for (const entry of this.attempts) {
911
+ if (!this.isHeld(this.holdKeyOf(entry))) due.push(entry.dueAt);
912
+ const deadline = this.heldDeadline(entry);
913
+ if (deadline !== void 0) due.push(deadline);
914
+ }
915
+ for (const entry of this.dues) due.push(entry.at);
360
916
  return due.length === 0 ? void 0 : Math.min(...due);
361
917
  }
918
+ /** Expire held attempts whose schedule-to-start timeout passed (not retried, 11 §2.3). */
919
+ expireHeld() {
920
+ const expired = this.attempts.filter((entry) => {
921
+ const deadline = this.heldDeadline(entry);
922
+ return deadline !== void 0 && deadline <= this.clock;
923
+ });
924
+ if (expired.length === 0) return false;
925
+ this.attempts = this.attempts.filter((entry) => !expired.includes(entry));
926
+ for (const entry of expired) {
927
+ const run = this.runs.get(entry.runId);
928
+ const activity = run?.state.activities[entry.activityId];
929
+ if (!run || run.state.status !== "RUNNING" || !activity || !chunkISOIA7NV_cjs.isActivityOpen(activity))
930
+ continue;
931
+ this.append(run, {
932
+ type: "ACTIVITY_TIMED_OUT",
933
+ payload: {
934
+ activityId: entry.activityId,
935
+ attempt: entry.attempt,
936
+ timeoutType: "SCHEDULE_TO_START"
937
+ }
938
+ });
939
+ }
940
+ return true;
941
+ }
942
+ /** Fire run-level deadlines: the end of a start delay, run and execution timeouts. */
943
+ fireRunDues() {
944
+ const due = this.dues.filter((entry) => entry.at <= this.clock).sort((a, b) => a.at - b.at);
945
+ if (due.length === 0) return false;
946
+ this.dues = this.dues.filter((entry) => !due.includes(entry));
947
+ for (const entry of due) {
948
+ const run = this.runs.get(entry.runId);
949
+ if (!run || run.state.status !== "RUNNING") continue;
950
+ if (entry.kind === "start") {
951
+ if (run.delayedUntil !== void 0) this.endDelay(run);
952
+ continue;
953
+ }
954
+ const timeoutType = entry.kind === "runTimeout" ? "WORKFLOW_RUN" : "WORKFLOW_EXECUTION";
955
+ const failure = {
956
+ errorType: "TIMEOUT",
957
+ message: timeoutType === "WORKFLOW_RUN" ? "The run timeout expired" : "The execution timeout of the chain expired",
958
+ type: "TimeoutFailure",
959
+ timeoutType,
960
+ source: "engine"
961
+ };
962
+ run.delayedUntil = void 0;
963
+ this.append(run, {
964
+ type: "WORKFLOW_TIMED_OUT",
965
+ payload: { timeoutType, failure: toJsonValue(failure) }
966
+ });
967
+ this.onClosed(run);
968
+ }
969
+ return true;
970
+ }
362
971
  fireDue() {
972
+ const expired = this.expireHeld();
973
+ const fired = this.fireRunDues();
363
974
  const due = this.timers.filter((timer) => timer.fireAt <= this.clock).sort((a, b) => a.fireAt - b.fireAt);
364
- if (due.length === 0) return false;
975
+ if (due.length === 0) return expired || fired;
365
976
  this.timers = this.timers.filter((timer) => !due.includes(timer));
366
977
  for (const timer of due) {
367
978
  const run = this.runs.get(timer.runId);
@@ -374,15 +985,27 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
374
985
  async runTask(run) {
375
986
  const taskId = run.state.task.taskId ?? `${run.runId}-task-${run.taskCounter}`;
376
987
  this.append(run, { type: "WORKFLOW_TASK_STARTED", payload: { taskId, attempt: 1 } });
988
+ const delivered = [...run.updates.values()].filter(
989
+ (update) => update.status === "PENDING" || update.status === "ADMITTED"
990
+ );
991
+ const updates = delivered.map((update) => ({
992
+ updateId: update.updateId,
993
+ name: update.name,
994
+ args: update.args,
995
+ ...update.headers !== void 0 ? { headers: { ...update.headers } } : {},
996
+ ...update.status === "ADMITTED" ? { admitted: true } : {}
997
+ }));
377
998
  const request = {
378
- protocol: chunk623FVQSN_cjs.HISTORY_PROTOCOL,
999
+ protocol: chunkTYF56RGB_cjs.HISTORY_PROTOCOL,
379
1000
  kind: "task",
380
1001
  workflowFn: run.workflowFn,
381
1002
  info: run.info,
382
1003
  history: run.history,
383
- nowMs: this.clock
1004
+ nowMs: this.clock,
1005
+ ...updates.length > 0 ? { updates } : {},
1006
+ ...this.codeFeatures.length > 0 ? { features: [...this.codeFeatures] } : {}
384
1007
  };
385
- const result = this.executor ? await this.executor(request) : await runWorkflowTaskInProcess(this.registry, request);
1008
+ const result = await this.executeWithLocalActivities(run, request);
386
1009
  const fail = (cause, message) => {
387
1010
  this.append(run, {
388
1011
  type: "WORKFLOW_TASK_FAILED",
@@ -395,29 +1018,145 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
395
1018
  run.taskFailure = result;
396
1019
  return;
397
1020
  }
398
- const checked = chunkPZCVF76Q_cjs.validateCommands(result.commands, { enabled: this.enabled });
1021
+ const relief = {
1022
+ grantedLocalActivityIds: [],
1023
+ deliveredUpdateIds: delivered.map((update) => update.updateId)
1024
+ };
1025
+ const checked = chunkHMZUGSMU_cjs.validateCommands(result.commands, { enabled: this.enabled, relief });
399
1026
  if (!checked.ok) {
400
1027
  fail(checked.cause, checked.issues.map((issue) => issue.message).join("; "));
401
1028
  return;
402
1029
  }
403
- const drafts = chunkP6TA5EZT_cjs.eventsForCommands(run.state, checked.commands, {
1030
+ const drafts = chunkISOIA7NV_cjs.eventsForCommands(run.state, checked.commands, {
404
1031
  taskId,
405
1032
  nowMs: this.clock,
406
- enabled: this.enabled
1033
+ enabled: this.enabled,
1034
+ relief,
1035
+ updates: Object.fromEntries(
1036
+ delivered.map((update) => [
1037
+ update.updateId,
1038
+ {
1039
+ name: update.name,
1040
+ args: update.args,
1041
+ ...update.headers !== void 0 ? { headers: update.headers } : {}
1042
+ }
1043
+ ])
1044
+ )
407
1045
  });
408
1046
  if (!drafts.ok) {
409
1047
  fail(drafts.cause, drafts.issues.map((issue) => issue.message).join("; "));
410
1048
  return;
411
1049
  }
1050
+ if (result.unfinishedHandlers !== void 0 && result.unfinishedHandlers.length > 0)
1051
+ run.unfinishedHandlers = result.unfinishedHandlers;
1052
+ this.recordUpdateReplies(run, checked.commands, delivered);
1053
+ this.runSinks(run, result.sinkCalls ?? []);
412
1054
  this.append(run, { type: "WORKFLOW_TASK_COMPLETED", taskId, payload: { taskId } });
413
1055
  for (const draft of drafts.events) this.append(run, draft);
414
1056
  for (const command of checked.commands)
415
- if (run.state.status === "RUNNING" || chunk623FVQSN_cjs.TERMINAL_COMMANDS.has(command.type))
1057
+ if (run.state.status === "RUNNING" || chunkTYF56RGB_cjs.TERMINAL_COMMANDS.has(command.type))
416
1058
  this.afterCommand(run, command);
417
1059
  }
1060
+ /** What a task's update replies mean for the run's update rows. */
1061
+ recordUpdateReplies(run, commands, delivered) {
1062
+ const answered = /* @__PURE__ */ new Set();
1063
+ for (const command of commands) {
1064
+ if (command.type !== "ACCEPT_UPDATE" && command.type !== "REJECT_UPDATE" && command.type !== "COMPLETE_UPDATE")
1065
+ continue;
1066
+ const entry = run.updates.get(command.updateId);
1067
+ if (!entry) continue;
1068
+ answered.add(command.updateId);
1069
+ if (command.type === "ACCEPT_UPDATE") entry.status = "ACCEPTED";
1070
+ else if (command.type === "REJECT_UPDATE") {
1071
+ entry.status = "REJECTED";
1072
+ entry.failure = command.failure;
1073
+ } else {
1074
+ entry.status = "COMPLETED";
1075
+ if (command.failure !== void 0) entry.failure = command.failure;
1076
+ else entry.result = command.result ?? null;
1077
+ }
1078
+ }
1079
+ for (const update of delivered)
1080
+ if (!answered.has(update.updateId) && update.status === "PENDING") {
1081
+ update.status = "REJECTED";
1082
+ update.failure = {
1083
+ errorType: "VALIDATION",
1084
+ type: "UpdateNotHandled",
1085
+ message: `The workflow task did not answer update "${update.name}"`
1086
+ };
1087
+ }
1088
+ }
1089
+ /** Keep a task's sink calls and call the configured sinks with them. */
1090
+ runSinks(run, calls) {
1091
+ for (const call of calls) {
1092
+ run.sinkCalls.push(call);
1093
+ const fn = this.sinks[call.sink]?.[call.fn];
1094
+ if (fn === void 0) continue;
1095
+ try {
1096
+ fn(...call.args);
1097
+ } catch {
1098
+ }
1099
+ }
1100
+ }
1101
+ execute(request) {
1102
+ return this.executor ? this.executor(request) : runWorkflowTaskInProcess(this.registry, request);
1103
+ }
1104
+ /**
1105
+ * Run a workflow task as the worker does (11 §2.12): while it asks for
1106
+ * local activities, run each through its mock and run the same task again
1107
+ * with the outcomes, up to 1,000 rounds.
1108
+ */
1109
+ async executeWithLocalActivities(run, request) {
1110
+ const outcomes = /* @__PURE__ */ new Map();
1111
+ let result = await this.execute(request);
1112
+ for (let round = 0; result.outcome === "localActivityRequested"; round++) {
1113
+ if (round >= 1e3)
1114
+ return {
1115
+ ...result,
1116
+ outcome: "failed",
1117
+ commands: [],
1118
+ failure: { cause: "INTERNAL", message: "The task asked for local activities 1000 times" }
1119
+ };
1120
+ for (const wanted of result.localActivityRequests ?? [])
1121
+ outcomes.set(wanted.localActivityId, await this.runLocalActivity(run, wanted));
1122
+ result = await this.execute({ ...request, localActivityResults: [...outcomes.values()] });
1123
+ }
1124
+ return result;
1125
+ }
1126
+ async runLocalActivity(run, wanted) {
1127
+ const mock = this.mocks.get(`${wanted.nodeType}#${wanted.operation}`) ?? this.mocks.get(wanted.nodeType);
1128
+ try {
1129
+ if (!mock)
1130
+ throw new chunkZCGKGDCL_cjs.ApplicationError(
1131
+ `No mock for ${wanted.nodeType} ${wanted.operation} (use env.mock)`,
1132
+ { errorType: "VALIDATION", nonRetryable: true, type: "UnmockedActivity" }
1133
+ );
1134
+ const result = toJsonValue(
1135
+ await mock(wanted.args, {
1136
+ runId: run.runId,
1137
+ activityId: wanted.localActivityId,
1138
+ attempt: wanted.attempt,
1139
+ nodeType: wanted.nodeType,
1140
+ operation: wanted.operation,
1141
+ local: true,
1142
+ ...wanted.connection !== void 0 ? { connection: wanted.connection } : {}
1143
+ })
1144
+ );
1145
+ return { localActivityId: wanted.localActivityId, result, attempts: wanted.attempt };
1146
+ } catch (error) {
1147
+ const failure = chunkZCGKGDCL_cjs.errorToFailure(error, `node:${wanted.nodeType}`);
1148
+ delete failure.stackTrace;
1149
+ return {
1150
+ localActivityId: wanted.localActivityId,
1151
+ failure: toJsonValue(failure),
1152
+ attempts: wanted.attempt
1153
+ };
1154
+ }
1155
+ }
418
1156
  afterCommand(run, command) {
419
1157
  switch (command.type) {
420
1158
  case "SCHEDULE_ACTIVITY": {
1159
+ const user = command.kind === "user";
421
1160
  const attempt = {
422
1161
  runId: run.runId,
423
1162
  activityId: command.activityId,
@@ -425,12 +1164,16 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
425
1164
  dueAt: this.clock,
426
1165
  scheduledAt: this.clock,
427
1166
  args: command.args,
428
- nodeType: command.nodeType,
429
- operation: command.operation,
1167
+ kind: command.kind,
1168
+ nodeType: user ? "" : command.nodeType,
1169
+ operation: user ? command.activityName : command.operation,
430
1170
  retry: command.retry,
431
1171
  cancelRequested: false,
432
- ...command.connection !== void 0 ? { connection: command.connection } : {},
433
- ...command.scheduleToCloseTimeout !== void 0 ? { scheduleToClose: command.scheduleToCloseTimeout } : {}
1172
+ ...!user && command.connection !== void 0 ? { connection: command.connection } : {},
1173
+ ...user ? { taskQueue: command.taskQueue } : {},
1174
+ ...command.headers !== void 0 ? { headers: { ...command.headers } } : {},
1175
+ ...command.scheduleToCloseTimeout !== void 0 ? { scheduleToClose: command.scheduleToCloseTimeout } : {},
1176
+ ...command.scheduleToStartTimeout !== void 0 ? { scheduleToStart: command.scheduleToStartTimeout } : {}
434
1177
  };
435
1178
  this.attempts.push(attempt);
436
1179
  return;
@@ -505,18 +1248,25 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
505
1248
  return;
506
1249
  }
507
1250
  case "CONTINUE_AS_NEW": {
508
- const next = this.createRun(
509
- run.workflowFn,
510
- command.input,
511
- {
512
- ...run.info,
513
- runId: void 0,
514
- continuedFromRunId: run.runId,
515
- firstRunId: run.info.firstRunId ?? run.runId
516
- },
517
- run.parent
518
- );
519
- run.continuedTo = next;
1251
+ const options = command.options;
1252
+ const config = {
1253
+ ...this.chainConfig(run.config),
1254
+ // The run timeout restarts and the attempt count resets; the
1255
+ // execution timeout of the chain carries over (11 §2.20).
1256
+ lastCompletionResult: command.input
1257
+ };
1258
+ if (typeof options["taskQueue"] === "string") config.taskQueue = options["taskQueue"];
1259
+ if (typeof options["workflowTaskTimeout"] === "number")
1260
+ config.workflowTaskTimeoutMs = options["workflowTaskTimeout"];
1261
+ if (options["versioningBehavior"] === "PINNED" || options["versioningBehavior"] === "AUTO_UPGRADE")
1262
+ config.versioningBehavior = options["versioningBehavior"];
1263
+ const memo = options["context"];
1264
+ if (typeof memo === "object" && memo !== null && !Array.isArray(memo)) config.memo = memo;
1265
+ else if (Object.keys(run.state.context).length > 0) config.memo = { ...run.state.context };
1266
+ const retry = options["retry"];
1267
+ if (chunkISOIA7NV_cjs.continueAsNewRetryShape(options) === "run" && typeof retry === "object" && retry !== null && !Array.isArray(retry))
1268
+ config.retry = retry;
1269
+ this.startSuccessor(run, command.input, config);
520
1270
  this.onClosed(run);
521
1271
  return;
522
1272
  }
@@ -529,11 +1279,62 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
529
1279
  return;
530
1280
  }
531
1281
  }
1282
+ /** What a successor of a run inherits (continue-as-new, run retry). */
1283
+ chainConfig(config) {
1284
+ const out = { workflowKey: config.workflowKey, runAttempt: 1 };
1285
+ for (const key of [
1286
+ "businessId",
1287
+ "executionDeadline",
1288
+ "executionTimeoutMs",
1289
+ "runTimeoutMs",
1290
+ "workflowTaskTimeoutMs",
1291
+ "retry",
1292
+ "versioningBehavior",
1293
+ "taskQueue",
1294
+ "memo"
1295
+ ])
1296
+ if (config[key] !== void 0) Object.assign(out, { [key]: config[key] });
1297
+ return out;
1298
+ }
1299
+ /** Start the next run of a chain; the closed run's parent and handles follow it. */
1300
+ startSuccessor(run, input, config) {
1301
+ const next = this.createRun(
1302
+ run.workflowFn,
1303
+ input,
1304
+ {
1305
+ ...run.info,
1306
+ runId: void 0,
1307
+ continuedFromRunId: run.runId,
1308
+ firstRunId: run.info.firstRunId ?? run.runId
1309
+ },
1310
+ run.parent,
1311
+ {},
1312
+ config
1313
+ );
1314
+ run.continuedTo = next;
1315
+ return next;
1316
+ }
532
1317
  resolveTarget(run, target) {
533
1318
  if ("runId" in target) return target.runId;
534
1319
  if ("parent" in target) return run.parent?.runId ?? run.info.parentRunId ?? void 0;
535
- if ("childId" in target) return run.children.get(target.childId);
536
- return void 0;
1320
+ if ("childId" in target) {
1321
+ let childRunId = run.children.get(target.childId);
1322
+ while (childRunId !== void 0) {
1323
+ const next = this.runs.get(childRunId)?.continuedTo;
1324
+ if (next === void 0) break;
1325
+ childRunId = next;
1326
+ }
1327
+ return childRunId;
1328
+ }
1329
+ return this.resolveWorkflowId(target.workflowKey, target.workflowId, target.firstRunId);
1330
+ }
1331
+ /** The open run of a workflow id, else its latest run (11 §2.1). */
1332
+ resolveWorkflowId(workflowKey, workflowId, firstRunId) {
1333
+ const matching = this.runOrder.map((id) => this.run(id)).filter(
1334
+ (candidate) => candidate.config.workflowKey === workflowKey && candidate.config.businessId === workflowId && (firstRunId === void 0 || (candidate.info.firstRunId ?? candidate.runId) === firstRunId)
1335
+ );
1336
+ const open = matching.find((candidate) => candidate.state.status === "RUNNING");
1337
+ return (open ?? matching[matching.length - 1])?.runId;
537
1338
  }
538
1339
  startChild(run, command) {
539
1340
  const byFn = command.workflowFn !== void 0 && (this.executor !== void 0 || this.registry.byName.has(command.workflowFn));
@@ -566,6 +1367,28 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
566
1367
  });
567
1368
  return;
568
1369
  }
1370
+ const options = command.options;
1371
+ const ms = (key) => typeof options[key] === "number" ? options[key] : void 0;
1372
+ const executionTimeoutMs = ms("executionTimeout");
1373
+ const childKey = command.workflowKey ?? this.registry.byName.get(workflowFn)?.name ?? workflowFn;
1374
+ const config = { workflowKey: childKey, runAttempt: 1 };
1375
+ if (typeof options.workflowId === "string") config.businessId = options.workflowId;
1376
+ if (executionTimeoutMs !== void 0) {
1377
+ config.executionTimeoutMs = executionTimeoutMs;
1378
+ config.executionDeadline = this.clock + executionTimeoutMs;
1379
+ }
1380
+ const runTimeoutMs = ms("runTimeout");
1381
+ if (runTimeoutMs !== void 0) config.runTimeoutMs = runTimeoutMs;
1382
+ const taskTimeoutMs = ms("workflowTaskTimeout");
1383
+ if (taskTimeoutMs !== void 0) config.workflowTaskTimeoutMs = taskTimeoutMs;
1384
+ const startDelayMs = ms("startDelay");
1385
+ if (startDelayMs !== void 0) config.startDelayMs = startDelayMs;
1386
+ if (typeof options.summary === "string") config.summary = options.summary;
1387
+ if (typeof options.details === "string") config.details = options.details;
1388
+ if (options.context !== void 0) config.memo = options.context;
1389
+ if (options.versioningBehavior !== void 0)
1390
+ config.versioningBehavior = options.versioningBehavior;
1391
+ if (options.retry !== void 0) config.retry = options.retry;
569
1392
  const childRunId = this.createRun(
570
1393
  workflowFn,
571
1394
  command.input,
@@ -574,7 +1397,8 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
574
1397
  {
575
1398
  parentRunId: run.runId,
576
1399
  parentClosePolicy: command.options.parentClosePolicy
577
- }
1400
+ },
1401
+ config
578
1402
  );
579
1403
  run.children.set(command.childId, childRunId);
580
1404
  this.append(run, {
@@ -607,7 +1431,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
607
1431
  payload: {
608
1432
  childId: entry.childId,
609
1433
  childRunId,
610
- failure: toJsonValue(chunkFMSW2HDF_cjs.errorToFailure(error, "engine"))
1434
+ failure: toJsonValue(chunkZCGKGDCL_cjs.errorToFailure(error, "engine"))
611
1435
  }
612
1436
  });
613
1437
  }
@@ -616,7 +1440,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
616
1440
  const run = this.runs.get(attempt.runId);
617
1441
  if (!run || run.state.status !== "RUNNING") return;
618
1442
  const activity = run.state.activities[attempt.activityId];
619
- if (!activity || !chunkP6TA5EZT_cjs.isActivityOpen(activity)) return;
1443
+ if (!activity || !chunkISOIA7NV_cjs.isActivityOpen(activity)) return;
620
1444
  if (attempt.scheduleToClose !== void 0 && this.clock - attempt.scheduledAt > attempt.scheduleToClose) {
621
1445
  this.append(run, {
622
1446
  type: "ACTIVITY_TIMED_OUT",
@@ -628,35 +1452,151 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
628
1452
  });
629
1453
  return;
630
1454
  }
631
- const mock = this.mocks.get(`${attempt.nodeType}#${attempt.operation}`) ?? this.mocks.get(attempt.nodeType);
632
1455
  let failure;
633
1456
  let result = null;
1457
+ let heartbeatDetails = attempt.heartbeatDetails;
1458
+ let asyncToken;
634
1459
  try {
635
- if (!mock)
636
- throw new chunkFMSW2HDF_cjs.ApplicationError(
637
- `No mock for ${attempt.nodeType} ${attempt.operation} (use env.mock)`,
638
- {
639
- errorType: "VALIDATION",
640
- nonRetryable: true,
641
- type: "UnmockedActivity"
1460
+ if (attempt.kind === "user") {
1461
+ const impl = chunkVA4OFR72_cjs.findActivityImplementation(this.activityImpls, attempt.operation);
1462
+ if (!impl)
1463
+ throw new chunkZCGKGDCL_cjs.ApplicationError(
1464
+ `No implementation of activity ${attempt.operation} (use env.registerActivity or env.mockActivity)`,
1465
+ { errorType: "VALIDATION", nonRetryable: true, type: "ActivityNotRegistered" }
1466
+ );
1467
+ const ctx = this.activityContext(
1468
+ attempt,
1469
+ (details) => {
1470
+ heartbeatDetails = details;
1471
+ },
1472
+ (token) => {
1473
+ asyncToken = token;
642
1474
  }
643
1475
  );
644
- result = toJsonValue(
645
- await mock(attempt.args, {
646
- runId: attempt.runId,
647
- activityId: attempt.activityId,
648
- attempt: attempt.attempt,
649
- nodeType: attempt.nodeType,
650
- operation: attempt.operation,
651
- ...attempt.connection !== void 0 ? { connection: attempt.connection } : {}
652
- })
653
- );
1476
+ result = toJsonValue(
1477
+ await chunkVA4OFR72_cjs.executeActivity(impl, ctx, attempt.args, this.activityInterceptors)
1478
+ );
1479
+ } else {
1480
+ const mock = this.mocks.get(`${attempt.nodeType}#${attempt.operation}`) ?? this.mocks.get(attempt.nodeType);
1481
+ if (!mock)
1482
+ throw new chunkZCGKGDCL_cjs.ApplicationError(
1483
+ `No mock for ${attempt.nodeType} ${attempt.operation} (use env.mock)`,
1484
+ {
1485
+ errorType: "VALIDATION",
1486
+ nonRetryable: true,
1487
+ type: "UnmockedActivity"
1488
+ }
1489
+ );
1490
+ result = toJsonValue(
1491
+ await mock(attempt.args, {
1492
+ runId: attempt.runId,
1493
+ activityId: attempt.activityId,
1494
+ attempt: attempt.attempt,
1495
+ nodeType: attempt.nodeType,
1496
+ operation: attempt.operation,
1497
+ ...attempt.connection !== void 0 ? { connection: attempt.connection } : {},
1498
+ ...attempt.heartbeatDetails !== void 0 ? { heartbeatDetails: attempt.heartbeatDetails } : {},
1499
+ heartbeat: (details) => {
1500
+ heartbeatDetails = toJsonValue(details);
1501
+ }
1502
+ })
1503
+ );
1504
+ }
654
1505
  } catch (error) {
655
- failure = chunkFMSW2HDF_cjs.errorToFailure(error, `node:${attempt.nodeType}`);
1506
+ failure = chunkZCGKGDCL_cjs.errorToFailure(
1507
+ error,
1508
+ attempt.kind === "user" ? "sdk-ts" : `node:${attempt.nodeType}`
1509
+ );
656
1510
  delete failure.stackTrace;
657
1511
  }
658
- if (run.state.status !== "RUNNING" || !chunkP6TA5EZT_cjs.isActivityOpen(run.state.activities[attempt.activityId] ?? activity))
1512
+ if (run.state.status !== "RUNNING" || !chunkISOIA7NV_cjs.isActivityOpen(run.state.activities[attempt.activityId] ?? activity))
659
1513
  return;
1514
+ if (asyncToken !== void 0 && failure === void 0) {
1515
+ this.asyncAttempts.set(asyncToken, {
1516
+ ...attempt,
1517
+ ...heartbeatDetails !== void 0 ? { heartbeatDetails } : {}
1518
+ });
1519
+ return;
1520
+ }
1521
+ this.finishAttempt(run, attempt, failure, result, heartbeatDetails);
1522
+ }
1523
+ /** The `ActivityContext` of one user-activity attempt. */
1524
+ activityContext(attempt, onHeartbeat, onAsync) {
1525
+ const run = this.runs.get(attempt.runId);
1526
+ const listeners = /* @__PURE__ */ new Set();
1527
+ const signal = {
1528
+ get aborted() {
1529
+ return attempt.cancelRequested;
1530
+ },
1531
+ addEventListener: (_type, listener) => {
1532
+ listeners.add(listener);
1533
+ },
1534
+ removeEventListener: (_type, listener) => {
1535
+ listeners.delete(listener);
1536
+ }
1537
+ };
1538
+ return {
1539
+ info: {
1540
+ runId: attempt.runId,
1541
+ workspaceId: this.workspaceId,
1542
+ ...run?.config.workflowKey !== void 0 ? { workflowKey: run.config.workflowKey } : {},
1543
+ activityId: attempt.activityId,
1544
+ activityName: attempt.operation,
1545
+ taskQueue: attempt.taskQueue ?? "managed",
1546
+ attempt: attempt.attempt,
1547
+ ...attempt.heartbeatDetails !== void 0 ? { heartbeatDetails: attempt.heartbeatDetails } : {},
1548
+ headers: { ...attempt.headers ?? {} }
1549
+ },
1550
+ heartbeat: (details) => {
1551
+ onHeartbeat(toJsonValue(details));
1552
+ return Promise.resolve({ cancelRequested: attempt.cancelRequested, paused: false });
1553
+ },
1554
+ cancellationSignal: signal,
1555
+ completeAsync: () => {
1556
+ const token = `test-task-token:${attempt.runId}:${attempt.activityId}:${attempt.attempt}`;
1557
+ onAsync(token);
1558
+ return Promise.resolve(token);
1559
+ },
1560
+ connection: (name) => {
1561
+ const found = this.connections[name];
1562
+ if (found === void 0)
1563
+ return Promise.reject(
1564
+ new chunkZCGKGDCL_cjs.ApplicationError(`No connection "${name}" in the test environment`, {
1565
+ errorType: "AUTHORIZATION",
1566
+ nonRetryable: true,
1567
+ type: "ConnectionNotReleased"
1568
+ })
1569
+ );
1570
+ return Promise.resolve({ ...found });
1571
+ }
1572
+ };
1573
+ }
1574
+ /** Complete an activity that called `completeAsync()` (`completeActivityAsync`). */
1575
+ async completeActivityAsync(token, result) {
1576
+ const attempt = this.takeAsync(token);
1577
+ const run = this.run(attempt.runId);
1578
+ this.finishAttempt(run, attempt, void 0, toJsonValue(result), attempt.heartbeatDetails);
1579
+ await this.runUntilIdle(false);
1580
+ }
1581
+ /** Fail an activity that called `completeAsync()` (`failActivityAsync`); the retry policy applies. */
1582
+ async failActivityAsync(token, error) {
1583
+ const attempt = this.takeAsync(token);
1584
+ const run = this.run(attempt.runId);
1585
+ const failure = chunkZCGKGDCL_cjs.errorToFailure(error, "sdk-ts");
1586
+ delete failure.stackTrace;
1587
+ this.finishAttempt(run, attempt, failure, null, attempt.heartbeatDetails);
1588
+ await this.runUntilIdle(false);
1589
+ }
1590
+ takeAsync(token) {
1591
+ const attempt = this.asyncAttempts.get(token);
1592
+ if (!attempt) throw new Error(`Unknown or used activity task token ${token}`);
1593
+ this.asyncAttempts.delete(token);
1594
+ return attempt;
1595
+ }
1596
+ /** Record an attempt's outcome: completion, a final failure or timeout, or the next attempt. */
1597
+ finishAttempt(run, attempt, failure, result, heartbeatDetails) {
1598
+ const open = run.state.activities[attempt.activityId];
1599
+ if (run.state.status !== "RUNNING" || !open || !chunkISOIA7NV_cjs.isActivityOpen(open)) return;
660
1600
  const started = () => {
661
1601
  this.append(run, {
662
1602
  type: "ACTIVITY_STARTED",
@@ -672,7 +1612,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
672
1612
  return;
673
1613
  }
674
1614
  if (failure.timeoutType !== void 0 || failure.type === "TimeoutFailure") {
675
- const decision2 = chunkP6TA5EZT_cjs.computeRetryDelay(attempt.retry, attempt.attempt, failure);
1615
+ const decision2 = chunkTYF56RGB_cjs.computeRetryDelay(attempt.retry, attempt.attempt, failure);
676
1616
  if (!decision2.retry) {
677
1617
  started();
678
1618
  this.append(run, {
@@ -689,16 +1629,18 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
689
1629
  this.attempts.push({
690
1630
  ...attempt,
691
1631
  attempt: attempt.attempt + 1,
692
- dueAt: this.clock + decision2.delayMs
1632
+ dueAt: this.clock + decision2.delayMs,
1633
+ ...heartbeatDetails !== void 0 ? { heartbeatDetails } : {}
693
1634
  });
694
1635
  return;
695
1636
  }
696
- const decision = chunkP6TA5EZT_cjs.computeRetryDelay(attempt.retry, attempt.attempt, failure);
1637
+ const decision = chunkTYF56RGB_cjs.computeRetryDelay(attempt.retry, attempt.attempt, failure);
697
1638
  if (decision.retry) {
698
1639
  this.attempts.push({
699
1640
  ...attempt,
700
1641
  attempt: attempt.attempt + 1,
701
- dueAt: this.clock + decision.delayMs
1642
+ dueAt: this.clock + decision.delayMs,
1643
+ ...heartbeatDetails !== void 0 ? { heartbeatDetails } : {}
702
1644
  });
703
1645
  return;
704
1646
  }
@@ -712,23 +1654,68 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
712
1654
  }
713
1655
  });
714
1656
  }
715
- onClosed(run) {
1657
+ /**
1658
+ * Run-level retry (11 §2.17): a failed or run-timed-out run whose policy
1659
+ * allows another attempt is followed by a new run of the chain after the
1660
+ * backoff, with `runAttempt + 1` and the failure as `lastFailure`.
1661
+ */
1662
+ retryRun(run) {
1663
+ if (run.continuedTo !== void 0) return;
1664
+ const last = run.history[run.history.length - 1];
1665
+ if (!last || last.type !== "WORKFLOW_FAILED" && last.type !== "WORKFLOW_TIMED_OUT") return;
1666
+ const failure = last.payload["failure"] ?? { errorType: "TIMEOUT", message: "timed out", timeoutType: "WORKFLOW_RUN" };
1667
+ const decision = chunkTYF56RGB_cjs.computeRunRetryDelay(run.config.retry, run.config.runAttempt, failure);
1668
+ if (!decision.retry) return;
1669
+ const config = {
1670
+ ...this.chainConfig(run.config),
1671
+ runAttempt: run.config.runAttempt + 1,
1672
+ lastFailure: failure
1673
+ };
1674
+ if (decision.delayMs > 0) config.firstTaskDelayMs = decision.delayMs;
1675
+ this.startSuccessor(run, run.state.input ?? null, config);
1676
+ }
1677
+ /**
1678
+ * A run closed: drop its pending work, retry it, apply the parent-close
1679
+ * policy to its children (except `keptChildren`, which follow a reset
1680
+ * fork), settle its open updates and notify its parent.
1681
+ */
1682
+ onClosed(run, keptChildren = /* @__PURE__ */ new Set()) {
716
1683
  this.timers = this.timers.filter((timer) => timer.runId !== run.runId);
717
1684
  this.attempts = this.attempts.filter((entry) => entry.runId !== run.runId);
1685
+ this.dues = this.dues.filter((entry) => entry.runId !== run.runId);
1686
+ for (const [token, entry] of this.asyncAttempts)
1687
+ if (entry.runId === run.runId) this.asyncAttempts.delete(token);
1688
+ this.retryRun(run);
718
1689
  for (const [childId2, childRunId] of run.children) {
1690
+ if (keptChildren.has(childId2)) continue;
719
1691
  const child = run.state.children[childId2];
720
- if (!child || !chunkP6TA5EZT_cjs.isChildOpen(child) || childRunId === void 0) continue;
1692
+ if (!child || !chunkISOIA7NV_cjs.isChildOpen(child) || childRunId === void 0) continue;
721
1693
  if (child.parentClosePolicy === "TERMINATE") this.terminate(childRunId, "parent closed");
722
1694
  else if (child.parentClosePolicy === "REQUEST_CANCEL")
723
1695
  this.requestCancel(childRunId, "parent closed");
724
1696
  }
1697
+ for (const update of run.updates.values()) {
1698
+ if (update.status !== "PENDING" && update.status !== "ACCEPTED" && update.status !== "ADMITTED")
1699
+ continue;
1700
+ const accepted = update.status === "ACCEPTED";
1701
+ update.status = accepted ? "COMPLETED" : "REJECTED";
1702
+ update.failure = {
1703
+ errorType: accepted ? "PERMANENT" : "VALIDATION",
1704
+ type: "RunClosed",
1705
+ message: `The run closed before update "${update.name}" ${accepted ? "completed" : "was accepted"}`
1706
+ };
1707
+ }
725
1708
  if (!run.parent) return;
726
1709
  const parent = this.runs.get(run.parent.runId);
727
1710
  if (!parent || parent.state.status !== "RUNNING") return;
728
1711
  const childId = run.parent.childId;
729
- if (!parent.state.children[childId] || !chunkP6TA5EZT_cjs.isChildOpen(parent.state.children[childId])) return;
1712
+ if (!parent.state.children[childId] || !chunkISOIA7NV_cjs.isChildOpen(parent.state.children[childId])) return;
730
1713
  const last = run.history[run.history.length - 1];
731
1714
  if (!last) return;
1715
+ if (run.resetTo !== void 0) {
1716
+ parent.children.set(childId, run.resetTo);
1717
+ return;
1718
+ }
732
1719
  if (run.continuedTo !== void 0) {
733
1720
  const next = this.runs.get(run.continuedTo);
734
1721
  if (next) {
@@ -769,26 +1756,41 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
769
1756
  default:
770
1757
  this.append(parent, {
771
1758
  type: "CHILD_RUN_TIMED_OUT",
772
- payload: { ...base, timeoutType: "WORKFLOW_RUN" }
1759
+ payload: {
1760
+ ...base,
1761
+ timeoutType: last.payload["timeoutType"] === "WORKFLOW_EXECUTION" ? "WORKFLOW_EXECUTION" : "WORKFLOW_RUN"
1762
+ }
773
1763
  });
774
1764
  }
775
1765
  }
776
1766
  async resultOf(runId) {
777
1767
  await this.runUntilIdle(this.timeSkipping);
778
1768
  let run = this.run(runId);
779
- while (run.continuedTo !== void 0) run = this.run(run.continuedTo);
1769
+ while (run.continuedTo !== void 0 || run.resetTo !== void 0)
1770
+ run = this.run(run.continuedTo ?? run.resetTo ?? run.runId);
780
1771
  if (run.taskFailure) throw new WorkflowTaskFailedError(run.runId, run.taskFailure);
1772
+ if (this.failOnUnfinishedHandlers && run.unfinishedHandlers !== void 0)
1773
+ throw new UnfinishedHandlersError(run.runId, run.unfinishedHandlers);
781
1774
  const last = run.history[run.history.length - 1];
782
1775
  switch (run.state.status) {
783
1776
  case "COMPLETED":
784
1777
  return run.state.output ?? null;
1778
+ case "TIMED_OUT":
1779
+ throw new WorkflowFailedError(
1780
+ run.runId,
1781
+ last?.payload["failure"] ?? {
1782
+ errorType: "TIMEOUT",
1783
+ message: "timed out",
1784
+ type: "TimeoutFailure"
1785
+ }
1786
+ );
785
1787
  case "FAILED":
786
1788
  throw new WorkflowFailedError(
787
1789
  run.runId,
788
1790
  run.state.failure ?? { errorType: "UNKNOWN", message: "failed" }
789
1791
  );
790
1792
  case "CANCELLED":
791
- throw new chunkFMSW2HDF_cjs.CancelledFailure(`Run ${run.runId} was cancelled`);
1793
+ throw new chunkZCGKGDCL_cjs.CancelledFailure(`Run ${run.runId} was cancelled`);
792
1794
  case "TERMINATED":
793
1795
  throw new WorkflowFailedError(run.runId, {
794
1796
  errorType: "PERMANENT",
@@ -819,7 +1821,7 @@ var ReplayError = class extends Error {
819
1821
  function replayRequest(workflowFn, history, info = {}, nowMs) {
820
1822
  const last = history[history.length - 1];
821
1823
  return {
822
- protocol: chunk623FVQSN_cjs.HISTORY_PROTOCOL,
1824
+ protocol: chunkTYF56RGB_cjs.HISTORY_PROTOCOL,
823
1825
  kind: "verify",
824
1826
  workflowFn,
825
1827
  info: { runId: "replay", workspaceId: "replay", ...info },
@@ -829,14 +1831,14 @@ function replayRequest(workflowFn, history, info = {}, nowMs) {
829
1831
  }
830
1832
  function eventsOf(input) {
831
1833
  if (Array.isArray(input)) return { events: input };
832
- const file = typeof input === "string" ? chunkPZCVF76Q_cjs.parseHistoryFile(input) : input;
1834
+ const file = typeof input === "string" ? chunkHMZUGSMU_cjs.parseHistoryFile(input) : input;
833
1835
  return { events: file.events, file };
834
1836
  }
835
1837
  async function replay(workflows, input, options = {}) {
836
1838
  const { events, file } = eventsOf(input);
837
1839
  const started = events[0]?.type === "WORKFLOW_STARTED" ? events[0].payload["workflowFn"] : void 0;
838
1840
  const recordedFn = options.workflowFn ?? file?.workflowFn ?? (typeof started === "string" ? started : void 0);
839
- const map = chunkDHTLALBL_cjs.isDurableWorkflow(workflows) ? { [recordedFn ?? workflows.name]: workflows } : { ...workflows };
1841
+ const map = chunkVA4OFR72_cjs.isDurableWorkflow(workflows) ? { [recordedFn ?? workflows.name]: workflows } : { ...workflows };
840
1842
  const workflowFn = recordedFn ?? Object.keys(map)[0] ?? "";
841
1843
  const result = await runWorkflowTaskInProcess(
842
1844
  registryOf(map),
@@ -849,7 +1851,7 @@ async function replay(workflows, input, options = {}) {
849
1851
  );
850
1852
  if (result.outcome === "failed") {
851
1853
  if (result.failure?.cause === "NON_DETERMINISM")
852
- throw new chunkFMSW2HDF_cjs.DeterminismViolation(result.failure.message);
1854
+ throw new chunkZCGKGDCL_cjs.DeterminismViolation(result.failure.message);
853
1855
  throw new ReplayError(result);
854
1856
  }
855
1857
  return result;
@@ -898,16 +1900,16 @@ function assertHistory(history, expected, options = {}) {
898
1900
  );
899
1901
  }
900
1902
  function definitionOf(value) {
901
- return chunkGBQ33SIZ_cjs.normalizeDefinition(chunkSAOBPYYJ_cjs.isTier1Workflow(value) ? chunkSAOBPYYJ_cjs.toIR(value) : value);
1903
+ return chunk54FLQNUM_cjs.normalizeDefinition(chunkIQPXHQQQ_cjs.isTier1Workflow(value) ? chunkIQPXHQQQ_cjs.toIR(value) : value);
902
1904
  }
903
1905
  function expectIR(value) {
904
1906
  const definition = definitionOf(value);
905
- const hash = chunkGBQ33SIZ_cjs.irHash(definition);
1907
+ const hash = chunk54FLQNUM_cjs.irHash(definition);
906
1908
  return {
907
1909
  definition,
908
1910
  irHash: hash,
909
1911
  toEqualIR(other) {
910
- const otherHash = chunkGBQ33SIZ_cjs.irHash(definitionOf(other));
1912
+ const otherHash = chunk54FLQNUM_cjs.irHash(definitionOf(other));
911
1913
  if (otherHash !== hash)
912
1914
  throw new HistoryAssertionError(`The IR differs: ${hash} versus ${otherHash}`);
913
1915
  }
@@ -950,7 +1952,7 @@ async function simulate(definition, options = {}) {
950
1952
  output = produced.output;
951
1953
  handle = produced.handle;
952
1954
  } else output = produced;
953
- } else if (node.type === chunkGBQ33SIZ_cjs.CODE_WORKFLOW_NODE_TYPE) {
1955
+ } else if (node.type === chunk54FLQNUM_cjs.CODE_WORKFLOW_NODE_TYPE) {
954
1956
  const state = node.args?.state;
955
1957
  const workflowFn = chunkSAENRNBJ_cjs.isRecord(state) && typeof state["workflowFn"] === "string" ? state["workflowFn"] : "";
956
1958
  const fn = options.workflows?.[workflowFn];
@@ -1018,30 +2020,35 @@ async function runWorkflowTaskInVm(script, request, options = {}) {
1018
2020
  await settle();
1019
2021
  if (step !== "more") break;
1020
2022
  if (Date.now() > deadline)
1021
- return chunkJD2VQIDZ_cjs.failedTaskResult(
2023
+ return chunk672KMMBK_cjs.failedTaskResult(
1022
2024
  "TASK_TIMEOUT",
1023
2025
  `The workflow task ran past its ${timeout} ms budget`
1024
2026
  );
1025
2027
  }
1026
2028
  const json = run("globalThis.__fluidgridsRuntime.complete()", "complete.js");
1027
2029
  if (typeof json !== "string")
1028
- return chunkJD2VQIDZ_cjs.failedTaskResult("INTERNAL", "The runtime returned no result");
2030
+ return chunk672KMMBK_cjs.failedTaskResult("INTERNAL", "The runtime returned no result");
1029
2031
  return JSON.parse(json);
1030
2032
  } catch (error) {
1031
2033
  const fields = typeof error === "object" && error !== null ? error : {};
1032
2034
  const message = typeof fields.message === "string" ? fields.message : String(error);
1033
2035
  const name = typeof fields.name === "string" ? fields.name : "";
1034
- if (/timed out/i.test(message)) return chunkJD2VQIDZ_cjs.failedTaskResult("TASK_TIMEOUT", message);
1035
- if (name === "DeterminismViolation") return chunkJD2VQIDZ_cjs.failedTaskResult("NON_DETERMINISM", message);
1036
- return chunkJD2VQIDZ_cjs.failedTaskResult("WORKFLOW_CODE_ERROR", `${name || "Error"}: ${message}`);
2036
+ if (/timed out/i.test(message)) return chunk672KMMBK_cjs.failedTaskResult("TASK_TIMEOUT", message);
2037
+ if (name === "DeterminismViolation") return chunk672KMMBK_cjs.failedTaskResult("NON_DETERMINISM", message);
2038
+ return chunk672KMMBK_cjs.failedTaskResult("WORKFLOW_CODE_ERROR", `${name || "Error"}: ${message}`);
1037
2039
  }
1038
2040
  }
1039
2041
 
1040
2042
  exports.HistoryAssertionError = HistoryAssertionError;
2043
+ exports.QueryFailedError = QueryFailedError;
2044
+ exports.QueryRejectedError = QueryRejectedError;
1041
2045
  exports.ReplayError = ReplayError;
1042
2046
  exports.RunBlockedError = RunBlockedError;
1043
2047
  exports.TestRunHandle = TestRunHandle;
1044
2048
  exports.TestWorkflowEnvironment = TestWorkflowEnvironment;
2049
+ exports.UnfinishedHandlersError = UnfinishedHandlersError;
2050
+ exports.UpdateRefusedError = UpdateRefusedError;
2051
+ exports.WorkflowAlreadyStartedError = WorkflowAlreadyStartedError;
1045
2052
  exports.WorkflowFailedError = WorkflowFailedError;
1046
2053
  exports.WorkflowTaskFailedError = WorkflowTaskFailedError;
1047
2054
  exports.assertHistory = assertHistory;