pg-workflows 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.entry.cjs +49 -21
- package/dist/client.entry.d.cts +48 -11
- package/dist/client.entry.d.ts +48 -11
- package/dist/client.entry.js +6 -2
- package/dist/client.entry.js.map +8 -8
- package/dist/index.cjs +401 -125
- package/dist/index.d.cts +68 -35
- package/dist/index.d.ts +68 -35
- package/dist/index.js +359 -107
- package/dist/index.js.map +12 -12
- package/dist/shared/{chunk-fr76gdwj.js → chunk-ahxqsytt.js} +49 -23
- package/dist/shared/chunk-ahxqsytt.js.map +16 -0
- package/package.json +1 -1
- package/dist/shared/chunk-fr76gdwj.js.map +0 -16
package/dist/index.cjs
CHANGED
|
@@ -65,16 +65,12 @@ var __export = (target, all) => {
|
|
|
65
65
|
var exports_src = {};
|
|
66
66
|
__export(exports_src, {
|
|
67
67
|
workflow: () => workflow,
|
|
68
|
-
validateWorkflowId: () => validateWorkflowId,
|
|
69
|
-
validateResourceId: () => validateResourceId,
|
|
70
|
-
parseDuration: () => parseDuration,
|
|
71
68
|
createWorkflowRef: () => createWorkflowRef,
|
|
72
69
|
WorkflowStatus: () => WorkflowStatus,
|
|
73
70
|
WorkflowRunNotFoundError: () => WorkflowRunNotFoundError,
|
|
74
71
|
WorkflowEngineError: () => WorkflowEngineError,
|
|
75
72
|
WorkflowEngine: () => WorkflowEngine,
|
|
76
|
-
WorkflowClient: () => WorkflowClient
|
|
77
|
-
StepType: () => StepType
|
|
73
|
+
WorkflowClient: () => WorkflowClient
|
|
78
74
|
});
|
|
79
75
|
module.exports = __toCommonJS(exports_src);
|
|
80
76
|
|
|
@@ -90,10 +86,15 @@ var WORKFLOW_RUN_DLQ_QUEUE_NAME = "workflow_run_dlq";
|
|
|
90
86
|
var DEFAULT_PGBOSS_SCHEMA = "pgboss_v12_pgworkflow";
|
|
91
87
|
var MAX_WORKFLOW_ID_LENGTH = 256;
|
|
92
88
|
var MAX_RESOURCE_ID_LENGTH = 256;
|
|
89
|
+
var INVOKE_CHILD_WORKFLOW_TIMELINE_SUFFIX = "invoke-child-workflow";
|
|
90
|
+
var WAIT_FOR_TIMELINE_SUFFIX = "wait-for";
|
|
91
|
+
var invokeChildWorkflowTimelineKey = (stepId) => `${stepId}-${INVOKE_CHILD_WORKFLOW_TIMELINE_SUFFIX}`;
|
|
92
|
+
var waitForTimelineKey = (stepId) => `${stepId}-${WAIT_FOR_TIMELINE_SUFFIX}`;
|
|
93
|
+
var isInvokeChildWorkflowTimelineEntry = (entry) => !!entry && typeof entry === "object" && ("invokeChildWorkflow" in entry);
|
|
93
94
|
|
|
94
95
|
// src/db/migration.ts
|
|
95
96
|
var MIGRATION_LOCK_ID = 738291645;
|
|
96
|
-
var CURRENT_SCHEMA_VERSION =
|
|
97
|
+
var CURRENT_SCHEMA_VERSION = 4;
|
|
97
98
|
async function runMigrations(db) {
|
|
98
99
|
if (await isSchemaUpToDate(db)) {
|
|
99
100
|
return;
|
|
@@ -151,6 +152,11 @@ async function runMigrations(db) {
|
|
|
151
152
|
commands.push("ALTER TABLE workflow_runs ALTER COLUMN resource_id TYPE varchar(256)");
|
|
152
153
|
commands.push("ALTER TABLE workflow_runs ALTER COLUMN workflow_id TYPE varchar(256)");
|
|
153
154
|
}
|
|
155
|
+
if (currentVersion < 4) {
|
|
156
|
+
commands.push("ALTER TABLE workflow_runs ADD COLUMN IF NOT EXISTS parent_run_id varchar(32)");
|
|
157
|
+
commands.push("ALTER TABLE workflow_runs ADD COLUMN IF NOT EXISTS parent_step_id varchar(256)");
|
|
158
|
+
commands.push("ALTER TABLE workflow_runs ADD COLUMN IF NOT EXISTS parent_resource_id varchar(256)");
|
|
159
|
+
}
|
|
154
160
|
if (currentVersion === 0) {
|
|
155
161
|
commands.push(`INSERT INTO workflow_schema_version (version) VALUES (${CURRENT_SCHEMA_VERSION})`);
|
|
156
162
|
} else {
|
|
@@ -213,7 +219,10 @@ function mapRowToWorkflowRun(row) {
|
|
|
213
219
|
retryCount: row.retry_count,
|
|
214
220
|
maxRetries: row.max_retries,
|
|
215
221
|
jobId: row.job_id,
|
|
216
|
-
idempotencyKey: row.idempotency_key
|
|
222
|
+
idempotencyKey: row.idempotency_key,
|
|
223
|
+
parentRunId: row.parent_run_id,
|
|
224
|
+
parentStepId: row.parent_step_id,
|
|
225
|
+
parentResourceId: row.parent_resource_id
|
|
217
226
|
};
|
|
218
227
|
}
|
|
219
228
|
async function insertWorkflowRun({
|
|
@@ -224,7 +233,10 @@ async function insertWorkflowRun({
|
|
|
224
233
|
input,
|
|
225
234
|
maxRetries,
|
|
226
235
|
timeoutAt,
|
|
227
|
-
idempotencyKey
|
|
236
|
+
idempotencyKey,
|
|
237
|
+
parentRunId,
|
|
238
|
+
parentStepId,
|
|
239
|
+
parentResourceId
|
|
228
240
|
}, db) {
|
|
229
241
|
const runId = generateKSUID("run");
|
|
230
242
|
const now = new Date;
|
|
@@ -241,9 +253,12 @@ async function insertWorkflowRun({
|
|
|
241
253
|
updated_at,
|
|
242
254
|
timeline,
|
|
243
255
|
retry_count,
|
|
244
|
-
idempotency_key
|
|
256
|
+
idempotency_key,
|
|
257
|
+
parent_run_id,
|
|
258
|
+
parent_step_id,
|
|
259
|
+
parent_resource_id
|
|
245
260
|
)
|
|
246
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
|
|
261
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
|
|
247
262
|
ON CONFLICT (idempotency_key) WHERE idempotency_key IS NOT NULL DO NOTHING
|
|
248
263
|
RETURNING *`, [
|
|
249
264
|
runId,
|
|
@@ -258,7 +273,10 @@ async function insertWorkflowRun({
|
|
|
258
273
|
now,
|
|
259
274
|
"{}",
|
|
260
275
|
0,
|
|
261
|
-
idempotencyKey ?? null
|
|
276
|
+
idempotencyKey ?? null,
|
|
277
|
+
parentRunId ?? null,
|
|
278
|
+
parentStepId ?? null,
|
|
279
|
+
parentResourceId ?? null
|
|
262
280
|
]);
|
|
263
281
|
if (result.rows[0]) {
|
|
264
282
|
return { run: mapRowToWorkflowRun(result.rows[0]), created: true };
|
|
@@ -521,15 +539,6 @@ var WorkflowStatus;
|
|
|
521
539
|
WorkflowStatus2["FAILED"] = "failed";
|
|
522
540
|
WorkflowStatus2["CANCELLED"] = "cancelled";
|
|
523
541
|
})(WorkflowStatus ||= {});
|
|
524
|
-
var StepType;
|
|
525
|
-
((StepType2) => {
|
|
526
|
-
StepType2["PAUSE"] = "pause";
|
|
527
|
-
StepType2["RUN"] = "run";
|
|
528
|
-
StepType2["WAIT_FOR"] = "waitFor";
|
|
529
|
-
StepType2["WAIT_UNTIL"] = "waitUntil";
|
|
530
|
-
StepType2["DELAY"] = "delay";
|
|
531
|
-
StepType2["POLL"] = "poll";
|
|
532
|
-
})(StepType ||= {});
|
|
533
542
|
|
|
534
543
|
// src/client.ts
|
|
535
544
|
var LOG_PREFIX = "[WorkflowClient]";
|
|
@@ -636,7 +645,8 @@ class WorkflowClient {
|
|
|
636
645
|
};
|
|
637
646
|
await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {
|
|
638
647
|
startAfter: new Date,
|
|
639
|
-
expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds
|
|
648
|
+
expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds,
|
|
649
|
+
db: _db
|
|
640
650
|
});
|
|
641
651
|
}
|
|
642
652
|
return insertedRun;
|
|
@@ -699,6 +709,11 @@ class WorkflowClient {
|
|
|
699
709
|
if (current.status !== "paused" /* PAUSED */) {
|
|
700
710
|
throw new WorkflowEngineError(`Cannot resume workflow run in '${current.status}' status, must be 'paused'`, current.workflowId, runId);
|
|
701
711
|
}
|
|
712
|
+
const currentStepId = current.currentStepId;
|
|
713
|
+
const currentStepTimelineEntry = current.timeline[invokeChildWorkflowTimelineKey(currentStepId)];
|
|
714
|
+
if (isInvokeChildWorkflowTimelineEntry(currentStepTimelineEntry)) {
|
|
715
|
+
return current;
|
|
716
|
+
}
|
|
702
717
|
return this.triggerEvent({
|
|
703
718
|
runId,
|
|
704
719
|
resourceId,
|
|
@@ -717,8 +732,12 @@ class WorkflowClient {
|
|
|
717
732
|
if (run.status !== "paused" /* PAUSED */) {
|
|
718
733
|
return run;
|
|
719
734
|
}
|
|
720
|
-
const
|
|
721
|
-
const
|
|
735
|
+
const currentStepId = run.currentStepId;
|
|
736
|
+
const currentStepTimelineEntry = run.timeline[invokeChildWorkflowTimelineKey(currentStepId)];
|
|
737
|
+
if (isInvokeChildWorkflowTimelineEntry(currentStepTimelineEntry)) {
|
|
738
|
+
return run;
|
|
739
|
+
}
|
|
740
|
+
const waitForEntry = run.timeline[waitForTimelineKey(currentStepId)];
|
|
722
741
|
if (!waitForEntry || typeof waitForEntry !== "object" || !("waitFor" in waitForEntry)) {
|
|
723
742
|
return run;
|
|
724
743
|
}
|
|
@@ -736,7 +755,7 @@ class WorkflowClient {
|
|
|
736
755
|
resourceId,
|
|
737
756
|
data: {
|
|
738
757
|
timeline: import_es_toolkit.merge(freshRun.timeline, {
|
|
739
|
-
[
|
|
758
|
+
[currentStepId]: {
|
|
740
759
|
output: data ?? {},
|
|
741
760
|
timestamp: new Date
|
|
742
761
|
}
|
|
@@ -836,7 +855,10 @@ function createWorkflowRef(id, options) {
|
|
|
836
855
|
retries: defineOptions?.retries
|
|
837
856
|
});
|
|
838
857
|
Object.defineProperty(ref, "id", { value: id, enumerable: true });
|
|
839
|
-
Object.defineProperty(ref, "inputSchema", {
|
|
858
|
+
Object.defineProperty(ref, "inputSchema", {
|
|
859
|
+
value: options?.inputSchema,
|
|
860
|
+
enumerable: true
|
|
861
|
+
});
|
|
840
862
|
return ref;
|
|
841
863
|
}
|
|
842
864
|
function createWorkflowFactory(plugins = []) {
|
|
@@ -856,31 +878,6 @@ function createWorkflowFactory(plugins = []) {
|
|
|
856
878
|
return factory;
|
|
857
879
|
}
|
|
858
880
|
var workflow = createWorkflowFactory();
|
|
859
|
-
// src/duration.ts
|
|
860
|
-
var import_parse_duration = __toESM(require("parse-duration"));
|
|
861
|
-
var MS_PER_SECOND = 1000;
|
|
862
|
-
var MS_PER_MINUTE = 60 * MS_PER_SECOND;
|
|
863
|
-
var MS_PER_HOUR = 60 * MS_PER_MINUTE;
|
|
864
|
-
var MS_PER_DAY = 24 * MS_PER_HOUR;
|
|
865
|
-
var MS_PER_WEEK = 7 * MS_PER_DAY;
|
|
866
|
-
function parseDuration(duration) {
|
|
867
|
-
if (typeof duration === "string") {
|
|
868
|
-
if (duration.trim() === "") {
|
|
869
|
-
throw new WorkflowEngineError("Invalid duration: empty string");
|
|
870
|
-
}
|
|
871
|
-
const ms2 = import_parse_duration.default(duration);
|
|
872
|
-
if (ms2 == null || ms2 <= 0) {
|
|
873
|
-
throw new WorkflowEngineError(`Invalid duration: "${duration}"`);
|
|
874
|
-
}
|
|
875
|
-
return ms2;
|
|
876
|
-
}
|
|
877
|
-
const { weeks = 0, days = 0, hours = 0, minutes = 0, seconds = 0 } = duration;
|
|
878
|
-
const ms = weeks * MS_PER_WEEK + days * MS_PER_DAY + hours * MS_PER_HOUR + minutes * MS_PER_MINUTE + seconds * MS_PER_SECOND;
|
|
879
|
-
if (ms <= 0) {
|
|
880
|
-
throw new WorkflowEngineError("Invalid duration: must be a positive value");
|
|
881
|
-
}
|
|
882
|
-
return ms;
|
|
883
|
-
}
|
|
884
881
|
// src/engine.ts
|
|
885
882
|
var import_es_toolkit2 = require("es-toolkit");
|
|
886
883
|
var import_pg2 = __toESM(require("pg"));
|
|
@@ -931,7 +928,7 @@ function parseWorkflowHandler(handler) {
|
|
|
931
928
|
const propertyAccess = node.expression;
|
|
932
929
|
const objectName = propertyAccess.expression.getText(sourceFile);
|
|
933
930
|
const methodName = propertyAccess.name.text;
|
|
934
|
-
if (objectName === "step" && (methodName === "run" || methodName === "waitFor" || methodName === "pause" || methodName === "waitUntil" || methodName === "delay" || methodName === "sleep" || methodName === "poll")) {
|
|
931
|
+
if (objectName === "step" && (methodName === "run" || methodName === "waitFor" || methodName === "pause" || methodName === "waitUntil" || methodName === "delay" || methodName === "sleep" || methodName === "poll" || methodName === "invokeChildWorkflow")) {
|
|
935
932
|
const firstArg = node.arguments[0];
|
|
936
933
|
if (firstArg) {
|
|
937
934
|
const { id, isDynamic } = extractStepId(firstArg);
|
|
@@ -956,6 +953,32 @@ function parseWorkflowHandler(handler) {
|
|
|
956
953
|
return { steps: Array.from(steps.values()) };
|
|
957
954
|
}
|
|
958
955
|
|
|
956
|
+
// src/duration.ts
|
|
957
|
+
var import_parse_duration = __toESM(require("parse-duration"));
|
|
958
|
+
var MS_PER_SECOND = 1000;
|
|
959
|
+
var MS_PER_MINUTE = 60 * MS_PER_SECOND;
|
|
960
|
+
var MS_PER_HOUR = 60 * MS_PER_MINUTE;
|
|
961
|
+
var MS_PER_DAY = 24 * MS_PER_HOUR;
|
|
962
|
+
var MS_PER_WEEK = 7 * MS_PER_DAY;
|
|
963
|
+
function parseDuration(duration) {
|
|
964
|
+
if (typeof duration === "string") {
|
|
965
|
+
if (duration.trim() === "") {
|
|
966
|
+
throw new WorkflowEngineError("Invalid duration: empty string");
|
|
967
|
+
}
|
|
968
|
+
const ms2 = import_parse_duration.default(duration);
|
|
969
|
+
if (ms2 == null || ms2 <= 0) {
|
|
970
|
+
throw new WorkflowEngineError(`Invalid duration: "${duration}"`);
|
|
971
|
+
}
|
|
972
|
+
return ms2;
|
|
973
|
+
}
|
|
974
|
+
const { weeks = 0, days = 0, hours = 0, minutes = 0, seconds = 0 } = duration;
|
|
975
|
+
const ms = weeks * MS_PER_WEEK + days * MS_PER_DAY + hours * MS_PER_HOUR + minutes * MS_PER_MINUTE + seconds * MS_PER_SECOND;
|
|
976
|
+
if (ms <= 0) {
|
|
977
|
+
throw new WorkflowEngineError("Invalid duration: must be a positive value");
|
|
978
|
+
}
|
|
979
|
+
return ms;
|
|
980
|
+
}
|
|
981
|
+
|
|
959
982
|
// src/engine.ts
|
|
960
983
|
var LOG_PREFIX2 = "[WorkflowEngine]";
|
|
961
984
|
var StepTypeToIcon = {
|
|
@@ -964,7 +987,8 @@ var StepTypeToIcon = {
|
|
|
964
987
|
["pause" /* PAUSE */]: "⏸",
|
|
965
988
|
["waitUntil" /* WAIT_UNTIL */]: "⏲",
|
|
966
989
|
["delay" /* DELAY */]: "⏱",
|
|
967
|
-
["poll" /* POLL */]: "↻"
|
|
990
|
+
["poll" /* POLL */]: "↻",
|
|
991
|
+
["invokeChildWorkflow" /* INVOKE_CHILD_WORKFLOW */]: "↪"
|
|
968
992
|
};
|
|
969
993
|
var defaultLogger2 = {
|
|
970
994
|
log: (_message) => console.warn(_message),
|
|
@@ -976,6 +1000,7 @@ var retrySendOptions = (maxRetries) => ({
|
|
|
976
1000
|
retryBackoff: true,
|
|
977
1001
|
retryDelay: 1
|
|
978
1002
|
});
|
|
1003
|
+
var getInvokeChildWorkflowEventName = (childRunId) => `__invoke_child_workflow_completed:${childRunId}`;
|
|
979
1004
|
var defaultHeartbeatSeconds = process.env.WORKFLOW_RUN_HEARTBEAT_SECONDS ? Number.parseInt(process.env.WORKFLOW_RUN_HEARTBEAT_SECONDS, 10) : 30;
|
|
980
1005
|
|
|
981
1006
|
class WorkflowEngine {
|
|
@@ -1081,31 +1106,57 @@ class WorkflowEngine {
|
|
|
1081
1106
|
this.workflows.clear();
|
|
1082
1107
|
return this;
|
|
1083
1108
|
}
|
|
1084
|
-
|
|
1085
|
-
let workflowId;
|
|
1086
|
-
let input;
|
|
1087
|
-
let resourceId;
|
|
1088
|
-
let idempotencyKey;
|
|
1089
|
-
let options;
|
|
1109
|
+
resolveWorkflowRunParameters(refOrParams, inputArg, optionsArg) {
|
|
1090
1110
|
if (typeof refOrParams === "function" && "id" in refOrParams) {
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
workflowId = params.workflowId;
|
|
1099
|
-
input = params.input;
|
|
1100
|
-
resourceId = params.resourceId;
|
|
1101
|
-
idempotencyKey = params.idempotencyKey;
|
|
1102
|
-
options = params.options;
|
|
1111
|
+
return {
|
|
1112
|
+
workflowId: refOrParams.id,
|
|
1113
|
+
input: inputArg,
|
|
1114
|
+
options: optionsArg,
|
|
1115
|
+
resourceId: optionsArg?.resourceId,
|
|
1116
|
+
idempotencyKey: optionsArg?.idempotencyKey
|
|
1117
|
+
};
|
|
1103
1118
|
}
|
|
1104
|
-
|
|
1105
|
-
|
|
1119
|
+
const params = refOrParams;
|
|
1120
|
+
return {
|
|
1121
|
+
workflowId: params.workflowId,
|
|
1122
|
+
input: params.input,
|
|
1123
|
+
resourceId: params.resourceId ?? params.options?.resourceId,
|
|
1124
|
+
idempotencyKey: params.idempotencyKey ?? params.options?.idempotencyKey,
|
|
1125
|
+
options: params.options
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
1128
|
+
async startWorkflow(refOrParams, inputArg, optionsArg) {
|
|
1129
|
+
const { workflowId, input, resourceId, idempotencyKey, options } = this.resolveWorkflowRunParameters(refOrParams, inputArg, optionsArg);
|
|
1106
1130
|
if (!this._started) {
|
|
1107
|
-
await this.start(false
|
|
1131
|
+
await this.start(false);
|
|
1108
1132
|
}
|
|
1133
|
+
const { run } = await this.createWorkflowRun({
|
|
1134
|
+
workflowId,
|
|
1135
|
+
input,
|
|
1136
|
+
resourceId,
|
|
1137
|
+
idempotencyKey,
|
|
1138
|
+
options
|
|
1139
|
+
});
|
|
1140
|
+
this.logger.log("Started workflow run", {
|
|
1141
|
+
runId: run.id,
|
|
1142
|
+
workflowId
|
|
1143
|
+
});
|
|
1144
|
+
return run;
|
|
1145
|
+
}
|
|
1146
|
+
async createWorkflowRun({
|
|
1147
|
+
workflowId,
|
|
1148
|
+
input,
|
|
1149
|
+
resourceId,
|
|
1150
|
+
idempotencyKey,
|
|
1151
|
+
options,
|
|
1152
|
+
parentRunId,
|
|
1153
|
+
parentStepId,
|
|
1154
|
+
parentResourceId,
|
|
1155
|
+
enqueue = true,
|
|
1156
|
+
db
|
|
1157
|
+
}) {
|
|
1158
|
+
validateWorkflowId(workflowId);
|
|
1159
|
+
validateResourceId(resourceId);
|
|
1109
1160
|
const workflow2 = this.workflows.get(workflowId);
|
|
1110
1161
|
if (!workflow2) {
|
|
1111
1162
|
throw new WorkflowEngineError(`Unknown workflow ${workflowId}`);
|
|
@@ -1122,38 +1173,60 @@ class WorkflowEngine {
|
|
|
1122
1173
|
}
|
|
1123
1174
|
}
|
|
1124
1175
|
const initialStepId = workflow2.steps[0]?.id ?? "__start__";
|
|
1125
|
-
const
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
};
|
|
1144
|
-
await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {
|
|
1145
|
-
startAfter: new Date,
|
|
1146
|
-
expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds2,
|
|
1147
|
-
...retrySendOptions(insertedRun.maxRetries)
|
|
1148
|
-
});
|
|
1176
|
+
const timeoutAt = options?.timeout ? new Date(Date.now() + options.timeout) : workflow2.timeout ? new Date(Date.now() + workflow2.timeout) : null;
|
|
1177
|
+
const insertRun = async (targetDb) => await insertWorkflowRun({
|
|
1178
|
+
resourceId,
|
|
1179
|
+
workflowId,
|
|
1180
|
+
currentStepId: initialStepId,
|
|
1181
|
+
status: "running" /* RUNNING */,
|
|
1182
|
+
input,
|
|
1183
|
+
maxRetries: options?.retries ?? workflow2.retries ?? 0,
|
|
1184
|
+
timeoutAt,
|
|
1185
|
+
idempotencyKey,
|
|
1186
|
+
parentRunId,
|
|
1187
|
+
parentStepId,
|
|
1188
|
+
parentResourceId
|
|
1189
|
+
}, targetDb);
|
|
1190
|
+
const insertAndEnqueue = async (targetDb) => {
|
|
1191
|
+
const result = await insertRun(targetDb);
|
|
1192
|
+
if (enqueue && result.created) {
|
|
1193
|
+
await this.enqueueWorkflowRun(result.run, options, targetDb);
|
|
1149
1194
|
}
|
|
1150
|
-
return
|
|
1151
|
-
}
|
|
1152
|
-
this.
|
|
1195
|
+
return result;
|
|
1196
|
+
};
|
|
1197
|
+
const { run, created } = db ? await insertAndEnqueue(db) : await withPostgresTransaction(this.boss.getDb(), insertAndEnqueue, this.pool);
|
|
1198
|
+
return { run, created };
|
|
1199
|
+
}
|
|
1200
|
+
async enqueueWorkflowRun(run, options, db) {
|
|
1201
|
+
const job = {
|
|
1153
1202
|
runId: run.id,
|
|
1154
|
-
|
|
1203
|
+
resourceId: run.resourceId ?? undefined,
|
|
1204
|
+
workflowId: run.workflowId,
|
|
1205
|
+
input: run.input
|
|
1206
|
+
};
|
|
1207
|
+
await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {
|
|
1208
|
+
startAfter: new Date,
|
|
1209
|
+
expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds2,
|
|
1210
|
+
...retrySendOptions(run.maxRetries),
|
|
1211
|
+
...db ? { db } : {}
|
|
1212
|
+
});
|
|
1213
|
+
}
|
|
1214
|
+
async notifyParentOfChildTerminalRun(childRun) {
|
|
1215
|
+
if (!childRun.parentRunId || !childRun.parentStepId) {
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
const parentRun = await getWorkflowRun({
|
|
1219
|
+
runId: childRun.parentRunId,
|
|
1220
|
+
resourceId: childRun.parentResourceId ?? undefined
|
|
1221
|
+
}, { db: this.db });
|
|
1222
|
+
if (!parentRun || parentRun.status === "completed" /* COMPLETED */ || parentRun.status === "failed" /* FAILED */ || parentRun.status === "cancelled" /* CANCELLED */) {
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
await this.triggerEvent({
|
|
1226
|
+
runId: parentRun.id,
|
|
1227
|
+
resourceId: parentRun.resourceId ?? undefined,
|
|
1228
|
+
eventName: getInvokeChildWorkflowEventName(childRun.id)
|
|
1155
1229
|
});
|
|
1156
|
-
return run;
|
|
1157
1230
|
}
|
|
1158
1231
|
async pauseWorkflow({
|
|
1159
1232
|
runId,
|
|
@@ -1185,6 +1258,9 @@ class WorkflowEngine {
|
|
|
1185
1258
|
if (current.status !== "paused" /* PAUSED */) {
|
|
1186
1259
|
throw new WorkflowEngineError(`Cannot resume workflow run in '${current.status}' status, must be 'paused'`, current.workflowId, runId);
|
|
1187
1260
|
}
|
|
1261
|
+
if (this.getInvokeChildWorkflowStepEntry(current.timeline, current.currentStepId)) {
|
|
1262
|
+
return current;
|
|
1263
|
+
}
|
|
1188
1264
|
return this.triggerEvent({
|
|
1189
1265
|
runId,
|
|
1190
1266
|
resourceId,
|
|
@@ -1204,6 +1280,9 @@ class WorkflowEngine {
|
|
|
1204
1280
|
return run;
|
|
1205
1281
|
}
|
|
1206
1282
|
const stepId = run.currentStepId;
|
|
1283
|
+
if (this.getInvokeChildWorkflowStepEntry(run.timeline, stepId)) {
|
|
1284
|
+
return run;
|
|
1285
|
+
}
|
|
1207
1286
|
const waitForStep = this.getWaitForStepEntry(run.timeline, stepId);
|
|
1208
1287
|
if (!waitForStep) {
|
|
1209
1288
|
return run;
|
|
@@ -1252,6 +1331,7 @@ class WorkflowEngine {
|
|
|
1252
1331
|
expectedStatuses: ["pending" /* PENDING */, "running" /* RUNNING */, "paused" /* PAUSED */]
|
|
1253
1332
|
});
|
|
1254
1333
|
this.logger.log(`cancelled workflow run with id ${runId}`);
|
|
1334
|
+
await this.notifyParentOfChildTerminalRun(run);
|
|
1255
1335
|
return run;
|
|
1256
1336
|
}
|
|
1257
1337
|
async triggerEvent({
|
|
@@ -1489,6 +1569,22 @@ class WorkflowEngine {
|
|
|
1489
1569
|
}
|
|
1490
1570
|
const timeoutMs = options?.timeout ? parseDuration(options.timeout) : undefined;
|
|
1491
1571
|
return this.pollStep({ run, stepId, conditionFn, intervalMs, timeoutMs });
|
|
1572
|
+
},
|
|
1573
|
+
invokeChildWorkflow: async (stepId, refOrParams, inputArg, optionsArg) => {
|
|
1574
|
+
if (!run) {
|
|
1575
|
+
throw new WorkflowEngineError("Missing workflow run", workflowId, runId);
|
|
1576
|
+
}
|
|
1577
|
+
const resolvedChildCall = this.resolveWorkflowRunParameters(refOrParams, inputArg, optionsArg);
|
|
1578
|
+
const childWorkflowInvocation = {
|
|
1579
|
+
run,
|
|
1580
|
+
stepId,
|
|
1581
|
+
workflowId: resolvedChildCall.workflowId,
|
|
1582
|
+
input: resolvedChildCall.input,
|
|
1583
|
+
options: resolvedChildCall.options,
|
|
1584
|
+
resourceId: resolvedChildCall.resourceId,
|
|
1585
|
+
idempotencyKey: resolvedChildCall.idempotencyKey
|
|
1586
|
+
};
|
|
1587
|
+
return this.invokeChildWorkflowStep(childWorkflowInvocation);
|
|
1492
1588
|
}
|
|
1493
1589
|
};
|
|
1494
1590
|
let step = { ...baseStep };
|
|
@@ -1501,7 +1597,9 @@ class WorkflowEngine {
|
|
|
1501
1597
|
input: run.input,
|
|
1502
1598
|
workflowId: run.workflowId,
|
|
1503
1599
|
runId: run.id,
|
|
1504
|
-
timeline
|
|
1600
|
+
get timeline() {
|
|
1601
|
+
return run?.timeline ?? {};
|
|
1602
|
+
},
|
|
1505
1603
|
logger: this.logger,
|
|
1506
1604
|
step
|
|
1507
1605
|
};
|
|
@@ -1513,7 +1611,7 @@ class WorkflowEngine {
|
|
|
1513
1611
|
const shouldComplete = run.status === "running" /* RUNNING */ && (noParsedSteps || isLastParsedStep || hasPluginSteps && result !== undefined);
|
|
1514
1612
|
if (shouldComplete) {
|
|
1515
1613
|
const normalizedResult = result === undefined ? {} : result;
|
|
1516
|
-
await this.updateRun({
|
|
1614
|
+
const completedRun = await this.updateRun({
|
|
1517
1615
|
runId,
|
|
1518
1616
|
resourceId: scopedResourceId,
|
|
1519
1617
|
data: {
|
|
@@ -1523,6 +1621,7 @@ class WorkflowEngine {
|
|
|
1523
1621
|
jobId: job?.id
|
|
1524
1622
|
}
|
|
1525
1623
|
});
|
|
1624
|
+
await this.notifyParentOfChildTerminalRun(completedRun);
|
|
1526
1625
|
this.logger.log("Workflow run completed.", {
|
|
1527
1626
|
runId,
|
|
1528
1627
|
workflowId
|
|
@@ -1530,7 +1629,7 @@ class WorkflowEngine {
|
|
|
1530
1629
|
}
|
|
1531
1630
|
} catch (error) {
|
|
1532
1631
|
if (runId) {
|
|
1533
|
-
await this.updateRun({
|
|
1632
|
+
const updatedRun = await this.updateRun({
|
|
1534
1633
|
runId,
|
|
1535
1634
|
resourceId: scopedResourceId,
|
|
1536
1635
|
data: {
|
|
@@ -1538,6 +1637,9 @@ class WorkflowEngine {
|
|
|
1538
1637
|
jobId: job?.id
|
|
1539
1638
|
}
|
|
1540
1639
|
});
|
|
1640
|
+
if (updatedRun.status === "completed" /* COMPLETED */ || updatedRun.status === "failed" /* FAILED */ || updatedRun.status === "cancelled" /* CANCELLED */) {
|
|
1641
|
+
await this.notifyParentOfChildTerminalRun(updatedRun);
|
|
1642
|
+
}
|
|
1541
1643
|
}
|
|
1542
1644
|
throw error;
|
|
1543
1645
|
}
|
|
@@ -1549,7 +1651,7 @@ class WorkflowEngine {
|
|
|
1549
1651
|
const run = await getWorkflowRun({ runId }, { db: this.db });
|
|
1550
1652
|
if (!run || run.status !== "running" /* RUNNING */)
|
|
1551
1653
|
return;
|
|
1552
|
-
await this.updateRun({
|
|
1654
|
+
const failedRun = await this.updateRun({
|
|
1553
1655
|
runId,
|
|
1554
1656
|
resourceId: run.resourceId ?? undefined,
|
|
1555
1657
|
data: {
|
|
@@ -1557,6 +1659,7 @@ class WorkflowEngine {
|
|
|
1557
1659
|
error: run.error ?? "Workflow run worker died or job expired before completion"
|
|
1558
1660
|
}
|
|
1559
1661
|
});
|
|
1662
|
+
await this.notifyParentOfChildTerminalRun(failedRun);
|
|
1560
1663
|
this.logger.log("Marked stuck workflow run as failed", {
|
|
1561
1664
|
runId,
|
|
1562
1665
|
workflowId: run.workflowId
|
|
@@ -1567,9 +1670,195 @@ class WorkflowEngine {
|
|
|
1567
1670
|
return stepEntry && typeof stepEntry === "object" && "output" in stepEntry ? stepEntry : null;
|
|
1568
1671
|
}
|
|
1569
1672
|
getWaitForStepEntry(timeline, stepId) {
|
|
1570
|
-
const entry = timeline[
|
|
1673
|
+
const entry = timeline[waitForTimelineKey(stepId)];
|
|
1571
1674
|
return entry && typeof entry === "object" && "waitFor" in entry ? entry : null;
|
|
1572
1675
|
}
|
|
1676
|
+
getInvokeChildWorkflowStepEntry(timeline, stepId) {
|
|
1677
|
+
const entry = timeline[invokeChildWorkflowTimelineKey(stepId)];
|
|
1678
|
+
return isInvokeChildWorkflowTimelineEntry(entry) ? entry : null;
|
|
1679
|
+
}
|
|
1680
|
+
getCompletedChildOutput(childRun) {
|
|
1681
|
+
return childRun.output === undefined ? {} : childRun.output;
|
|
1682
|
+
}
|
|
1683
|
+
throwForNonCompletedChild(childRun) {
|
|
1684
|
+
throw new WorkflowEngineError(`Child workflow ${childRun.workflowId} ${childRun.status}${childRun.error ? `: ${childRun.error}` : ""}`, childRun.workflowId, childRun.id);
|
|
1685
|
+
}
|
|
1686
|
+
assertInvokeChildWorkflowStepOwnership({
|
|
1687
|
+
childRun,
|
|
1688
|
+
parentRun,
|
|
1689
|
+
stepId,
|
|
1690
|
+
workflowId
|
|
1691
|
+
}) {
|
|
1692
|
+
const expectedParentResourceId = parentRun.resourceId ?? null;
|
|
1693
|
+
const matches = childRun.workflowId === workflowId && childRun.parentRunId === parentRun.id && childRun.parentStepId === stepId && childRun.parentResourceId === expectedParentResourceId;
|
|
1694
|
+
if (!matches) {
|
|
1695
|
+
throw new WorkflowEngineError(`Idempotency key resolved to workflow run ${childRun.id}, which does not belong to invokeChildWorkflow step '${stepId}'`, workflowId, parentRun.id);
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
async invokeChildWorkflowStep({
|
|
1699
|
+
run,
|
|
1700
|
+
stepId,
|
|
1701
|
+
workflowId,
|
|
1702
|
+
input,
|
|
1703
|
+
resourceId,
|
|
1704
|
+
idempotencyKey,
|
|
1705
|
+
options
|
|
1706
|
+
}) {
|
|
1707
|
+
let invokeOutput;
|
|
1708
|
+
let hasInvokeOutput = false;
|
|
1709
|
+
const childResourceId = resourceId ?? run.resourceId ?? undefined;
|
|
1710
|
+
const childIdempotencyKey = idempotencyKey;
|
|
1711
|
+
await withPostgresTransaction(this.db, async (db) => {
|
|
1712
|
+
const lockedRun = await this.getRun({ runId: run.id, resourceId: run.resourceId ?? undefined }, { exclusiveLock: true, db });
|
|
1713
|
+
if (lockedRun.status === "cancelled" /* CANCELLED */ || lockedRun.status === "paused" /* PAUSED */ || lockedRun.status === "failed" /* FAILED */) {
|
|
1714
|
+
return;
|
|
1715
|
+
}
|
|
1716
|
+
const lockedCached = this.getCachedStepEntry(lockedRun.timeline, stepId);
|
|
1717
|
+
if (lockedCached?.output !== undefined) {
|
|
1718
|
+
invokeOutput = lockedCached.output;
|
|
1719
|
+
hasInvokeOutput = true;
|
|
1720
|
+
return;
|
|
1721
|
+
}
|
|
1722
|
+
const lockedInvoke = this.getInvokeChildWorkflowStepEntry(lockedRun.timeline, stepId);
|
|
1723
|
+
if (lockedInvoke) {
|
|
1724
|
+
const existingChildResourceId = "childResourceId" in lockedInvoke.invokeChildWorkflow ? lockedInvoke.invokeChildWorkflow.childResourceId ?? undefined : childResourceId;
|
|
1725
|
+
const existingChildRun = await this.getRun({
|
|
1726
|
+
runId: lockedInvoke.invokeChildWorkflow.childRunId,
|
|
1727
|
+
resourceId: existingChildResourceId
|
|
1728
|
+
});
|
|
1729
|
+
if (existingChildRun.status === "completed" /* COMPLETED */) {
|
|
1730
|
+
invokeOutput = this.getCompletedChildOutput(existingChildRun);
|
|
1731
|
+
hasInvokeOutput = true;
|
|
1732
|
+
await this.updateRun({
|
|
1733
|
+
runId: run.id,
|
|
1734
|
+
resourceId: run.resourceId ?? undefined,
|
|
1735
|
+
data: {
|
|
1736
|
+
timeline: import_es_toolkit2.merge(lockedRun.timeline, {
|
|
1737
|
+
[stepId]: {
|
|
1738
|
+
output: invokeOutput,
|
|
1739
|
+
timestamp: new Date
|
|
1740
|
+
}
|
|
1741
|
+
})
|
|
1742
|
+
}
|
|
1743
|
+
}, { db });
|
|
1744
|
+
return;
|
|
1745
|
+
}
|
|
1746
|
+
if (existingChildRun.status === "failed" /* FAILED */ || existingChildRun.status === "cancelled" /* CANCELLED */) {
|
|
1747
|
+
this.throwForNonCompletedChild(existingChildRun);
|
|
1748
|
+
}
|
|
1749
|
+
await this.pauseRunForWait({
|
|
1750
|
+
run: lockedRun,
|
|
1751
|
+
stepId,
|
|
1752
|
+
eventName: getInvokeChildWorkflowEventName(existingChildRun.id),
|
|
1753
|
+
skipOutput: true,
|
|
1754
|
+
db
|
|
1755
|
+
});
|
|
1756
|
+
return;
|
|
1757
|
+
}
|
|
1758
|
+
const result = await this.createWorkflowRun({
|
|
1759
|
+
workflowId,
|
|
1760
|
+
input,
|
|
1761
|
+
resourceId: childResourceId,
|
|
1762
|
+
idempotencyKey: childIdempotencyKey,
|
|
1763
|
+
options,
|
|
1764
|
+
parentRunId: run.id,
|
|
1765
|
+
parentStepId: stepId,
|
|
1766
|
+
parentResourceId: run.resourceId ?? undefined,
|
|
1767
|
+
enqueue: true,
|
|
1768
|
+
db
|
|
1769
|
+
});
|
|
1770
|
+
const childRun = result.run;
|
|
1771
|
+
if (!result.created) {
|
|
1772
|
+
this.assertInvokeChildWorkflowStepOwnership({
|
|
1773
|
+
childRun,
|
|
1774
|
+
parentRun: lockedRun,
|
|
1775
|
+
stepId,
|
|
1776
|
+
workflowId
|
|
1777
|
+
});
|
|
1778
|
+
if (childRun.status === "completed" /* COMPLETED */) {
|
|
1779
|
+
invokeOutput = this.getCompletedChildOutput(childRun);
|
|
1780
|
+
hasInvokeOutput = true;
|
|
1781
|
+
await this.updateRun({
|
|
1782
|
+
runId: run.id,
|
|
1783
|
+
resourceId: run.resourceId ?? undefined,
|
|
1784
|
+
data: {
|
|
1785
|
+
timeline: import_es_toolkit2.merge(lockedRun.timeline, {
|
|
1786
|
+
[invokeChildWorkflowTimelineKey(stepId)]: {
|
|
1787
|
+
invokeChildWorkflow: {
|
|
1788
|
+
childRunId: childRun.id,
|
|
1789
|
+
childWorkflowId: childRun.workflowId,
|
|
1790
|
+
childResourceId: childRun.resourceId
|
|
1791
|
+
},
|
|
1792
|
+
timestamp: new Date
|
|
1793
|
+
},
|
|
1794
|
+
[stepId]: {
|
|
1795
|
+
output: invokeOutput,
|
|
1796
|
+
timestamp: new Date
|
|
1797
|
+
}
|
|
1798
|
+
})
|
|
1799
|
+
}
|
|
1800
|
+
}, { db });
|
|
1801
|
+
return;
|
|
1802
|
+
}
|
|
1803
|
+
if (childRun.status === "failed" /* FAILED */ || childRun.status === "cancelled" /* CANCELLED */) {
|
|
1804
|
+
this.throwForNonCompletedChild(childRun);
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
await this.pauseRunForWait({
|
|
1808
|
+
run: lockedRun,
|
|
1809
|
+
stepId,
|
|
1810
|
+
eventName: getInvokeChildWorkflowEventName(childRun.id),
|
|
1811
|
+
skipOutput: true,
|
|
1812
|
+
db,
|
|
1813
|
+
timeline: import_es_toolkit2.merge(lockedRun.timeline, {
|
|
1814
|
+
[invokeChildWorkflowTimelineKey(stepId)]: {
|
|
1815
|
+
invokeChildWorkflow: {
|
|
1816
|
+
childRunId: childRun.id,
|
|
1817
|
+
childWorkflowId: childRun.workflowId,
|
|
1818
|
+
childResourceId: childRun.resourceId
|
|
1819
|
+
},
|
|
1820
|
+
timestamp: new Date
|
|
1821
|
+
}
|
|
1822
|
+
})
|
|
1823
|
+
});
|
|
1824
|
+
}, this.pool);
|
|
1825
|
+
if (hasInvokeOutput) {
|
|
1826
|
+
return invokeOutput;
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
async pauseRunForWait({
|
|
1830
|
+
run,
|
|
1831
|
+
stepId,
|
|
1832
|
+
eventName,
|
|
1833
|
+
timeoutEvent,
|
|
1834
|
+
skipOutput,
|
|
1835
|
+
db,
|
|
1836
|
+
timeline
|
|
1837
|
+
}) {
|
|
1838
|
+
const baseTimeline = timeline ?? run.timeline;
|
|
1839
|
+
const waitFor = {};
|
|
1840
|
+
if (eventName)
|
|
1841
|
+
waitFor.eventName = eventName;
|
|
1842
|
+
if (timeoutEvent)
|
|
1843
|
+
waitFor.timeoutEvent = timeoutEvent;
|
|
1844
|
+
if (skipOutput)
|
|
1845
|
+
waitFor.skipOutput = true;
|
|
1846
|
+
await this.updateRun({
|
|
1847
|
+
runId: run.id,
|
|
1848
|
+
resourceId: run.resourceId ?? undefined,
|
|
1849
|
+
data: {
|
|
1850
|
+
status: "paused" /* PAUSED */,
|
|
1851
|
+
currentStepId: stepId,
|
|
1852
|
+
pausedAt: new Date,
|
|
1853
|
+
timeline: import_es_toolkit2.merge(baseTimeline, {
|
|
1854
|
+
[waitForTimelineKey(stepId)]: {
|
|
1855
|
+
waitFor,
|
|
1856
|
+
timestamp: new Date
|
|
1857
|
+
}
|
|
1858
|
+
})
|
|
1859
|
+
}
|
|
1860
|
+
}, { db });
|
|
1861
|
+
}
|
|
1573
1862
|
async runStep({
|
|
1574
1863
|
stepId,
|
|
1575
1864
|
run,
|
|
@@ -1607,7 +1896,7 @@ class WorkflowEngine {
|
|
|
1607
1896
|
if (output === undefined) {
|
|
1608
1897
|
output = {};
|
|
1609
1898
|
}
|
|
1610
|
-
|
|
1899
|
+
const updated = await this.updateRun({
|
|
1611
1900
|
runId: run.id,
|
|
1612
1901
|
resourceId: run.resourceId ?? undefined,
|
|
1613
1902
|
data: {
|
|
@@ -1619,6 +1908,7 @@ class WorkflowEngine {
|
|
|
1619
1908
|
})
|
|
1620
1909
|
}
|
|
1621
1910
|
}, { db });
|
|
1911
|
+
Object.assign(run, updated);
|
|
1622
1912
|
return output;
|
|
1623
1913
|
} catch (error) {
|
|
1624
1914
|
this.logger.error(`Step ${stepId} failed:`, error, {
|
|
@@ -1658,21 +1948,7 @@ ${error.stack}` : String(error)
|
|
|
1658
1948
|
const timeoutEvent = timeoutDate ? `__timeout_${stepId}` : undefined;
|
|
1659
1949
|
await withPostgresTransaction(this.db, async (db) => {
|
|
1660
1950
|
const freshRun = await this.getRun({ runId: run.id, resourceId: run.resourceId ?? undefined }, { exclusiveLock: true, db });
|
|
1661
|
-
return this.
|
|
1662
|
-
runId: run.id,
|
|
1663
|
-
resourceId: run.resourceId ?? undefined,
|
|
1664
|
-
data: {
|
|
1665
|
-
status: "paused" /* PAUSED */,
|
|
1666
|
-
currentStepId: stepId,
|
|
1667
|
-
pausedAt: new Date,
|
|
1668
|
-
timeline: import_es_toolkit2.merge(freshRun.timeline, {
|
|
1669
|
-
[`${stepId}-wait-for`]: {
|
|
1670
|
-
waitFor: { eventName, timeoutEvent },
|
|
1671
|
-
timestamp: new Date
|
|
1672
|
-
}
|
|
1673
|
-
})
|
|
1674
|
-
}
|
|
1675
|
-
}, { db });
|
|
1951
|
+
return this.pauseRunForWait({ run: freshRun, stepId, eventName, timeoutEvent, db });
|
|
1676
1952
|
}, this.pool);
|
|
1677
1953
|
if (timeoutDate && timeoutEvent) {
|
|
1678
1954
|
try {
|
|
@@ -1786,7 +2062,7 @@ ${error.stack}` : String(error)
|
|
|
1786
2062
|
pausedAt: new Date,
|
|
1787
2063
|
timeline: import_es_toolkit2.merge(freshRun.timeline, {
|
|
1788
2064
|
[`${stepId}-poll`]: { startedAt: startedAt.toISOString() },
|
|
1789
|
-
[
|
|
2065
|
+
[waitForTimelineKey(stepId)]: {
|
|
1790
2066
|
waitFor: { timeoutEvent: pollEvent, skipOutput: true },
|
|
1791
2067
|
timestamp: new Date
|
|
1792
2068
|
}
|
|
@@ -1861,5 +2137,5 @@ ${error.stack}` : String(error)
|
|
|
1861
2137
|
}
|
|
1862
2138
|
}
|
|
1863
2139
|
|
|
1864
|
-
//# debugId=
|
|
2140
|
+
//# debugId=B0870008EFFA04F064756E2164756E21
|
|
1865
2141
|
//# sourceMappingURL=index.js.map
|