sfn-diagram 0.2.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/LICENSE +21 -0
- package/README.md +461 -0
- package/dist/index.cjs +1951 -0
- package/dist/index.d.cts +1076 -0
- package/dist/index.d.ts +1076 -0
- package/dist/index.js +1911 -0
- package/package.json +81 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-present Yusuf Afzal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
# sfn-diagram
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/sfn-diagram)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
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.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- **Multiple Output Formats**: SVG (D3.js), Mermaid syntax, and PNG
|
|
11
|
+
- **Automatic Layout**: Smart graph positioning using Dagre layout engine
|
|
12
|
+
- **Full ASL Support**: All state types (Pass, Task, Choice, Wait, Succeed, Fail, Parallel, Map)
|
|
13
|
+
- **Customizable Themes**: AWS light/dark themes plus custom theme support
|
|
14
|
+
- **Flexible Layouts**: Top-bottom, left-right, right-left, bottom-top
|
|
15
|
+
- **Type-Safe**: Full TypeScript support with comprehensive type definitions
|
|
16
|
+
- **AWS SDK Integration**: Direct integration with AWS Step Functions API
|
|
17
|
+
- **Dual APIs**: Function-based and class-based interfaces
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install sfn-diagram
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
### Function-based API
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { generateSvg } from 'sfn-diagram';
|
|
31
|
+
import { writeFileSync } from 'fs';
|
|
32
|
+
|
|
33
|
+
const asl = {
|
|
34
|
+
StartAt: 'HelloWorld',
|
|
35
|
+
States: {
|
|
36
|
+
HelloWorld: {
|
|
37
|
+
Type: 'Pass',
|
|
38
|
+
Result: 'Hello, World!',
|
|
39
|
+
End: true
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const { svg, width, height } = generateSvg({
|
|
45
|
+
aslDefinition: asl,
|
|
46
|
+
theme: 'dark',
|
|
47
|
+
layout: 'LR'
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
writeFileSync('diagram.svg', svg);
|
|
51
|
+
console.log(`Generated ${width}x${height} diagram`);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Class-based API
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { SfnDiagramGenerator } from 'sfn-diagram';
|
|
58
|
+
|
|
59
|
+
const generator = new SfnDiagramGenerator()
|
|
60
|
+
.setAsl(asl)
|
|
61
|
+
.setTheme('dark')
|
|
62
|
+
.setLayout('TB')
|
|
63
|
+
.setNodeDimensions({ width: 150, height: 80 });
|
|
64
|
+
|
|
65
|
+
const { svg } = generator.generateSvg();
|
|
66
|
+
const { mermaid } = generator.generateMermaid();
|
|
67
|
+
const { png } = await generator.exportPng();
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## API Reference
|
|
71
|
+
|
|
72
|
+
### generateSvg(params)
|
|
73
|
+
|
|
74
|
+
Generate an SVG diagram using D3.js and Dagre layout.
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import { generateSvg } from 'sfn-diagram';
|
|
78
|
+
|
|
79
|
+
const result = generateSvg({
|
|
80
|
+
aslDefinition: asl, // ASL definition (object or JSON string)
|
|
81
|
+
theme: 'light', // 'light', 'dark', or CustomTheme object
|
|
82
|
+
layout: 'TB', // 'TB', 'LR', 'RL', 'BT'
|
|
83
|
+
nodeWidth: 120, // Node width in pixels
|
|
84
|
+
nodeHeight: 60, // Node height in pixels
|
|
85
|
+
rankSeparation: 50, // Vertical spacing between ranks
|
|
86
|
+
nodeSeparation: 50, // Horizontal spacing between nodes
|
|
87
|
+
padding: 20, // Diagram padding
|
|
88
|
+
edgeStyle: 'curved', // 'curved', 'straight', 'orthogonal'
|
|
89
|
+
showStateTypes: false, // Display state types on nodes
|
|
90
|
+
includeComments: true, // Use state comments as labels
|
|
91
|
+
customColors: {} // Override colors for specific states
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Returns: { svg: string, width: number, height: number, nodeCount: number }
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### generateMermaid(params)
|
|
98
|
+
|
|
99
|
+
Generate Mermaid.js diagram syntax.
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { generateMermaid } from 'sfn-diagram';
|
|
103
|
+
|
|
104
|
+
const result = generateMermaid({
|
|
105
|
+
aslDefinition: asl,
|
|
106
|
+
includeComments: true
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Returns: { mermaid: string, nodeCount: number, edgeCount: number }
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### generateDiagram(params)
|
|
113
|
+
|
|
114
|
+
Generate both SVG and Mermaid output simultaneously.
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
import { generateDiagram } from 'sfn-diagram';
|
|
118
|
+
|
|
119
|
+
const result = generateDiagram({
|
|
120
|
+
aslDefinition: asl,
|
|
121
|
+
theme: 'dark'
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Returns: { svg: SvgOutput, mermaid: MermaidOutput }
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### exportPng(params)
|
|
128
|
+
|
|
129
|
+
Export diagram as PNG image.
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
import { exportPng } from 'sfn-diagram';
|
|
133
|
+
|
|
134
|
+
const result = await exportPng({
|
|
135
|
+
aslDefinition: asl,
|
|
136
|
+
theme: 'light',
|
|
137
|
+
quality: 1.0,
|
|
138
|
+
transparent: false
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Returns: { png: Buffer, width: number, height: number }
|
|
142
|
+
writeFileSync('diagram.png', result.png);
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### generateFromAwsResponse(params)
|
|
146
|
+
|
|
147
|
+
Generate diagram directly from AWS SDK response.
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
import { SFNClient, DescribeStateMachineCommand } from '@aws-sdk/client-sfn';
|
|
151
|
+
import { generateFromAwsResponse } from 'sfn-diagram';
|
|
152
|
+
|
|
153
|
+
const client = new SFNClient({ region: 'us-east-1' });
|
|
154
|
+
const response = await client.send(
|
|
155
|
+
new DescribeStateMachineCommand({
|
|
156
|
+
stateMachineArn: 'arn:aws:states:us-east-1:123456789012:stateMachine:MyStateMachine'
|
|
157
|
+
})
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
const { svg } = generateFromAwsResponse({
|
|
161
|
+
awsResponse: response,
|
|
162
|
+
theme: 'dark'
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### SfnDiagramGenerator Class
|
|
167
|
+
|
|
168
|
+
Fluent interface for generating diagrams.
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import { SfnDiagramGenerator } from 'sfn-diagram';
|
|
172
|
+
|
|
173
|
+
const generator = new SfnDiagramGenerator()
|
|
174
|
+
.setAsl(asl)
|
|
175
|
+
.setTheme('dark')
|
|
176
|
+
.setLayout('LR')
|
|
177
|
+
.setNodeDimensions({ width: 150, height: 80 })
|
|
178
|
+
.setSpacing({ rankSeparation: 60, nodeSeparation: 60 })
|
|
179
|
+
.setEdgeStyle('curved')
|
|
180
|
+
.setPadding(30);
|
|
181
|
+
|
|
182
|
+
// Generate outputs
|
|
183
|
+
const svgResult = generator.generateSvg();
|
|
184
|
+
const mermaidResult = generator.generateMermaid();
|
|
185
|
+
const pngResult = await generator.exportPng({ quality: 1.0 });
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Configuration Options
|
|
189
|
+
|
|
190
|
+
### Themes
|
|
191
|
+
|
|
192
|
+
**Built-in themes:**
|
|
193
|
+
- `'light'` - AWS light theme (default)
|
|
194
|
+
- `'dark'` - AWS dark theme
|
|
195
|
+
|
|
196
|
+
**Custom theme:**
|
|
197
|
+
```typescript
|
|
198
|
+
const customTheme = {
|
|
199
|
+
backgroundColor: '#ffffff',
|
|
200
|
+
nodeStroke: '#232f3e',
|
|
201
|
+
nodeStrokeWidth: 2,
|
|
202
|
+
fontSize: 14,
|
|
203
|
+
fontFamily: 'Arial, sans-serif',
|
|
204
|
+
stateColors: {
|
|
205
|
+
Pass: '#4CAF50',
|
|
206
|
+
Task: '#2196F3',
|
|
207
|
+
Choice: '#FF9800',
|
|
208
|
+
Wait: '#9C27B0',
|
|
209
|
+
Succeed: '#4CAF50',
|
|
210
|
+
Fail: '#F44336',
|
|
211
|
+
Parallel: '#00BCD4',
|
|
212
|
+
Map: '#3F51B5'
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
generateSvg({ aslDefinition: asl, theme: customTheme });
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Layouts
|
|
220
|
+
|
|
221
|
+
- `'TB'` - Top to Bottom (default)
|
|
222
|
+
- `'LR'` - Left to Right
|
|
223
|
+
- `'RL'` - Right to Left
|
|
224
|
+
- `'BT'` - Bottom to Top
|
|
225
|
+
|
|
226
|
+
### Edge Styles
|
|
227
|
+
|
|
228
|
+
- `'curved'` - Smooth curved paths (default)
|
|
229
|
+
- `'straight'` - Direct straight lines
|
|
230
|
+
- `'orthogonal'` - Right-angled paths
|
|
231
|
+
|
|
232
|
+
### AWS Service Icons
|
|
233
|
+
|
|
234
|
+
Display AWS service icons on Task state nodes to improve diagram readability and quickly identify which AWS services are being used.
|
|
235
|
+
|
|
236
|
+
**Basic Usage:**
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
import { generateSvg } from 'sfn-diagram';
|
|
240
|
+
|
|
241
|
+
const { svg } = generateSvg({
|
|
242
|
+
aslDefinition: asl,
|
|
243
|
+
showIcons: true, // Enable icons
|
|
244
|
+
iconPosition: 'left', // Icon placement (default)
|
|
245
|
+
iconSize: 24 // Icon dimensions in pixels (default)
|
|
246
|
+
});
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
**Supported Services (30+):**
|
|
250
|
+
|
|
251
|
+
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.
|
|
252
|
+
|
|
253
|
+
**Icon Positioning:**
|
|
254
|
+
|
|
255
|
+
- `'left'` - Icon to the left of label (default, matches AWS Console style)
|
|
256
|
+
- `'top'` - Icon above label
|
|
257
|
+
- `'right'` - Icon to the right of label
|
|
258
|
+
|
|
259
|
+
**Custom Icon Resolver:**
|
|
260
|
+
|
|
261
|
+
Provide your own icon URLs for services:
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
const { svg } = generateSvg({
|
|
265
|
+
aslDefinition: asl,
|
|
266
|
+
showIcons: true,
|
|
267
|
+
iconResolver: (service) => {
|
|
268
|
+
if (service === 'lambda') {
|
|
269
|
+
return 'https://my-cdn.com/lambda-icon.svg';
|
|
270
|
+
}
|
|
271
|
+
return null; // Fall back to default
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Recommended Node Dimensions:**
|
|
277
|
+
|
|
278
|
+
For optimal icon visibility, use wider nodes:
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
const { svg } = generateSvg({
|
|
282
|
+
aslDefinition: asl,
|
|
283
|
+
showIcons: true,
|
|
284
|
+
nodeWidth: 150, // Default: 120
|
|
285
|
+
nodeHeight: 70 // Default: 60
|
|
286
|
+
});
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
**Important Notes:**
|
|
290
|
+
- Icons are only displayed on Task states (states with AWS service integrations)
|
|
291
|
+
- Icons are sourced from [aws-icons](https://www.npmjs.com/package/aws-icons) via jsDelivr CDN
|
|
292
|
+
- **PNG export limitation**: External CDN images may not render in PNG output due to headless browser limitations. **Use SVG output for diagrams with icons.**
|
|
293
|
+
- Unsupported services gracefully fall back to text-only labels
|
|
294
|
+
- Icons are opt-in via `showIcons: true` (disabled by default)
|
|
295
|
+
|
|
296
|
+
## Supported State Types
|
|
297
|
+
|
|
298
|
+
All AWS Step Functions state types are fully supported:
|
|
299
|
+
|
|
300
|
+
| State Type | Shape | Description |
|
|
301
|
+
|------------|-------|-------------|
|
|
302
|
+
| **Pass** | Rectangle | Passes input to output, optionally with transformation |
|
|
303
|
+
| **Task** | Rectangle | Performs work via Lambda, Activity, or service integration |
|
|
304
|
+
| **Choice** | Diamond | Adds branching logic based on input |
|
|
305
|
+
| **Wait** | Rectangle | Delays execution for specified time |
|
|
306
|
+
| **Succeed** | Circle | Terminates successfully |
|
|
307
|
+
| **Fail** | Circle | Terminates with failure |
|
|
308
|
+
| **Parallel** | Rectangle | Executes branches in parallel |
|
|
309
|
+
| **Map** | Rectangle | Iterates over array items |
|
|
310
|
+
|
|
311
|
+
## Examples
|
|
312
|
+
|
|
313
|
+
### Complex State Machine
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
import { generateSvg } from 'sfn-diagram';
|
|
317
|
+
|
|
318
|
+
const complexAsl = {
|
|
319
|
+
Comment: 'Order processing workflow',
|
|
320
|
+
StartAt: 'ValidateOrder',
|
|
321
|
+
States: {
|
|
322
|
+
ValidateOrder: {
|
|
323
|
+
Type: 'Task',
|
|
324
|
+
Resource: 'arn:aws:lambda:us-east-1:123456789012:function:ValidateOrder',
|
|
325
|
+
Next: 'CheckInventory',
|
|
326
|
+
Catch: [{
|
|
327
|
+
ErrorEquals: ['ValidationError'],
|
|
328
|
+
Next: 'OrderFailed'
|
|
329
|
+
}]
|
|
330
|
+
},
|
|
331
|
+
CheckInventory: {
|
|
332
|
+
Type: 'Task',
|
|
333
|
+
Resource: 'arn:aws:lambda:us-east-1:123456789012:function:CheckInventory',
|
|
334
|
+
Next: 'IsInStock'
|
|
335
|
+
},
|
|
336
|
+
IsInStock: {
|
|
337
|
+
Type: 'Choice',
|
|
338
|
+
Choices: [{
|
|
339
|
+
Variable: '$.inStock',
|
|
340
|
+
BooleanEquals: true,
|
|
341
|
+
Next: 'ProcessPayment'
|
|
342
|
+
}],
|
|
343
|
+
Default: 'OutOfStock'
|
|
344
|
+
},
|
|
345
|
+
ProcessPayment: {
|
|
346
|
+
Type: 'Task',
|
|
347
|
+
Resource: 'arn:aws:states:::dynamodb:putItem',
|
|
348
|
+
Next: 'OrderSucceeded'
|
|
349
|
+
},
|
|
350
|
+
OutOfStock: {
|
|
351
|
+
Type: 'Fail',
|
|
352
|
+
Error: 'OutOfStockError',
|
|
353
|
+
Cause: 'Item not available'
|
|
354
|
+
},
|
|
355
|
+
OrderFailed: {
|
|
356
|
+
Type: 'Fail',
|
|
357
|
+
Error: 'OrderValidationError'
|
|
358
|
+
},
|
|
359
|
+
OrderSucceeded: {
|
|
360
|
+
Type: 'Succeed'
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
const { svg } = generateSvg({
|
|
366
|
+
aslDefinition: complexAsl,
|
|
367
|
+
theme: 'dark',
|
|
368
|
+
layout: 'TB',
|
|
369
|
+
edgeStyle: 'curved',
|
|
370
|
+
nodeWidth: 150,
|
|
371
|
+
nodeHeight: 70
|
|
372
|
+
});
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Parallel State Machine
|
|
376
|
+
|
|
377
|
+
```typescript
|
|
378
|
+
const parallelAsl = {
|
|
379
|
+
StartAt: 'ProcessInParallel',
|
|
380
|
+
States: {
|
|
381
|
+
ProcessInParallel: {
|
|
382
|
+
Type: 'Parallel',
|
|
383
|
+
Branches: [
|
|
384
|
+
{
|
|
385
|
+
StartAt: 'Branch1',
|
|
386
|
+
States: {
|
|
387
|
+
Branch1: { Type: 'Pass', Result: 'Branch 1', End: true }
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
StartAt: 'Branch2',
|
|
392
|
+
States: {
|
|
393
|
+
Branch2: { Type: 'Pass', Result: 'Branch 2', End: true }
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
],
|
|
397
|
+
Next: 'FinalState'
|
|
398
|
+
},
|
|
399
|
+
FinalState: {
|
|
400
|
+
Type: 'Succeed'
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
const { svg } = generateSvg({ aslDefinition: parallelAsl });
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### Export Multiple Formats
|
|
409
|
+
|
|
410
|
+
```typescript
|
|
411
|
+
import { generateDiagram, exportPng } from 'sfn-diagram';
|
|
412
|
+
import { writeFileSync } from 'fs';
|
|
413
|
+
|
|
414
|
+
// Generate SVG and Mermaid
|
|
415
|
+
const { svg, mermaid } = generateDiagram({ aslDefinition: asl });
|
|
416
|
+
writeFileSync('diagram.svg', svg.svg);
|
|
417
|
+
writeFileSync('diagram.mmd', mermaid.mermaid);
|
|
418
|
+
|
|
419
|
+
// Generate PNG
|
|
420
|
+
const { png } = await exportPng({
|
|
421
|
+
aslDefinition: asl,
|
|
422
|
+
quality: 1.0,
|
|
423
|
+
transparent: false
|
|
424
|
+
});
|
|
425
|
+
writeFileSync('diagram.png', png);
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
## TypeScript Support
|
|
429
|
+
|
|
430
|
+
Full TypeScript definitions included:
|
|
431
|
+
|
|
432
|
+
```typescript
|
|
433
|
+
import type {
|
|
434
|
+
AslDefinition,
|
|
435
|
+
DiagramOptions,
|
|
436
|
+
SvgOutput,
|
|
437
|
+
MermaidOutput,
|
|
438
|
+
PngOutput,
|
|
439
|
+
CustomTheme,
|
|
440
|
+
StateType
|
|
441
|
+
} from 'sfn-diagram';
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
## Contributing
|
|
445
|
+
|
|
446
|
+
Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
447
|
+
|
|
448
|
+
## License
|
|
449
|
+
|
|
450
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
451
|
+
|
|
452
|
+
## Author
|
|
453
|
+
|
|
454
|
+
Yusuf Afzal
|
|
455
|
+
|
|
456
|
+
## Links
|
|
457
|
+
|
|
458
|
+
- [GitHub Repository](https://github.com/yusufaf/sfn-diagram)
|
|
459
|
+
- [npm Package](https://www.npmjs.com/package/sfn-diagram)
|
|
460
|
+
- [Issue Tracker](https://github.com/yusufaf/sfn-diagram/issues)
|
|
461
|
+
- [AWS Step Functions Documentation](https://docs.aws.amazon.com/step-functions/)
|