Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 0 additions & 31 deletions .eslintrc

This file was deleted.

17 changes: 11 additions & 6 deletions .github/workflows/stepfunctions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,20 @@ jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [10.x, 12.x, 14.x]
node-version: [20.x, 24.x, 26.x]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: yarn install --ci
- run: yarn test
- run: npm install
- run: npm run lint
- run: npm test
- name: Upload coverage
uses: codecov/codecov-action@v1.0.12
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
continue-on-error: true
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
npx lint-staged
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
coverage
package-lock.json
2 changes: 1 addition & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
"singleQuote": true,
"trailingComma": "all",
"useTabs": false
}
}
27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,26 @@ Use `console.table` to list down the transitions that occured.
`abort` is made available within the replaced Task handlers made with `bindTaskResource`. this allows you to abort a call
from within a handler itself.

## Requirements

Node.js `>= 20`. The library is tested on Node 20, 24, and 26.

## Support

The spec implemented in https://states-language.net/spec.html is fully supported by this library besides the ones below:
The spec implemented in https://states-language.net/spec.html is supported by this library, including the newer (post-2020) JSONPath additions:

- **Intrinsic functions** inside `Parameters`, `ItemSelector` and `ResultSelector` payload templates: `States.Format`, `States.StringToJson`, `States.JsonToString`, `States.Array`, `States.ArrayPartition`, `States.ArrayContains`, `States.ArrayRange`, `States.ArrayGetItem`, `States.ArrayLength`, `States.ArrayUnique`, `States.Base64Encode`, `States.Base64Decode`, `States.Hash`, `States.JsonMerge`, `States.MathRandom`, `States.MathAdd`, `States.StringSplit` and `States.UUID` (including nested calls).
- **`Choice` operators** `StringMatches`, `IsNull`, `IsPresent`, `IsBoolean`, `IsNumeric`, `IsString`, `IsTimestamp`, and all the `*Path` comparison variants (e.g. `NumericGreaterThanPath`, `StringEqualsPath`).
- **`ResultSelector`** on `Task`, `Map` and `Parallel` (applied before `ResultPath` and `OutputPath`).
- **`Map`** accepts `ItemProcessor`/`ItemSelector` as aliases of `Iterator`/`Parameters`, and honours `MaxConcurrency`, `ItemBatcher` (`MaxItemsPerBatch`, `BatchInput`) and the `ToleratedFailureCount`/`ToleratedFailurePercentage` thresholds.

### JSONata (Nov 2024)

Set `QueryLanguage: "JSONata"` on the state machine or an individual state. `{% … %}` expressions are evaluated with [`jsonata`](https://www.npmjs.com/package/jsonata), with the `$states` object (`$states.input`, `$states.result`, `$states.context`) and any assigned variables bound. Supported on `Pass` (`Output`), `Task` (`Arguments`, `Output`), `Choice` (`Condition`), `Map` (`Items`, `ItemSelector`, `Output`) and `Parallel` (`Output`).

### Variables (Nov 2024)

`Assign` is supported in both JSONPath and JSONata modes. Assigned variables are referenced as `$name` in later states and follow AWS scoping: a `Map`/`Parallel` child can read outer variables but its own assignments do not leak back to the parent scope.

**Experimental**

Expand All @@ -127,6 +144,11 @@ The spec implemented in https://states-language.net/spec.html is fully supported

The above features are labeled experimental because it cannot be fully spec compliant(yet) due to AWS specific cases.

**Not yet supported**

- JSONata on `Wait`/`Succeed`/`Fail`, and the `$states.errorOutput` binding inside a `Catch`.
- Distributed `Map` infrastructure (`ItemReader`, `ResultWriter`); `ItemProcessor` always runs inline.

## Caveats

1. `Wait` will wait for at most 30 seconds. This is because it's expected that this library
Expand All @@ -139,12 +161,13 @@ PR's are welcome to help finish the ones below :)

- [ ] Change arn in bindTaskResource instead of the State name
- [ ] Run `sls invoke local` instead of binding resolvers
- [ ] Typescript typings
- [x] Typescript typings
- [ ] Run via CLI
- [ ] Remove the "experimental" label on retry and catch
- [ ] More accurate timing mechanism
- [ ] use `jest.fakeTimers()` in the test
- [ ] Walk through states ala "generator" style. e.g, `yield sm.next()`
- [x] Support the JSONata query language and Variables (`Assign`)

## License

Expand Down
21 changes: 21 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const js = require('@eslint/js');
const globals = require('globals');

module.exports = [
js.configs.recommended,
{
languageOptions: {
ecmaVersion: 2022,
sourceType: 'commonjs',
globals: {
...globals.node,
...globals.jest,
},
},
// Formatting is owned by Prettier (enforced via `prettier --check` in the
// lint script); ESLint only covers code quality here.
rules: {
'no-unused-vars': ['error', { args: 'none', varsIgnorePattern: '^_' }],
},
},
];
52 changes: 52 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { EventEmitter } from 'events';

declare namespace StepFunction {
/** Options accepted by `startExecution`. */
interface ExecutionOptions {
/** Respect the real durations of `Wait` states instead of capping them. */
respectTime?: boolean;
/** Maximum number of seconds a `Wait` state may block for. Defaults to 30. */
maxWaitTime?: number;
/** Maximum number of branches/iterations run concurrently. Defaults to 10. */
maxConcurrency?: number;
}

/** A bound Task handler, e.g. a Serverless/Lambda handler. */
type TaskResource = (input: any) => any;

/** An Amazon States Language state machine definition. */
type StateMachine = Record<string, any>;

interface Options {
/** Friendly name for the execution. Defaults to the StateMachine `StartAt`. */
Name?: string;
StateMachine: StateMachine;
/** Map of Task state name to its handler. */
Resources?: Record<string, TaskResource>;
}
}

/**
* An in-memory AWS Step Functions / Amazon States Language interpreter, made to
* run Node.js Lambda handlers inside a test environment.
*/
declare class StepFunction extends EventEmitter {
constructor(sm: StepFunction.Options);

/** Start an execution, passing `input` to the first state. */
startExecution(
input?: any,
opts?: StepFunction.ExecutionOptions,
): Promise<void>;

/** Return the final output of the most recent execution. */
getExecutionResult(): any;

/** Pretty-print the recorded transitions with `console.table`. */
getReport(): void;

/** Replace a Task's resource with the provided handler. */
bindTaskResource(task: string, fn: StepFunction.TaskResource): void;
}

export = StepFunction;
Loading
Loading