aws-local-stepfunctions 0.7.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 +80 -4
- package/build/CLI.cjs +46 -3
- package/build/main.browser.esm.js +322 -85
- package/build/main.d.ts +95 -19
- package/build/main.node.cjs +322 -85
- package/build/main.node.esm.js +322 -85
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -2,7 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
A TypeScript implementation of the [Amazon States Language specification](https://states-language.net/spec.html).
|
|
4
4
|
|
|
5
|
-
This package lets you run AWS Step Functions completely locally, both in Node.js and in the browser!
|
|
5
|
+
This package lets you run AWS Step Functions state machines completely locally, both in Node.js and in the browser!
|
|
6
|
+
|
|
7
|
+
<p align="left">
|
|
8
|
+
<a href="/LICENSE">
|
|
9
|
+
<img alt="Project license (MIT)" src="https://img.shields.io/github/license/nibble-4bits/aws-local-stepfunctions">
|
|
10
|
+
</a>
|
|
11
|
+
<a href="https://github.com/nibble-4bits/aws-local-stepfunctions/actions/workflows/pr-run-tests.yml">
|
|
12
|
+
<img alt="GitHub Workflow Status (with event)" src="https://img.shields.io/github/actions/workflow/status/nibble-4bits/aws-local-stepfunctions/pr-run-tests.yml">
|
|
13
|
+
</a>
|
|
14
|
+
<a href="https://www.npmjs.com/package/aws-local-stepfunctions">
|
|
15
|
+
<img alt="Latest npm version" src="https://img.shields.io/npm/v/aws-local-stepfunctions">
|
|
16
|
+
</a>
|
|
17
|
+
<a href="https://www.npmjs.com/package/aws-local-stepfunctions">
|
|
18
|
+
<img alt="node-lts" src="https://img.shields.io/node/v-lts/aws-local-stepfunctions">
|
|
19
|
+
</a>
|
|
20
|
+
<a href="https://www.npmjs.com/package/aws-local-stepfunctions">
|
|
21
|
+
<img alt="npm type definitions" src="https://img.shields.io/npm/types/aws-local-stepfunctions">
|
|
22
|
+
</a>
|
|
23
|
+
</p>
|
|
6
24
|
|
|
7
25
|
## Table of contents
|
|
8
26
|
|
|
@@ -22,6 +40,7 @@ This package lets you run AWS Step Functions completely locally, both in Node.js
|
|
|
22
40
|
- [Overriding Task and Wait states](#overriding-task-and-wait-states)
|
|
23
41
|
- [Task state override](#task-state-override)
|
|
24
42
|
- [Wait state override](#wait-state-override)
|
|
43
|
+
- [Passing a custom Context Object](#passing-a-custom-context-object)
|
|
25
44
|
- [Disabling ASL validations](#disabling-asl-validations)
|
|
26
45
|
- [Exit codes](#exit-codes)
|
|
27
46
|
- [Examples](#examples)
|
|
@@ -119,8 +138,9 @@ const stateMachine = new StateMachine(machineDefinition, {
|
|
|
119
138
|
|
|
120
139
|
Runs the state machine with the given `input` parameter and returns an object with the following properties:
|
|
121
140
|
|
|
141
|
+
- `result`: A `Promise` that resolves with the result of the execution once it terminates.
|
|
122
142
|
- `abort`: A function that takes no parameters and doesn't return any value. If called, [aborts the execution](/docs/feature-support.md#abort-a-running-execution) and throws an `ExecutionAbortedError`, unless the `noThrowOnAbort` option is set.
|
|
123
|
-
- `
|
|
143
|
+
- `eventLogs`: An `AsyncGenerator` that [produces a log of events](/docs/feature-support.md#execution-event-logs) as the execution runs. To learn more about the events, their type, and their format, see the [following document](/docs/execution-event-logs.md).
|
|
124
144
|
|
|
125
145
|
Each execution is independent of all others, meaning that you can concurrently call this method as many times as needed, without worrying about race conditions.
|
|
126
146
|
|
|
@@ -132,6 +152,7 @@ Each execution is independent of all others, meaning that you can concurrently c
|
|
|
132
152
|
- `taskResourceLocalHandlers?`: An [object that overrides](/docs/feature-support.md#task-state-resource-override) the resource of the specified `Task` states to run a local function.
|
|
133
153
|
- `waitTimeOverrides?`: An [object that overrides](/docs/feature-support.md#wait-state-duration-override) the wait duration of the specified `Wait` states. The specified override duration should be in milliseconds.
|
|
134
154
|
- `noThrowOnAbort?`: If this option is set to `true`, aborting the execution will simply return `null` as result instead of throwing.
|
|
155
|
+
- `context?`: An object that will be used as the [Context Object](https://docs.aws.amazon.com/step-functions/latest/dg/input-output-contextobject.html) for the execution. If not passed, the Context Object will default to an empty object. This option is useful to mock the Context Object in case your definition references it in a JSONPath.
|
|
135
156
|
|
|
136
157
|
#### Basic example:
|
|
137
158
|
|
|
@@ -212,7 +233,11 @@ Note that each line of the output corresponds to the result of each input, in th
|
|
|
212
233
|
|
|
213
234
|
### Passing input from stdin
|
|
214
235
|
|
|
215
|
-
`local-sfn` can also read the execution input from the standard input.
|
|
236
|
+
`local-sfn` can also read the execution input from the standard input.
|
|
237
|
+
|
|
238
|
+
If the first line of stdin can be parsed as a single JSON value, then `local-sfn` will consider each line as an input. Otherwise, the entire stdin will be considered as a single JSON input.
|
|
239
|
+
|
|
240
|
+
For example, assume you have the following text file, called `inputs.txt`, and you want to pass the contents of the file as inputs to `local-sfn`:
|
|
216
241
|
|
|
217
242
|
```txt
|
|
218
243
|
{ "num1": 1, "num2": 2 }
|
|
@@ -220,6 +245,8 @@ Note that each line of the output corresponds to the result of each input, in th
|
|
|
220
245
|
{ "num1": 5, "num2": 6 }
|
|
221
246
|
```
|
|
222
247
|
|
|
248
|
+
Because the first line is parsable as JSON, `local-sfn` will process each line as a single input.
|
|
249
|
+
|
|
223
250
|
You can then run the following command to pass the inputs of the text file to `local-sfn`:
|
|
224
251
|
|
|
225
252
|
```sh
|
|
@@ -232,7 +259,16 @@ Alternatively, using input redirection:
|
|
|
232
259
|
local-sfn -f state-machine.json < inputs.txt
|
|
233
260
|
```
|
|
234
261
|
|
|
235
|
-
|
|
262
|
+
On the other hand, assume you have this additional file, called `input.json`:
|
|
263
|
+
|
|
264
|
+
```json
|
|
265
|
+
{
|
|
266
|
+
"num1": 5,
|
|
267
|
+
"num2": 3
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
If you pass this file as input, `local-sfn` will automatically detect that it is a single, multiline JSON value and process it as a single value.
|
|
236
272
|
|
|
237
273
|
### Overriding Task and Wait states
|
|
238
274
|
|
|
@@ -299,6 +335,46 @@ local-sfn \
|
|
|
299
335
|
|
|
300
336
|
This command would execute the state machine, and override `Wait` states `WaitResponse` and `PauseUntilSignal` to pause the execution for 1500 and 250 milliseconds, respectively. The `Delay` state wouldn't be paused at all, since the override value is set to 0.
|
|
301
337
|
|
|
338
|
+
### Passing a custom Context Object
|
|
339
|
+
|
|
340
|
+
If the JSONPaths in your definition reference the Context Object, you can provide a mock Context Object by passing either the `--context` or the `--context-file` option. For example, given the following definition:
|
|
341
|
+
|
|
342
|
+
```json
|
|
343
|
+
{
|
|
344
|
+
"StartAt": "Get execution context data",
|
|
345
|
+
"States": {
|
|
346
|
+
"Get execution context data": {
|
|
347
|
+
"Type": "Pass",
|
|
348
|
+
"Parameters": {
|
|
349
|
+
"execId.$": "$$.Execution.Id",
|
|
350
|
+
"execName.$": "$$.Execution.Name"
|
|
351
|
+
},
|
|
352
|
+
"End": true
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
And given the following `context.json` file:
|
|
359
|
+
|
|
360
|
+
```json
|
|
361
|
+
{
|
|
362
|
+
"Execution": {
|
|
363
|
+
"Id": "arn:aws:states:us-east-1:123456789012:execution:stateMachineName:executionName",
|
|
364
|
+
"Name": "executionName"
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
You could provide the Context Object to the execution in the following manner:
|
|
370
|
+
|
|
371
|
+
```sh
|
|
372
|
+
local-sfn \
|
|
373
|
+
-f state-machine.json \
|
|
374
|
+
--context-file context.json \
|
|
375
|
+
'{}'
|
|
376
|
+
```
|
|
377
|
+
|
|
302
378
|
### Disabling ASL validations
|
|
303
379
|
|
|
304
380
|
Before attempting to run the state machine with the given inputs, the state machine definition itself is validated to check that:
|
package/build/CLI.cjs
CHANGED
|
@@ -38,7 +38,7 @@ var import_readline = __toESM(require("readline"), 1);
|
|
|
38
38
|
var import_commander = require("commander");
|
|
39
39
|
|
|
40
40
|
// package.json
|
|
41
|
-
var version = "0.
|
|
41
|
+
var version = "1.0.0";
|
|
42
42
|
|
|
43
43
|
// src/cli/ArgumentParsers.ts
|
|
44
44
|
var import_fs = require("fs");
|
|
@@ -110,6 +110,33 @@ function parseOverrideWaitOption(value, previous = {}) {
|
|
|
110
110
|
previous[waitStateName] = Number(duration);
|
|
111
111
|
return previous;
|
|
112
112
|
}
|
|
113
|
+
function parseContextOption(command, context) {
|
|
114
|
+
const jsonOrError = tryJSONParse(context);
|
|
115
|
+
if (jsonOrError instanceof Error) {
|
|
116
|
+
command.error(
|
|
117
|
+
`error: parsing of context object passed in option '--context <json>' failed: ${jsonOrError.message}`,
|
|
118
|
+
{
|
|
119
|
+
exitCode: 1 /* PreExecutionFailure */
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
return jsonOrError;
|
|
124
|
+
}
|
|
125
|
+
function parseContextFileOption(command, contextFile) {
|
|
126
|
+
let file;
|
|
127
|
+
try {
|
|
128
|
+
file = (0, import_fs.readFileSync)(contextFile).toString();
|
|
129
|
+
} catch (error) {
|
|
130
|
+
command.error(`error: ${error.message}`, { exitCode: 1 /* PreExecutionFailure */ });
|
|
131
|
+
}
|
|
132
|
+
const jsonOrError = tryJSONParse(file);
|
|
133
|
+
if (jsonOrError instanceof Error) {
|
|
134
|
+
command.error(`error: parsing of context object in file '${contextFile}' failed: ${jsonOrError.message}`, {
|
|
135
|
+
exitCode: 1 /* PreExecutionFailure */
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return jsonOrError;
|
|
139
|
+
}
|
|
113
140
|
function parseInputArguments(command, value, previous = []) {
|
|
114
141
|
const jsonOrError = tryJSONParse(value);
|
|
115
142
|
if (jsonOrError instanceof Error) {
|
|
@@ -139,7 +166,8 @@ async function commandAction(inputs, options, command) {
|
|
|
139
166
|
overrides: {
|
|
140
167
|
taskResourceLocalHandlers: options.overrideTask,
|
|
141
168
|
waitTimeOverrides: options.overrideWait
|
|
142
|
-
}
|
|
169
|
+
},
|
|
170
|
+
context: options.context ?? options.contextFile
|
|
143
171
|
});
|
|
144
172
|
return result;
|
|
145
173
|
});
|
|
@@ -204,11 +232,21 @@ Example calls:
|
|
|
204
232
|
"-w, --override-wait <mapping>",
|
|
205
233
|
"Override a Wait state to pause for the specified amount of milliseconds, instead of pausing for the duration specified in the state definition. The mapping value has to be provided in the format [WaitStateToOverride]:[number]."
|
|
206
234
|
).argParser(parseOverrideWaitOption)
|
|
235
|
+
).addOption(
|
|
236
|
+
new import_commander.Option(
|
|
237
|
+
"--context <json>",
|
|
238
|
+
"A JSON object that will be passed to each execution as the context object."
|
|
239
|
+
).argParser((value) => parseContextOption(command, value))
|
|
240
|
+
).addOption(
|
|
241
|
+
new import_commander.Option(
|
|
242
|
+
"--context-file <path>",
|
|
243
|
+
"Path to a file containing a JSON object that will be passed to each execution as the context object."
|
|
244
|
+
).argParser((value) => parseContextFileOption(command, value))
|
|
207
245
|
).addOption(
|
|
208
246
|
new import_commander.Option("--no-jsonpath-validation", "Disable validation of JSONPath strings in the state machine definition.")
|
|
209
247
|
).addOption(new import_commander.Option("--no-arn-validation", "Disable validation of ARNs in the state machine definition.")).argument(
|
|
210
248
|
"[inputs...]",
|
|
211
|
-
"Input data for the state machine, can be any valid JSON value. Each input represents a state machine execution
|
|
249
|
+
"Input data for the state machine, can be any valid JSON value. Each input represents a state machine execution.\n\nWhen reading from the standard input, if the first line can be parsed as a single JSON value, then each line will be considered as an input. Otherwise, the entire standard input will be considered as a single JSON input.",
|
|
212
250
|
(value, previous) => parseInputArguments(command, value, previous)
|
|
213
251
|
).hook("preAction", preActionHook).action(commandAction);
|
|
214
252
|
return command;
|
|
@@ -226,6 +264,11 @@ if (require.main === module) {
|
|
|
226
264
|
for await (const line of rl) {
|
|
227
265
|
stdin.push(line);
|
|
228
266
|
}
|
|
267
|
+
const firstLineJSON = tryJSONParse(stdin[0]);
|
|
268
|
+
if (firstLineJSON instanceof Error) {
|
|
269
|
+
await program.parseAsync([...process.argv, stdin.join("").trim()]);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
229
272
|
await program.parseAsync([...process.argv, ...stdin.filter((line) => line)]);
|
|
230
273
|
}
|
|
231
274
|
})();
|