@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.
- package/README.md +112 -4
- package/dist/{activation-CESehfYi.d.cts → activation-DqUfpHzk.d.cts} +1 -1
- package/dist/{activation-BnVQMv9y.d.ts → activation-xpx1oWuo.d.ts} +1 -1
- package/dist/{chunk-MJ5TGYVG.js → chunk-2D3MYIIF.js} +969 -153
- package/dist/{chunk-2B37XAFQ.cjs → chunk-3U2NU7YC.cjs} +24 -11
- package/dist/{chunk-NEIUQASE.cjs → chunk-4QKB4ARC.cjs} +3 -3
- package/dist/{chunk-GBQ33SIZ.cjs → chunk-54FLQNUM.cjs} +12 -1
- package/dist/{chunk-2DDULZFM.js → chunk-5HIVIV53.js} +86 -75
- package/dist/chunk-5MFVJM76.js +1222 -0
- package/dist/{chunk-EWYADREB.cjs → chunk-672KMMBK.cjs} +2 -2
- package/dist/{chunk-KXJDRQ6G.js → chunk-6A2FGSUS.js} +22 -2
- package/dist/{chunk-OIX4O6UR.js → chunk-6OLN6BMB.js} +16 -3
- package/dist/{chunk-6FSHT5IL.js → chunk-7EZIANC7.js} +1 -1
- package/dist/chunk-A5SXCA62.cjs +93 -0
- package/dist/chunk-AC6ZEXVR.js +85 -0
- package/dist/{chunk-FWBRQWRX.js → chunk-AE5Q6ZAJ.js} +167 -10
- package/dist/{chunk-7ILGCUI6.js → chunk-C4F5KJTI.js} +142 -3
- package/dist/{chunk-WXXNCHUY.js → chunk-G5H32GIG.js} +1 -1
- package/dist/{chunk-OMY3CKUZ.cjs → chunk-GEQDGUGB.cjs} +1042 -226
- package/dist/{chunk-25BKWR2O.js → chunk-HCM7ZC7Q.js} +1 -1
- package/dist/{chunk-I47EENR4.cjs → chunk-HMZUGSMU.cjs} +673 -156
- package/dist/{chunk-NXFBVDOI.cjs → chunk-IQPXHQQQ.cjs} +8 -4
- package/dist/{chunk-RUQIMTN5.cjs → chunk-ISOIA7NV.cjs} +178 -15
- package/dist/chunk-JSC75O5C.cjs +167 -0
- package/dist/{chunk-BD7ZPG53.js → chunk-NWQ5WRLE.js} +10 -2
- package/dist/chunk-ODZ2IAR2.cjs +1247 -0
- package/dist/{chunk-FQSJI5NV.js → chunk-SR7TR5KX.js} +6 -2
- package/dist/{chunk-OKX3FYIM.cjs → chunk-TCTE7DX5.cjs} +3 -3
- package/dist/{chunk-3FIDHONL.cjs → chunk-TYF56RGB.cjs} +99 -80
- package/dist/{chunk-J3PYFGKA.cjs → chunk-VA4OFR72.cjs} +162 -4
- package/dist/chunk-VU5S5A7V.js +150 -0
- package/dist/{chunk-A36CCOWS.js → chunk-YEHR4NNE.js} +633 -128
- package/dist/{chunk-ELL2RBML.cjs → chunk-ZCGKGDCL.cjs} +23 -1
- package/dist/codegen/index.d.cts +2 -2
- package/dist/codegen/index.d.ts +2 -2
- package/dist/{collect-BTHjQaSp.d.ts → collect-6NIEufHd.d.ts} +20 -3
- package/dist/{collect-CSyOg5XC.d.cts → collect-CcTCKqx6.d.cts} +20 -3
- package/dist/{file-cgL9l9l8.d.cts → file-BxYpwjRQ.d.cts} +250 -15
- package/dist/{file-olQudcx5.d.ts → file-CFdPQJI9.d.ts} +250 -15
- package/dist/history/index.cjs +283 -106
- package/dist/history/index.d.cts +549 -10
- package/dist/history/index.d.ts +549 -10
- package/dist/history/index.js +5 -4
- package/dist/index.cjs +146 -53
- package/dist/index.d.cts +38 -14
- package/dist/index.d.ts +38 -14
- package/dist/index.js +6 -5
- package/dist/interceptors-CNcr2dlk.d.ts +159 -0
- package/dist/interceptors-CqkNZVfI.d.cts +159 -0
- package/dist/ir/index.cjs +339 -36
- package/dist/ir/index.d.cts +244 -8
- package/dist/ir/index.d.ts +244 -8
- package/dist/ir/index.js +306 -21
- package/dist/{lower-3S6PsqjJ.d.cts → lower-BtRfIW2A.d.cts} +23 -9
- package/dist/{lower-DmZpQ8hJ.d.ts → lower-CpsMFOFX.d.ts} +23 -9
- package/dist/{manifest-BJjrQt77.d.ts → manifest-D-I_twys.d.ts} +1 -1
- package/dist/{manifest-gRI2Q5Fj.d.cts → manifest-DahBQVM8.d.cts} +1 -1
- package/dist/node-evaluator-DGQDPSPI.cjs +24 -0
- package/dist/node-evaluator-LEEVD7H7.js +14 -0
- package/dist/payload-fields-BVRQn2yH.d.cts +122 -0
- package/dist/payload-fields-oOBWxDiG.d.ts +122 -0
- package/dist/quickjs/index.cjs +27 -27
- package/dist/quickjs/index.d.cts +6 -6
- package/dist/quickjs/index.d.ts +6 -6
- package/dist/quickjs/index.js +9 -9
- package/dist/roundtrip/index.cjs +72 -66
- package/dist/roundtrip/index.d.cts +25 -11
- package/dist/roundtrip/index.d.ts +25 -11
- package/dist/roundtrip/index.js +13 -11
- package/dist/runtime/index.cjs +19 -19
- package/dist/runtime/index.d.cts +139 -12
- package/dist/runtime/index.d.ts +139 -12
- package/dist/runtime/index.js +6 -6
- package/dist/testing/index.cjs +688 -121
- package/dist/testing/index.d.cts +174 -10
- package/dist/testing/index.d.ts +174 -10
- package/dist/testing/index.js +646 -82
- package/dist/{types-CnIOinoz.d.ts → types-Bv2i4cBX.d.cts} +126 -23
- package/dist/{types-CQKOhPTa.d.cts → types-DGx-b9eq.d.ts} +126 -23
- package/dist/{types-Bb2wRnJ5.d.cts → types-V7jEEUaL.d.cts} +1 -1
- package/dist/{types-Bb2wRnJ5.d.ts → types-V7jEEUaL.d.ts} +1 -1
- package/dist/{workflow-8uRU9rhL.d.ts → workflow-B18OeF7g.d.ts} +2 -2
- package/dist/{workflow-DWTPHFbt.d.ts → workflow-BGnv8SS6.d.ts} +261 -14
- package/dist/{workflow-CZOXUlQ5.d.cts → workflow-BJPFv3cp.d.cts} +2 -2
- package/dist/{workflow-O6e64ZcG.d.cts → workflow-DS32Gtws.d.cts} +261 -14
- package/fixtures/histories/activity-options-updated.history.json +159 -0
- package/fixtures/histories/activity-paused-unpaused.history.json +160 -0
- package/fixtures/histories/codec-opaque.history.json +229 -0
- package/fixtures/histories/dynamic-workflow.history.json +150 -0
- package/fixtures/histories/interceptor-headers.history.json +339 -0
- package/fixtures/histories/query-custom.history.json +213 -0
- package/fixtures/histories/query-default-handler.history.json +120 -0
- package/fixtures/histories/reset-forked-reapplied-signals.history.json +239 -0
- package/fixtures/histories/reset-reapplied-update-admitted.history.json +228 -0
- package/fixtures/histories/search-attributes-upserted.history.json +177 -0
- package/fixtures/histories/update-accepted-completed.history.json +45 -30
- package/fixtures/histories/update-default-handler.history.json +246 -0
- package/fixtures/histories/update-handler-awaits-activity.history.json +196 -0
- package/fixtures/histories/update-not-handled.history.json +138 -0
- package/fixtures/histories/update-rejected-no-event.history.json +190 -0
- package/fixtures/histories/update-with-start-admitted.history.json +150 -0
- package/fixtures/histories/user-activity-cancel.history.json +149 -0
- package/fixtures/histories/user-activity-retry.history.json +143 -0
- package/fixtures/histories/user-activity.history.json +149 -0
- package/package.json +1 -1
- package/schema/bridge-v2.schema.json +1062 -0
- package/schema/history-file.schema.json +255 -81
- package/schema/ir-v2.schema.json +246 -1
- package/schema/payload-fields.json +162 -0
- package/schema/run-event.schema.json +239 -80
- package/schema/workflow-command.schema.json +210 -84
- package/schema/workflow-task.schema.json +532 -167
- package/dist/chunk-6QPOJZT6.cjs +0 -1180
- package/dist/chunk-A2OHX3UQ.js +0 -1156
- package/dist/chunk-PWIUEWC3.js +0 -81
- package/dist/chunk-YHBVMOMK.cjs +0 -87
- package/dist/node-evaluator-SOADN23V.js +0 -14
- package/dist/node-evaluator-YGDEXK4U.cjs +0 -24
package/dist/testing/index.cjs
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
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
|
|
10
|
+
var chunkHMZUGSMU_cjs = require('../chunk-HMZUGSMU.cjs');
|
|
11
|
+
require('../chunk-JSC75O5C.cjs');
|
|
11
12
|
var chunkSAENRNBJ_cjs = require('../chunk-SAENRNBJ.cjs');
|
|
12
|
-
var
|
|
13
|
-
var
|
|
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
|
|
17
|
+
var chunkVA4OFR72_cjs = require('../chunk-VA4OFR72.cjs');
|
|
17
18
|
require('../chunk-FR7KYWRO.cjs');
|
|
18
|
-
var
|
|
19
|
-
|
|
20
|
-
var
|
|
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
|
|
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 =
|
|
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:
|
|
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,
|
|
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 :
|
|
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 ??
|
|
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 ??
|
|
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.
|
|
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:
|
|
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 +
|
|
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
|
|
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:
|
|
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(
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
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
|
-
|
|
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 &&
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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 || !
|
|
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:
|
|
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
|
|
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 =
|
|
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" ||
|
|
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
|
|
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 =
|
|
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
|
-
|
|
742
|
-
|
|
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
|
-
|
|
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 (
|
|
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(
|
|
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 || !
|
|
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 (
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
nonRetryable: true,
|
|
1037
|
-
|
|
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
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
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 =
|
|
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" || !
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 || !
|
|
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] || !
|
|
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
|
|
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
|
|
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:
|
|
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" ?
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
1907
|
+
const hash = chunk54FLQNUM_cjs.irHash(definition);
|
|
1344
1908
|
return {
|
|
1345
1909
|
definition,
|
|
1346
1910
|
irHash: hash,
|
|
1347
1911
|
toEqualIR(other) {
|
|
1348
|
-
const otherHash =
|
|
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 ===
|
|
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
|
|
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
|
|
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
|
|
1473
|
-
if (name === "DeterminismViolation") return
|
|
1474
|
-
return
|
|
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;
|