@synergenius/flow-weaver 0.2.1 → 0.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 +261 -200
- package/dist/annotation-generator.js +36 -0
- package/dist/api/generate-in-place.js +39 -0
- package/dist/api/generate.js +11 -1
- package/dist/api/manipulation/nodes.js +22 -0
- package/dist/ast/types.d.ts +27 -1
- package/dist/built-in-nodes/index.d.ts +1 -0
- package/dist/built-in-nodes/index.js +1 -0
- package/dist/built-in-nodes/invoke-workflow.js +12 -1
- package/dist/built-in-nodes/mock-types.d.ts +2 -0
- package/dist/built-in-nodes/wait-for-agent.d.ts +13 -0
- package/dist/built-in-nodes/wait-for-agent.js +26 -0
- package/dist/chevrotain-parser/fan-parser.d.ts +38 -0
- package/dist/chevrotain-parser/fan-parser.js +149 -0
- package/dist/chevrotain-parser/grammar-diagrams.d.ts +1 -0
- package/dist/chevrotain-parser/grammar-diagrams.js +3 -0
- package/dist/chevrotain-parser/index.d.ts +3 -1
- package/dist/chevrotain-parser/index.js +3 -1
- package/dist/chevrotain-parser/tokens.d.ts +2 -0
- package/dist/chevrotain-parser/tokens.js +10 -0
- package/dist/cli/commands/diagram.d.ts +2 -1
- package/dist/cli/commands/diagram.js +9 -6
- package/dist/cli/commands/docs.d.ts +11 -0
- package/dist/cli/commands/docs.js +77 -0
- package/dist/cli/commands/run.js +59 -1
- package/dist/cli/flow-weaver.mjs +2447 -594
- package/dist/cli/index.js +40 -2
- package/dist/diagram/geometry.d.ts +9 -4
- package/dist/diagram/geometry.js +262 -31
- package/dist/diagram/html-viewer.d.ts +12 -0
- package/dist/diagram/html-viewer.js +399 -0
- package/dist/diagram/index.d.ts +12 -0
- package/dist/diagram/index.js +22 -0
- package/dist/diagram/renderer.js +137 -116
- package/dist/diagram/types.d.ts +1 -0
- package/dist/doc-metadata/extractors/annotations.js +282 -1
- package/dist/doc-metadata/types.d.ts +6 -0
- package/dist/docs/index.d.ts +54 -0
- package/dist/docs/index.js +256 -0
- package/dist/generator/control-flow.d.ts +13 -0
- package/dist/generator/control-flow.js +74 -0
- package/dist/generator/inngest.js +23 -0
- package/dist/generator/unified.js +122 -2
- package/dist/jsdoc-parser.d.ts +24 -0
- package/dist/jsdoc-parser.js +41 -1
- package/dist/mcp/agent-channel.d.ts +35 -0
- package/dist/mcp/agent-channel.js +61 -0
- package/dist/mcp/run-registry.d.ts +29 -0
- package/dist/mcp/run-registry.js +24 -0
- package/dist/mcp/server.js +2 -0
- package/dist/mcp/tools-diagram.d.ts +1 -1
- package/dist/mcp/tools-diagram.js +15 -7
- package/dist/mcp/tools-docs.d.ts +3 -0
- package/dist/mcp/tools-docs.js +62 -0
- package/dist/mcp/tools-editor.js +77 -3
- package/dist/mcp/tools-query.js +3 -1
- package/dist/mcp/workflow-executor.d.ts +28 -0
- package/dist/mcp/workflow-executor.js +66 -3
- package/dist/parser.d.ts +8 -0
- package/dist/parser.js +100 -0
- package/dist/runtime/ExecutionContext.d.ts +2 -0
- package/dist/runtime/ExecutionContext.js +2 -0
- package/dist/runtime/events.d.ts +1 -1
- package/dist/sugar-optimizer.js +28 -3
- package/dist/validator.d.ts +8 -0
- package/dist/validator.js +92 -0
- package/docs/reference/advanced-annotations.md +431 -0
- package/docs/reference/built-in-nodes.md +225 -0
- package/docs/reference/cli-reference.md +882 -0
- package/docs/reference/compilation.md +351 -0
- package/docs/reference/concepts.md +400 -0
- package/docs/reference/debugging.md +255 -0
- package/docs/reference/deployment.md +207 -0
- package/docs/reference/error-codes.md +686 -0
- package/docs/reference/export-interface.md +229 -0
- package/docs/reference/iterative-development.md +186 -0
- package/docs/reference/jsdoc-grammar.md +471 -0
- package/docs/reference/marketplace.md +205 -0
- package/docs/reference/node-conversion.md +308 -0
- package/docs/reference/patterns.md +161 -0
- package/docs/reference/scaffold.md +160 -0
- package/docs/reference/tutorial.md +519 -0
- package/package.json +10 -4
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Advanced Annotations
|
|
3
|
+
description: Pull execution, execution strategies, merge strategies, auto-connect, strict types, path and map sugar, node attributes, and multi-workflow files
|
|
4
|
+
keywords: [pullExecution, executeWhen, mergeStrategy, autoConnect, strictTypes, path, map, sugar, attributes, expr, portOrder, portLabel, minimized, multi-workflow, CONJUNCTION, DISJUNCTION, FIRST, LAST, COLLECT, MERGE, CONCAT]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Advanced Annotations
|
|
8
|
+
|
|
9
|
+
This guide covers annotations that go beyond the basics in [Concepts](concepts). Each feature is fully supported by the parser, validator, and compiler.
|
|
10
|
+
|
|
11
|
+
## Pull Execution
|
|
12
|
+
|
|
13
|
+
Pull execution enables **lazy evaluation**. Nodes marked with `@pullExecution` don't execute eagerly — they only run when a downstream node actually consumes their output.
|
|
14
|
+
|
|
15
|
+
### Node Type Level
|
|
16
|
+
|
|
17
|
+
Declare a node type as pull-executed by default:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
/**
|
|
21
|
+
* @flowWeaver nodeType
|
|
22
|
+
* @expression
|
|
23
|
+
* @pullExecution execute
|
|
24
|
+
* @input value
|
|
25
|
+
* @output tripled
|
|
26
|
+
*/
|
|
27
|
+
function triple(value: number): { tripled: number } {
|
|
28
|
+
return { tripled: value * 3 };
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The argument (`execute`) specifies which STEP port triggers the lazy evaluation.
|
|
33
|
+
|
|
34
|
+
### Instance Level Override
|
|
35
|
+
|
|
36
|
+
Override pull execution per-instance in a workflow using the `[pullExecution: ...]` attribute:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
/**
|
|
40
|
+
* @flowWeaver workflow
|
|
41
|
+
* @node t triple [pullExecution: execute]
|
|
42
|
+
* @connect Start.value -> t.value
|
|
43
|
+
* @connect t.tripled -> Exit.result
|
|
44
|
+
*/
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
This is useful when a node type is not pull-executed by default, but a specific instance should be lazy.
|
|
48
|
+
|
|
49
|
+
### How It Works
|
|
50
|
+
|
|
51
|
+
1. During compilation, pull execution nodes are tracked separately
|
|
52
|
+
2. Their output variables use `let` declarations (initially `undefined`)
|
|
53
|
+
3. The node function is only called when a downstream node reads the output
|
|
54
|
+
4. If no downstream node reads the output, the node never executes
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Execution Strategies (`@executeWhen`)
|
|
59
|
+
|
|
60
|
+
Controls how a node evaluates incoming STEP signals before firing. This matters when a node has multiple STEP inputs.
|
|
61
|
+
|
|
62
|
+
| Strategy | Behavior | Use Case |
|
|
63
|
+
|----------|----------|----------|
|
|
64
|
+
| `CONJUNCTION` | Execute when **ALL** incoming signals arrive (AND) | Default. Synchronization points |
|
|
65
|
+
| `DISJUNCTION` | Execute when **ANY** signal arrives (OR) | Priority routing, first-response |
|
|
66
|
+
| `CUSTOM` | Execution controlled by custom logic | Advanced patterns |
|
|
67
|
+
|
|
68
|
+
### Node Type Level
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
/**
|
|
72
|
+
* @flowWeaver nodeType
|
|
73
|
+
* @executeWhen DISJUNCTION
|
|
74
|
+
* @input data
|
|
75
|
+
* @output result
|
|
76
|
+
*/
|
|
77
|
+
function firstResponse(execute: boolean, data: string) {
|
|
78
|
+
if (!execute) return { onSuccess: false, onFailure: false, result: '' };
|
|
79
|
+
return { onSuccess: true, onFailure: false, result: data };
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Instance Level
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
/**
|
|
87
|
+
* @flowWeaver workflow
|
|
88
|
+
* @node fr firstResponse [executeWhen: DISJUNCTION]
|
|
89
|
+
*/
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Merge Strategies
|
|
95
|
+
|
|
96
|
+
When multiple connections target the same DATA input port, a merge strategy determines how the values are combined. Without a merge strategy, multiple connections to the same input produce a validation error (`MULTIPLE_CONNECTIONS_TO_INPUT`).
|
|
97
|
+
|
|
98
|
+
| Strategy | Behavior | Result Type |
|
|
99
|
+
|----------|----------|-------------|
|
|
100
|
+
| `FIRST` | First non-undefined value | Same as port type |
|
|
101
|
+
| `LAST` | Last non-undefined value | Same as port type |
|
|
102
|
+
| `COLLECT` | Collect all values into an array | Array |
|
|
103
|
+
| `MERGE` | Deep merge with `Object.assign` | Object |
|
|
104
|
+
| `CONCAT` | Concatenate arrays/flatten | Array |
|
|
105
|
+
|
|
106
|
+
### Declaring Merge Strategy
|
|
107
|
+
|
|
108
|
+
Set the strategy on the port definition using `[mergeStrategy:X]`:
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
/**
|
|
112
|
+
* @flowWeaver nodeType
|
|
113
|
+
* @expression
|
|
114
|
+
* @input items [mergeStrategy:COLLECT] - Collect all incoming items
|
|
115
|
+
* @output combined
|
|
116
|
+
*/
|
|
117
|
+
function aggregate(items: unknown[]): { combined: unknown[] } {
|
|
118
|
+
return { combined: items };
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Generated Code
|
|
123
|
+
|
|
124
|
+
The compiler generates appropriate merge expressions:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// FIRST: returns first non-undefined value
|
|
128
|
+
const merged = (() => { const __s__ = [a, b, c]; return __s__.find(v => v !== undefined); })();
|
|
129
|
+
|
|
130
|
+
// COLLECT: wraps all into array
|
|
131
|
+
const merged = [a, b, c];
|
|
132
|
+
|
|
133
|
+
// MERGE: Object.assign
|
|
134
|
+
const merged = Object.assign({}, a, b, c);
|
|
135
|
+
|
|
136
|
+
// CONCAT: flatten arrays
|
|
137
|
+
const merged = [a, b, c].flat();
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Auto-Connect (`@autoConnect`)
|
|
143
|
+
|
|
144
|
+
Enables automatic linear connection wiring. When `@autoConnect` is present and no explicit `@connect` annotations exist, nodes are wired sequentially in declaration order:
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
Start -> first @node -> second @node -> ... -> last @node -> Exit
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Data ports are matched by name — if node A has an output named `result` and node B has an input named `result`, they are automatically connected.
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
/**
|
|
154
|
+
* @flowWeaver workflow
|
|
155
|
+
* @autoConnect
|
|
156
|
+
* @node v validateRecord
|
|
157
|
+
* @node e enrichRecord
|
|
158
|
+
* @node s scoreRecord
|
|
159
|
+
* @param data - Input record
|
|
160
|
+
* @returns result - Scored record
|
|
161
|
+
*/
|
|
162
|
+
export function pipeline(params: { data: Record<string, unknown> }): { result: Record<string, unknown> } {
|
|
163
|
+
throw new Error('Not compiled');
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
This is equivalent to manually writing:
|
|
168
|
+
```
|
|
169
|
+
@connect Start.data -> v.data
|
|
170
|
+
@connect v.onSuccess -> e.execute
|
|
171
|
+
@connect v.result -> e.data
|
|
172
|
+
@connect e.onSuccess -> s.execute
|
|
173
|
+
@connect e.result -> s.data
|
|
174
|
+
@connect s.result -> Exit.result
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**Important:** If any explicit `@connect` annotations are present, `@autoConnect` is disabled. It's all-or-nothing.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Strict Types (`@strictTypes`)
|
|
182
|
+
|
|
183
|
+
By default, type mismatches between connected ports produce warnings. With `@strictTypes`, they become errors.
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
/**
|
|
187
|
+
* @flowWeaver workflow
|
|
188
|
+
* @strictTypes
|
|
189
|
+
* @node n myNode
|
|
190
|
+
* @connect Start.count -> n.text
|
|
191
|
+
*/
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Type compatibility levels:
|
|
195
|
+
- **exact** — Same type (e.g. `STRING` → `STRING`)
|
|
196
|
+
- **assignable** — Safe conversion (e.g. `NUMBER` → `ANY`)
|
|
197
|
+
- **coercible** — Lossy conversion (e.g. `NUMBER` → `STRING`) — warning by default, error with `@strictTypes`
|
|
198
|
+
- **incompatible** — No conversion possible — always an error
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Path Sugar (`@path`)
|
|
203
|
+
|
|
204
|
+
Syntactic sugar for declaring multi-step execution routes. A `@path` annotation expands to a chain of STEP connections (execute → onSuccess).
|
|
205
|
+
|
|
206
|
+
### Basic Syntax
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
/**
|
|
210
|
+
* @flowWeaver workflow
|
|
211
|
+
* @node v validate
|
|
212
|
+
* @node e enrich
|
|
213
|
+
* @node s score
|
|
214
|
+
* @path Start -> v -> e -> s -> Exit
|
|
215
|
+
*/
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
This expands to:
|
|
219
|
+
```
|
|
220
|
+
@connect Start.execute -> v.execute
|
|
221
|
+
@connect v.onSuccess -> e.execute
|
|
222
|
+
@connect e.onSuccess -> s.execute
|
|
223
|
+
@connect s.onSuccess -> Exit.execute
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Branching with `:ok` and `:fail`
|
|
227
|
+
|
|
228
|
+
Use `:ok` or `:fail` suffixes to route through `onSuccess` or `onFailure`:
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
/**
|
|
232
|
+
* @flowWeaver workflow
|
|
233
|
+
* @node v validate
|
|
234
|
+
* @node router routeUrgency
|
|
235
|
+
* @node handler handle
|
|
236
|
+
* @node esc escalate
|
|
237
|
+
*
|
|
238
|
+
* @path Start -> v -> router:ok -> handler -> Exit
|
|
239
|
+
* @path Start -> v -> router:fail -> esc -> Exit
|
|
240
|
+
*/
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Without a suffix, `:ok` (onSuccess) is the default. Duplicate connections from overlapping paths are automatically deduplicated.
|
|
244
|
+
|
|
245
|
+
### Path Validation
|
|
246
|
+
|
|
247
|
+
The sugar optimizer validates that all nodes referenced in `@path` exist and that the expected control-flow connections are still valid. Stale paths are automatically filtered during parse-regenerate round-trips.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Map Sugar (`@map`)
|
|
252
|
+
|
|
253
|
+
Syntactic sugar for forEach iteration patterns. A `@map` expands to a synthetic iterator node type with proper scopes and connections.
|
|
254
|
+
|
|
255
|
+
### Basic Syntax
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
/**
|
|
259
|
+
* @flowWeaver workflow
|
|
260
|
+
* @node proc doubleIt
|
|
261
|
+
* @map loop proc over Start.items
|
|
262
|
+
* @connect loop.results -> Exit.results
|
|
263
|
+
*/
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
This creates a `loop` instance of a synthetic `MAP_ITERATOR` node type that:
|
|
267
|
+
1. Takes `Start.items` as the array to iterate
|
|
268
|
+
2. Calls `proc` (doubleIt) for each element
|
|
269
|
+
3. Collects results into `loop.results`
|
|
270
|
+
|
|
271
|
+
### With Explicit Port Mapping
|
|
272
|
+
|
|
273
|
+
Specify which input/output ports to use on the child node:
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
@map loop proc(file -> post) over scan.files
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
This maps:
|
|
280
|
+
- `scan.files` array elements → `proc.file` (input)
|
|
281
|
+
- `proc.post` (output) → collected into `loop.results`
|
|
282
|
+
|
|
283
|
+
If ports are omitted, the first non-STEP input and first non-STEP output are used automatically.
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Node Instance Attributes
|
|
288
|
+
|
|
289
|
+
Node instances in workflows support attribute brackets `[...]` for configuration. Multiple brackets can be combined.
|
|
290
|
+
|
|
291
|
+
### Expression Bindings (`[expr: ...]`)
|
|
292
|
+
|
|
293
|
+
Set port values via JavaScript expressions instead of connections:
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
@node wait waitForEvent [expr: eventName="'app/expense.approved'", match="'data.expenseId'", timeout="'48h'"]
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Each assignment is `portName="expression"`. Multiple assignments are comma-separated.
|
|
300
|
+
|
|
301
|
+
### Port Order (`[portOrder: ...]`)
|
|
302
|
+
|
|
303
|
+
Control the visual ordering of ports:
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
@node myNode MyType [portOrder: input1=1, input2=2, output1=3]
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### Port Labels (`[portLabel: ...]`)
|
|
310
|
+
|
|
311
|
+
Override port display labels:
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
@node myNode MyType [portLabel: execute="Start Here", onSuccess="Done"]
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Minimized (`[minimized]`)
|
|
318
|
+
|
|
319
|
+
Display the node in a collapsed/minimized state:
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
@node helper HelperNode [minimized]
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Size (`[size: W H]`)
|
|
326
|
+
|
|
327
|
+
Custom node dimensions in the visual editor:
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
@node big BigNode [size: 400 300]
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Color (`[color: "..."]`)
|
|
334
|
+
|
|
335
|
+
Custom node color:
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
@node special MyType [color: "#ff6b35"]
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Icon (`[icon: "..."]`)
|
|
342
|
+
|
|
343
|
+
Custom node icon:
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
@node db DatabaseNode [icon: "database"]
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Tags (`[tags: ...]`)
|
|
350
|
+
|
|
351
|
+
Visual tags/badges on the instance. Each tag has a label string and optional tooltip:
|
|
352
|
+
|
|
353
|
+
```typescript
|
|
354
|
+
@node myNode MyType [tags: "async" "Runs asynchronously", "beta"]
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Combining Attributes
|
|
358
|
+
|
|
359
|
+
Multiple attribute brackets can appear on the same `@node`:
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
@node wait waitForEvent [expr: eventName="'approval'", timeout="'24h'"] [minimized] [color: "#3b82f6"]
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## Multi-Workflow Files
|
|
368
|
+
|
|
369
|
+
A single TypeScript file can contain multiple `@flowWeaver workflow` annotations. Each workflow is a separate exported function.
|
|
370
|
+
|
|
371
|
+
```typescript
|
|
372
|
+
/**
|
|
373
|
+
* @flowWeaver workflow
|
|
374
|
+
* @node v validate
|
|
375
|
+
* @path Start -> v -> Exit
|
|
376
|
+
*/
|
|
377
|
+
export function validatePipeline(params: { data: string }) { ... }
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* @flowWeaver workflow
|
|
381
|
+
* @node e enrich
|
|
382
|
+
* @path Start -> e -> Exit
|
|
383
|
+
*/
|
|
384
|
+
export function enrichPipeline(params: { data: string }) { ... }
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### Targeting a Specific Workflow
|
|
388
|
+
|
|
389
|
+
Most CLI commands accept `--workflow-name` or `-w` to target a specific workflow:
|
|
390
|
+
|
|
391
|
+
```bash
|
|
392
|
+
flow-weaver compile multi.ts --workflow-name validatePipeline
|
|
393
|
+
flow-weaver validate multi.ts -w enrichPipeline
|
|
394
|
+
flow-weaver run multi.ts -w validatePipeline --params '{"data": "test"}'
|
|
395
|
+
flow-weaver describe multi.ts --workflow-name enrichPipeline
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
Without this flag, all workflows in the file are processed.
|
|
399
|
+
|
|
400
|
+
### Cross-Workflow References
|
|
401
|
+
|
|
402
|
+
Workflows in the same file can reference each other as node types. The parser does a first-pass signature extraction, so the order of declaration doesn't matter.
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
## Node Type Annotations
|
|
407
|
+
|
|
408
|
+
These annotations go on `@flowWeaver nodeType` blocks:
|
|
409
|
+
|
|
410
|
+
| Annotation | Purpose | Example |
|
|
411
|
+
|------------|---------|---------|
|
|
412
|
+
| `@name` | Override display name | `@name MyCustomName` |
|
|
413
|
+
| `@label` | Human-readable label | `@label Fetch with Timeout` |
|
|
414
|
+
| `@description` | Node description | `@description Validates expense data` |
|
|
415
|
+
| `@color` | Custom color | `@color "#ff6b35"` |
|
|
416
|
+
| `@icon` | Custom icon | `@icon "database"` |
|
|
417
|
+
| `@tag` | Visual tag/badge | `@tag async` or `@tag beta "Experimental"` |
|
|
418
|
+
| `@scope` | Provides a named scope | `@scope processItem` |
|
|
419
|
+
| `@expression` | Expression mode (simplified signature) | `@expression` |
|
|
420
|
+
| `@executeWhen` | Execution strategy | `@executeWhen DISJUNCTION` |
|
|
421
|
+
| `@pullExecution` | Lazy evaluation | `@pullExecution execute` |
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
## Related Topics
|
|
426
|
+
|
|
427
|
+
- [Concepts](concepts) — Core workflow fundamentals
|
|
428
|
+
- [JSDoc Grammar](jsdoc-grammar) — Formal EBNF syntax for all annotations
|
|
429
|
+
- [Compilation](compilation) — How annotations affect code generation
|
|
430
|
+
- [Error Codes](error-codes) — Validation errors for annotation issues
|
|
431
|
+
- [CLI Reference](cli-reference) — All command flags
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Built-in Nodes
|
|
3
|
+
description: Built-in runtime nodes (delay, waitForEvent, invokeWorkflow) and the mock system for testing
|
|
4
|
+
keywords: [delay, waitForEvent, invokeWorkflow, built-in, runtime, mock, mocks, FwMockConfig, testing, fast, events, invocations, sleep, duration, timeout]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Built-in Nodes
|
|
8
|
+
|
|
9
|
+
Flow Weaver provides three built-in node types for common runtime operations. All three support a **mock system** for local testing without real side effects.
|
|
10
|
+
|
|
11
|
+
## delay
|
|
12
|
+
|
|
13
|
+
Pauses execution for a specified duration.
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
/**
|
|
17
|
+
* @flowWeaver nodeType
|
|
18
|
+
* @input duration - Duration to sleep (e.g. "30s", "5m", "1h", "2d")
|
|
19
|
+
* @output elapsed - Always true after sleep completes
|
|
20
|
+
*/
|
|
21
|
+
async function delay(execute: boolean, duration: string)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Duration Format
|
|
25
|
+
|
|
26
|
+
`<number><unit>` where unit is one of:
|
|
27
|
+
|
|
28
|
+
| Unit | Meaning | Example |
|
|
29
|
+
|------|---------|---------|
|
|
30
|
+
| `ms` | Milliseconds | `500ms` |
|
|
31
|
+
| `s` | Seconds | `30s` |
|
|
32
|
+
| `m` | Minutes | `5m` |
|
|
33
|
+
| `h` | Hours | `1h` |
|
|
34
|
+
| `d` | Days | `2d` |
|
|
35
|
+
|
|
36
|
+
### Usage in Workflow
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
/**
|
|
40
|
+
* @flowWeaver workflow
|
|
41
|
+
* @node wait delay [expr: duration="'30s'"]
|
|
42
|
+
* @path Start -> wait -> Exit
|
|
43
|
+
*/
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Mock Behavior
|
|
47
|
+
|
|
48
|
+
When `fast: true` is set in mock config, `delay` sleeps for 1ms instead of the real duration.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## waitForEvent
|
|
53
|
+
|
|
54
|
+
Pauses execution until a named event is received. Designed for human-in-the-loop patterns and inter-workflow communication.
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
/**
|
|
58
|
+
* @flowWeaver nodeType
|
|
59
|
+
* @input eventName - Event name to wait for (e.g. "app/approval.received")
|
|
60
|
+
* @input [match] - Field to match between trigger and waited event (e.g. "data.requestId")
|
|
61
|
+
* @input [timeout] - Max wait time (e.g. "24h", "7d"). Empty = no timeout
|
|
62
|
+
* @output eventData - The received event's data payload
|
|
63
|
+
*/
|
|
64
|
+
async function waitForEvent(execute: boolean, eventName: string, match?: string, timeout?: string)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Usage in Workflow
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
/**
|
|
71
|
+
* @flowWeaver workflow
|
|
72
|
+
* @node wait waitForEvent [expr: eventName="'app/expense.approved'", match="'data.expenseId'", timeout="'48h'"]
|
|
73
|
+
* @path Start -> wait -> Exit
|
|
74
|
+
*/
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Mock Behavior
|
|
78
|
+
|
|
79
|
+
- If `events[eventName]` is set in mock config → returns that data via `onSuccess`
|
|
80
|
+
- If no mock data for the event name → simulates timeout via `onFailure`
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## invokeWorkflow
|
|
85
|
+
|
|
86
|
+
Invokes another workflow (Inngest function) and waits for its result. Enables workflow composition.
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
/**
|
|
90
|
+
* @flowWeaver nodeType
|
|
91
|
+
* @input functionId - Inngest function ID (e.g. "my-service/sub-workflow")
|
|
92
|
+
* @input payload - Data to pass as event.data to the invoked function
|
|
93
|
+
* @input [timeout] - Max wait time (e.g. "1h")
|
|
94
|
+
* @output result - Return value from the invoked function
|
|
95
|
+
*/
|
|
96
|
+
async function invokeWorkflow(execute: boolean, functionId: string, payload: object, timeout?: string)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Usage in Workflow
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
/**
|
|
103
|
+
* @flowWeaver workflow
|
|
104
|
+
* @node sub invokeWorkflow [expr: functionId="'my-service/payment-processor'", timeout="'5m'"]
|
|
105
|
+
* @connect Start.payload -> sub.payload
|
|
106
|
+
* @connect sub.result -> Exit.result
|
|
107
|
+
* @path Start -> sub -> Exit
|
|
108
|
+
*/
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Mock Behavior
|
|
112
|
+
|
|
113
|
+
- If `invocations[functionId]` is set in mock config → returns that result via `onSuccess`
|
|
114
|
+
- If no mock data for the function ID → simulates failure via `onFailure`
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Mock System
|
|
119
|
+
|
|
120
|
+
The mock system lets you test workflows with built-in nodes locally without real delays, event systems, or external workflow invocations.
|
|
121
|
+
|
|
122
|
+
### FwMockConfig
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
interface FwMockConfig {
|
|
126
|
+
/** Mock event data keyed by event name. Used by waitForEvent. */
|
|
127
|
+
events?: Record<string, object>;
|
|
128
|
+
/** Mock invocation results keyed by functionId. Used by invokeWorkflow. */
|
|
129
|
+
invocations?: Record<string, object>;
|
|
130
|
+
/** When true, delay nodes skip the real sleep (1ms instead of full duration). */
|
|
131
|
+
fast?: boolean;
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### CLI Usage
|
|
136
|
+
|
|
137
|
+
Pass mock config directly:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
flow-weaver run workflow.ts --mocks '{"fast": true, "events": {"app/approved": {"status": "ok"}}}'
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Or from a file:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
flow-weaver run workflow.ts --mocks-file mocks.json
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**mocks.json:**
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"fast": true,
|
|
153
|
+
"events": {
|
|
154
|
+
"app/expense.approved": { "status": "approved", "approvedBy": "manager@co.com" },
|
|
155
|
+
"app/expense.withdrawn": { "status": "withdrawn" }
|
|
156
|
+
},
|
|
157
|
+
"invocations": {
|
|
158
|
+
"my-service/payment-processor": { "transactionId": "tx-123", "success": true }
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Programmatic Usage
|
|
164
|
+
|
|
165
|
+
Set mocks on `globalThis` before running the workflow:
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
(globalThis as any).__fw_mocks__ = {
|
|
169
|
+
fast: true,
|
|
170
|
+
events: {
|
|
171
|
+
'app/expense.approved': { status: 'approved' }
|
|
172
|
+
},
|
|
173
|
+
invocations: {
|
|
174
|
+
'my-service/sub-workflow': { result: 'success' }
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// Run your compiled workflow
|
|
179
|
+
const result = await expenseWorkflow({ expenseId: 'exp-1', amount: 500 });
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Testing Patterns
|
|
183
|
+
|
|
184
|
+
**Unit test with mocks:**
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
188
|
+
|
|
189
|
+
describe('expense workflow', () => {
|
|
190
|
+
beforeEach(() => {
|
|
191
|
+
(globalThis as any).__fw_mocks__ = {
|
|
192
|
+
fast: true,
|
|
193
|
+
events: {
|
|
194
|
+
'app/expense.approved': { status: 'approved' }
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
afterEach(() => {
|
|
200
|
+
delete (globalThis as any).__fw_mocks__;
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('should process approved expense', async () => {
|
|
204
|
+
const result = await expenseWorkflow({ expenseId: 'e1', amount: 100 });
|
|
205
|
+
expect(result.onSuccess).toBe(true);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Testing timeout paths:**
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
// Don't provide mock data for the event to simulate timeout
|
|
214
|
+
(globalThis as any).__fw_mocks__ = { fast: true };
|
|
215
|
+
// waitForEvent will follow onFailure path
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Related Topics
|
|
221
|
+
|
|
222
|
+
- [CLI Reference](cli-reference) — `run` command with `--mocks` flags
|
|
223
|
+
- [Compilation](compilation) — Inngest target for durable built-in node execution
|
|
224
|
+
- [Debugging](debugging) — Tracing and troubleshooting
|
|
225
|
+
- [Advanced Annotations](advanced-annotations) — Expression bindings for node inputs
|