sfn-diagram 1.3.0 → 1.4.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 +54 -1002
- package/custom-elements.json +275 -0
- package/dist/cli.js +882 -125
- package/dist/element-auto.cjs +3750 -0
- package/dist/element-auto.d.cts +1 -0
- package/dist/element-auto.d.ts +1 -0
- package/dist/element-auto.js +3727 -0
- package/dist/element.cjs +3735 -0
- package/dist/element.d.cts +226 -0
- package/dist/element.d.ts +226 -0
- package/dist/element.js +3710 -0
- package/dist/index.cjs +784 -123
- package/dist/index.d.cts +48 -24
- package/dist/index.d.ts +48 -24
- package/dist/index.js +784 -124
- package/dist/png.cjs +244 -36
- package/dist/png.d.cts +9 -0
- package/dist/png.d.ts +9 -0
- package/dist/png.js +244 -36
- package/package.json +51 -12
package/README.md
CHANGED
|
@@ -4,83 +4,53 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/sfn-diagram)
|
|
5
5
|
[](https://github.com/yusufaf/sfn-diagram/actions/workflows/unit-test.yml)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
|
-
[](https://sfn.yusufaf.dev)
|
|
8
8
|
|
|
9
|
-
Generate
|
|
9
|
+
Generate diagrams from AWS Step Functions ASL (Amazon States Language) definitions, CloudFormation/SAM/CDK templates, or live AWS state machines. Outputs SVG, Mermaid, standalone HTML, and PNG.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
**📖 [Documentation](https://sfn.yusufaf.dev)** · **▶ [Live playground](https://sfn.yusufaf.dev/playground/)** — paste any ASL definition and preview the diagram instantly, no install required.
|
|
12
12
|
|
|
13
13
|
<picture>
|
|
14
14
|
<source media="(prefers-color-scheme: dark)" srcset="docs/images/parallel-dark.svg">
|
|
15
15
|
<img src="docs/images/parallel-light.svg" alt="Example diagram of a Parallel state Step Functions workflow generated by sfn-diagram" width="410">
|
|
16
16
|
</picture>
|
|
17
17
|
|
|
18
|
-
##
|
|
19
|
-
|
|
20
|
-
- [What it looks like](#what-it-looks-like)
|
|
21
|
-
- [Why sfn-diagram](#why-sfn-diagram)
|
|
22
|
-
- [Features](#features)
|
|
23
|
-
- [Installation](#installation)
|
|
24
|
-
- [Runtime Support](#runtime-support)
|
|
25
|
-
- [Command-line Usage](#command-line-usage)
|
|
26
|
-
- [Docker](#docker)
|
|
27
|
-
- [Quick Start](#quick-start)
|
|
28
|
-
- [API Reference](#api-reference)
|
|
29
|
-
- [Configuration Options](#configuration-options)
|
|
30
|
-
- [Supported State Types](#supported-state-types)
|
|
31
|
-
- [Examples](#examples)
|
|
32
|
-
- [TypeScript Support](#typescript-support)
|
|
33
|
-
- [Use with your framework](#use-with-your-framework)
|
|
34
|
-
- [Ecosystem](#ecosystem)
|
|
35
|
-
- [Contributing](#contributing)
|
|
18
|
+
## Installation
|
|
36
19
|
|
|
37
|
-
|
|
20
|
+
```bash
|
|
21
|
+
npm install sfn-diagram
|
|
22
|
+
```
|
|
38
23
|
|
|
39
|
-
|
|
24
|
+
The core package pulls in **no browser engine** — SVG and Mermaid generation stay lightweight. PNG export relies on a headless browser, provided by the optional peer dependency `node-html-to-image`. Install it only if you use `sfn-diagram/png`:
|
|
40
25
|
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
"StartAt": "ValidateOrder",
|
|
44
|
-
"States": {
|
|
45
|
-
"ValidateOrder": { "Type": "Pass", "Next": "CheckStock" },
|
|
46
|
-
"CheckStock": {
|
|
47
|
-
"Type": "Choice",
|
|
48
|
-
"Choices": [{ "Variable": "$.inStock", "BooleanEquals": true, "Next": "ChargePayment" }],
|
|
49
|
-
"Default": "CancelOrder"
|
|
50
|
-
},
|
|
51
|
-
"ChargePayment": { "Type": "Task", "Resource": "arn:aws:lambda:...:charge-payment", "Next": "ShipOrder" },
|
|
52
|
-
"ShipOrder": { "Type": "Task", "Resource": "arn:aws:lambda:...:ship-order", "Next": "OrderComplete" },
|
|
53
|
-
"CancelOrder": { "Type": "Fail", "Error": "OutOfStock" },
|
|
54
|
-
"OrderComplete": { "Type": "Succeed" }
|
|
55
|
-
}
|
|
56
|
-
}
|
|
26
|
+
```bash
|
|
27
|
+
npm install sfn-diagram node-html-to-image
|
|
57
28
|
```
|
|
58
29
|
|
|
59
|
-
|
|
30
|
+
## Quick start
|
|
60
31
|
|
|
61
|
-
```
|
|
62
|
-
|
|
32
|
+
```ts
|
|
33
|
+
import { generateSvg } from 'sfn-diagram';
|
|
63
34
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
35
|
+
const { svg } = generateSvg({
|
|
36
|
+
aslDefinition: {
|
|
37
|
+
StartAt: 'Hello',
|
|
38
|
+
States: {
|
|
39
|
+
Hello: { Type: 'Pass', Next: 'World' },
|
|
40
|
+
World: { Type: 'Succeed' },
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
layout: 'TB',
|
|
44
|
+
theme: 'light',
|
|
45
|
+
});
|
|
46
|
+
```
|
|
70
47
|
|
|
71
|
-
|
|
72
|
-
OrderComplete --> [*]
|
|
48
|
+
Mermaid instead of SVG? Swap in `generateMermaid`. Rendering a live state machine, a CDK template, or a PNG? See the [quick start guide](https://sfn.yusufaf.dev/quick-start/).
|
|
73
49
|
|
|
74
|
-
|
|
75
|
-
classDef failState fill:#ffebee,stroke:#f44336,stroke-width:3px
|
|
76
|
-
classDef choiceState fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
|
|
77
|
-
classDef taskState fill:#fff3e0,stroke:#ef6c00,stroke-width:2px
|
|
50
|
+
Prefer the command line:
|
|
78
51
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
class ShipOrder taskState
|
|
82
|
-
class CancelOrder failState
|
|
83
|
-
class OrderComplete successState
|
|
52
|
+
```bash
|
|
53
|
+
npx sfn-diagram diagram my-workflow.asl.json --format svg --out diagram.svg
|
|
84
54
|
```
|
|
85
55
|
|
|
86
56
|
## Why sfn-diagram
|
|
@@ -91,7 +61,7 @@ There's no shortage of ways to look at a state machine — this is where sfn-dia
|
|
|
91
61
|
|---|---|---|---|
|
|
92
62
|
| Input | ASL, CloudFormation/SAM/CDK templates, live AWS state machines | Deployed state machine only | Manual Mermaid you write by hand |
|
|
93
63
|
| Output | SVG, Mermaid, PNG, interactive HTML | Static graph in-browser | Mermaid diagram only |
|
|
94
|
-
| CI / PR integration | [GitHub Action](
|
|
64
|
+
| CI / PR integration | [GitHub Action](https://sfn.yusufaf.dev/ecosystem/github-action/) posts a diff overlay on every PR that touches ASL | None | None |
|
|
95
65
|
| Execution overlays | Paints a real run's path/status/duration onto the diagram | Basic per-execution highlighting, console-only | Not applicable |
|
|
96
66
|
| Runs where | CLI, Node, browser, edge runtimes | AWS Console only | Web app only |
|
|
97
67
|
| Automation | Full programmatic API (`generateSvg`, `generateMermaid`, etc.) | None — UI only | None — UI only |
|
|
@@ -112,611 +82,9 @@ In short: reach for the AWS Console visualizer to eyeball a state machine you al
|
|
|
112
82
|
- **AWS SDK Integration**: Direct integration with AWS Step Functions API
|
|
113
83
|
- **Dual APIs**: Function-based and class-based interfaces
|
|
114
84
|
- **Runs Anywhere**: SVG and Mermaid generation has zero platform dependencies — works in Node, the browser, and edge runtimes
|
|
85
|
+
- **Collapse Large Diagrams**: Replace Parallel/Map containers with placeholder nodes before layout so huge diagrams stay readable, with a live toggle in the interactive HTML viewer. See the [configuration guide](https://sfn.yusufaf.dev/guides/configuration/) for `collapse` and every other option.
|
|
115
86
|
|
|
116
|
-
##
|
|
117
|
-
|
|
118
|
-
```bash
|
|
119
|
-
npm install sfn-diagram
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
The core package pulls in **no browser engine** — SVG and Mermaid generation stay lightweight. PNG export relies on a headless browser, provided by the optional peer dependency `node-html-to-image`. Install it only if you use `sfn-diagram/png`:
|
|
123
|
-
|
|
124
|
-
```bash
|
|
125
|
-
npm install sfn-diagram node-html-to-image
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
## Runtime Support
|
|
129
|
-
|
|
130
|
-
The core entry (`sfn-diagram`) builds SVG with a DOM-free string renderer, so
|
|
131
|
-
`generateSvg`, `generateMermaid`, `generateDiagram`, and `generateFromAwsResponse`
|
|
132
|
-
run in **Node, browsers, and edge runtimes** (Cloudflare Workers, Vercel Edge, Deno, Bun)
|
|
133
|
-
with no DOM polyfill.
|
|
134
|
-
|
|
135
|
-
PNG export (`sfn-diagram/png`) and the CLI are **Node-only** — they rely on a headless
|
|
136
|
-
browser (`node-html-to-image`) and Node's filesystem respectively. Because `node-html-to-image`
|
|
137
|
-
is an **optional peer dependency**, install it alongside `sfn-diagram` when you need PNG output;
|
|
138
|
-
`exportPng` throws an actionable error if it is missing.
|
|
139
|
-
|
|
140
|
-
**Node versions:** the package requires **Node >= 20**. PNG export additionally requires
|
|
141
|
-
**Node >= 22.12.0**, the floor set by `node-html-to-image` v6 — SVG, Mermaid, and HTML
|
|
142
|
-
output are unaffected and keep working on Node 20.
|
|
143
|
-
|
|
144
|
-
```ts
|
|
145
|
-
// Works in Node, browser, and edge:
|
|
146
|
-
import { generateSvg } from 'sfn-diagram';
|
|
147
|
-
|
|
148
|
-
// Node-only:
|
|
149
|
-
import { exportPng } from 'sfn-diagram/png';
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
## Command-line Usage
|
|
153
|
-
|
|
154
|
-
The package ships a CLI for use without writing any JavaScript:
|
|
155
|
-
|
|
156
|
-
```bash
|
|
157
|
-
npx sfn-diagram state.asl.json --format svg -o diagram.svg
|
|
158
|
-
npx sfn-diagram state.asl.json --format mermaid > diagram.mmd
|
|
159
|
-
cat state.asl.json | npx sfn-diagram - --format svg
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
| Flag | Description |
|
|
163
|
-
|---|---|
|
|
164
|
-
| `--format <svg\|mermaid\|png\|html>` | Output format (default: `svg`) |
|
|
165
|
-
| `-o`, `--output <path>` | Output file (required for `png`; stdout otherwise) |
|
|
166
|
-
| `--theme <light\|dark>` | Color theme for SVG/PNG/HTML (default: `light`) |
|
|
167
|
-
| `--layout <TB\|LR\|RL\|BT>` | Graph direction (default: `TB`) |
|
|
168
|
-
| `--hide-catch` | Drop error-handler (`Catch`) branches |
|
|
169
|
-
| `--hide-variables` | Drop the `$var` annotations for ASL `Assign` blocks |
|
|
170
|
-
| `--show-icons` | Draw [AWS service icons](#aws-service-icons) on Task states |
|
|
171
|
-
| `--icon-position <left\|top\|right>` | Icon placement relative to the label (default: `left`) |
|
|
172
|
-
| `--icon-size <pixels>` | Icon size in pixels (default: `24`) |
|
|
173
|
-
| `--diff <baseline>` | Compare the input (head) against a baseline definition |
|
|
174
|
-
| `--execution <history.json>` | Overlay a `GetExecutionHistory` result on the diagram |
|
|
175
|
-
| `--resolve-cfn` | Treat the input as a CloudFormation/SAM/CDK template |
|
|
176
|
-
| `--resource <logicalId>` | State machine to extract when the template has several |
|
|
177
|
-
| `-h`, `--help` / `-v`, `--version` | Show help / version and exit |
|
|
178
|
-
|
|
179
|
-
### Diff and execution overlays from the CLI
|
|
180
|
-
|
|
181
|
-
```bash
|
|
182
|
-
# Highlight what changed between two revisions of a definition
|
|
183
|
-
npx sfn-diagram head.asl.json --diff base.asl.json -o diff.svg
|
|
184
|
-
npx sfn-diagram head.asl.json --diff base.asl.json --format mermaid > diff.mmd
|
|
185
|
-
|
|
186
|
-
# Colour a diagram by what actually happened in a run
|
|
187
|
-
aws stepfunctions get-execution-history --execution-arn "$ARN" > history.json
|
|
188
|
-
npx sfn-diagram state.asl.json --execution history.json -o run.svg
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
Both flags support `--format svg` and `--format mermaid` only, and cannot be combined
|
|
192
|
-
with each other. The change/status summary is written to **stderr**, so the diagram on
|
|
193
|
-
stdout still pipes cleanly:
|
|
194
|
-
|
|
195
|
-
```
|
|
196
|
-
Diff summary:
|
|
197
|
-
Added: NewStep
|
|
198
|
-
Modified: StepB
|
|
199
|
-
Removed: StepC
|
|
200
|
-
Unchanged: 1
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
`--execution` accepts either a full `GetExecutionHistory` response (`{"events": [...]}`)
|
|
204
|
-
or a bare events array. See [generateDiff](#generatemermaiddiffparams--generatediffparams)
|
|
205
|
-
and [generateExecution](#generateexecutionparams--generatemermaidexecutionparams) for the
|
|
206
|
-
programmatic equivalents.
|
|
207
|
-
|
|
208
|
-
CloudFormation/SAM/CDK templates work as input too — see [Extracting ASL from a CDK/CloudFormation template](#extracting-asl-from-a-cdkcloudformation-template).
|
|
209
|
-
|
|
210
|
-
> **`--format png` needs the optional `node-html-to-image` peer.** It is not installed by default. With `npx`, run `npx --package sfn-diagram --package node-html-to-image sfn-diagram …`; in a project, `npm install node-html-to-image`. Without it the CLI exits with an actionable error. Or skip the install entirely with the [Docker image](#docker), which bundles Chromium.
|
|
211
|
-
|
|
212
|
-
## Docker
|
|
213
|
-
|
|
214
|
-
A prebuilt image is published to GitHub Container Registry with Chromium baked in, so PNG export works out of the box:
|
|
215
|
-
|
|
216
|
-
```bash
|
|
217
|
-
docker run --rm -v "$PWD":/work ghcr.io/yusufaf/sfn-diagram:latest \
|
|
218
|
-
/work/state.asl.json --format svg -o /work/diagram.svg
|
|
219
|
-
|
|
220
|
-
docker run --rm -v "$PWD":/work ghcr.io/yusufaf/sfn-diagram:latest \
|
|
221
|
-
/work/state.asl.json --format png -o /work/diagram.png
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
Tags: `latest`, `<major>`, `<major>.<minor>`, `<major>.<minor>.<patch>`.
|
|
225
|
-
|
|
226
|
-
## Quick Start
|
|
227
|
-
|
|
228
|
-
### Function-based API
|
|
229
|
-
|
|
230
|
-
```typescript
|
|
231
|
-
import { generateSvg } from 'sfn-diagram';
|
|
232
|
-
import { writeFileSync } from 'fs';
|
|
233
|
-
|
|
234
|
-
const asl = {
|
|
235
|
-
StartAt: 'HelloWorld',
|
|
236
|
-
States: {
|
|
237
|
-
HelloWorld: {
|
|
238
|
-
Type: 'Pass',
|
|
239
|
-
Result: 'Hello, World!',
|
|
240
|
-
End: true
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
const { svg, width, height } = generateSvg({
|
|
246
|
-
aslDefinition: asl,
|
|
247
|
-
theme: 'dark',
|
|
248
|
-
layout: 'LR'
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
writeFileSync('diagram.svg', svg);
|
|
252
|
-
console.log(`Generated ${width}x${height} diagram`);
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
### Class-based API
|
|
256
|
-
|
|
257
|
-
```typescript
|
|
258
|
-
import { SfnDiagramGenerator } from 'sfn-diagram';
|
|
259
|
-
|
|
260
|
-
const generator = new SfnDiagramGenerator({
|
|
261
|
-
theme: 'dark',
|
|
262
|
-
layout: 'TB',
|
|
263
|
-
nodeWidth: 150,
|
|
264
|
-
nodeHeight: 80,
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
const { svg } = generator.generateSvg({ aslDefinition: asl });
|
|
268
|
-
const { code } = generator.generateMermaid({ aslDefinition: asl });
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
## API Reference
|
|
272
|
-
|
|
273
|
-
### generateSvg(params)
|
|
274
|
-
|
|
275
|
-
Generate an SVG diagram using D3.js and Dagre layout.
|
|
276
|
-
|
|
277
|
-
```typescript
|
|
278
|
-
import { generateSvg } from 'sfn-diagram';
|
|
279
|
-
|
|
280
|
-
const result = generateSvg({
|
|
281
|
-
aslDefinition: asl, // ASL definition (object or JSON string)
|
|
282
|
-
theme: 'light', // 'light', 'dark', or CustomTheme object
|
|
283
|
-
layout: 'TB', // 'TB', 'LR', 'RL', 'BT'
|
|
284
|
-
nodeWidth: 120, // Node width in pixels
|
|
285
|
-
nodeHeight: 60, // Node height in pixels
|
|
286
|
-
rankSeparation: 50, // Vertical spacing between ranks
|
|
287
|
-
nodeSeparation: 50, // Horizontal spacing between nodes
|
|
288
|
-
padding: 20, // Diagram padding
|
|
289
|
-
edgeStyle: 'curved', // 'curved', 'straight', 'orthogonal'
|
|
290
|
-
showStateTypes: false, // Display state types on nodes
|
|
291
|
-
showVariables: true, // Annotate nodes with the variables they Assign
|
|
292
|
-
includeComments: true, // Use state comments as labels
|
|
293
|
-
customColors: {} // Override colors for specific states
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
// Returns SvgOutput: { svg: string, width: number, height: number, metadata: { edgeCount: number, nodeCount: number } }
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
### generateMermaid(params)
|
|
300
|
-
|
|
301
|
-
Generate Mermaid.js diagram syntax.
|
|
302
|
-
|
|
303
|
-
```typescript
|
|
304
|
-
import { generateMermaid } from 'sfn-diagram';
|
|
305
|
-
|
|
306
|
-
const result = generateMermaid({
|
|
307
|
-
aslDefinition: asl,
|
|
308
|
-
includeComments: true
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
// Returns MermaidOutput: { code: string, metadata: { edgeCount: number, stateCount: number } }
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
### generateDiagram(params)
|
|
315
|
-
|
|
316
|
-
Generate a diagram, choosing the output format via the `format` option (defaults to `'svg'`).
|
|
317
|
-
|
|
318
|
-
```typescript
|
|
319
|
-
import { generateDiagram } from 'sfn-diagram';
|
|
320
|
-
|
|
321
|
-
const svgResult = generateDiagram({
|
|
322
|
-
aslDefinition: asl,
|
|
323
|
-
theme: 'dark'
|
|
324
|
-
}); // Returns SvgOutput
|
|
325
|
-
|
|
326
|
-
const mermaidResult = generateDiagram({
|
|
327
|
-
aslDefinition: asl,
|
|
328
|
-
format: 'mermaid'
|
|
329
|
-
}); // Returns MermaidOutput
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
### exportPng(params)
|
|
333
|
-
|
|
334
|
-
Export diagram as PNG image. Node-only — imported from the `sfn-diagram/png` subpath.
|
|
335
|
-
|
|
336
|
-
```typescript
|
|
337
|
-
import { exportPng } from 'sfn-diagram/png';
|
|
338
|
-
|
|
339
|
-
const result = await exportPng({
|
|
340
|
-
aslDefinition: asl,
|
|
341
|
-
theme: 'light',
|
|
342
|
-
pngQuality: 90, // 1–100 (default 90)
|
|
343
|
-
backgroundColor: 'transparent'
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
// Returns PngOutput: { buffer: Buffer, width: number, height: number, metadata: { format: 'png' } }
|
|
347
|
-
writeFileSync('diagram.png', result.buffer);
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
### generateFromAwsResponse(params)
|
|
351
|
-
|
|
352
|
-
Generate diagram directly from AWS SDK response.
|
|
353
|
-
|
|
354
|
-
```typescript
|
|
355
|
-
import { SFNClient, DescribeStateMachineCommand } from '@aws-sdk/client-sfn';
|
|
356
|
-
import { generateFromAwsResponse } from 'sfn-diagram';
|
|
357
|
-
|
|
358
|
-
const client = new SFNClient({ region: 'us-east-1' });
|
|
359
|
-
const response = await client.send(
|
|
360
|
-
new DescribeStateMachineCommand({
|
|
361
|
-
stateMachineArn: 'arn:aws:states:us-east-1:123456789012:stateMachine:MyStateMachine'
|
|
362
|
-
})
|
|
363
|
-
);
|
|
364
|
-
|
|
365
|
-
const { svg } = generateFromAwsResponse({
|
|
366
|
-
response,
|
|
367
|
-
theme: 'dark'
|
|
368
|
-
});
|
|
369
|
-
```
|
|
370
|
-
|
|
371
|
-
### Extracting ASL from a CDK/CloudFormation template
|
|
372
|
-
|
|
373
|
-
`cdk synth` emits a state machine whose `DefinitionString` is an `Fn::Join` full
|
|
374
|
-
of intrinsics, not plain ASL. The `sfn-diagram/cfn` subpath flattens it:
|
|
375
|
-
|
|
376
|
-
```typescript
|
|
377
|
-
import { extractAslFromTemplate } from 'sfn-diagram/cfn';
|
|
378
|
-
import { generateMermaid } from 'sfn-diagram';
|
|
379
|
-
|
|
380
|
-
const { aslDefinition, warnings } = extractAslFromTemplate({ template: cdkSynthJson });
|
|
381
|
-
const { code } = generateMermaid({ aslDefinition });
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
Both JSON and YAML templates are supported (CloudFormation short-form tags like
|
|
385
|
-
`!Sub` / `!GetAtt` included), and `DefinitionSubstitutions` are applied. When a
|
|
386
|
-
template contains more than one state machine, pass `resourceId` to pick one.
|
|
387
|
-
|
|
388
|
-
CLI (JSON templates auto-detect; use `--resolve-cfn` for YAML):
|
|
389
|
-
|
|
390
|
-
```bash
|
|
391
|
-
cdk synth > template.json
|
|
392
|
-
npx sfn-diagram template.json --format mermaid
|
|
393
|
-
npx sfn-diagram template.yaml --resolve-cfn --resource MyMachine --format svg -o out.svg
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
Intrinsics that don't affect the flow become readable placeholders
|
|
397
|
-
(`${AWS::Partition}`, `<Ref:LogicalId>`). External `DefinitionUri` definitions
|
|
398
|
-
are not supported — pass a template with an inline definition.
|
|
399
|
-
|
|
400
|
-
### generateMermaidDiff(params) / generateDiff(params)
|
|
401
|
-
|
|
402
|
-
Compare two ASL definitions and highlight what changed. `generateMermaidDiff` returns Mermaid code (renders inline on GitHub); `generateDiff` returns the same comparison as an SVG. Added states are green, modified yellow, removed red — and both return a `metadata` change summary (`added`, `modified`, `removed`, `unchanged`). The comparison is order-insensitive, so reordering a state's properties is **not** flagged as a change.
|
|
403
|
-
|
|
404
|
-
```typescript
|
|
405
|
-
import { generateMermaidDiff } from 'sfn-diagram';
|
|
406
|
-
|
|
407
|
-
const { code, metadata } = generateMermaidDiff({
|
|
408
|
-
before: baseAsl, // old (base) ASL definition, object or JSON string
|
|
409
|
-
after: headAsl, // new (head) ASL definition, object or JSON string
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
metadata; // { added: [...], modified: [...], removed: [...], unchanged: [...], stateCount, edgeCount }
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
For the order-processing workflow above, adding a `FraudCheck` step, bumping `ChargePayment`'s resource, and dropping `CancelOrder` renders like this:
|
|
416
|
-
|
|
417
|
-
```mermaid
|
|
418
|
-
stateDiagram-v2
|
|
419
|
-
|
|
420
|
-
[*] --> ValidateOrder
|
|
421
|
-
ValidateOrder --> CheckStock
|
|
422
|
-
CheckStock --> ChargePayment: $.inStock == true
|
|
423
|
-
CheckStock --> OrderComplete: Default
|
|
424
|
-
ChargePayment --> FraudCheck
|
|
425
|
-
FraudCheck --> ShipOrder
|
|
426
|
-
ShipOrder --> OrderComplete
|
|
427
|
-
|
|
428
|
-
OrderComplete --> [*]
|
|
429
|
-
CancelOrder --> [*]
|
|
430
|
-
|
|
431
|
-
classDef diffAdded fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px
|
|
432
|
-
classDef diffModified fill:#fff9c4,stroke:#f57f17,stroke-width:2px
|
|
433
|
-
classDef diffRemoved fill:#ffcdd2,stroke:#c62828,stroke-width:2px
|
|
434
|
-
|
|
435
|
-
class FraudCheck diffAdded
|
|
436
|
-
class CheckStock diffModified
|
|
437
|
-
class ChargePayment diffModified
|
|
438
|
-
class CancelOrder diffRemoved
|
|
439
|
-
```
|
|
440
|
-
|
|
441
|
-
> This is exactly what the [GitHub Action](#github-action) posts on pull requests that touch ASL files.
|
|
442
|
-
|
|
443
|
-
### generateExecution(params) / generateMermaidExecution(params)
|
|
444
|
-
|
|
445
|
-
Overlay a **real execution** onto the diagram. Where the diff shows how a definition
|
|
446
|
-
_changed_, the execution overlay shows what one _run_ actually did: which path it took,
|
|
447
|
-
which states succeeded (green), failed (red), were caught and recovered (orange), or were
|
|
448
|
-
never reached (grey) — plus per-state duration and retry counts.
|
|
449
|
-
|
|
450
|
-
Pass the ASL definition plus the execution's history. `history` accepts the events array
|
|
451
|
-
from `GetExecutionHistory`, the raw command output, or a JSON string of either — so the
|
|
452
|
-
core stays credential-free and runs in the browser.
|
|
453
|
-
|
|
454
|
-
```typescript
|
|
455
|
-
import { generateExecution, generateMermaidExecution } from 'sfn-diagram';
|
|
456
|
-
|
|
457
|
-
// history: events from `aws stepfunctions get-execution-history`, or the SDK response
|
|
458
|
-
const { svg, metadata } = generateExecution({ aslDefinition: asl, history });
|
|
459
|
-
|
|
460
|
-
metadata;
|
|
461
|
-
// { succeeded: [...], failed: [...], caught: [...], notReached: [...], running: [...],
|
|
462
|
-
// takenEdgeCount, executionStatus, nodeCount, edgeCount }
|
|
463
|
-
|
|
464
|
-
// Mermaid variant (states coloured + duration/retry annotations in labels):
|
|
465
|
-
const { code } = generateMermaidExecution({ aslDefinition: asl, history });
|
|
466
|
-
```
|
|
467
|
-
|
|
468
|
-
> **Note:** Mermaid `stateDiagram-v2` cannot style individual transitions, so taken-path
|
|
469
|
-
> emphasis in Mermaid is expressed through node colours and label annotations. The SVG
|
|
470
|
-
> overlay additionally dims the transitions the run did not take.
|
|
471
|
-
|
|
472
|
-
Need just the data (no rendering)? `parseExecutionHistory({ events })` returns the pure
|
|
473
|
-
`ExecutionOverlay` model — per-state status, attempts, duration, and the taken edges — for
|
|
474
|
-
building your own UI.
|
|
475
|
-
|
|
476
|
-
```typescript
|
|
477
|
-
import { parseExecutionHistory } from 'sfn-diagram';
|
|
478
|
-
|
|
479
|
-
const overlay = parseExecutionHistory({ events });
|
|
480
|
-
overlay.states['ProcessOrder']; // { status: 'succeeded', attempts: 1, durationMs: 1250 }
|
|
481
|
-
overlay.takenEdges; // [{ from: 'ValidateOrder', to: 'ProcessOrder' }, ...]
|
|
482
|
-
```
|
|
483
|
-
|
|
484
|
-
Fetching history from AWS (Node) — use the `sfn-diagram/aws` helper, which paginates `GetExecutionHistory` for you:
|
|
485
|
-
|
|
486
|
-
```typescript
|
|
487
|
-
import { SFNClient } from '@aws-sdk/client-sfn';
|
|
488
|
-
import { fetchExecutionHistory } from 'sfn-diagram/aws';
|
|
489
|
-
|
|
490
|
-
const client = new SFNClient({ region: 'us-east-1' });
|
|
491
|
-
const events = await fetchExecutionHistory({ client, executionArn });
|
|
492
|
-
|
|
493
|
-
const { svg } = generateExecution({ aslDefinition: asl, history: events });
|
|
494
|
-
```
|
|
495
|
-
|
|
496
|
-
`sfn-diagram/aws` is a Node-only subpath. `@aws-sdk/client-sfn` is an **optional peer dependency** — install it yourself (`npm i @aws-sdk/client-sfn`); the core `sfn-diagram` package stays dependency-free and browser-safe.
|
|
497
|
-
|
|
498
|
-
<details>
|
|
499
|
-
<summary>Prefer to paginate yourself? The manual loop:</summary>
|
|
500
|
-
|
|
501
|
-
```typescript
|
|
502
|
-
import { SFNClient, GetExecutionHistoryCommand } from '@aws-sdk/client-sfn';
|
|
503
|
-
|
|
504
|
-
const client = new SFNClient({ region: 'us-east-1' });
|
|
505
|
-
const events = [];
|
|
506
|
-
let nextToken;
|
|
507
|
-
do {
|
|
508
|
-
const page = await client.send(
|
|
509
|
-
new GetExecutionHistoryCommand({ executionArn, nextToken, maxResults: 1000 }),
|
|
510
|
-
);
|
|
511
|
-
events.push(...(page.events ?? []));
|
|
512
|
-
nextToken = page.nextToken;
|
|
513
|
-
} while (nextToken);
|
|
514
|
-
|
|
515
|
-
const { svg } = generateExecution({ aslDefinition: asl, history: events });
|
|
516
|
-
```
|
|
517
|
-
</details>
|
|
518
|
-
|
|
519
|
-
### SfnDiagramGenerator Class
|
|
520
|
-
|
|
521
|
-
Reusable generator that holds diagram options once and applies them to every call. Configure options via the constructor or the fluent `setOptions()` method; pass the `aslDefinition` per generation.
|
|
522
|
-
|
|
523
|
-
```typescript
|
|
524
|
-
import { SfnDiagramGenerator } from 'sfn-diagram';
|
|
525
|
-
|
|
526
|
-
const generator = new SfnDiagramGenerator({
|
|
527
|
-
theme: 'dark',
|
|
528
|
-
layout: 'LR',
|
|
529
|
-
nodeWidth: 150,
|
|
530
|
-
nodeHeight: 80,
|
|
531
|
-
rankSeparation: 60,
|
|
532
|
-
nodeSeparation: 60,
|
|
533
|
-
edgeStyle: 'curved',
|
|
534
|
-
padding: 30,
|
|
535
|
-
});
|
|
536
|
-
|
|
537
|
-
// Update options later (chainable)
|
|
538
|
-
generator.setOptions({ theme: 'light' });
|
|
539
|
-
|
|
540
|
-
// Generate outputs (aslDefinition passed per call)
|
|
541
|
-
const svgResult = generator.generateSvg({ aslDefinition: asl });
|
|
542
|
-
const mermaidResult = generator.generateMermaid({ aslDefinition: asl });
|
|
543
|
-
```
|
|
544
|
-
|
|
545
|
-
> PNG export is a standalone function from `sfn-diagram/png` (`exportPng`), not a method on this class.
|
|
546
|
-
|
|
547
|
-
## Configuration Options
|
|
548
|
-
|
|
549
|
-
### Themes
|
|
550
|
-
|
|
551
|
-
**Built-in themes:**
|
|
552
|
-
- `'light'` - AWS light theme (default)
|
|
553
|
-
- `'dark'` - AWS dark theme
|
|
554
|
-
|
|
555
|
-
**Custom theme:**
|
|
556
|
-
|
|
557
|
-
A `CustomTheme` sets the background, per-state-type fill/stroke colours, edge colours, and typography. Pass it anywhere a theme is accepted.
|
|
558
|
-
|
|
559
|
-
```typescript
|
|
560
|
-
import type { CustomTheme } from 'sfn-diagram';
|
|
561
|
-
|
|
562
|
-
const customTheme: CustomTheme = {
|
|
563
|
-
background: '#ffffff',
|
|
564
|
-
edgeColors: {
|
|
565
|
-
choice: '#7b1fa2',
|
|
566
|
-
default: '#607d8b',
|
|
567
|
-
error: '#f44336',
|
|
568
|
-
normal: '#232f3e',
|
|
569
|
-
retry: '#f9a825', // optional; falls back to `error` when omitted
|
|
570
|
-
},
|
|
571
|
-
fontFamily: 'Arial, sans-serif',
|
|
572
|
-
fontSize: 14,
|
|
573
|
-
nodeColors: {
|
|
574
|
-
Pass: { fill: '#e8f5e9', stroke: '#4caf50' },
|
|
575
|
-
Task: { fill: '#e3f2fd', stroke: '#2196f3' },
|
|
576
|
-
Choice: { fill: '#fff3e0', stroke: '#ff9800' },
|
|
577
|
-
Wait: { fill: '#f3e5f5', stroke: '#9c27b0' },
|
|
578
|
-
Succeed: { fill: '#e8f5e9', stroke: '#4caf50' },
|
|
579
|
-
Fail: { fill: '#ffebee', stroke: '#f44336' },
|
|
580
|
-
Parallel: { fill: '#e0f7fa', stroke: '#00bcd4' },
|
|
581
|
-
Map: { fill: '#e8eaf6', stroke: '#3f51b5' },
|
|
582
|
-
},
|
|
583
|
-
textColor: '#232f3e',
|
|
584
|
-
};
|
|
585
|
-
|
|
586
|
-
generateSvg({ aslDefinition: asl, theme: customTheme });
|
|
587
|
-
```
|
|
588
|
-
|
|
589
|
-
### Layouts
|
|
590
|
-
|
|
591
|
-
- `'TB'` - Top to Bottom (default)
|
|
592
|
-
- `'LR'` - Left to Right
|
|
593
|
-
- `'RL'` - Right to Left
|
|
594
|
-
- `'BT'` - Bottom to Top
|
|
595
|
-
|
|
596
|
-
### Edge Styles
|
|
597
|
-
|
|
598
|
-
- `'curved'` - Smooth curved paths (default)
|
|
599
|
-
- `'straight'` - Direct straight lines
|
|
600
|
-
- `'orthogonal'` - Right-angled paths
|
|
601
|
-
|
|
602
|
-
### Large diagrams
|
|
603
|
-
|
|
604
|
-
Big, branchy state machines are hard to read as a static image. A few options help:
|
|
605
|
-
|
|
606
|
-
- **`--format html`** (or `generateHtml()`) — a self-contained interactive viewer
|
|
607
|
-
(drag to pan, wheel to zoom, fit/reset toolbar). No external dependencies, opens
|
|
608
|
-
offline straight from `file://`.
|
|
609
|
-
```bash
|
|
610
|
-
npx sfn-diagram state.asl.json --format html -o diagram.html
|
|
611
|
-
```
|
|
612
|
-
> **Known limitation:** if you also pass `showIcons: true`, the embedded SVG
|
|
613
|
-
> references AWS service icons hosted on a jsDelivr CDN (see
|
|
614
|
-
> [AWS Service Icons](#aws-service-icons) below), so the HTML is no longer fully
|
|
615
|
-
> offline — icons won't load without network access.
|
|
616
|
-
- **`--hide-catch`** (or `catchHandling: 'hide'`) — drop per-state error-handler
|
|
617
|
-
(`Catch`) branches so the happy path stands out. A handler that's also reachable
|
|
618
|
-
via the happy path is kept.
|
|
619
|
-
```bash
|
|
620
|
-
npx sfn-diagram state.asl.json --hide-catch --format svg -o diagram.svg
|
|
621
|
-
```
|
|
622
|
-
- **`--layout LR`** (or `layout: 'LR'`) — the default `TB` layout makes catch-heavy
|
|
623
|
-
or deeply branching machines extremely tall; `LR` reads better for wide graphs.
|
|
624
|
-
|
|
625
|
-
### Variables and Distributed Map
|
|
626
|
-
|
|
627
|
-
Two pieces of modern ASL are rendered explicitly, because both are otherwise
|
|
628
|
-
invisible in a diagram.
|
|
629
|
-
|
|
630
|
-
**Variables (`Assign`).** A state that assigns variables is annotated with their
|
|
631
|
-
names beneath its label — `$orderId, $total`. The list caps at three names, then
|
|
632
|
-
collapses to `+N more`, so a state assigning many variables cannot blow out the
|
|
633
|
-
node width. Disable with `showVariables: false`.
|
|
634
|
-
|
|
635
|
-
```typescript
|
|
636
|
-
const { svg } = generateSvg({ aslDefinition: asl, showVariables: false });
|
|
637
|
-
```
|
|
638
|
-
|
|
639
|
-
**Distributed Map.** A Map whose `ItemProcessor` declares
|
|
640
|
-
`ProcessorConfig.Mode: 'DISTRIBUTED'` runs a child execution per batch rather than
|
|
641
|
-
iterating inline, so it is labelled `Distributed` in the container header instead
|
|
642
|
-
of rendering identically to an inline Map. `MaxConcurrency` is shown alongside it
|
|
643
|
-
when set.
|
|
644
|
-
|
|
645
|
-
Its `ItemReader` (dataset source — S3 or Athena) and `ResultWriter` (result sink)
|
|
646
|
-
each become a satellite node beside the container, wired in and out of the Map.
|
|
647
|
-
With `showIcons: true` they pick up the appropriate AWS service icon, resolved
|
|
648
|
-
from the ARN the same way Task states are.
|
|
649
|
-
|
|
650
|
-
```
|
|
651
|
-
ItemReader (s3) ──▶ ProcessItems ──▶ ResultWriter (s3)
|
|
652
|
-
Distributed · max 100
|
|
653
|
-
```
|
|
654
|
-
|
|
655
|
-
### AWS Service Icons
|
|
656
|
-
|
|
657
|
-
Display AWS service icons on Task state nodes to improve diagram readability and quickly identify which AWS services are being used.
|
|
658
|
-
|
|
659
|
-
**Basic Usage:**
|
|
660
|
-
|
|
661
|
-
```typescript
|
|
662
|
-
import { generateSvg } from 'sfn-diagram';
|
|
663
|
-
|
|
664
|
-
const { svg } = generateSvg({
|
|
665
|
-
aslDefinition: asl,
|
|
666
|
-
showIcons: true, // Enable icons
|
|
667
|
-
iconPosition: 'left', // Icon placement (default)
|
|
668
|
-
iconSize: 24 // Icon dimensions in pixels (default)
|
|
669
|
-
});
|
|
670
|
-
```
|
|
671
|
-
|
|
672
|
-
**Supported Services (30+):**
|
|
673
|
-
|
|
674
|
-
Lambda, ECS, Fargate, EC2, Batch, DynamoDB, RDS, Aurora, Neptune, S3, EFS, FSx, SQS, SNS, EventBridge, Kinesis, Glue, Athena, EMR, Redshift, SageMaker, Bedrock, Comprehend, Rekognition, Step Functions, API Gateway, AppSync, CloudWatch, CloudFormation, Systems Manager, Secrets Manager, KMS, and more.
|
|
675
|
-
|
|
676
|
-
**Icon Positioning:**
|
|
677
|
-
|
|
678
|
-
- `'left'` - Icon to the left of label (default, matches AWS Console style)
|
|
679
|
-
- `'top'` - Icon above label
|
|
680
|
-
- `'right'` - Icon to the right of label
|
|
681
|
-
|
|
682
|
-
**Custom Icon Resolver:**
|
|
683
|
-
|
|
684
|
-
Provide your own icon URLs for services:
|
|
685
|
-
|
|
686
|
-
```typescript
|
|
687
|
-
const { svg } = generateSvg({
|
|
688
|
-
aslDefinition: asl,
|
|
689
|
-
showIcons: true,
|
|
690
|
-
iconResolver: (service) => {
|
|
691
|
-
if (service === 'lambda') {
|
|
692
|
-
return 'https://my-cdn.com/lambda-icon.svg';
|
|
693
|
-
}
|
|
694
|
-
return null; // Fall back to default
|
|
695
|
-
}
|
|
696
|
-
});
|
|
697
|
-
```
|
|
698
|
-
|
|
699
|
-
**Recommended Node Dimensions:**
|
|
700
|
-
|
|
701
|
-
For optimal icon visibility, use wider nodes:
|
|
702
|
-
|
|
703
|
-
```typescript
|
|
704
|
-
const { svg } = generateSvg({
|
|
705
|
-
aslDefinition: asl,
|
|
706
|
-
showIcons: true,
|
|
707
|
-
nodeWidth: 150, // Default: 120
|
|
708
|
-
nodeHeight: 70 // Default: 60
|
|
709
|
-
});
|
|
710
|
-
```
|
|
711
|
-
|
|
712
|
-
**Important Notes:**
|
|
713
|
-
- Icons are only displayed on Task states (states with AWS service integrations)
|
|
714
|
-
- Icons are sourced from [aws-icons](https://www.npmjs.com/package/aws-icons) via jsDelivr CDN
|
|
715
|
-
- **PNG export limitation**: External CDN images may not render in PNG output due to headless browser limitations. **Use SVG output for diagrams with icons.**
|
|
716
|
-
- Unsupported services gracefully fall back to text-only labels
|
|
717
|
-
- Icons are opt-in via `showIcons: true` (disabled by default)
|
|
718
|
-
|
|
719
|
-
## Supported State Types
|
|
87
|
+
## Supported state types
|
|
720
88
|
|
|
721
89
|
All AWS Step Functions state types are fully supported:
|
|
722
90
|
|
|
@@ -731,360 +99,44 @@ All AWS Step Functions state types are fully supported:
|
|
|
731
99
|
| **Parallel** | Rectangle | Executes branches in parallel |
|
|
732
100
|
| **Map** | Rectangle | Iterates over array items (legacy `Iterator` and modern `ItemProcessor`/Distributed Map) |
|
|
733
101
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
- **`Catch`** blocks render as dashed error edges to their handler states.
|
|
737
|
-
- **`Retry`** policies render as a labelled self-loop on the state (e.g. `↻ States.Timeout (4x); States.ALL (2x)`) — a self-transition in Mermaid output.
|
|
738
|
-
|
|
739
|
-
### Query languages
|
|
740
|
-
|
|
741
|
-
Both JSONPath and JSONata (`QueryLanguage: "JSONata"`) definitions are supported. Choice branch labels are derived from JSONPath comparison operators (`$.score >= 90`, `And`/`Or`/`Not`, `Is*` checks) or from JSONata `Condition` expressions, whichever the state uses.
|
|
742
|
-
|
|
743
|
-
## Examples
|
|
744
|
-
|
|
745
|
-
### Complex State Machine
|
|
746
|
-
|
|
747
|
-
```typescript
|
|
748
|
-
import { generateSvg } from 'sfn-diagram';
|
|
749
|
-
|
|
750
|
-
const complexAsl = {
|
|
751
|
-
Comment: 'Order processing workflow',
|
|
752
|
-
StartAt: 'ValidateOrder',
|
|
753
|
-
States: {
|
|
754
|
-
ValidateOrder: {
|
|
755
|
-
Type: 'Task',
|
|
756
|
-
Resource: 'arn:aws:lambda:us-east-1:123456789012:function:ValidateOrder',
|
|
757
|
-
Next: 'CheckInventory',
|
|
758
|
-
Catch: [{
|
|
759
|
-
ErrorEquals: ['ValidationError'],
|
|
760
|
-
Next: 'OrderFailed'
|
|
761
|
-
}]
|
|
762
|
-
},
|
|
763
|
-
CheckInventory: {
|
|
764
|
-
Type: 'Task',
|
|
765
|
-
Resource: 'arn:aws:lambda:us-east-1:123456789012:function:CheckInventory',
|
|
766
|
-
Next: 'IsInStock'
|
|
767
|
-
},
|
|
768
|
-
IsInStock: {
|
|
769
|
-
Type: 'Choice',
|
|
770
|
-
Choices: [{
|
|
771
|
-
Variable: '$.inStock',
|
|
772
|
-
BooleanEquals: true,
|
|
773
|
-
Next: 'ProcessPayment'
|
|
774
|
-
}],
|
|
775
|
-
Default: 'OutOfStock'
|
|
776
|
-
},
|
|
777
|
-
ProcessPayment: {
|
|
778
|
-
Type: 'Task',
|
|
779
|
-
Resource: 'arn:aws:states:::dynamodb:putItem',
|
|
780
|
-
Next: 'OrderSucceeded'
|
|
781
|
-
},
|
|
782
|
-
OutOfStock: {
|
|
783
|
-
Type: 'Fail',
|
|
784
|
-
Error: 'OutOfStockError',
|
|
785
|
-
Cause: 'Item not available'
|
|
786
|
-
},
|
|
787
|
-
OrderFailed: {
|
|
788
|
-
Type: 'Fail',
|
|
789
|
-
Error: 'OrderValidationError'
|
|
790
|
-
},
|
|
791
|
-
OrderSucceeded: {
|
|
792
|
-
Type: 'Succeed'
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
};
|
|
796
|
-
|
|
797
|
-
const { svg } = generateSvg({
|
|
798
|
-
aslDefinition: complexAsl,
|
|
799
|
-
theme: 'dark',
|
|
800
|
-
layout: 'TB',
|
|
801
|
-
edgeStyle: 'curved',
|
|
802
|
-
nodeWidth: 150,
|
|
803
|
-
nodeHeight: 70
|
|
804
|
-
});
|
|
805
|
-
```
|
|
806
|
-
|
|
807
|
-
### Parallel State Machine
|
|
808
|
-
|
|
809
|
-
```typescript
|
|
810
|
-
const parallelAsl = {
|
|
811
|
-
StartAt: 'ProcessInParallel',
|
|
812
|
-
States: {
|
|
813
|
-
ProcessInParallel: {
|
|
814
|
-
Type: 'Parallel',
|
|
815
|
-
Branches: [
|
|
816
|
-
{
|
|
817
|
-
StartAt: 'Branch1',
|
|
818
|
-
States: {
|
|
819
|
-
Branch1: { Type: 'Pass', Result: 'Branch 1', End: true }
|
|
820
|
-
}
|
|
821
|
-
},
|
|
822
|
-
{
|
|
823
|
-
StartAt: 'Branch2',
|
|
824
|
-
States: {
|
|
825
|
-
Branch2: { Type: 'Pass', Result: 'Branch 2', End: true }
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
],
|
|
829
|
-
Next: 'FinalState'
|
|
830
|
-
},
|
|
831
|
-
FinalState: {
|
|
832
|
-
Type: 'Succeed'
|
|
833
|
-
}
|
|
834
|
-
}
|
|
835
|
-
};
|
|
836
|
-
|
|
837
|
-
const { svg } = generateSvg({ aslDefinition: parallelAsl });
|
|
838
|
-
```
|
|
839
|
-
|
|
840
|
-
### Export Multiple Formats
|
|
841
|
-
|
|
842
|
-
```typescript
|
|
843
|
-
import { generateSvg, generateMermaid } from 'sfn-diagram';
|
|
844
|
-
import { exportPng } from 'sfn-diagram/png';
|
|
845
|
-
import { writeFileSync } from 'fs';
|
|
846
|
-
|
|
847
|
-
// Generate SVG and Mermaid
|
|
848
|
-
const { svg } = generateSvg({ aslDefinition: asl });
|
|
849
|
-
const { code } = generateMermaid({ aslDefinition: asl });
|
|
850
|
-
writeFileSync('diagram.svg', svg);
|
|
851
|
-
writeFileSync('diagram.mmd', code);
|
|
852
|
-
|
|
853
|
-
// Generate PNG (Node-only)
|
|
854
|
-
const { buffer } = await exportPng({
|
|
855
|
-
aslDefinition: asl,
|
|
856
|
-
pngQuality: 90,
|
|
857
|
-
backgroundColor: 'transparent'
|
|
858
|
-
});
|
|
859
|
-
writeFileSync('diagram.png', buffer);
|
|
860
|
-
```
|
|
861
|
-
|
|
862
|
-
## TypeScript Support
|
|
863
|
-
|
|
864
|
-
Full TypeScript definitions included:
|
|
865
|
-
|
|
866
|
-
```typescript
|
|
867
|
-
import type {
|
|
868
|
-
AslDefinition,
|
|
869
|
-
DiagramOptions,
|
|
870
|
-
SvgOutput,
|
|
871
|
-
MermaidOutput,
|
|
872
|
-
CustomTheme,
|
|
873
|
-
StateType
|
|
874
|
-
} from 'sfn-diagram';
|
|
875
|
-
|
|
876
|
-
// PNG types live on the Node-only subpath
|
|
877
|
-
import type { PngOutput, ExportPngParams } from 'sfn-diagram/png';
|
|
878
|
-
```
|
|
879
|
-
|
|
880
|
-
## Use with your framework
|
|
881
|
-
|
|
882
|
-
`generateSvg()` returns an SVG **string** and the core has no DOM dependency, so any
|
|
883
|
-
framework can render a diagram by injecting that string. There is nothing React-specific
|
|
884
|
-
in the core — [`sfn-diagram-react`](packages/sfn-diagram-react/) exists for convenience,
|
|
885
|
-
not necessity.
|
|
886
|
-
|
|
887
|
-
Each snippet below is the whole integration. See [API Reference](#api-reference) for the
|
|
888
|
-
full option set (`theme`, `layout`, `showIcons`, …) and [`generateMermaid`](#generatemermaidparams)
|
|
889
|
-
if you would rather emit Mermaid than SVG.
|
|
102
|
+
`Catch` blocks render as dashed error edges, `Retry` policies as labelled self-loops, and both JSONPath and JSONata definitions are supported. Details in the [state types guide](https://sfn.yusufaf.dev/guides/state-types/).
|
|
890
103
|
|
|
891
|
-
|
|
104
|
+
## Documentation
|
|
892
105
|
|
|
893
|
-
|
|
894
|
-
<script lang="ts">
|
|
895
|
-
import { generateSvg } from 'sfn-diagram';
|
|
106
|
+
Full documentation lives at **[sfn.yusufaf.dev](https://sfn.yusufaf.dev)**.
|
|
896
107
|
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
**Vue 3**
|
|
905
|
-
|
|
906
|
-
```vue
|
|
907
|
-
<script setup lang="ts">
|
|
908
|
-
import { computed } from 'vue';
|
|
909
|
-
import { generateSvg } from 'sfn-diagram';
|
|
910
|
-
import type { AslDefinition } from 'sfn-diagram';
|
|
911
|
-
|
|
912
|
-
const props = defineProps<{ definition: AslDefinition | string }>();
|
|
913
|
-
const svg = computed(() => generateSvg({ aslDefinition: props.definition }).svg);
|
|
914
|
-
</script>
|
|
915
|
-
|
|
916
|
-
<template>
|
|
917
|
-
<div v-html="svg" />
|
|
918
|
-
</template>
|
|
919
|
-
```
|
|
920
|
-
|
|
921
|
-
**Solid**
|
|
922
|
-
|
|
923
|
-
```tsx
|
|
924
|
-
import { createMemo } from 'solid-js';
|
|
925
|
-
import { generateSvg } from 'sfn-diagram';
|
|
926
|
-
import type { AslDefinition } from 'sfn-diagram';
|
|
927
|
-
|
|
928
|
-
export function SfnDiagram(props: { definition: AslDefinition | string }) {
|
|
929
|
-
const svg = createMemo(() => generateSvg({ aslDefinition: props.definition }).svg);
|
|
930
|
-
return <div innerHTML={svg()} />;
|
|
931
|
-
}
|
|
932
|
-
```
|
|
933
|
-
|
|
934
|
-
**Angular**
|
|
935
|
-
|
|
936
|
-
`[innerHTML]` strips SVG unless the value is marked trusted, so the sanitizer bypass is required.
|
|
937
|
-
|
|
938
|
-
```ts
|
|
939
|
-
import { Component, computed, inject, input } from '@angular/core';
|
|
940
|
-
import { DomSanitizer } from '@angular/platform-browser';
|
|
941
|
-
import { generateSvg } from 'sfn-diagram';
|
|
942
|
-
import type { AslDefinition } from 'sfn-diagram';
|
|
943
|
-
|
|
944
|
-
@Component({
|
|
945
|
-
selector: 'sfn-diagram',
|
|
946
|
-
template: `<div [innerHTML]="svg()"></div>`,
|
|
947
|
-
})
|
|
948
|
-
export class SfnDiagramComponent {
|
|
949
|
-
readonly definition = input.required<AslDefinition | string>();
|
|
950
|
-
private readonly sanitizer = inject(DomSanitizer);
|
|
951
|
-
|
|
952
|
-
readonly svg = computed(() =>
|
|
953
|
-
this.sanitizer.bypassSecurityTrustHtml(
|
|
954
|
-
generateSvg({ aslDefinition: this.definition() }).svg
|
|
955
|
-
)
|
|
956
|
-
);
|
|
957
|
-
}
|
|
958
|
-
```
|
|
108
|
+
- [Introduction](https://sfn.yusufaf.dev/introduction/) — what it does and how it compares
|
|
109
|
+
- [Quick start](https://sfn.yusufaf.dev/quick-start/) — your first diagram
|
|
110
|
+
- [Command line](https://sfn.yusufaf.dev/guides/cli/) — the `sfn-diagram` CLI, diffs, and execution overlays
|
|
111
|
+
- [Configuration](https://sfn.yusufaf.dev/guides/configuration/) — themes, layouts, edge styles, service icons
|
|
112
|
+
- [Examples](https://sfn.yusufaf.dev/guides/examples/) — complete worked examples
|
|
113
|
+
- [Use with your framework](https://sfn.yusufaf.dev/guides/frameworks/) — Next.js, Remix, SvelteKit, Astro
|
|
114
|
+
- [API reference](https://sfn.yusufaf.dev/reference/) — generated from source, always current
|
|
959
115
|
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
Astro runs the frontmatter at build time, so the diagram ships as static markup with
|
|
963
|
-
**zero client-side JavaScript** — the DOM-free core at its best. (Astro also hosts React
|
|
964
|
-
islands, so `sfn-diagram-react` works there too if you need interactivity.)
|
|
965
|
-
|
|
966
|
-
```astro
|
|
967
|
-
---
|
|
968
|
-
import { generateSvg } from 'sfn-diagram';
|
|
969
|
-
// `?raw` gives the file as a string, which `aslDefinition` accepts directly
|
|
970
|
-
import definition from '../workflows/order-processing.asl.json?raw';
|
|
971
|
-
|
|
972
|
-
const { svg } = generateSvg({ aslDefinition: definition, theme: 'light' });
|
|
973
|
-
---
|
|
974
|
-
|
|
975
|
-
<Fragment set:html={svg} />
|
|
976
|
-
```
|
|
977
|
-
|
|
978
|
-
**Vanilla JS / htmx / anything else**
|
|
979
|
-
|
|
980
|
-
```js
|
|
981
|
-
import { generateSvg } from 'sfn-diagram';
|
|
982
|
-
|
|
983
|
-
const response = await fetch('/workflows/order-processing.asl.json');
|
|
984
|
-
const { svg } = generateSvg({ aslDefinition: await response.text() });
|
|
985
|
-
document.querySelector('#diagram').innerHTML = svg;
|
|
986
|
-
```
|
|
987
|
-
|
|
988
|
-
> **On the "unsafe HTML" APIs.** Every snippet above uses its framework's raw-HTML escape
|
|
989
|
-
> hatch (`{@html}`, `v-html`, `innerHTML`, `dangerouslySetInnerHTML`). The SVG builder
|
|
990
|
-
> HTML-escapes every attribute and text value it emits, following the HTML serialization
|
|
991
|
-
> algorithm, so state names, comments, and choice conditions taken from your ASL are
|
|
992
|
-
> escaped before they reach the string.
|
|
116
|
+
Working with an AI coding agent? The docs are published as [llms.txt](https://sfn.yusufaf.dev/llms.txt), and every page is available as raw Markdown by appending `.md` to its URL.
|
|
993
117
|
|
|
994
118
|
## Ecosystem
|
|
995
119
|
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
pnpm dev
|
|
1004
|
-
```
|
|
1005
|
-
|
|
1006
|
-
Paste any ASL JSON, switch themes, and see the SVG diagram update instantly — no install required beyond the dev server. Switch **Mode** to _Execution overlay_ to paste an execution history alongside the definition and watch the run's path light up.
|
|
1007
|
-
|
|
1008
|
-
### VS Code Extension
|
|
1009
|
-
|
|
1010
|
-
Preview Step Functions diagrams directly inside VS Code. Located in [`packages/vscode-sfn-diagram/`](packages/vscode-sfn-diagram/).
|
|
1011
|
-
|
|
1012
|
-
**Install from source:**
|
|
1013
|
-
```bash
|
|
1014
|
-
cd packages/vscode-sfn-diagram
|
|
1015
|
-
pnpm install
|
|
1016
|
-
pnpm package # produces vscode-sfn-diagram-*.vsix
|
|
1017
|
-
code --install-extension vscode-sfn-diagram-*.vsix
|
|
1018
|
-
```
|
|
1019
|
-
|
|
1020
|
-
**Usage:** Open any `.json` or `.asl` file and run **Step Functions: Preview Step Functions Diagram** from the command palette, or click the diagram icon in the editor title bar.
|
|
1021
|
-
|
|
1022
|
-
### React Component
|
|
1023
|
-
|
|
1024
|
-
Render diagrams in a React app with the [`sfn-diagram-react`](https://www.npmjs.com/package/sfn-diagram-react) package ([source](packages/sfn-diagram-react/)). It wraps `generateSvg`/`generateMermaid` in a component with the same platform-agnostic core, so it works in any React renderer. React 18 and 19 are both supported.
|
|
1025
|
-
|
|
1026
|
-
```bash
|
|
1027
|
-
npm install sfn-diagram-react sfn-diagram react
|
|
1028
|
-
```
|
|
1029
|
-
|
|
1030
|
-
```tsx
|
|
1031
|
-
import { SfnDiagram } from 'sfn-diagram-react';
|
|
1032
|
-
|
|
1033
|
-
<SfnDiagram
|
|
1034
|
-
definition={asl} // ASL object or JSON string
|
|
1035
|
-
format="svg" // 'svg' (default) | 'mermaid'
|
|
1036
|
-
theme="dark" // 'light' | 'dark' | CustomTheme
|
|
1037
|
-
layout="LR" // 'TB' | 'LR' | 'RL' | 'BT'
|
|
1038
|
-
history={history} // optional: renders an execution overlay
|
|
1039
|
-
onError={(err) => console.error(err)}
|
|
1040
|
-
/>
|
|
1041
|
-
```
|
|
1042
|
-
|
|
1043
|
-
### GitHub Action
|
|
1044
|
-
|
|
1045
|
-
Comment a Step Functions diagram on every pull request that touches an ASL file. For **changed** files the comment highlights the diff — added states green, modified yellow, removed red — plus a summary table of what changed; **new** and **deleted** files get a plain diagram. Everything is Mermaid, so it renders inline in the PR with no image hosting. The comment is upserted (updated in place) on each push.
|
|
1046
|
-
|
|
1047
|
-
Available on the [GitHub Marketplace](https://github.com/marketplace/actions/step-functions-diagram-preview) as [`yusufaf/sfn-diagram-action`](https://github.com/yusufaf/sfn-diagram-action) — pin the moving major tag `@v1`. (Source lives here in [`packages/github-action-sfn-diagram/`](packages/github-action-sfn-diagram/); the Marketplace repo is generated from it.)
|
|
1048
|
-
|
|
1049
|
-
```yaml
|
|
1050
|
-
# .github/workflows/sfn-preview.yml
|
|
1051
|
-
name: Step Functions Preview
|
|
1052
|
-
on:
|
|
1053
|
-
pull_request:
|
|
1054
|
-
paths: ['**/*.asl.json', '**/*.asl']
|
|
1055
|
-
|
|
1056
|
-
permissions:
|
|
1057
|
-
contents: read
|
|
1058
|
-
pull-requests: write # required to post the comment
|
|
1059
|
-
|
|
1060
|
-
jobs:
|
|
1061
|
-
preview:
|
|
1062
|
-
runs-on: ubuntu-latest
|
|
1063
|
-
steps:
|
|
1064
|
-
- uses: actions/checkout@v5
|
|
1065
|
-
with: { fetch-depth: 0 } # needed to diff base vs head
|
|
1066
|
-
- uses: yusufaf/sfn-diagram-action@v1
|
|
1067
|
-
```
|
|
120
|
+
| | |
|
|
121
|
+
|---|---|
|
|
122
|
+
| **[Playground](https://sfn.yusufaf.dev/playground/)** | Interactive browser editor for ASL definitions and execution overlays |
|
|
123
|
+
| **[VS Code extension](https://sfn.yusufaf.dev/ecosystem/vscode/)** | Preview diagrams in VS Code, Cursor, Windsurf, VSCodium, and Theia |
|
|
124
|
+
| **[`<sfn-diagram>` web component](https://sfn.yusufaf.dev/ecosystem/web-component/)** | Framework-agnostic custom element — Vue, Svelte, Solid, Angular, Astro, Hono, vanilla HTML |
|
|
125
|
+
| **[React component](https://sfn.yusufaf.dev/ecosystem/react/)** | `sfn-diagram-react` — render diagrams in any React renderer |
|
|
126
|
+
| **[GitHub Action](https://sfn.yusufaf.dev/ecosystem/github-action/)** | Comment a diagram and diff on every PR that touches an ASL file |
|
|
1068
127
|
|
|
1069
|
-
|
|
128
|
+
## Runtime support
|
|
1070
129
|
|
|
1071
|
-
|
|
130
|
+
Core (`sfn-diagram`) is platform-agnostic — it runs in Node, the browser, and edge runtimes. Only `sfn-diagram/png` and the CLI are Node-only. See [runtime support](https://sfn.yusufaf.dev/guides/runtimes/).
|
|
1072
131
|
|
|
1073
132
|
## Contributing
|
|
1074
133
|
|
|
1075
|
-
Contributions are welcome
|
|
134
|
+
Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
1076
135
|
|
|
1077
136
|
## License
|
|
1078
137
|
|
|
1079
|
-
MIT
|
|
138
|
+
MIT — see [LICENSE](LICENSE).
|
|
1080
139
|
|
|
1081
140
|
## Author
|
|
1082
141
|
|
|
1083
142
|
Yusuf Afzal
|
|
1084
|
-
|
|
1085
|
-
## Links
|
|
1086
|
-
|
|
1087
|
-
- [GitHub Repository](https://github.com/yusufaf/sfn-diagram)
|
|
1088
|
-
- [npm Package](https://www.npmjs.com/package/sfn-diagram)
|
|
1089
|
-
- [Issue Tracker](https://github.com/yusufaf/sfn-diagram/issues)
|
|
1090
|
-
- [AWS Step Functions Documentation](https://docs.aws.amazon.com/step-functions/)
|