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 CHANGED
@@ -4,83 +4,53 @@
4
4
  [![npm downloads](https://img.shields.io/npm/dm/sfn-diagram.svg)](https://www.npmjs.com/package/sfn-diagram)
5
5
  [![Unit Test](https://github.com/yusufaf/sfn-diagram/actions/workflows/unit-test.yml/badge.svg)](https://github.com/yusufaf/sfn-diagram/actions/workflows/unit-test.yml)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
- [![Live Playground](https://img.shields.io/badge/playground-live-brightgreen)](https://yusufaf.github.io/sfn-diagram/)
7
+ [![Docs](https://img.shields.io/badge/docs-sfn.yusufaf.dev-brightgreen)](https://sfn.yusufaf.dev)
8
8
 
9
- Generate beautiful, interactive diagrams from AWS Step Functions ASL (Amazon States Language) definitions. Supports dual output formats: D3.js-based SVG and Mermaid.js diagram code, plus PNG export.
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
- **▶ [Try it in the live playground](https://yusufaf.github.io/sfn-diagram/)** — paste any ASL definition and preview the diagram instantly, no install required.
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
- ## Table of Contents
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
- ## What it looks like
20
+ ```bash
21
+ npm install sfn-diagram
22
+ ```
38
23
 
39
- Give it an ASL definition like this order-processing workflow ([`examples/order-processing.asl.json`](examples/order-processing.asl.json)):
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
- ```jsonc
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
- …and `generateMermaid` turns it into a diagram GitHub renders inline (the same code also drives SVG and PNG output):
30
+ ## Quick start
60
31
 
61
- ```mermaid
62
- stateDiagram-v2
32
+ ```ts
33
+ import { generateSvg } from 'sfn-diagram';
63
34
 
64
- [*] --> ValidateOrder
65
- ValidateOrder --> CheckStock
66
- CheckStock --> ChargePayment: $.inStock == true
67
- CheckStock --> CancelOrder: Default
68
- ChargePayment --> ShipOrder
69
- ShipOrder --> OrderComplete
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
- CancelOrder --> [*]
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
- classDef successState fill:#e8f5e8,stroke:#4caf50,stroke-width:3px
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
- class CheckStock choiceState
80
- class ChargePayment taskState
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](#github-action) posts a diff overlay on every PR that touches ASL | None | None |
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
- ## Installation
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
- ### Error handling & retries
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
- **Svelte 5**
104
+ ## Documentation
892
105
 
893
- ```svelte
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
- let { definition } = $props();
898
- const svg = $derived(generateSvg({ aslDefinition: definition }).svg);
899
- </script>
900
-
901
- {@html svg}
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
- **Astro**
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
- ### Playground
997
-
998
- An interactive browser-based editor for exploring ASL definitions and previewing diagrams in real time. **[Open the live playground →](https://yusufaf.github.io/sfn-diagram/)** or run it locally from the [`playground/`](playground/) directory.
999
-
1000
- ```bash
1001
- cd playground
1002
- pnpm install
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
- Inputs: `github-token` (defaults to `${{ github.token }}`), `asl-glob` (comma-separated globs, default `**/*.asl.json,**/*.asl`), `comment-tag` (marker used to find/update the comment, default `sfn-diagram-preview`).
128
+ ## Runtime support
1070
129
 
1071
- Optionally overlay a real run: set `execution-mode` (`latest` or `latest-failed`) and `state-machine-arn` to append the most recent (or most recent failed) execution as a Mermaid overlay beneath the diff. This is opt-in (`off` by default), needs AWS credentials (`states:ListExecutions` + `states:GetExecutionHistory`), and applies when exactly one ASL file changed — see the [action README](packages/github-action-sfn-diagram/README.marketplace.md) for a full workflow.
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! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
134
+ Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
1076
135
 
1077
136
  ## License
1078
137
 
1079
- MIT License - see [LICENSE](LICENSE) for details.
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/)