@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.
Files changed (83) hide show
  1. package/README.md +261 -200
  2. package/dist/annotation-generator.js +36 -0
  3. package/dist/api/generate-in-place.js +39 -0
  4. package/dist/api/generate.js +11 -1
  5. package/dist/api/manipulation/nodes.js +22 -0
  6. package/dist/ast/types.d.ts +27 -1
  7. package/dist/built-in-nodes/index.d.ts +1 -0
  8. package/dist/built-in-nodes/index.js +1 -0
  9. package/dist/built-in-nodes/invoke-workflow.js +12 -1
  10. package/dist/built-in-nodes/mock-types.d.ts +2 -0
  11. package/dist/built-in-nodes/wait-for-agent.d.ts +13 -0
  12. package/dist/built-in-nodes/wait-for-agent.js +26 -0
  13. package/dist/chevrotain-parser/fan-parser.d.ts +38 -0
  14. package/dist/chevrotain-parser/fan-parser.js +149 -0
  15. package/dist/chevrotain-parser/grammar-diagrams.d.ts +1 -0
  16. package/dist/chevrotain-parser/grammar-diagrams.js +3 -0
  17. package/dist/chevrotain-parser/index.d.ts +3 -1
  18. package/dist/chevrotain-parser/index.js +3 -1
  19. package/dist/chevrotain-parser/tokens.d.ts +2 -0
  20. package/dist/chevrotain-parser/tokens.js +10 -0
  21. package/dist/cli/commands/diagram.d.ts +2 -1
  22. package/dist/cli/commands/diagram.js +9 -6
  23. package/dist/cli/commands/docs.d.ts +11 -0
  24. package/dist/cli/commands/docs.js +77 -0
  25. package/dist/cli/commands/run.js +59 -1
  26. package/dist/cli/flow-weaver.mjs +2447 -594
  27. package/dist/cli/index.js +40 -2
  28. package/dist/diagram/geometry.d.ts +9 -4
  29. package/dist/diagram/geometry.js +262 -31
  30. package/dist/diagram/html-viewer.d.ts +12 -0
  31. package/dist/diagram/html-viewer.js +399 -0
  32. package/dist/diagram/index.d.ts +12 -0
  33. package/dist/diagram/index.js +22 -0
  34. package/dist/diagram/renderer.js +137 -116
  35. package/dist/diagram/types.d.ts +1 -0
  36. package/dist/doc-metadata/extractors/annotations.js +282 -1
  37. package/dist/doc-metadata/types.d.ts +6 -0
  38. package/dist/docs/index.d.ts +54 -0
  39. package/dist/docs/index.js +256 -0
  40. package/dist/generator/control-flow.d.ts +13 -0
  41. package/dist/generator/control-flow.js +74 -0
  42. package/dist/generator/inngest.js +23 -0
  43. package/dist/generator/unified.js +122 -2
  44. package/dist/jsdoc-parser.d.ts +24 -0
  45. package/dist/jsdoc-parser.js +41 -1
  46. package/dist/mcp/agent-channel.d.ts +35 -0
  47. package/dist/mcp/agent-channel.js +61 -0
  48. package/dist/mcp/run-registry.d.ts +29 -0
  49. package/dist/mcp/run-registry.js +24 -0
  50. package/dist/mcp/server.js +2 -0
  51. package/dist/mcp/tools-diagram.d.ts +1 -1
  52. package/dist/mcp/tools-diagram.js +15 -7
  53. package/dist/mcp/tools-docs.d.ts +3 -0
  54. package/dist/mcp/tools-docs.js +62 -0
  55. package/dist/mcp/tools-editor.js +77 -3
  56. package/dist/mcp/tools-query.js +3 -1
  57. package/dist/mcp/workflow-executor.d.ts +28 -0
  58. package/dist/mcp/workflow-executor.js +66 -3
  59. package/dist/parser.d.ts +8 -0
  60. package/dist/parser.js +100 -0
  61. package/dist/runtime/ExecutionContext.d.ts +2 -0
  62. package/dist/runtime/ExecutionContext.js +2 -0
  63. package/dist/runtime/events.d.ts +1 -1
  64. package/dist/sugar-optimizer.js +28 -3
  65. package/dist/validator.d.ts +8 -0
  66. package/dist/validator.js +92 -0
  67. package/docs/reference/advanced-annotations.md +431 -0
  68. package/docs/reference/built-in-nodes.md +225 -0
  69. package/docs/reference/cli-reference.md +882 -0
  70. package/docs/reference/compilation.md +351 -0
  71. package/docs/reference/concepts.md +400 -0
  72. package/docs/reference/debugging.md +255 -0
  73. package/docs/reference/deployment.md +207 -0
  74. package/docs/reference/error-codes.md +686 -0
  75. package/docs/reference/export-interface.md +229 -0
  76. package/docs/reference/iterative-development.md +186 -0
  77. package/docs/reference/jsdoc-grammar.md +471 -0
  78. package/docs/reference/marketplace.md +205 -0
  79. package/docs/reference/node-conversion.md +308 -0
  80. package/docs/reference/patterns.md +161 -0
  81. package/docs/reference/scaffold.md +160 -0
  82. package/docs/reference/tutorial.md +519 -0
  83. 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