aws-local-stepfunctions 0.6.0 → 1.0.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/README.md +249 -4
- package/build/CLI.cjs +279 -0
- package/build/main.browser.esm.js +349 -98
- package/build/main.d.ts +97 -21
- package/build/main.node.cjs +349 -98
- package/build/main.node.esm.js +349 -98
- package/package.json +9 -2
package/build/main.node.esm.js
CHANGED
|
@@ -25,27 +25,11 @@ var ExecutionAbortedError = class extends Error {
|
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
// src/error/
|
|
29
|
-
var
|
|
30
|
-
constructor(message) {
|
|
31
|
-
super(message);
|
|
32
|
-
this.name = "RuntimeError";
|
|
33
|
-
this.retryable = true;
|
|
34
|
-
this.catchable = true;
|
|
35
|
-
}
|
|
36
|
-
get isRetryable() {
|
|
37
|
-
return this.retryable;
|
|
38
|
-
}
|
|
39
|
-
get isCatchable() {
|
|
40
|
-
return this.catchable;
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
// src/error/predefined/StatesTimeoutError.ts
|
|
45
|
-
var StatesTimeoutError = class extends RuntimeError {
|
|
28
|
+
// src/error/ExecutionTimeoutError.ts
|
|
29
|
+
var ExecutionTimeoutError = class extends Error {
|
|
46
30
|
constructor() {
|
|
47
|
-
super("
|
|
48
|
-
this.name = "
|
|
31
|
+
super("Execution timed out");
|
|
32
|
+
this.name = "ExecutionTimeoutError";
|
|
49
33
|
}
|
|
50
34
|
};
|
|
51
35
|
|
|
@@ -96,20 +80,32 @@ function sfc32(a, b, c, d) {
|
|
|
96
80
|
return (t >>> 0) / 4294967296;
|
|
97
81
|
};
|
|
98
82
|
}
|
|
99
|
-
function getRandomNumber(min, max,
|
|
100
|
-
return Math.floor(
|
|
83
|
+
function getRandomNumber(min, max, rng = Math.random) {
|
|
84
|
+
return Math.floor(rng() * (max - min + 1)) + min;
|
|
101
85
|
}
|
|
102
86
|
|
|
103
87
|
// src/util/index.ts
|
|
104
88
|
function isPlainObj(value) {
|
|
105
89
|
return !!value && Object.getPrototypeOf(value) === Object.prototype;
|
|
106
90
|
}
|
|
107
|
-
function sleep(ms, abortSignal) {
|
|
91
|
+
function sleep(ms, abortSignal, rootAbortSignal) {
|
|
108
92
|
return new Promise((resolve) => {
|
|
109
|
-
|
|
110
|
-
|
|
93
|
+
if (abortSignal?.aborted || rootAbortSignal?.aborted) {
|
|
94
|
+
return resolve();
|
|
95
|
+
}
|
|
96
|
+
const onAbort = () => {
|
|
97
|
+
abortSignal?.removeEventListener("abort", onAbort);
|
|
98
|
+
rootAbortSignal?.removeEventListener("abort", onAbort);
|
|
111
99
|
clearTimeout(timeout);
|
|
112
|
-
|
|
100
|
+
resolve();
|
|
101
|
+
};
|
|
102
|
+
const timeout = setTimeout(() => {
|
|
103
|
+
abortSignal?.removeEventListener("abort", onAbort);
|
|
104
|
+
rootAbortSignal?.removeEventListener("abort", onAbort);
|
|
105
|
+
resolve();
|
|
106
|
+
}, ms);
|
|
107
|
+
abortSignal?.addEventListener("abort", onAbort);
|
|
108
|
+
rootAbortSignal?.addEventListener("abort", onAbort);
|
|
113
109
|
});
|
|
114
110
|
}
|
|
115
111
|
function byteToHex(byte) {
|
|
@@ -125,6 +121,22 @@ function jsonPathQuery(pathExpression, json, context) {
|
|
|
125
121
|
return jp({ path: pathExpression, json, wrap: false });
|
|
126
122
|
}
|
|
127
123
|
|
|
124
|
+
// src/error/RuntimeError.ts
|
|
125
|
+
var RuntimeError = class extends Error {
|
|
126
|
+
constructor(message) {
|
|
127
|
+
super(message);
|
|
128
|
+
this.name = "RuntimeError";
|
|
129
|
+
this.retryable = true;
|
|
130
|
+
this.catchable = true;
|
|
131
|
+
}
|
|
132
|
+
get isRetryable() {
|
|
133
|
+
return this.retryable;
|
|
134
|
+
}
|
|
135
|
+
get isCatchable() {
|
|
136
|
+
return this.catchable;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
128
140
|
// src/error/predefined/StatesResultPathMatchFailureError.ts
|
|
129
141
|
var StatesResultPathMatchFailureError = class extends RuntimeError {
|
|
130
142
|
constructor() {
|
|
@@ -169,7 +181,7 @@ function validateArgumentType(allowedTypes, argPosition, funcArg, funcName) {
|
|
|
169
181
|
if (matchesAllowedType)
|
|
170
182
|
break;
|
|
171
183
|
}
|
|
172
|
-
const expectedType = allowedTypes.map((type) => `
|
|
184
|
+
const expectedType = allowedTypes.map((type) => `'${type}'`).join(" | ");
|
|
173
185
|
if (!matchesAllowedType) {
|
|
174
186
|
throw new StatesRuntimeError(
|
|
175
187
|
`Intrinsic function ${funcName} expected argument ${argPosition} to be of type ${expectedType}, but received ${typeof funcArg}`
|
|
@@ -197,7 +209,7 @@ function validateArgumentConstraints(argConstraints, argPosition, funcArg, funcN
|
|
|
197
209
|
if (matchesAllConstraints)
|
|
198
210
|
break;
|
|
199
211
|
}
|
|
200
|
-
const expectedConstraints = argConstraints.map((constraint) => `
|
|
212
|
+
const expectedConstraints = argConstraints.map((constraint) => `'${constraint}'`).join(" | ");
|
|
201
213
|
if (!matchesAllConstraints) {
|
|
202
214
|
throw new StatesRuntimeError(
|
|
203
215
|
`Intrinsic function ${funcName} expected argument ${argPosition} to satisfy the following constraints: ${expectedConstraints}`
|
|
@@ -819,7 +831,7 @@ function processPayloadTemplate(payloadTemplate, json, context) {
|
|
|
819
831
|
let sanitizedKey = key;
|
|
820
832
|
let resolvedValue = value;
|
|
821
833
|
if (isPlainObj(value)) {
|
|
822
|
-
resolvedValue = processPayloadTemplate(value, json);
|
|
834
|
+
resolvedValue = processPayloadTemplate(value, json, context);
|
|
823
835
|
}
|
|
824
836
|
if (key.endsWith(".$") && typeof value === "string") {
|
|
825
837
|
sanitizedKey = key.replace(".$", "");
|
|
@@ -859,8 +871,9 @@ function processOutputPath(path, result, context) {
|
|
|
859
871
|
|
|
860
872
|
// src/stateMachine/stateActions/BaseStateAction.ts
|
|
861
873
|
var BaseStateAction = class {
|
|
862
|
-
constructor(stateDefinition) {
|
|
874
|
+
constructor(stateDefinition, stateName) {
|
|
863
875
|
this.stateDefinition = stateDefinition;
|
|
876
|
+
this.stateName = stateName;
|
|
864
877
|
}
|
|
865
878
|
buildExecutionResult(stateResult) {
|
|
866
879
|
const executionResult = { stateResult, nextState: "", isEndState: false };
|
|
@@ -885,8 +898,8 @@ var StatesNoChoiceMatchedError = class extends RuntimeError {
|
|
|
885
898
|
// src/stateMachine/stateActions/ChoiceStateAction.ts
|
|
886
899
|
import wcmatch from "wildcard-match";
|
|
887
900
|
var ChoiceStateAction = class extends BaseStateAction {
|
|
888
|
-
constructor(stateDefinition) {
|
|
889
|
-
super(stateDefinition);
|
|
901
|
+
constructor(stateDefinition, stateName) {
|
|
902
|
+
super(stateDefinition, stateName);
|
|
890
903
|
}
|
|
891
904
|
testChoiceRule(choiceRule, input) {
|
|
892
905
|
if ("And" in choiceRule) {
|
|
@@ -1109,8 +1122,8 @@ var FailStateError = class extends RuntimeError {
|
|
|
1109
1122
|
|
|
1110
1123
|
// src/stateMachine/stateActions/FailStateAction.ts
|
|
1111
1124
|
var FailStateAction = class extends BaseStateAction {
|
|
1112
|
-
constructor(stateDefinition) {
|
|
1113
|
-
super(stateDefinition);
|
|
1125
|
+
constructor(stateDefinition, stateName) {
|
|
1126
|
+
super(stateDefinition, stateName);
|
|
1114
1127
|
}
|
|
1115
1128
|
async execute(input, context, options) {
|
|
1116
1129
|
throw new FailStateError(this.stateDefinition.Error, this.stateDefinition.Cause);
|
|
@@ -1121,10 +1134,17 @@ var FailStateAction = class extends BaseStateAction {
|
|
|
1121
1134
|
import pLimit from "p-limit";
|
|
1122
1135
|
var DEFAULT_MAX_CONCURRENCY = 40;
|
|
1123
1136
|
var MapStateAction = class extends BaseStateAction {
|
|
1124
|
-
constructor(stateDefinition) {
|
|
1125
|
-
super(stateDefinition);
|
|
1137
|
+
constructor(stateDefinition, stateName) {
|
|
1138
|
+
super(stateDefinition, stateName);
|
|
1126
1139
|
this.executionAbortFuncs = [];
|
|
1127
1140
|
}
|
|
1141
|
+
async forwardEventsToRootEventLogger(eventLogger, executionEventLogs, index, parentStateRawInput) {
|
|
1142
|
+
if (!eventLogger)
|
|
1143
|
+
return;
|
|
1144
|
+
for await (const event of executionEventLogs) {
|
|
1145
|
+
eventLogger.forwardNestedMapEvent(event, index, this.stateName, parentStateRawInput);
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1128
1148
|
processItem(stateMachine, item, input, context, index, options) {
|
|
1129
1149
|
const state = this.stateDefinition;
|
|
1130
1150
|
let paramValue;
|
|
@@ -1139,6 +1159,7 @@ var MapStateAction = class extends BaseStateAction {
|
|
|
1139
1159
|
}
|
|
1140
1160
|
const execution = stateMachine.run(paramValue ?? item, options?.runOptions);
|
|
1141
1161
|
this.executionAbortFuncs.push(execution.abort);
|
|
1162
|
+
this.forwardEventsToRootEventLogger(options?.eventLogger, execution.eventLogs, index, options?.rawInput);
|
|
1142
1163
|
return execution.result;
|
|
1143
1164
|
}
|
|
1144
1165
|
async execute(input, context, options) {
|
|
@@ -1150,7 +1171,10 @@ var MapStateAction = class extends BaseStateAction {
|
|
|
1150
1171
|
if (!Array.isArray(items)) {
|
|
1151
1172
|
throw new StatesRuntimeError("Input of Map state must be an array or ItemsPath property must point to an array");
|
|
1152
1173
|
}
|
|
1153
|
-
const iteratorStateMachine = new StateMachine(state.Iterator,
|
|
1174
|
+
const iteratorStateMachine = new StateMachine(state.Iterator, {
|
|
1175
|
+
...options?.stateMachineOptions,
|
|
1176
|
+
validationOptions: { _noValidate: true }
|
|
1177
|
+
});
|
|
1154
1178
|
const limit = pLimit(state.MaxConcurrency || DEFAULT_MAX_CONCURRENCY);
|
|
1155
1179
|
const processedItemsPromise = items.map(
|
|
1156
1180
|
(item, i) => limit(() => this.processItem(iteratorStateMachine, item, input, context, i, options))
|
|
@@ -1174,14 +1198,25 @@ var MapStateAction = class extends BaseStateAction {
|
|
|
1174
1198
|
import pLimit2 from "p-limit";
|
|
1175
1199
|
var DEFAULT_CONCURRENCY = 40;
|
|
1176
1200
|
var ParallelStateAction = class extends BaseStateAction {
|
|
1177
|
-
constructor(stateDefinition) {
|
|
1178
|
-
super(stateDefinition);
|
|
1201
|
+
constructor(stateDefinition, stateName) {
|
|
1202
|
+
super(stateDefinition, stateName);
|
|
1179
1203
|
this.executionAbortFuncs = [];
|
|
1180
1204
|
}
|
|
1205
|
+
async forwardEventsToRootEventLogger(eventLogger, executionEventLogs, parentStateRawInput) {
|
|
1206
|
+
if (!eventLogger)
|
|
1207
|
+
return;
|
|
1208
|
+
for await (const event of executionEventLogs) {
|
|
1209
|
+
eventLogger.forwardNestedParallelEvent(event, this.stateName, parentStateRawInput);
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1181
1212
|
processBranch(branch, input, context, options) {
|
|
1182
|
-
const stateMachine = new StateMachine(branch,
|
|
1213
|
+
const stateMachine = new StateMachine(branch, {
|
|
1214
|
+
...options?.stateMachineOptions,
|
|
1215
|
+
validationOptions: { _noValidate: true }
|
|
1216
|
+
});
|
|
1183
1217
|
const execution = stateMachine.run(input, options?.runOptions);
|
|
1184
1218
|
this.executionAbortFuncs.push(execution.abort);
|
|
1219
|
+
this.forwardEventsToRootEventLogger(options?.eventLogger, execution.eventLogs, options?.rawInput);
|
|
1185
1220
|
return execution.result;
|
|
1186
1221
|
}
|
|
1187
1222
|
async execute(input, context, options) {
|
|
@@ -1205,8 +1240,8 @@ var ParallelStateAction = class extends BaseStateAction {
|
|
|
1205
1240
|
|
|
1206
1241
|
// src/stateMachine/stateActions/PassStateAction.ts
|
|
1207
1242
|
var PassStateAction = class extends BaseStateAction {
|
|
1208
|
-
constructor(stateDefinition) {
|
|
1209
|
-
super(stateDefinition);
|
|
1243
|
+
constructor(stateDefinition, stateName) {
|
|
1244
|
+
super(stateDefinition, stateName);
|
|
1210
1245
|
}
|
|
1211
1246
|
async execute(input, context, options) {
|
|
1212
1247
|
if (this.stateDefinition.Result) {
|
|
@@ -1218,8 +1253,8 @@ var PassStateAction = class extends BaseStateAction {
|
|
|
1218
1253
|
|
|
1219
1254
|
// src/stateMachine/stateActions/SucceedStateAction.ts
|
|
1220
1255
|
var SucceedStateAction = class extends BaseStateAction {
|
|
1221
|
-
constructor(stateDefinition) {
|
|
1222
|
-
super(stateDefinition);
|
|
1256
|
+
constructor(stateDefinition, stateName) {
|
|
1257
|
+
super(stateDefinition, stateName);
|
|
1223
1258
|
}
|
|
1224
1259
|
async execute(input, context, options) {
|
|
1225
1260
|
return { stateResult: input, nextState: "", isEndState: true };
|
|
@@ -1235,12 +1270,12 @@ var LambdaClient = class {
|
|
|
1235
1270
|
if (config) {
|
|
1236
1271
|
if (!config.region) {
|
|
1237
1272
|
throw new StatesRuntimeError(
|
|
1238
|
-
"
|
|
1273
|
+
"'awsConfig' option was specified for state machine, but 'region' property is not set"
|
|
1239
1274
|
);
|
|
1240
1275
|
}
|
|
1241
1276
|
if (config.credentials) {
|
|
1242
1277
|
const credentialsTypes = Object.keys(config.credentials);
|
|
1243
|
-
const credentialsNames = credentialsTypes.map((name) =>
|
|
1278
|
+
const credentialsNames = credentialsTypes.map((name) => `'${name}'`).join(", ");
|
|
1244
1279
|
if (credentialsTypes.length > 1) {
|
|
1245
1280
|
throw new StatesRuntimeError(
|
|
1246
1281
|
`More than one type of AWS credentials were specified: ${credentialsNames}. Only one type may be specified`
|
|
@@ -1274,7 +1309,7 @@ var LambdaClient = class {
|
|
|
1274
1309
|
}
|
|
1275
1310
|
if (invocationResult.FunctionError) {
|
|
1276
1311
|
const errorResult = resultValue;
|
|
1277
|
-
throw new FailStateError(errorResult.errorType, `Execution of Lambda function
|
|
1312
|
+
throw new FailStateError(errorResult.errorType, `Execution of Lambda function '${funcNameOrArn}' failed`);
|
|
1278
1313
|
}
|
|
1279
1314
|
return resultValue;
|
|
1280
1315
|
}
|
|
@@ -1282,8 +1317,8 @@ var LambdaClient = class {
|
|
|
1282
1317
|
|
|
1283
1318
|
// src/stateMachine/stateActions/TaskStateAction.ts
|
|
1284
1319
|
var TaskStateAction = class extends BaseStateAction {
|
|
1285
|
-
constructor(stateDefinition) {
|
|
1286
|
-
super(stateDefinition);
|
|
1320
|
+
constructor(stateDefinition, stateName) {
|
|
1321
|
+
super(stateDefinition, stateName);
|
|
1287
1322
|
}
|
|
1288
1323
|
async execute(input, context, options) {
|
|
1289
1324
|
const state = this.stateDefinition;
|
|
@@ -1299,36 +1334,44 @@ var TaskStateAction = class extends BaseStateAction {
|
|
|
1299
1334
|
|
|
1300
1335
|
// src/stateMachine/stateActions/WaitStateAction.ts
|
|
1301
1336
|
var WaitStateAction = class extends BaseStateAction {
|
|
1302
|
-
constructor(stateDefinition) {
|
|
1303
|
-
super(stateDefinition);
|
|
1337
|
+
constructor(stateDefinition, stateName) {
|
|
1338
|
+
super(stateDefinition, stateName);
|
|
1304
1339
|
}
|
|
1305
1340
|
async execute(input, context, options) {
|
|
1306
1341
|
const state = this.stateDefinition;
|
|
1307
1342
|
if (options?.waitTimeOverrideOption !== void 0) {
|
|
1308
|
-
await sleep(options.waitTimeOverrideOption, options.abortSignal);
|
|
1343
|
+
await sleep(options.waitTimeOverrideOption, options.abortSignal, options.rootAbortSignal);
|
|
1309
1344
|
return this.buildExecutionResult(input);
|
|
1310
1345
|
}
|
|
1311
1346
|
if (state.Seconds) {
|
|
1312
|
-
await sleep(state.Seconds * 1e3, options?.abortSignal);
|
|
1347
|
+
await sleep(state.Seconds * 1e3, options?.abortSignal, options?.rootAbortSignal);
|
|
1313
1348
|
} else if (state.Timestamp) {
|
|
1314
1349
|
const dateTimestamp = new Date(state.Timestamp);
|
|
1315
1350
|
const currentTime = Date.now();
|
|
1316
1351
|
const timeDiff = dateTimestamp.getTime() - currentTime;
|
|
1317
|
-
await sleep(timeDiff, options?.abortSignal);
|
|
1352
|
+
await sleep(timeDiff, options?.abortSignal, options?.rootAbortSignal);
|
|
1318
1353
|
} else if (state.SecondsPath) {
|
|
1319
1354
|
const seconds = jsonPathQuery(state.SecondsPath, input, context);
|
|
1320
|
-
await sleep(seconds * 1e3, options?.abortSignal);
|
|
1355
|
+
await sleep(seconds * 1e3, options?.abortSignal, options?.rootAbortSignal);
|
|
1321
1356
|
} else if (state.TimestampPath) {
|
|
1322
1357
|
const timestamp = jsonPathQuery(state.TimestampPath, input, context);
|
|
1323
1358
|
const dateTimestamp = new Date(timestamp);
|
|
1324
1359
|
const currentTime = Date.now();
|
|
1325
1360
|
const timeDiff = dateTimestamp.getTime() - currentTime;
|
|
1326
|
-
await sleep(timeDiff, options?.abortSignal);
|
|
1361
|
+
await sleep(timeDiff, options?.abortSignal, options?.rootAbortSignal);
|
|
1327
1362
|
}
|
|
1328
1363
|
return this.buildExecutionResult(input);
|
|
1329
1364
|
}
|
|
1330
1365
|
};
|
|
1331
1366
|
|
|
1367
|
+
// src/error/predefined/StatesTimeoutError.ts
|
|
1368
|
+
var StatesTimeoutError = class extends RuntimeError {
|
|
1369
|
+
constructor() {
|
|
1370
|
+
super("States.Timeout");
|
|
1371
|
+
this.name = "States.Timeout";
|
|
1372
|
+
}
|
|
1373
|
+
};
|
|
1374
|
+
|
|
1332
1375
|
// src/stateMachine/StateExecutor.ts
|
|
1333
1376
|
import cloneDeep2 from "lodash/cloneDeep.js";
|
|
1334
1377
|
var DEFAULT_MAX_ATTEMPTS = 3;
|
|
@@ -1366,6 +1409,7 @@ var StateExecutor = class {
|
|
|
1366
1409
|
} = await this.stateHandlers[this.stateDefinition.Type](
|
|
1367
1410
|
// @ts-expect-error Indexing `this.stateActions` by non-literal value produces a `never` type for the `this.stateDefinition` parameter of the handler being called
|
|
1368
1411
|
this.stateDefinition,
|
|
1412
|
+
rawInput,
|
|
1369
1413
|
processedInput,
|
|
1370
1414
|
context,
|
|
1371
1415
|
this.stateName,
|
|
@@ -1376,7 +1420,7 @@ var StateExecutor = class {
|
|
|
1376
1420
|
} catch (error) {
|
|
1377
1421
|
const { shouldRetry, waitTimeBeforeRetry } = this.shouldRetry(error);
|
|
1378
1422
|
if (shouldRetry && waitTimeBeforeRetry) {
|
|
1379
|
-
await sleep(waitTimeBeforeRetry, options.abortSignal);
|
|
1423
|
+
await sleep(waitTimeBeforeRetry, options.abortSignal, options.runOptions?._rootAbortSignal);
|
|
1380
1424
|
return this.execute(input, context, options);
|
|
1381
1425
|
}
|
|
1382
1426
|
const { nextState, errorOutput, resultPath } = this.catchError(error);
|
|
@@ -1478,10 +1522,10 @@ var StateExecutor = class {
|
|
|
1478
1522
|
* Invokes the Lambda function specified in the `Resource` field
|
|
1479
1523
|
* and sets the current result of the state machine to the value returned by the Lambda.
|
|
1480
1524
|
*/
|
|
1481
|
-
async executeTaskState(stateDefinition, input, context, stateName, options) {
|
|
1525
|
+
async executeTaskState(stateDefinition, rawInput, input, context, stateName, options) {
|
|
1482
1526
|
const overrideFn = options.runOptions?.overrides?.taskResourceLocalHandlers?.[stateName];
|
|
1483
1527
|
const awsConfig = options.stateMachineOptions?.awsConfig;
|
|
1484
|
-
const taskStateAction = new TaskStateAction(stateDefinition);
|
|
1528
|
+
const taskStateAction = new TaskStateAction(stateDefinition, stateName);
|
|
1485
1529
|
const executionResult = await taskStateAction.execute(input, context, { overrideFn, awsConfig });
|
|
1486
1530
|
return executionResult;
|
|
1487
1531
|
}
|
|
@@ -1491,11 +1535,13 @@ var StateExecutor = class {
|
|
|
1491
1535
|
* Creates a new state machine for each of the branches specified in the `Branches` field,
|
|
1492
1536
|
* and then executes each branch state machine by passing them the Parallel state input.
|
|
1493
1537
|
*/
|
|
1494
|
-
async executeParallelState(stateDefinition, input, context, stateName, options) {
|
|
1495
|
-
const parallelStateAction = new ParallelStateAction(stateDefinition);
|
|
1538
|
+
async executeParallelState(stateDefinition, rawInput, input, context, stateName, options) {
|
|
1539
|
+
const parallelStateAction = new ParallelStateAction(stateDefinition, stateName);
|
|
1496
1540
|
const executionResult = await parallelStateAction.execute(input, context, {
|
|
1497
1541
|
stateMachineOptions: options.stateMachineOptions,
|
|
1498
|
-
runOptions: options.runOptions
|
|
1542
|
+
runOptions: options.runOptions,
|
|
1543
|
+
eventLogger: options.eventLogger,
|
|
1544
|
+
rawInput
|
|
1499
1545
|
});
|
|
1500
1546
|
return executionResult;
|
|
1501
1547
|
}
|
|
@@ -1506,11 +1552,13 @@ var StateExecutor = class {
|
|
|
1506
1552
|
* by the `ItemsPath` field, and then processes each item by passing it
|
|
1507
1553
|
* as the input to the state machine specified in the `Iterator` field.
|
|
1508
1554
|
*/
|
|
1509
|
-
async executeMapState(stateDefinition, input, context, stateName, options) {
|
|
1510
|
-
const mapStateAction = new MapStateAction(stateDefinition);
|
|
1555
|
+
async executeMapState(stateDefinition, rawInput, input, context, stateName, options) {
|
|
1556
|
+
const mapStateAction = new MapStateAction(stateDefinition, stateName);
|
|
1511
1557
|
const executionResult = await mapStateAction.execute(input, context, {
|
|
1512
1558
|
stateMachineOptions: options.stateMachineOptions,
|
|
1513
|
-
runOptions: options.runOptions
|
|
1559
|
+
runOptions: options.runOptions,
|
|
1560
|
+
eventLogger: options.eventLogger,
|
|
1561
|
+
rawInput
|
|
1514
1562
|
});
|
|
1515
1563
|
return executionResult;
|
|
1516
1564
|
}
|
|
@@ -1520,8 +1568,8 @@ var StateExecutor = class {
|
|
|
1520
1568
|
* If the `Result` field is specified, copies `Result` into the current result.
|
|
1521
1569
|
* Else, copies the current input into the current result.
|
|
1522
1570
|
*/
|
|
1523
|
-
async executePassState(stateDefinition, input, context, stateName, options) {
|
|
1524
|
-
const passStateAction = new PassStateAction(stateDefinition);
|
|
1571
|
+
async executePassState(stateDefinition, rawInput, input, context, stateName, options) {
|
|
1572
|
+
const passStateAction = new PassStateAction(stateDefinition, stateName);
|
|
1525
1573
|
const executionResult = await passStateAction.execute(input, context);
|
|
1526
1574
|
return executionResult;
|
|
1527
1575
|
}
|
|
@@ -1531,13 +1579,13 @@ var StateExecutor = class {
|
|
|
1531
1579
|
* Pauses the state machine execution for a certain amount of time
|
|
1532
1580
|
* based on one of the `Seconds`, `Timestamp`, `SecondsPath` or `TimestampPath` fields.
|
|
1533
1581
|
*/
|
|
1534
|
-
async executeWaitState(stateDefinition, input, context, stateName, options) {
|
|
1582
|
+
async executeWaitState(stateDefinition, rawInput, input, context, stateName, options) {
|
|
1535
1583
|
const waitTimeOverrideOption = options.runOptions?.overrides?.waitTimeOverrides?.[stateName];
|
|
1536
|
-
const
|
|
1537
|
-
const waitStateAction = new WaitStateAction(stateDefinition);
|
|
1584
|
+
const waitStateAction = new WaitStateAction(stateDefinition, stateName);
|
|
1538
1585
|
const executionResult = await waitStateAction.execute(input, context, {
|
|
1539
1586
|
waitTimeOverrideOption,
|
|
1540
|
-
abortSignal
|
|
1587
|
+
abortSignal: options.abortSignal,
|
|
1588
|
+
rootAbortSignal: options.runOptions?._rootAbortSignal
|
|
1541
1589
|
});
|
|
1542
1590
|
return executionResult;
|
|
1543
1591
|
}
|
|
@@ -1555,8 +1603,8 @@ var StateExecutor = class {
|
|
|
1555
1603
|
* If no rule matches and the `Default` field is not specified, throws a
|
|
1556
1604
|
* States.NoChoiceMatched error.
|
|
1557
1605
|
*/
|
|
1558
|
-
async executeChoiceState(stateDefinition, input, context, stateName, options) {
|
|
1559
|
-
const choiceStateAction = new ChoiceStateAction(stateDefinition);
|
|
1606
|
+
async executeChoiceState(stateDefinition, rawInput, input, context, stateName, options) {
|
|
1607
|
+
const choiceStateAction = new ChoiceStateAction(stateDefinition, stateName);
|
|
1560
1608
|
const executionResult = await choiceStateAction.execute(input, context);
|
|
1561
1609
|
return executionResult;
|
|
1562
1610
|
}
|
|
@@ -1565,8 +1613,8 @@ var StateExecutor = class {
|
|
|
1565
1613
|
*
|
|
1566
1614
|
* Ends the state machine execution successfully.
|
|
1567
1615
|
*/
|
|
1568
|
-
async executeSucceedState(stateDefinition, input, context, stateName, options) {
|
|
1569
|
-
const succeedStateAction = new SucceedStateAction(stateDefinition);
|
|
1616
|
+
async executeSucceedState(stateDefinition, rawInput, input, context, stateName, options) {
|
|
1617
|
+
const succeedStateAction = new SucceedStateAction(stateDefinition, stateName);
|
|
1570
1618
|
const executionResult = await succeedStateAction.execute(input, context);
|
|
1571
1619
|
return executionResult;
|
|
1572
1620
|
}
|
|
@@ -1575,13 +1623,186 @@ var StateExecutor = class {
|
|
|
1575
1623
|
*
|
|
1576
1624
|
* Ends the state machine execution and marks it as a failure.
|
|
1577
1625
|
*/
|
|
1578
|
-
async executeFailState(stateDefinition, input, context, stateName, options) {
|
|
1579
|
-
const failStateAction = new FailStateAction(stateDefinition);
|
|
1626
|
+
async executeFailState(stateDefinition, rawInput, input, context, stateName, options) {
|
|
1627
|
+
const failStateAction = new FailStateAction(stateDefinition, stateName);
|
|
1580
1628
|
const executionResult = await failStateAction.execute(input, context);
|
|
1581
1629
|
return executionResult;
|
|
1582
1630
|
}
|
|
1583
1631
|
};
|
|
1584
1632
|
|
|
1633
|
+
// src/stateMachine/EventLogger.ts
|
|
1634
|
+
var EventLogger = class {
|
|
1635
|
+
constructor() {
|
|
1636
|
+
this.eventTarget = new EventTarget();
|
|
1637
|
+
this.eventQueue = [];
|
|
1638
|
+
this.isLoggerClosed = false;
|
|
1639
|
+
}
|
|
1640
|
+
async *getEvents() {
|
|
1641
|
+
while (true) {
|
|
1642
|
+
if (this.eventQueue.length === 0) {
|
|
1643
|
+
await this.waitForNewEvent();
|
|
1644
|
+
}
|
|
1645
|
+
let event = null;
|
|
1646
|
+
while (event = this.eventQueue.shift()) {
|
|
1647
|
+
yield event;
|
|
1648
|
+
}
|
|
1649
|
+
if (this.isLoggerClosed)
|
|
1650
|
+
return;
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
/**
|
|
1654
|
+
* Forward nested events created by `Map` states, to the root state machine event logger.
|
|
1655
|
+
* @param event An event dispatched by the nested state machine spawned by a `Map` state.
|
|
1656
|
+
* @param index Index of the current iteration being processed.
|
|
1657
|
+
* @param mapStateName Name of the `Map` state being executed.
|
|
1658
|
+
* @param mapStateRawInput Raw input passed to the `Map` state being executed.
|
|
1659
|
+
*/
|
|
1660
|
+
forwardNestedMapEvent(event, index, mapStateName, mapStateRawInput) {
|
|
1661
|
+
switch (event.type) {
|
|
1662
|
+
case "ExecutionStarted":
|
|
1663
|
+
this.dispatchMapIterationStartedEvent(event, index, mapStateName, mapStateRawInput);
|
|
1664
|
+
break;
|
|
1665
|
+
case "ExecutionSucceeded":
|
|
1666
|
+
this.dispatchMapIterationSucceededEvent(event, index, mapStateName, mapStateRawInput);
|
|
1667
|
+
break;
|
|
1668
|
+
case "ExecutionFailed":
|
|
1669
|
+
this.dispatchMapIterationFailedEvent(event, index, mapStateName, mapStateRawInput);
|
|
1670
|
+
break;
|
|
1671
|
+
case "StateEntered":
|
|
1672
|
+
case "StateExited":
|
|
1673
|
+
event.index = index;
|
|
1674
|
+
this.dispatch(event);
|
|
1675
|
+
break;
|
|
1676
|
+
case "ExecutionAborted":
|
|
1677
|
+
case "ExecutionTimeout":
|
|
1678
|
+
return;
|
|
1679
|
+
default:
|
|
1680
|
+
this.dispatch(event);
|
|
1681
|
+
break;
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
/**
|
|
1685
|
+
* Forward nested events created by `Parallel` states, to the root state machine event logger.
|
|
1686
|
+
* @param event An event dispatched by the nested state machines spawned by a `Parallel` state.
|
|
1687
|
+
* @param parallelStateName Name of the `Parallel` state being executed.
|
|
1688
|
+
* @param parallelStateRawInput Raw input passed to the `Parallel` state being executed.
|
|
1689
|
+
*/
|
|
1690
|
+
forwardNestedParallelEvent(event, parallelStateName, parallelStateRawInput) {
|
|
1691
|
+
switch (event.type) {
|
|
1692
|
+
case "ExecutionStarted":
|
|
1693
|
+
this.dispatchParallelBranchStartedEvent(event, parallelStateName, parallelStateRawInput);
|
|
1694
|
+
break;
|
|
1695
|
+
case "ExecutionSucceeded":
|
|
1696
|
+
this.dispatchParallelBranchSucceededEvent(event, parallelStateName, parallelStateRawInput);
|
|
1697
|
+
break;
|
|
1698
|
+
case "ExecutionFailed":
|
|
1699
|
+
this.dispatchParallelBranchFailedEvent(event, parallelStateName, parallelStateRawInput);
|
|
1700
|
+
break;
|
|
1701
|
+
case "ExecutionAborted":
|
|
1702
|
+
case "ExecutionTimeout":
|
|
1703
|
+
return;
|
|
1704
|
+
default:
|
|
1705
|
+
this.dispatch(event);
|
|
1706
|
+
break;
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
dispatchExecutionStartedEvent(input) {
|
|
1710
|
+
this.dispatch({ type: "ExecutionStarted", timestamp: Date.now(), input });
|
|
1711
|
+
}
|
|
1712
|
+
dispatchExecutionSucceededEvent(output) {
|
|
1713
|
+
this.dispatch({ type: "ExecutionSucceeded", timestamp: Date.now(), output });
|
|
1714
|
+
this.close();
|
|
1715
|
+
}
|
|
1716
|
+
dispatchExecutionFailedEvent(error) {
|
|
1717
|
+
this.dispatch({ type: "ExecutionFailed", timestamp: Date.now(), Error: error.name, Cause: error.message });
|
|
1718
|
+
this.close();
|
|
1719
|
+
}
|
|
1720
|
+
dispatchExecutionAbortedEvent() {
|
|
1721
|
+
this.dispatch({ type: "ExecutionAborted", timestamp: Date.now() });
|
|
1722
|
+
this.close();
|
|
1723
|
+
}
|
|
1724
|
+
dispatchExecutionTimeoutEvent() {
|
|
1725
|
+
this.dispatch({ type: "ExecutionTimeout", timestamp: Date.now() });
|
|
1726
|
+
this.close();
|
|
1727
|
+
}
|
|
1728
|
+
dispatchStateEnteredEvent(stateName, stateType, input) {
|
|
1729
|
+
this.dispatch({
|
|
1730
|
+
type: "StateEntered",
|
|
1731
|
+
timestamp: Date.now(),
|
|
1732
|
+
state: { name: stateName, type: stateType, input }
|
|
1733
|
+
});
|
|
1734
|
+
}
|
|
1735
|
+
dispatchStateExitedEvent(stateName, stateType, input, output) {
|
|
1736
|
+
this.dispatch({
|
|
1737
|
+
type: "StateExited",
|
|
1738
|
+
timestamp: Date.now(),
|
|
1739
|
+
state: { name: stateName, type: stateType, input, output }
|
|
1740
|
+
});
|
|
1741
|
+
}
|
|
1742
|
+
dispatchMapIterationStartedEvent(event, index, mapStateName, mapStateRawInput) {
|
|
1743
|
+
this.dispatch({
|
|
1744
|
+
...event,
|
|
1745
|
+
type: "MapIterationStarted",
|
|
1746
|
+
index,
|
|
1747
|
+
parentState: { type: "Map", name: mapStateName, input: mapStateRawInput }
|
|
1748
|
+
});
|
|
1749
|
+
}
|
|
1750
|
+
dispatchMapIterationSucceededEvent(event, index, mapStateName, mapStateRawInput) {
|
|
1751
|
+
this.dispatch({
|
|
1752
|
+
...event,
|
|
1753
|
+
type: "MapIterationSucceeded",
|
|
1754
|
+
index,
|
|
1755
|
+
parentState: { type: "Map", name: mapStateName, input: mapStateRawInput }
|
|
1756
|
+
});
|
|
1757
|
+
}
|
|
1758
|
+
dispatchMapIterationFailedEvent(event, index, mapStateName, mapStateRawInput) {
|
|
1759
|
+
this.dispatch({
|
|
1760
|
+
...event,
|
|
1761
|
+
type: "MapIterationFailed",
|
|
1762
|
+
index,
|
|
1763
|
+
parentState: { type: "Map", name: mapStateName, input: mapStateRawInput }
|
|
1764
|
+
});
|
|
1765
|
+
}
|
|
1766
|
+
dispatchParallelBranchStartedEvent(event, parallelStateName, parallelStateRawInput) {
|
|
1767
|
+
this.dispatch({
|
|
1768
|
+
...event,
|
|
1769
|
+
type: "ParallelBranchStarted",
|
|
1770
|
+
parentState: { type: "Parallel", name: parallelStateName, input: parallelStateRawInput }
|
|
1771
|
+
});
|
|
1772
|
+
}
|
|
1773
|
+
dispatchParallelBranchSucceededEvent(event, parallelStateName, parallelStateRawInput) {
|
|
1774
|
+
this.dispatch({
|
|
1775
|
+
...event,
|
|
1776
|
+
type: "ParallelBranchSucceeded",
|
|
1777
|
+
parentState: { type: "Parallel", name: parallelStateName, input: parallelStateRawInput }
|
|
1778
|
+
});
|
|
1779
|
+
}
|
|
1780
|
+
dispatchParallelBranchFailedEvent(event, parallelStateName, parallelStateRawInput) {
|
|
1781
|
+
this.dispatch({
|
|
1782
|
+
...event,
|
|
1783
|
+
type: "ParallelBranchFailed",
|
|
1784
|
+
parentState: { type: "Parallel", name: parallelStateName, input: parallelStateRawInput }
|
|
1785
|
+
});
|
|
1786
|
+
}
|
|
1787
|
+
close() {
|
|
1788
|
+
this.isLoggerClosed = true;
|
|
1789
|
+
this.eventTarget.dispatchEvent(new Event("newEvent"));
|
|
1790
|
+
}
|
|
1791
|
+
dispatch(event) {
|
|
1792
|
+
if (this.isLoggerClosed)
|
|
1793
|
+
return;
|
|
1794
|
+
this.eventQueue.push(event);
|
|
1795
|
+
this.eventTarget.dispatchEvent(new Event("newEvent"));
|
|
1796
|
+
}
|
|
1797
|
+
waitForNewEvent() {
|
|
1798
|
+
if (this.isLoggerClosed)
|
|
1799
|
+
return;
|
|
1800
|
+
return new Promise((resolve) => {
|
|
1801
|
+
this.eventTarget.addEventListener("newEvent", resolve, { once: true });
|
|
1802
|
+
});
|
|
1803
|
+
}
|
|
1804
|
+
};
|
|
1805
|
+
|
|
1585
1806
|
// src/stateMachine/StateMachine.ts
|
|
1586
1807
|
import aslValidator from "asl-validator";
|
|
1587
1808
|
import cloneDeep3 from "lodash/cloneDeep.js";
|
|
@@ -1593,14 +1814,16 @@ var StateMachine = class {
|
|
|
1593
1814
|
* These options also apply to state machines defined in the `Iterator` field of `Map` states and in the `Branches` field of `Parallel` states.
|
|
1594
1815
|
*/
|
|
1595
1816
|
constructor(definition, stateMachineOptions) {
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1817
|
+
if (!stateMachineOptions?.validationOptions?._noValidate) {
|
|
1818
|
+
const { isValid, errorsText } = aslValidator(definition, {
|
|
1819
|
+
checkArn: true,
|
|
1820
|
+
checkPaths: true,
|
|
1821
|
+
...stateMachineOptions?.validationOptions
|
|
1822
|
+
});
|
|
1823
|
+
if (!isValid) {
|
|
1824
|
+
throw new Error(`State machine definition is invalid, see error(s) below:
|
|
1603
1825
|
${errorsText("\n")}`);
|
|
1826
|
+
}
|
|
1604
1827
|
}
|
|
1605
1828
|
this.definition = definition;
|
|
1606
1829
|
this.stateMachineOptions = stateMachineOptions;
|
|
@@ -1610,6 +1833,9 @@ var StateMachine = class {
|
|
|
1610
1833
|
* If the execution fails, the result will throw an `ExecutionError` explaining why the
|
|
1611
1834
|
* execution failed.
|
|
1612
1835
|
*
|
|
1836
|
+
* If the execution times out because the number of seconds specified in
|
|
1837
|
+
* the `TimeoutSeconds` top-level field has elapsed, the result will throw an `ExecutionTimeoutError`.
|
|
1838
|
+
*
|
|
1613
1839
|
* By default, if the execution is aborted, the result will throw an `ExecutionAbortedError`. This behavior can be changed by setting
|
|
1614
1840
|
* the `noThrowOnAbort` option to `true`, in which case the result will be `null`.
|
|
1615
1841
|
*
|
|
@@ -1618,30 +1844,47 @@ var StateMachine = class {
|
|
|
1618
1844
|
*/
|
|
1619
1845
|
run(input, options) {
|
|
1620
1846
|
const abortController = new AbortController();
|
|
1847
|
+
const eventLogger = new EventLogger();
|
|
1621
1848
|
let onAbortHandler;
|
|
1622
1849
|
const settleOnAbort = new Promise((resolve, reject) => {
|
|
1623
1850
|
if (options?.noThrowOnAbort) {
|
|
1624
|
-
onAbortHandler = () =>
|
|
1851
|
+
onAbortHandler = () => {
|
|
1852
|
+
eventLogger.dispatchExecutionAbortedEvent();
|
|
1853
|
+
resolve(null);
|
|
1854
|
+
};
|
|
1625
1855
|
} else {
|
|
1626
|
-
onAbortHandler = () =>
|
|
1856
|
+
onAbortHandler = () => {
|
|
1857
|
+
eventLogger.dispatchExecutionAbortedEvent();
|
|
1858
|
+
reject(new ExecutionAbortedError());
|
|
1859
|
+
};
|
|
1627
1860
|
}
|
|
1628
1861
|
abortController.signal.addEventListener("abort", onAbortHandler);
|
|
1629
1862
|
});
|
|
1630
|
-
let rejectOnTimeout
|
|
1631
|
-
|
|
1863
|
+
let rejectOnTimeout;
|
|
1864
|
+
let timeoutId;
|
|
1865
|
+
if (this.definition.TimeoutSeconds !== void 0) {
|
|
1632
1866
|
rejectOnTimeout = new Promise((_, reject) => {
|
|
1633
|
-
setTimeout(() => {
|
|
1867
|
+
timeoutId = setTimeout(() => {
|
|
1634
1868
|
abortController.signal.removeEventListener("abort", onAbortHandler);
|
|
1635
1869
|
abortController.abort();
|
|
1636
|
-
|
|
1870
|
+
eventLogger.dispatchExecutionTimeoutEvent();
|
|
1871
|
+
reject(new ExecutionTimeoutError());
|
|
1637
1872
|
}, this.definition.TimeoutSeconds * 1e3);
|
|
1638
1873
|
});
|
|
1639
1874
|
}
|
|
1640
|
-
const executionResult = this.execute(
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1875
|
+
const executionResult = this.execute(
|
|
1876
|
+
input,
|
|
1877
|
+
{
|
|
1878
|
+
stateMachineOptions: this.stateMachineOptions,
|
|
1879
|
+
runOptions: { ...options, _rootAbortSignal: options?._rootAbortSignal ?? abortController.signal },
|
|
1880
|
+
abortSignal: abortController.signal,
|
|
1881
|
+
eventLogger
|
|
1882
|
+
},
|
|
1883
|
+
() => {
|
|
1884
|
+
abortController.signal.removeEventListener("abort", onAbortHandler);
|
|
1885
|
+
clearTimeout(timeoutId);
|
|
1886
|
+
}
|
|
1887
|
+
);
|
|
1645
1888
|
const racingPromises = [executionResult, settleOnAbort];
|
|
1646
1889
|
if (rejectOnTimeout) {
|
|
1647
1890
|
racingPromises.push(rejectOnTimeout);
|
|
@@ -1649,37 +1892,45 @@ var StateMachine = class {
|
|
|
1649
1892
|
const result = Promise.race(racingPromises);
|
|
1650
1893
|
return {
|
|
1651
1894
|
abort: () => abortController.abort(),
|
|
1895
|
+
eventLogs: eventLogger.getEvents(),
|
|
1652
1896
|
result
|
|
1653
1897
|
};
|
|
1654
1898
|
}
|
|
1655
1899
|
/**
|
|
1656
1900
|
* Helper method that handles the execution of the machine states and the transitions between them.
|
|
1657
1901
|
*/
|
|
1658
|
-
async execute(input, options) {
|
|
1902
|
+
async execute(input, options, cleanupFn) {
|
|
1903
|
+
options.eventLogger.dispatchExecutionStartedEvent(input);
|
|
1904
|
+
const context = options.runOptions?.context ?? {};
|
|
1659
1905
|
let currState = this.definition.States[this.definition.StartAt];
|
|
1660
1906
|
let currStateName = this.definition.StartAt;
|
|
1661
1907
|
let currInput = cloneDeep3(input);
|
|
1662
1908
|
let currResult = null;
|
|
1663
1909
|
let nextState = "";
|
|
1664
1910
|
let isEndState = false;
|
|
1665
|
-
let context = {};
|
|
1666
1911
|
try {
|
|
1667
1912
|
do {
|
|
1913
|
+
options.eventLogger.dispatchStateEnteredEvent(currStateName, currState.Type, currInput);
|
|
1668
1914
|
const stateExecutor = new StateExecutor(currStateName, currState);
|
|
1669
1915
|
({ stateResult: currResult, nextState, isEndState } = await stateExecutor.execute(currInput, context, options));
|
|
1916
|
+
options.eventLogger.dispatchStateExitedEvent(currStateName, currState.Type, currInput, currResult);
|
|
1670
1917
|
currInput = currResult;
|
|
1671
1918
|
currState = this.definition.States[nextState];
|
|
1672
1919
|
currStateName = nextState;
|
|
1673
1920
|
} while (!isEndState && !options.abortSignal.aborted);
|
|
1674
1921
|
} catch (error) {
|
|
1922
|
+
options.eventLogger.dispatchExecutionFailedEvent(error);
|
|
1675
1923
|
throw new ExecutionError(error);
|
|
1924
|
+
} finally {
|
|
1925
|
+
cleanupFn();
|
|
1676
1926
|
}
|
|
1927
|
+
options.eventLogger.dispatchExecutionSucceededEvent(currResult);
|
|
1677
1928
|
return currResult;
|
|
1678
1929
|
}
|
|
1679
1930
|
};
|
|
1680
1931
|
export {
|
|
1681
1932
|
ExecutionAbortedError,
|
|
1682
1933
|
ExecutionError,
|
|
1683
|
-
|
|
1934
|
+
ExecutionTimeoutError,
|
|
1684
1935
|
StateMachine
|
|
1685
1936
|
};
|