@fluidgrids/workflows 2026.1029.1 → 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 (118) hide show
  1. package/README.md +112 -4
  2. package/dist/{activation-CESehfYi.d.cts → activation-DqUfpHzk.d.cts} +1 -1
  3. package/dist/{activation-BnVQMv9y.d.ts → activation-xpx1oWuo.d.ts} +1 -1
  4. package/dist/{chunk-MJ5TGYVG.js → chunk-2D3MYIIF.js} +969 -153
  5. package/dist/{chunk-2B37XAFQ.cjs → chunk-3U2NU7YC.cjs} +24 -11
  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-2DDULZFM.js → chunk-5HIVIV53.js} +86 -75
  9. package/dist/chunk-5MFVJM76.js +1222 -0
  10. package/dist/{chunk-EWYADREB.cjs → chunk-672KMMBK.cjs} +2 -2
  11. package/dist/{chunk-KXJDRQ6G.js → chunk-6A2FGSUS.js} +22 -2
  12. package/dist/{chunk-OIX4O6UR.js → chunk-6OLN6BMB.js} +16 -3
  13. package/dist/{chunk-6FSHT5IL.js → chunk-7EZIANC7.js} +1 -1
  14. package/dist/chunk-A5SXCA62.cjs +93 -0
  15. package/dist/chunk-AC6ZEXVR.js +85 -0
  16. package/dist/{chunk-FWBRQWRX.js → chunk-AE5Q6ZAJ.js} +167 -10
  17. package/dist/{chunk-7ILGCUI6.js → chunk-C4F5KJTI.js} +142 -3
  18. package/dist/{chunk-WXXNCHUY.js → chunk-G5H32GIG.js} +1 -1
  19. package/dist/{chunk-OMY3CKUZ.cjs → chunk-GEQDGUGB.cjs} +1042 -226
  20. package/dist/{chunk-25BKWR2O.js → chunk-HCM7ZC7Q.js} +1 -1
  21. package/dist/{chunk-I47EENR4.cjs → chunk-HMZUGSMU.cjs} +673 -156
  22. package/dist/{chunk-NXFBVDOI.cjs → chunk-IQPXHQQQ.cjs} +8 -4
  23. package/dist/{chunk-RUQIMTN5.cjs → chunk-ISOIA7NV.cjs} +178 -15
  24. package/dist/chunk-JSC75O5C.cjs +167 -0
  25. package/dist/{chunk-BD7ZPG53.js → chunk-NWQ5WRLE.js} +10 -2
  26. package/dist/chunk-ODZ2IAR2.cjs +1247 -0
  27. package/dist/{chunk-FQSJI5NV.js → chunk-SR7TR5KX.js} +6 -2
  28. package/dist/{chunk-OKX3FYIM.cjs → chunk-TCTE7DX5.cjs} +3 -3
  29. package/dist/{chunk-3FIDHONL.cjs → chunk-TYF56RGB.cjs} +99 -80
  30. package/dist/{chunk-J3PYFGKA.cjs → chunk-VA4OFR72.cjs} +162 -4
  31. package/dist/chunk-VU5S5A7V.js +150 -0
  32. package/dist/{chunk-A36CCOWS.js → chunk-YEHR4NNE.js} +633 -128
  33. package/dist/{chunk-ELL2RBML.cjs → chunk-ZCGKGDCL.cjs} +23 -1
  34. package/dist/codegen/index.d.cts +2 -2
  35. package/dist/codegen/index.d.ts +2 -2
  36. package/dist/{collect-BTHjQaSp.d.ts → collect-6NIEufHd.d.ts} +20 -3
  37. package/dist/{collect-CSyOg5XC.d.cts → collect-CcTCKqx6.d.cts} +20 -3
  38. package/dist/{file-cgL9l9l8.d.cts → file-BxYpwjRQ.d.cts} +250 -15
  39. package/dist/{file-olQudcx5.d.ts → file-CFdPQJI9.d.ts} +250 -15
  40. package/dist/history/index.cjs +283 -106
  41. package/dist/history/index.d.cts +549 -10
  42. package/dist/history/index.d.ts +549 -10
  43. package/dist/history/index.js +5 -4
  44. package/dist/index.cjs +146 -53
  45. package/dist/index.d.cts +38 -14
  46. package/dist/index.d.ts +38 -14
  47. package/dist/index.js +6 -5
  48. package/dist/interceptors-CNcr2dlk.d.ts +159 -0
  49. package/dist/interceptors-CqkNZVfI.d.cts +159 -0
  50. package/dist/ir/index.cjs +339 -36
  51. package/dist/ir/index.d.cts +244 -8
  52. package/dist/ir/index.d.ts +244 -8
  53. package/dist/ir/index.js +306 -21
  54. package/dist/{lower-3S6PsqjJ.d.cts → lower-BtRfIW2A.d.cts} +23 -9
  55. package/dist/{lower-DmZpQ8hJ.d.ts → lower-CpsMFOFX.d.ts} +23 -9
  56. package/dist/{manifest-BJjrQt77.d.ts → manifest-D-I_twys.d.ts} +1 -1
  57. package/dist/{manifest-gRI2Q5Fj.d.cts → manifest-DahBQVM8.d.cts} +1 -1
  58. package/dist/node-evaluator-DGQDPSPI.cjs +24 -0
  59. package/dist/node-evaluator-LEEVD7H7.js +14 -0
  60. package/dist/payload-fields-BVRQn2yH.d.cts +122 -0
  61. package/dist/payload-fields-oOBWxDiG.d.ts +122 -0
  62. package/dist/quickjs/index.cjs +27 -27
  63. package/dist/quickjs/index.d.cts +6 -6
  64. package/dist/quickjs/index.d.ts +6 -6
  65. package/dist/quickjs/index.js +9 -9
  66. package/dist/roundtrip/index.cjs +72 -66
  67. package/dist/roundtrip/index.d.cts +25 -11
  68. package/dist/roundtrip/index.d.ts +25 -11
  69. package/dist/roundtrip/index.js +13 -11
  70. package/dist/runtime/index.cjs +19 -19
  71. package/dist/runtime/index.d.cts +139 -12
  72. package/dist/runtime/index.d.ts +139 -12
  73. package/dist/runtime/index.js +6 -6
  74. package/dist/testing/index.cjs +688 -121
  75. package/dist/testing/index.d.cts +174 -10
  76. package/dist/testing/index.d.ts +174 -10
  77. package/dist/testing/index.js +646 -82
  78. package/dist/{types-CnIOinoz.d.ts → types-Bv2i4cBX.d.cts} +126 -23
  79. package/dist/{types-CQKOhPTa.d.cts → types-DGx-b9eq.d.ts} +126 -23
  80. package/dist/{types-Bb2wRnJ5.d.cts → types-V7jEEUaL.d.cts} +1 -1
  81. package/dist/{types-Bb2wRnJ5.d.ts → types-V7jEEUaL.d.ts} +1 -1
  82. package/dist/{workflow-8uRU9rhL.d.ts → workflow-B18OeF7g.d.ts} +2 -2
  83. package/dist/{workflow-DWTPHFbt.d.ts → workflow-BGnv8SS6.d.ts} +261 -14
  84. package/dist/{workflow-CZOXUlQ5.d.cts → workflow-BJPFv3cp.d.cts} +2 -2
  85. package/dist/{workflow-O6e64ZcG.d.cts → workflow-DS32Gtws.d.cts} +261 -14
  86. package/fixtures/histories/activity-options-updated.history.json +159 -0
  87. package/fixtures/histories/activity-paused-unpaused.history.json +160 -0
  88. package/fixtures/histories/codec-opaque.history.json +229 -0
  89. package/fixtures/histories/dynamic-workflow.history.json +150 -0
  90. package/fixtures/histories/interceptor-headers.history.json +339 -0
  91. package/fixtures/histories/query-custom.history.json +213 -0
  92. package/fixtures/histories/query-default-handler.history.json +120 -0
  93. package/fixtures/histories/reset-forked-reapplied-signals.history.json +239 -0
  94. package/fixtures/histories/reset-reapplied-update-admitted.history.json +228 -0
  95. package/fixtures/histories/search-attributes-upserted.history.json +177 -0
  96. package/fixtures/histories/update-accepted-completed.history.json +45 -30
  97. package/fixtures/histories/update-default-handler.history.json +246 -0
  98. package/fixtures/histories/update-handler-awaits-activity.history.json +196 -0
  99. package/fixtures/histories/update-not-handled.history.json +138 -0
  100. package/fixtures/histories/update-rejected-no-event.history.json +190 -0
  101. package/fixtures/histories/update-with-start-admitted.history.json +150 -0
  102. package/fixtures/histories/user-activity-cancel.history.json +149 -0
  103. package/fixtures/histories/user-activity-retry.history.json +143 -0
  104. package/fixtures/histories/user-activity.history.json +149 -0
  105. package/package.json +1 -1
  106. package/schema/bridge-v2.schema.json +1062 -0
  107. package/schema/history-file.schema.json +255 -81
  108. package/schema/ir-v2.schema.json +246 -1
  109. package/schema/payload-fields.json +162 -0
  110. package/schema/run-event.schema.json +239 -80
  111. package/schema/workflow-command.schema.json +210 -84
  112. package/schema/workflow-task.schema.json +532 -167
  113. package/dist/chunk-6QPOJZT6.cjs +0 -1180
  114. package/dist/chunk-A2OHX3UQ.js +0 -1156
  115. package/dist/chunk-PWIUEWC3.js +0 -81
  116. package/dist/chunk-YHBVMOMK.cjs +0 -87
  117. package/dist/node-evaluator-SOADN23V.js +0 -14
  118. package/dist/node-evaluator-YGDEXK4U.cjs +0 -24
@@ -1,23 +1,24 @@
1
1
  'use strict';
2
2
 
3
- var chunkEWYADREB_cjs = require('../chunk-EWYADREB.cjs');
4
- var chunkNXFBVDOI_cjs = require('../chunk-NXFBVDOI.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 chunkI47EENR4_cjs = require('../chunk-I47EENR4.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 chunkOMY3CKUZ_cjs = require('../chunk-OMY3CKUZ.cjs');
13
- var chunkELL2RBML_cjs = require('../chunk-ELL2RBML.cjs');
13
+ var chunkGEQDGUGB_cjs = require('../chunk-GEQDGUGB.cjs');
14
+ var chunkZCGKGDCL_cjs = require('../chunk-ZCGKGDCL.cjs');
14
15
  require('../chunk-Q4MWQNJK.cjs');
15
16
  var chunkL24YIZY7_cjs = require('../chunk-L24YIZY7.cjs');
16
- var chunkJ3PYFGKA_cjs = require('../chunk-J3PYFGKA.cjs');
17
+ var chunkVA4OFR72_cjs = require('../chunk-VA4OFR72.cjs');
17
18
  require('../chunk-FR7KYWRO.cjs');
18
- var chunkRUQIMTN5_cjs = require('../chunk-RUQIMTN5.cjs');
19
- var chunk3FIDHONL_cjs = require('../chunk-3FIDHONL.cjs');
20
- var chunkYHBVMOMK_cjs = require('../chunk-YHBVMOMK.cjs');
19
+ var chunkISOIA7NV_cjs = require('../chunk-ISOIA7NV.cjs');
20
+ require('../chunk-A5SXCA62.cjs');
21
+ var chunkTYF56RGB_cjs = require('../chunk-TYF56RGB.cjs');
21
22
  require('../chunk-Z2Y65YOY.cjs');
22
23
  var vm = require('vm');
23
24
 
@@ -25,8 +26,10 @@ var vm = require('vm');
25
26
  function drainJobs() {
26
27
  return new Promise((resolve) => setImmediate(resolve));
27
28
  }
28
- function registryOf(workflows) {
29
- return chunkOMY3CKUZ_cjs.buildWorkflowRegistry([["in-process", { ...workflows }]]);
29
+ function registryOf(workflows, interceptors) {
30
+ return chunkGEQDGUGB_cjs.buildWorkflowRegistry([
31
+ ["in-process", { ...workflows, ...interceptors !== void 0 ? { interceptors } : {} }]
32
+ ]);
30
33
  }
31
34
  async function hostLoop(abi, requestJson) {
32
35
  abi.start(requestJson);
@@ -36,12 +39,38 @@ async function hostLoop(abi, requestJson) {
36
39
  return abi.complete();
37
40
  }
38
41
  async function runWorkflowTaskInProcess(registry, request) {
39
- const abi = chunkOMY3CKUZ_cjs.createWorkflowRuntime(registry);
42
+ const abi = chunkGEQDGUGB_cjs.createWorkflowRuntime(registry);
40
43
  const json = await hostLoop(abi, JSON.stringify(request));
41
44
  return JSON.parse(json);
42
45
  }
43
46
 
44
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
+ };
45
74
  var WorkflowAlreadyStartedError = class extends Error {
46
75
  constructor(workflowKey, workflowId, existingRunId) {
47
76
  super(
@@ -74,7 +103,7 @@ var WorkflowFailedError = class extends Error {
74
103
  this.runId = runId;
75
104
  this.failure = failure;
76
105
  this.name = "WorkflowFailedError";
77
- Object.defineProperty(this, "cause", { value: chunkELL2RBML_cjs.failureToError(failure), enumerable: false });
106
+ Object.defineProperty(this, "cause", { value: chunkZCGKGDCL_cjs.failureToError(failure), enumerable: false });
78
107
  }
79
108
  runId;
80
109
  failure;
@@ -99,7 +128,7 @@ var RunBlockedError = class extends Error {
99
128
  }
100
129
  runId;
101
130
  };
102
- var TestRunHandle = class {
131
+ var TestRunHandle = class _TestRunHandle {
103
132
  constructor(env, runId) {
104
133
  this.env = env;
105
134
  this.runId = runId;
@@ -116,7 +145,7 @@ var TestRunHandle = class {
116
145
  }
117
146
  /** Deliver a signal and run until idle (without skipping time). */
118
147
  async signal(signal, payload) {
119
- this.env.deliverSignal(this.runId, chunkELL2RBML_cjs.signalName(signal), payload);
148
+ this.env.deliverSignal(this.runId, chunkZCGKGDCL_cjs.signalName(signal), payload);
120
149
  await this.env.runUntilIdle(false);
121
150
  }
122
151
  /** Request cancellation and run until idle (without skipping time). */
@@ -129,6 +158,22 @@ var TestRunHandle = class {
129
158
  this.env.terminate(this.runId, reason);
130
159
  await this.env.runUntilIdle(false);
131
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
+ }
132
177
  /** Run until this run (or the last run of its continue-as-new chain) ends; its output. */
133
178
  async result() {
134
179
  return this.env.resultOf(this.runId);
@@ -144,7 +189,7 @@ function toDate(value) {
144
189
  return typeof value === "number" ? value : Date.parse(value);
145
190
  }
146
191
  function optionalDuration(value, what) {
147
- return value === void 0 ? void 0 : chunkJ3PYFGKA_cjs.toMs(value, what);
192
+ return value === void 0 ? void 0 : chunkVA4OFR72_cjs.toMs(value, what);
148
193
  }
149
194
  var FAILED_STATUSES = /* @__PURE__ */ new Set([
150
195
  "FAILED",
@@ -152,6 +197,14 @@ var FAILED_STATUSES = /* @__PURE__ */ new Set([
152
197
  "TERMINATED",
153
198
  "TIMED_OUT"
154
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
+ }
155
208
  function toJsonValue(value) {
156
209
  if (value === void 0) return null;
157
210
  const text = JSON.stringify(value);
@@ -161,6 +214,8 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
161
214
  clock;
162
215
  timeSkipping;
163
216
  enabled;
217
+ /** The bundle features the gate's flags enable, sent with every task (`request.features`). */
218
+ codeFeatures;
164
219
  failOnUnfinishedHandlers;
165
220
  historyRelease;
166
221
  dues = [];
@@ -176,19 +231,65 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
176
231
  timers = [];
177
232
  mockedChildren = [];
178
233
  runCounter = 0;
234
+ updateCounter = 0;
179
235
  executor;
180
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();
181
244
  constructor(options) {
182
245
  this.clock = toDate(options.startTime);
183
246
  this.timeSkipping = options.timeSkipping !== false;
184
- this.enabled = options.enabled ?? "parity";
247
+ this.enabled = options.enabled ?? new Set(chunkISOIA7NV_cjs.COMMAND_FEATURES);
248
+ this.codeFeatures = chunkISOIA7NV_cjs.codeFeaturesEnabledBy(this.enabled);
185
249
  this.failOnUnfinishedHandlers = options.failOnUnfinishedHandlers !== false;
186
- this.historyRelease = options.historyRelease ?? chunk3FIDHONL_cjs.RUNTIME_RELEASE;
250
+ this.historyRelease = options.historyRelease ?? chunkTYF56RGB_cjs.RUNTIME_RELEASE;
187
251
  this.workspaceId = options.workspaceId ?? "test-workspace";
188
252
  this.workflows = { ...options.workflows ?? {} };
189
- this.registry = registryOf(this.workflows);
253
+ this.interceptors = options.interceptors;
254
+ this.registry = registryOf(this.workflows, this.interceptors);
190
255
  this.executor = options.taskExecutor;
191
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
+ );
192
293
  }
193
294
  /** Create an environment. */
194
295
  static async create(options = {}) {
@@ -220,6 +321,10 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
220
321
  if (nodeType === void 0) this.held.clear();
221
322
  else this.held.delete(nodeType);
222
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
+ }
223
328
  isHeld(nodeType) {
224
329
  return this.held.has("*") || this.held.has(nodeType);
225
330
  }
@@ -235,11 +340,17 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
235
340
  );
236
341
  const declared = this.workflows[workflowFn]?.options ?? {};
237
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
+ );
238
347
  if (options.workflowId !== void 0) {
239
348
  const existing = this.useExisting(workflowKey, options);
240
349
  if (existing !== void 0) {
241
350
  for (const signal of options.signals ?? [])
242
351
  this.deliverSignal(existing, signal.name, signal.payload);
352
+ if (options.update !== void 0)
353
+ this.addUpdate(this.run(existing), options.update, "PENDING");
243
354
  await this.runUntilIdle(false);
244
355
  return new TestRunHandle(this, existing);
245
356
  }
@@ -260,11 +371,15 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
260
371
  "workflowTaskTimeoutMs"
261
372
  ),
262
373
  ...this.durationConfig(options.startDelay, "startDelayMs"),
263
- ...retry !== void 0 ? { retry: chunkJ3PYFGKA_cjs.runRetryPolicyOf(retry) } : {},
374
+ ...retry !== void 0 ? { retry: chunkVA4OFR72_cjs.runRetryPolicyOf(retry) } : {},
264
375
  ...options.summary !== void 0 ? { summary: options.summary } : {},
265
376
  ...options.details !== void 0 ? { details: options.details } : {},
266
377
  ...options.memo !== void 0 ? { memo: toJsonValue(options.memo) } : {},
267
- ...(options.versioningBehavior ?? declared.versioningBehavior) !== void 0 ? { versioningBehavior: options.versioningBehavior ?? declared.versioningBehavior } : {}
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 } : {}
268
383
  };
269
384
  const runId = this.createRun(
270
385
  workflowFn,
@@ -272,13 +387,245 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
272
387
  { ...options.info, ...options.runId !== void 0 ? { runId: options.runId } : {} },
273
388
  void 0,
274
389
  {},
275
- config
390
+ config,
391
+ options.update !== void 0 ? [this.newUpdate(options.update, "ADMITTED")] : []
276
392
  );
277
393
  for (const signal of options.signals ?? [])
278
394
  this.deliverSignal(runId, signal.name, signal.payload);
279
395
  await this.runUntilIdle(false);
280
396
  return new TestRunHandle(this, runId);
281
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
+ }
282
629
  durationConfig(value, key) {
283
630
  const ms = optionalDuration(value, key);
284
631
  if (ms === void 0) return {};
@@ -314,7 +661,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
314
661
  }
315
662
  /** Advance the clock by `duration`, firing timers and running work as it comes due. */
316
663
  async sleep(duration) {
317
- const until = this.clock + chunkJ3PYFGKA_cjs.toMs(duration, "sleep duration");
664
+ const until = this.clock + chunkVA4OFR72_cjs.toMs(duration, "sleep duration");
318
665
  await this.runUntilIdle(false);
319
666
  for (; ; ) {
320
667
  const next = this.nextDue();
@@ -336,7 +683,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
336
683
  }
337
684
  historyFileOf(runId, extra = {}) {
338
685
  const run = this.run(runId);
339
- return chunkI47EENR4_cjs.createHistoryFile(run.workflowFn, this.historyOf(runId), {
686
+ return chunkHMZUGSMU_cjs.createHistoryFile(run.workflowFn, this.historyOf(runId), {
340
687
  info: { ...run.info },
341
688
  ...extra
342
689
  });
@@ -354,7 +701,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
354
701
  if (value === definition) return name2;
355
702
  const name = Object.hasOwn(this.workflows, definition.name) ? `${definition.name}#${this.runCounter}` : definition.name;
356
703
  this.workflows[name] = definition;
357
- this.registry = registryOf(this.workflows);
704
+ this.registry = registryOf(this.workflows, this.interceptors);
358
705
  return name;
359
706
  }
360
707
  run(runId) {
@@ -362,7 +709,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
362
709
  if (!run) throw new Error(`Unknown run ${runId}`);
363
710
  return run;
364
711
  }
365
- createRun(workflowFn, input, info, parent, extraStarted = {}, config = { workflowKey: workflowFn, runAttempt: 1 }) {
712
+ createRun(workflowFn, input, info, parent, extraStarted = {}, config = { workflowKey: workflowFn, runAttempt: 1 }, admitted = []) {
366
713
  this.runCounter += 1;
367
714
  const runId = info.runId ?? `run-${this.runCounter}`;
368
715
  const snapshot = {
@@ -379,12 +726,14 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
379
726
  runId,
380
727
  workflowFn,
381
728
  history: [],
382
- state: chunkRUQIMTN5_cjs.initialRunState(),
729
+ state: chunkISOIA7NV_cjs.initialRunState(),
383
730
  taskCounter: 0,
384
731
  info: snapshot,
385
732
  children: /* @__PURE__ */ new Map(),
386
733
  config,
387
- ...parent ? { parent } : {}
734
+ ...parent ? { parent } : {},
735
+ updates: /* @__PURE__ */ new Map(),
736
+ sinkCalls: []
388
737
  };
389
738
  const firstTaskDelay = config.startDelayMs ?? config.firstTaskDelayMs;
390
739
  if (firstTaskDelay !== void 0 && firstTaskDelay > 0) {
@@ -397,19 +746,30 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
397
746
  this.dues.push({ runId, kind: "executionTimeout", at: config.executionDeadline });
398
747
  this.runs.set(runId, run);
399
748
  this.runOrder.push(runId);
400
- this.append(run, {
401
- type: "WORKFLOW_STARTED",
402
- // The service writes the seed of ctx.random()/ctx.uuid() into the start
403
- // event so the history replays on its own; it uses the run id.
404
- payload: {
405
- workflowFn,
406
- input,
407
- taskQueue: config.taskQueue ?? "managed",
408
- randomnessSeed: runId,
409
- ...extraStarted,
410
- ...this.startedFields(config)
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);
411
770
  }
412
- });
771
+ this.scheduleTask(run);
772
+ }
413
773
  return runId;
414
774
  }
415
775
  /** The R2 fields of `WORKFLOW_STARTED`, each written only when it is set. */
@@ -437,9 +797,13 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
437
797
  if (config.lastCompletionResult !== void 0 && this.historyRelease >= 2)
438
798
  out["lastCompletionResult"] = config.lastCompletionResult;
439
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;
440
804
  return out;
441
805
  }
442
- append(run, draft) {
806
+ append(run, draft, schedule = true) {
443
807
  const event = {
444
808
  seq: run.history.length + 1,
445
809
  type: draft.type,
@@ -447,10 +811,10 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
447
811
  createdAt: new Date(this.clock).toISOString(),
448
812
  ...draft.taskId !== void 0 ? { taskId: draft.taskId } : {}
449
813
  };
450
- chunkRUQIMTN5_cjs.applyEvent(run.state, event);
814
+ chunkISOIA7NV_cjs.applyEvent(run.state, event);
451
815
  run.history.push(event);
452
816
  if (run.delayedUntil !== void 0 && event.type === "SIGNAL_RECEIVED") this.endDelay(run);
453
- if (run.delayedUntil === void 0 && chunk3FIDHONL_cjs.isInputEvent(event) && run.state.status === "RUNNING" && run.state.task.state === "NONE") {
817
+ if (schedule && run.delayedUntil === void 0 && chunkTYF56RGB_cjs.isInputEvent(event) && run.state.status === "RUNNING" && run.state.task.state === "NONE") {
454
818
  run.taskCounter += 1;
455
819
  const taskId = `${run.runId}-task-${run.taskCounter}`;
456
820
  const scheduled = {
@@ -459,7 +823,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
459
823
  payload: { taskId },
460
824
  createdAt: event.createdAt
461
825
  };
462
- chunkRUQIMTN5_cjs.applyEvent(run.state, scheduled);
826
+ chunkISOIA7NV_cjs.applyEvent(run.state, scheduled);
463
827
  run.history.push(scheduled);
464
828
  }
465
829
  return event;
@@ -468,19 +832,9 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
468
832
  endDelay(run) {
469
833
  run.delayedUntil = void 0;
470
834
  this.dues = this.dues.filter((due) => !(due.runId === run.runId && due.kind === "start"));
471
- if (run.state.status !== "RUNNING" || run.state.task.state !== "NONE") return;
472
- run.taskCounter += 1;
473
- const taskId = `${run.runId}-task-${run.taskCounter}`;
474
- const scheduled = {
475
- seq: run.history.length + 1,
476
- type: "WORKFLOW_TASK_SCHEDULED",
477
- payload: { taskId },
478
- createdAt: new Date(this.clock).toISOString()
479
- };
480
- chunkRUQIMTN5_cjs.applyEvent(run.state, scheduled);
481
- run.history.push(scheduled);
835
+ this.scheduleTask(run);
482
836
  }
483
- deliverSignal(runId, name, payload) {
837
+ deliverSignal(runId, name, payload, headers) {
484
838
  const run = this.runs.get(runId);
485
839
  if (!run || run.state.status !== "RUNNING") return false;
486
840
  this.append(run, {
@@ -488,7 +842,8 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
488
842
  payload: {
489
843
  name,
490
844
  payload: toJsonValue(payload),
491
- receivedAt: new Date(this.clock).toISOString()
845
+ receivedAt: new Date(this.clock).toISOString(),
846
+ ...headers !== void 0 ? { headers: { ...headers } } : {}
492
847
  }
493
848
  });
494
849
  return true;
@@ -526,7 +881,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
526
881
  continue;
527
882
  }
528
883
  const attempt = this.attempts.find(
529
- (entry) => entry.dueAt <= this.clock && !this.isHeld(entry.nodeType)
884
+ (entry) => entry.dueAt <= this.clock && !this.isHeld(this.holdKeyOf(entry))
530
885
  );
531
886
  if (attempt) {
532
887
  this.attempts = this.attempts.filter((entry) => entry !== attempt);
@@ -548,12 +903,12 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
548
903
  }
549
904
  /** When a held attempt's schedule-to-start timeout expires, if it has one. */
550
905
  heldDeadline(entry) {
551
- return this.isHeld(entry.nodeType) && entry.scheduleToStart !== void 0 ? entry.dueAt + entry.scheduleToStart : void 0;
906
+ return this.isHeld(this.holdKeyOf(entry)) && entry.scheduleToStart !== void 0 ? entry.dueAt + entry.scheduleToStart : void 0;
552
907
  }
553
908
  nextDue() {
554
909
  const due = [...this.timers.map((timer) => timer.fireAt)];
555
910
  for (const entry of this.attempts) {
556
- if (!this.isHeld(entry.nodeType)) due.push(entry.dueAt);
911
+ if (!this.isHeld(this.holdKeyOf(entry))) due.push(entry.dueAt);
557
912
  const deadline = this.heldDeadline(entry);
558
913
  if (deadline !== void 0) due.push(deadline);
559
914
  }
@@ -571,7 +926,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
571
926
  for (const entry of expired) {
572
927
  const run = this.runs.get(entry.runId);
573
928
  const activity = run?.state.activities[entry.activityId];
574
- if (!run || run.state.status !== "RUNNING" || !activity || !chunkRUQIMTN5_cjs.isActivityOpen(activity))
929
+ if (!run || run.state.status !== "RUNNING" || !activity || !chunkISOIA7NV_cjs.isActivityOpen(activity))
575
930
  continue;
576
931
  this.append(run, {
577
932
  type: "ACTIVITY_TIMED_OUT",
@@ -630,13 +985,25 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
630
985
  async runTask(run) {
631
986
  const taskId = run.state.task.taskId ?? `${run.runId}-task-${run.taskCounter}`;
632
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
+ }));
633
998
  const request = {
634
- protocol: chunk3FIDHONL_cjs.HISTORY_PROTOCOL,
999
+ protocol: chunkTYF56RGB_cjs.HISTORY_PROTOCOL,
635
1000
  kind: "task",
636
1001
  workflowFn: run.workflowFn,
637
1002
  info: run.info,
638
1003
  history: run.history,
639
- nowMs: this.clock
1004
+ nowMs: this.clock,
1005
+ ...updates.length > 0 ? { updates } : {},
1006
+ ...this.codeFeatures.length > 0 ? { features: [...this.codeFeatures] } : {}
640
1007
  };
641
1008
  const result = await this.executeWithLocalActivities(run, request);
642
1009
  const fail = (cause, message) => {
@@ -651,15 +1018,30 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
651
1018
  run.taskFailure = result;
652
1019
  return;
653
1020
  }
654
- const checked = chunkI47EENR4_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 });
655
1026
  if (!checked.ok) {
656
1027
  fail(checked.cause, checked.issues.map((issue) => issue.message).join("; "));
657
1028
  return;
658
1029
  }
659
- const drafts = chunkRUQIMTN5_cjs.eventsForCommands(run.state, checked.commands, {
1030
+ const drafts = chunkISOIA7NV_cjs.eventsForCommands(run.state, checked.commands, {
660
1031
  taskId,
661
1032
  nowMs: this.clock,
662
- 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
+ )
663
1045
  });
664
1046
  if (!drafts.ok) {
665
1047
  fail(drafts.cause, drafts.issues.map((issue) => issue.message).join("; "));
@@ -667,12 +1049,55 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
667
1049
  }
668
1050
  if (result.unfinishedHandlers !== void 0 && result.unfinishedHandlers.length > 0)
669
1051
  run.unfinishedHandlers = result.unfinishedHandlers;
1052
+ this.recordUpdateReplies(run, checked.commands, delivered);
1053
+ this.runSinks(run, result.sinkCalls ?? []);
670
1054
  this.append(run, { type: "WORKFLOW_TASK_COMPLETED", taskId, payload: { taskId } });
671
1055
  for (const draft of drafts.events) this.append(run, draft);
672
1056
  for (const command of checked.commands)
673
- if (run.state.status === "RUNNING" || chunk3FIDHONL_cjs.TERMINAL_COMMANDS.has(command.type))
1057
+ if (run.state.status === "RUNNING" || chunkTYF56RGB_cjs.TERMINAL_COMMANDS.has(command.type))
674
1058
  this.afterCommand(run, command);
675
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
+ }
676
1101
  execute(request) {
677
1102
  return this.executor ? this.executor(request) : runWorkflowTaskInProcess(this.registry, request);
678
1103
  }
@@ -702,7 +1127,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
702
1127
  const mock = this.mocks.get(`${wanted.nodeType}#${wanted.operation}`) ?? this.mocks.get(wanted.nodeType);
703
1128
  try {
704
1129
  if (!mock)
705
- throw new chunkELL2RBML_cjs.ApplicationError(
1130
+ throw new chunkZCGKGDCL_cjs.ApplicationError(
706
1131
  `No mock for ${wanted.nodeType} ${wanted.operation} (use env.mock)`,
707
1132
  { errorType: "VALIDATION", nonRetryable: true, type: "UnmockedActivity" }
708
1133
  );
@@ -719,7 +1144,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
719
1144
  );
720
1145
  return { localActivityId: wanted.localActivityId, result, attempts: wanted.attempt };
721
1146
  } catch (error) {
722
- const failure = chunkELL2RBML_cjs.errorToFailure(error, `node:${wanted.nodeType}`);
1147
+ const failure = chunkZCGKGDCL_cjs.errorToFailure(error, `node:${wanted.nodeType}`);
723
1148
  delete failure.stackTrace;
724
1149
  return {
725
1150
  localActivityId: wanted.localActivityId,
@@ -731,6 +1156,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
731
1156
  afterCommand(run, command) {
732
1157
  switch (command.type) {
733
1158
  case "SCHEDULE_ACTIVITY": {
1159
+ const user = command.kind === "user";
734
1160
  const attempt = {
735
1161
  runId: run.runId,
736
1162
  activityId: command.activityId,
@@ -738,11 +1164,14 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
738
1164
  dueAt: this.clock,
739
1165
  scheduledAt: this.clock,
740
1166
  args: command.args,
741
- nodeType: command.nodeType,
742
- operation: command.operation,
1167
+ kind: command.kind,
1168
+ nodeType: user ? "" : command.nodeType,
1169
+ operation: user ? command.activityName : command.operation,
743
1170
  retry: command.retry,
744
1171
  cancelRequested: false,
745
- ...command.connection !== void 0 ? { connection: command.connection } : {},
1172
+ ...!user && command.connection !== void 0 ? { connection: command.connection } : {},
1173
+ ...user ? { taskQueue: command.taskQueue } : {},
1174
+ ...command.headers !== void 0 ? { headers: { ...command.headers } } : {},
746
1175
  ...command.scheduleToCloseTimeout !== void 0 ? { scheduleToClose: command.scheduleToCloseTimeout } : {},
747
1176
  ...command.scheduleToStartTimeout !== void 0 ? { scheduleToStart: command.scheduleToStartTimeout } : {}
748
1177
  };
@@ -835,7 +1264,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
835
1264
  if (typeof memo === "object" && memo !== null && !Array.isArray(memo)) config.memo = memo;
836
1265
  else if (Object.keys(run.state.context).length > 0) config.memo = { ...run.state.context };
837
1266
  const retry = options["retry"];
838
- if (chunkRUQIMTN5_cjs.continueAsNewRetryShape(options) === "run" && typeof retry === "object" && retry !== null && !Array.isArray(retry))
1267
+ if (chunkISOIA7NV_cjs.continueAsNewRetryShape(options) === "run" && typeof retry === "object" && retry !== null && !Array.isArray(retry))
839
1268
  config.retry = retry;
840
1269
  this.startSuccessor(run, command.input, config);
841
1270
  this.onClosed(run);
@@ -1002,7 +1431,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
1002
1431
  payload: {
1003
1432
  childId: entry.childId,
1004
1433
  childRunId,
1005
- failure: toJsonValue(chunkELL2RBML_cjs.errorToFailure(error, "engine"))
1434
+ failure: toJsonValue(chunkZCGKGDCL_cjs.errorToFailure(error, "engine"))
1006
1435
  }
1007
1436
  });
1008
1437
  }
@@ -1011,7 +1440,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
1011
1440
  const run = this.runs.get(attempt.runId);
1012
1441
  if (!run || run.state.status !== "RUNNING") return;
1013
1442
  const activity = run.state.activities[attempt.activityId];
1014
- if (!activity || !chunkRUQIMTN5_cjs.isActivityOpen(activity)) return;
1443
+ if (!activity || !chunkISOIA7NV_cjs.isActivityOpen(activity)) return;
1015
1444
  if (attempt.scheduleToClose !== void 0 && this.clock - attempt.scheduledAt > attempt.scheduleToClose) {
1016
1445
  this.append(run, {
1017
1446
  type: "ACTIVITY_TIMED_OUT",
@@ -1023,40 +1452,151 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
1023
1452
  });
1024
1453
  return;
1025
1454
  }
1026
- const mock = this.mocks.get(`${attempt.nodeType}#${attempt.operation}`) ?? this.mocks.get(attempt.nodeType);
1027
1455
  let failure;
1028
1456
  let result = null;
1029
1457
  let heartbeatDetails = attempt.heartbeatDetails;
1458
+ let asyncToken;
1030
1459
  try {
1031
- if (!mock)
1032
- throw new chunkELL2RBML_cjs.ApplicationError(
1033
- `No mock for ${attempt.nodeType} ${attempt.operation} (use env.mock)`,
1034
- {
1035
- errorType: "VALIDATION",
1036
- nonRetryable: true,
1037
- 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;
1038
1474
  }
1039
1475
  );
1040
- result = toJsonValue(
1041
- await mock(attempt.args, {
1042
- runId: attempt.runId,
1043
- activityId: attempt.activityId,
1044
- attempt: attempt.attempt,
1045
- nodeType: attempt.nodeType,
1046
- operation: attempt.operation,
1047
- ...attempt.connection !== void 0 ? { connection: attempt.connection } : {},
1048
- ...attempt.heartbeatDetails !== void 0 ? { heartbeatDetails: attempt.heartbeatDetails } : {},
1049
- heartbeat: (details) => {
1050
- heartbeatDetails = toJsonValue(details);
1051
- }
1052
- })
1053
- );
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
+ }
1054
1505
  } catch (error) {
1055
- failure = chunkELL2RBML_cjs.errorToFailure(error, `node:${attempt.nodeType}`);
1506
+ failure = chunkZCGKGDCL_cjs.errorToFailure(
1507
+ error,
1508
+ attempt.kind === "user" ? "sdk-ts" : `node:${attempt.nodeType}`
1509
+ );
1056
1510
  delete failure.stackTrace;
1057
1511
  }
1058
- if (run.state.status !== "RUNNING" || !chunkRUQIMTN5_cjs.isActivityOpen(run.state.activities[attempt.activityId] ?? activity))
1512
+ if (run.state.status !== "RUNNING" || !chunkISOIA7NV_cjs.isActivityOpen(run.state.activities[attempt.activityId] ?? activity))
1059
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;
1060
1600
  const started = () => {
1061
1601
  this.append(run, {
1062
1602
  type: "ACTIVITY_STARTED",
@@ -1072,7 +1612,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
1072
1612
  return;
1073
1613
  }
1074
1614
  if (failure.timeoutType !== void 0 || failure.type === "TimeoutFailure") {
1075
- const decision2 = chunkYHBVMOMK_cjs.computeRetryDelay(attempt.retry, attempt.attempt, failure);
1615
+ const decision2 = chunkTYF56RGB_cjs.computeRetryDelay(attempt.retry, attempt.attempt, failure);
1076
1616
  if (!decision2.retry) {
1077
1617
  started();
1078
1618
  this.append(run, {
@@ -1094,7 +1634,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
1094
1634
  });
1095
1635
  return;
1096
1636
  }
1097
- const decision = chunkYHBVMOMK_cjs.computeRetryDelay(attempt.retry, attempt.attempt, failure);
1637
+ const decision = chunkTYF56RGB_cjs.computeRetryDelay(attempt.retry, attempt.attempt, failure);
1098
1638
  if (decision.retry) {
1099
1639
  this.attempts.push({
1100
1640
  ...attempt,
@@ -1124,7 +1664,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
1124
1664
  const last = run.history[run.history.length - 1];
1125
1665
  if (!last || last.type !== "WORKFLOW_FAILED" && last.type !== "WORKFLOW_TIMED_OUT") return;
1126
1666
  const failure = last.payload["failure"] ?? { errorType: "TIMEOUT", message: "timed out", timeoutType: "WORKFLOW_RUN" };
1127
- const decision = chunkYHBVMOMK_cjs.computeRunRetryDelay(run.config.retry, run.config.runAttempt, failure);
1667
+ const decision = chunkTYF56RGB_cjs.computeRunRetryDelay(run.config.retry, run.config.runAttempt, failure);
1128
1668
  if (!decision.retry) return;
1129
1669
  const config = {
1130
1670
  ...this.chainConfig(run.config),
@@ -1134,25 +1674,48 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
1134
1674
  if (decision.delayMs > 0) config.firstTaskDelayMs = decision.delayMs;
1135
1675
  this.startSuccessor(run, run.state.input ?? null, config);
1136
1676
  }
1137
- onClosed(run) {
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()) {
1138
1683
  this.timers = this.timers.filter((timer) => timer.runId !== run.runId);
1139
1684
  this.attempts = this.attempts.filter((entry) => entry.runId !== run.runId);
1140
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);
1141
1688
  this.retryRun(run);
1142
1689
  for (const [childId2, childRunId] of run.children) {
1690
+ if (keptChildren.has(childId2)) continue;
1143
1691
  const child = run.state.children[childId2];
1144
- if (!child || !chunkRUQIMTN5_cjs.isChildOpen(child) || childRunId === void 0) continue;
1692
+ if (!child || !chunkISOIA7NV_cjs.isChildOpen(child) || childRunId === void 0) continue;
1145
1693
  if (child.parentClosePolicy === "TERMINATE") this.terminate(childRunId, "parent closed");
1146
1694
  else if (child.parentClosePolicy === "REQUEST_CANCEL")
1147
1695
  this.requestCancel(childRunId, "parent closed");
1148
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
+ }
1149
1708
  if (!run.parent) return;
1150
1709
  const parent = this.runs.get(run.parent.runId);
1151
1710
  if (!parent || parent.state.status !== "RUNNING") return;
1152
1711
  const childId = run.parent.childId;
1153
- if (!parent.state.children[childId] || !chunkRUQIMTN5_cjs.isChildOpen(parent.state.children[childId])) return;
1712
+ if (!parent.state.children[childId] || !chunkISOIA7NV_cjs.isChildOpen(parent.state.children[childId])) return;
1154
1713
  const last = run.history[run.history.length - 1];
1155
1714
  if (!last) return;
1715
+ if (run.resetTo !== void 0) {
1716
+ parent.children.set(childId, run.resetTo);
1717
+ return;
1718
+ }
1156
1719
  if (run.continuedTo !== void 0) {
1157
1720
  const next = this.runs.get(run.continuedTo);
1158
1721
  if (next) {
@@ -1203,7 +1766,8 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
1203
1766
  async resultOf(runId) {
1204
1767
  await this.runUntilIdle(this.timeSkipping);
1205
1768
  let run = this.run(runId);
1206
- 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);
1207
1771
  if (run.taskFailure) throw new WorkflowTaskFailedError(run.runId, run.taskFailure);
1208
1772
  if (this.failOnUnfinishedHandlers && run.unfinishedHandlers !== void 0)
1209
1773
  throw new UnfinishedHandlersError(run.runId, run.unfinishedHandlers);
@@ -1226,7 +1790,7 @@ var TestWorkflowEnvironment = class _TestWorkflowEnvironment {
1226
1790
  run.state.failure ?? { errorType: "UNKNOWN", message: "failed" }
1227
1791
  );
1228
1792
  case "CANCELLED":
1229
- throw new chunkELL2RBML_cjs.CancelledFailure(`Run ${run.runId} was cancelled`);
1793
+ throw new chunkZCGKGDCL_cjs.CancelledFailure(`Run ${run.runId} was cancelled`);
1230
1794
  case "TERMINATED":
1231
1795
  throw new WorkflowFailedError(run.runId, {
1232
1796
  errorType: "PERMANENT",
@@ -1257,7 +1821,7 @@ var ReplayError = class extends Error {
1257
1821
  function replayRequest(workflowFn, history, info = {}, nowMs) {
1258
1822
  const last = history[history.length - 1];
1259
1823
  return {
1260
- protocol: chunk3FIDHONL_cjs.HISTORY_PROTOCOL,
1824
+ protocol: chunkTYF56RGB_cjs.HISTORY_PROTOCOL,
1261
1825
  kind: "verify",
1262
1826
  workflowFn,
1263
1827
  info: { runId: "replay", workspaceId: "replay", ...info },
@@ -1267,14 +1831,14 @@ function replayRequest(workflowFn, history, info = {}, nowMs) {
1267
1831
  }
1268
1832
  function eventsOf(input) {
1269
1833
  if (Array.isArray(input)) return { events: input };
1270
- const file = typeof input === "string" ? chunkI47EENR4_cjs.parseHistoryFile(input) : input;
1834
+ const file = typeof input === "string" ? chunkHMZUGSMU_cjs.parseHistoryFile(input) : input;
1271
1835
  return { events: file.events, file };
1272
1836
  }
1273
1837
  async function replay(workflows, input, options = {}) {
1274
1838
  const { events, file } = eventsOf(input);
1275
1839
  const started = events[0]?.type === "WORKFLOW_STARTED" ? events[0].payload["workflowFn"] : void 0;
1276
1840
  const recordedFn = options.workflowFn ?? file?.workflowFn ?? (typeof started === "string" ? started : void 0);
1277
- const map = chunkJ3PYFGKA_cjs.isDurableWorkflow(workflows) ? { [recordedFn ?? workflows.name]: workflows } : { ...workflows };
1841
+ const map = chunkVA4OFR72_cjs.isDurableWorkflow(workflows) ? { [recordedFn ?? workflows.name]: workflows } : { ...workflows };
1278
1842
  const workflowFn = recordedFn ?? Object.keys(map)[0] ?? "";
1279
1843
  const result = await runWorkflowTaskInProcess(
1280
1844
  registryOf(map),
@@ -1287,7 +1851,7 @@ async function replay(workflows, input, options = {}) {
1287
1851
  );
1288
1852
  if (result.outcome === "failed") {
1289
1853
  if (result.failure?.cause === "NON_DETERMINISM")
1290
- throw new chunkELL2RBML_cjs.DeterminismViolation(result.failure.message);
1854
+ throw new chunkZCGKGDCL_cjs.DeterminismViolation(result.failure.message);
1291
1855
  throw new ReplayError(result);
1292
1856
  }
1293
1857
  return result;
@@ -1336,16 +1900,16 @@ function assertHistory(history, expected, options = {}) {
1336
1900
  );
1337
1901
  }
1338
1902
  function definitionOf(value) {
1339
- return chunkGBQ33SIZ_cjs.normalizeDefinition(chunkNXFBVDOI_cjs.isTier1Workflow(value) ? chunkNXFBVDOI_cjs.toIR(value) : value);
1903
+ return chunk54FLQNUM_cjs.normalizeDefinition(chunkIQPXHQQQ_cjs.isTier1Workflow(value) ? chunkIQPXHQQQ_cjs.toIR(value) : value);
1340
1904
  }
1341
1905
  function expectIR(value) {
1342
1906
  const definition = definitionOf(value);
1343
- const hash = chunkGBQ33SIZ_cjs.irHash(definition);
1907
+ const hash = chunk54FLQNUM_cjs.irHash(definition);
1344
1908
  return {
1345
1909
  definition,
1346
1910
  irHash: hash,
1347
1911
  toEqualIR(other) {
1348
- const otherHash = chunkGBQ33SIZ_cjs.irHash(definitionOf(other));
1912
+ const otherHash = chunk54FLQNUM_cjs.irHash(definitionOf(other));
1349
1913
  if (otherHash !== hash)
1350
1914
  throw new HistoryAssertionError(`The IR differs: ${hash} versus ${otherHash}`);
1351
1915
  }
@@ -1388,7 +1952,7 @@ async function simulate(definition, options = {}) {
1388
1952
  output = produced.output;
1389
1953
  handle = produced.handle;
1390
1954
  } else output = produced;
1391
- } else if (node.type === chunkGBQ33SIZ_cjs.CODE_WORKFLOW_NODE_TYPE) {
1955
+ } else if (node.type === chunk54FLQNUM_cjs.CODE_WORKFLOW_NODE_TYPE) {
1392
1956
  const state = node.args?.state;
1393
1957
  const workflowFn = chunkSAENRNBJ_cjs.isRecord(state) && typeof state["workflowFn"] === "string" ? state["workflowFn"] : "";
1394
1958
  const fn = options.workflows?.[workflowFn];
@@ -1456,31 +2020,34 @@ async function runWorkflowTaskInVm(script, request, options = {}) {
1456
2020
  await settle();
1457
2021
  if (step !== "more") break;
1458
2022
  if (Date.now() > deadline)
1459
- return chunkEWYADREB_cjs.failedTaskResult(
2023
+ return chunk672KMMBK_cjs.failedTaskResult(
1460
2024
  "TASK_TIMEOUT",
1461
2025
  `The workflow task ran past its ${timeout} ms budget`
1462
2026
  );
1463
2027
  }
1464
2028
  const json = run("globalThis.__fluidgridsRuntime.complete()", "complete.js");
1465
2029
  if (typeof json !== "string")
1466
- return chunkEWYADREB_cjs.failedTaskResult("INTERNAL", "The runtime returned no result");
2030
+ return chunk672KMMBK_cjs.failedTaskResult("INTERNAL", "The runtime returned no result");
1467
2031
  return JSON.parse(json);
1468
2032
  } catch (error) {
1469
2033
  const fields = typeof error === "object" && error !== null ? error : {};
1470
2034
  const message = typeof fields.message === "string" ? fields.message : String(error);
1471
2035
  const name = typeof fields.name === "string" ? fields.name : "";
1472
- if (/timed out/i.test(message)) return chunkEWYADREB_cjs.failedTaskResult("TASK_TIMEOUT", message);
1473
- if (name === "DeterminismViolation") return chunkEWYADREB_cjs.failedTaskResult("NON_DETERMINISM", message);
1474
- return chunkEWYADREB_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}`);
1475
2039
  }
1476
2040
  }
1477
2041
 
1478
2042
  exports.HistoryAssertionError = HistoryAssertionError;
2043
+ exports.QueryFailedError = QueryFailedError;
2044
+ exports.QueryRejectedError = QueryRejectedError;
1479
2045
  exports.ReplayError = ReplayError;
1480
2046
  exports.RunBlockedError = RunBlockedError;
1481
2047
  exports.TestRunHandle = TestRunHandle;
1482
2048
  exports.TestWorkflowEnvironment = TestWorkflowEnvironment;
1483
2049
  exports.UnfinishedHandlersError = UnfinishedHandlersError;
2050
+ exports.UpdateRefusedError = UpdateRefusedError;
1484
2051
  exports.WorkflowAlreadyStartedError = WorkflowAlreadyStartedError;
1485
2052
  exports.WorkflowFailedError = WorkflowFailedError;
1486
2053
  exports.WorkflowTaskFailedError = WorkflowTaskFailedError;