flowcraft 1.0.0 → 2.0.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 (201) hide show
  1. package/README.md +37 -134
  2. package/dist/analysis.d.ts +43 -0
  3. package/dist/analysis.js +3 -0
  4. package/dist/chunk-55J6XMHW.js +3 -0
  5. package/dist/{chunk-7XUN3OQT.js.map → chunk-55J6XMHW.js.map} +1 -1
  6. package/dist/chunk-6DNEDIIT.js +123 -0
  7. package/dist/chunk-6DNEDIIT.js.map +1 -0
  8. package/dist/chunk-734J4PTM.js +100 -0
  9. package/dist/chunk-734J4PTM.js.map +1 -0
  10. package/dist/chunk-DSZSR7UE.js +40 -0
  11. package/dist/chunk-DSZSR7UE.js.map +1 -0
  12. package/dist/chunk-GTZC6PQI.js +22 -0
  13. package/dist/chunk-GTZC6PQI.js.map +1 -0
  14. package/dist/chunk-HMR2GEGE.js +3 -0
  15. package/dist/{chunk-F2RSES6P.js.map → chunk-HMR2GEGE.js.map} +1 -1
  16. package/dist/chunk-J3RNCPED.js +27 -0
  17. package/dist/chunk-J3RNCPED.js.map +1 -0
  18. package/dist/chunk-M23P46ZL.js +105 -0
  19. package/dist/chunk-M23P46ZL.js.map +1 -0
  20. package/dist/chunk-MICPMOTW.js +49 -0
  21. package/dist/chunk-MICPMOTW.js.map +1 -0
  22. package/dist/chunk-NPAJNLXQ.js +106 -0
  23. package/dist/chunk-NPAJNLXQ.js.map +1 -0
  24. package/dist/chunk-RAZXOMZC.js +64 -0
  25. package/dist/chunk-RAZXOMZC.js.map +1 -0
  26. package/dist/chunk-REH55ZXV.js +13 -0
  27. package/dist/chunk-REH55ZXV.js.map +1 -0
  28. package/dist/chunk-RW4FH7IL.js +135 -0
  29. package/dist/chunk-RW4FH7IL.js.map +1 -0
  30. package/dist/chunk-RYTIQZIB.js +303 -0
  31. package/dist/chunk-RYTIQZIB.js.map +1 -0
  32. package/dist/chunk-UYPIWXZG.js +62 -0
  33. package/dist/chunk-UYPIWXZG.js.map +1 -0
  34. package/dist/chunk-VFC342WL.js +29 -0
  35. package/dist/chunk-VFC342WL.js.map +1 -0
  36. package/dist/chunk-WXT3YEWU.js +28 -0
  37. package/dist/chunk-WXT3YEWU.js.map +1 -0
  38. package/dist/context.d.ts +23 -105
  39. package/dist/context.js +1 -1
  40. package/dist/errors.d.ts +15 -31
  41. package/dist/errors.js +1 -1
  42. package/dist/evaluator.d.ts +22 -0
  43. package/dist/evaluator.js +3 -0
  44. package/dist/evaluator.js.map +1 -0
  45. package/dist/flow.d.ts +54 -0
  46. package/dist/flow.js +4 -0
  47. package/dist/flow.js.map +1 -0
  48. package/dist/index.d.ts +14 -16
  49. package/dist/index.js +17 -25
  50. package/dist/linter.d.ts +24 -0
  51. package/dist/linter.js +4 -0
  52. package/dist/linter.js.map +1 -0
  53. package/dist/logger.d.ts +11 -36
  54. package/dist/logger.js +1 -1
  55. package/dist/node.d.ts +1 -0
  56. package/dist/node.js +3 -0
  57. package/dist/node.js.map +1 -0
  58. package/dist/runtime/adapter.d.ts +78 -0
  59. package/dist/runtime/adapter.js +15 -0
  60. package/dist/runtime/adapter.js.map +1 -0
  61. package/dist/runtime/executors.d.ts +26 -0
  62. package/dist/runtime/executors.js +4 -0
  63. package/dist/runtime/executors.js.map +1 -0
  64. package/dist/runtime/index.d.ts +7 -0
  65. package/dist/runtime/index.js +16 -0
  66. package/dist/runtime/runtime.d.ts +33 -0
  67. package/dist/runtime/runtime.js +14 -0
  68. package/dist/runtime/runtime.js.map +1 -0
  69. package/dist/runtime/state.d.ts +21 -0
  70. package/dist/runtime/state.js +4 -0
  71. package/dist/runtime/state.js.map +1 -0
  72. package/dist/runtime/traverser.d.ts +24 -0
  73. package/dist/runtime/traverser.js +5 -0
  74. package/dist/runtime/traverser.js.map +1 -0
  75. package/dist/runtime/types.d.ts +15 -0
  76. package/dist/runtime/types.js +3 -0
  77. package/dist/sanitizer.d.ts +10 -0
  78. package/dist/sanitizer.js +3 -0
  79. package/dist/{utils/sanitize.js.map → sanitizer.js.map} +1 -1
  80. package/dist/serializer.d.ts +15 -0
  81. package/dist/serializer.js +3 -0
  82. package/dist/serializer.js.map +1 -0
  83. package/dist/types-CZN_FcB6.d.ts +201 -0
  84. package/dist/types.d.ts +1 -3
  85. package/dist/types.js +1 -1
  86. package/package.json +9 -20
  87. package/LICENSE +0 -21
  88. package/dist/builder/graph/graph.d.ts +0 -57
  89. package/dist/builder/graph/graph.js +0 -21
  90. package/dist/builder/graph/graph.js.map +0 -1
  91. package/dist/builder/graph/index.d.ts +0 -8
  92. package/dist/builder/graph/index.js +0 -23
  93. package/dist/builder/graph/internal-nodes.d.ts +0 -59
  94. package/dist/builder/graph/internal-nodes.js +0 -20
  95. package/dist/builder/graph/internal-nodes.js.map +0 -1
  96. package/dist/builder/graph/runner.d.ts +0 -51
  97. package/dist/builder/graph/runner.js +0 -21
  98. package/dist/builder/graph/runner.js.map +0 -1
  99. package/dist/builder/graph/types.d.ts +0 -3
  100. package/dist/builder/graph/types.js +0 -3
  101. package/dist/builder/index.d.ts +0 -8
  102. package/dist/builder/index.js +0 -24
  103. package/dist/builder/index.js.map +0 -1
  104. package/dist/builder/patterns.d.ts +0 -136
  105. package/dist/builder/patterns.js +0 -19
  106. package/dist/builder/patterns.js.map +0 -1
  107. package/dist/chunk-3YMBNZ77.js +0 -441
  108. package/dist/chunk-3YMBNZ77.js.map +0 -1
  109. package/dist/chunk-64DNBF5W.js +0 -36
  110. package/dist/chunk-64DNBF5W.js.map +0 -1
  111. package/dist/chunk-6QCXIRLA.js +0 -18
  112. package/dist/chunk-6QCXIRLA.js.map +0 -1
  113. package/dist/chunk-7XUN3OQT.js +0 -3
  114. package/dist/chunk-AOHBHYF6.js +0 -7
  115. package/dist/chunk-AOHBHYF6.js.map +0 -1
  116. package/dist/chunk-BRFMFLR6.js +0 -85
  117. package/dist/chunk-BRFMFLR6.js.map +0 -1
  118. package/dist/chunk-ELEHMJPM.js +0 -13
  119. package/dist/chunk-ELEHMJPM.js.map +0 -1
  120. package/dist/chunk-F2RSES6P.js +0 -3
  121. package/dist/chunk-F6C6J7HK.js +0 -3
  122. package/dist/chunk-F6C6J7HK.js.map +0 -1
  123. package/dist/chunk-GMKJ34T2.js +0 -3
  124. package/dist/chunk-GMKJ34T2.js.map +0 -1
  125. package/dist/chunk-HEO3XL4Z.js +0 -328
  126. package/dist/chunk-HEO3XL4Z.js.map +0 -1
  127. package/dist/chunk-IIKTTIW5.js +0 -56
  128. package/dist/chunk-IIKTTIW5.js.map +0 -1
  129. package/dist/chunk-KOBEU2EM.js +0 -3
  130. package/dist/chunk-KOBEU2EM.js.map +0 -1
  131. package/dist/chunk-L5PK5VL2.js +0 -178
  132. package/dist/chunk-L5PK5VL2.js.map +0 -1
  133. package/dist/chunk-P3RPDZHO.js +0 -36
  134. package/dist/chunk-P3RPDZHO.js.map +0 -1
  135. package/dist/chunk-PNWOW52F.js +0 -19
  136. package/dist/chunk-PNWOW52F.js.map +0 -1
  137. package/dist/chunk-R27FIYR5.js +0 -62
  138. package/dist/chunk-R27FIYR5.js.map +0 -1
  139. package/dist/chunk-S4WFNGQG.js +0 -17
  140. package/dist/chunk-S4WFNGQG.js.map +0 -1
  141. package/dist/chunk-TS3M7MWA.js +0 -3
  142. package/dist/chunk-TS3M7MWA.js.map +0 -1
  143. package/dist/chunk-UY4PNPBX.js +0 -156
  144. package/dist/chunk-UY4PNPBX.js.map +0 -1
  145. package/dist/chunk-VMH2LRM6.js +0 -114
  146. package/dist/chunk-VMH2LRM6.js.map +0 -1
  147. package/dist/chunk-VZDHIOCH.js +0 -76
  148. package/dist/chunk-VZDHIOCH.js.map +0 -1
  149. package/dist/chunk-WGVHM7DU.js +0 -66
  150. package/dist/chunk-WGVHM7DU.js.map +0 -1
  151. package/dist/chunk-WR5PDOPP.js +0 -91
  152. package/dist/chunk-WR5PDOPP.js.map +0 -1
  153. package/dist/chunk-YR433ZDA.js +0 -20
  154. package/dist/chunk-YR433ZDA.js.map +0 -1
  155. package/dist/executors/in-memory.d.ts +0 -39
  156. package/dist/executors/in-memory.js +0 -6
  157. package/dist/executors/in-memory.js.map +0 -1
  158. package/dist/executors/types.d.ts +0 -3
  159. package/dist/executors/types.js +0 -3
  160. package/dist/executors/types.js.map +0 -1
  161. package/dist/functions.d.ts +0 -88
  162. package/dist/functions.js +0 -21
  163. package/dist/functions.js.map +0 -1
  164. package/dist/types-U76Ukj96.d.ts +0 -609
  165. package/dist/utils/analysis.d.ts +0 -75
  166. package/dist/utils/analysis.js +0 -3
  167. package/dist/utils/index.d.ts +0 -8
  168. package/dist/utils/index.js +0 -10
  169. package/dist/utils/index.js.map +0 -1
  170. package/dist/utils/mermaid.d.ts +0 -46
  171. package/dist/utils/mermaid.js +0 -4
  172. package/dist/utils/mermaid.js.map +0 -1
  173. package/dist/utils/middleware.d.ts +0 -11
  174. package/dist/utils/middleware.js +0 -3
  175. package/dist/utils/middleware.js.map +0 -1
  176. package/dist/utils/sanitize.d.ts +0 -19
  177. package/dist/utils/sanitize.js +0 -3
  178. package/dist/utils/sleep.d.ts +0 -9
  179. package/dist/utils/sleep.js +0 -4
  180. package/dist/utils/sleep.js.map +0 -1
  181. package/dist/workflow/AbstractNode.d.ts +0 -3
  182. package/dist/workflow/AbstractNode.js +0 -4
  183. package/dist/workflow/AbstractNode.js.map +0 -1
  184. package/dist/workflow/Flow.d.ts +0 -3
  185. package/dist/workflow/Flow.js +0 -16
  186. package/dist/workflow/Flow.js.map +0 -1
  187. package/dist/workflow/Node.d.ts +0 -3
  188. package/dist/workflow/Node.js +0 -15
  189. package/dist/workflow/Node.js.map +0 -1
  190. package/dist/workflow/index.d.ts +0 -4
  191. package/dist/workflow/index.js +0 -18
  192. package/dist/workflow/index.js.map +0 -1
  193. package/dist/workflow/node-patterns.d.ts +0 -55
  194. package/dist/workflow/node-patterns.js +0 -16
  195. package/dist/workflow/node-patterns.js.map +0 -1
  196. package/dist/workflow/registry.d.ts +0 -17
  197. package/dist/workflow/registry.js +0 -3
  198. package/dist/workflow/registry.js.map +0 -1
  199. /package/dist/{utils/analysis.js.map → analysis.js.map} +0 -0
  200. /package/dist/{builder/graph → runtime}/index.js.map +0 -0
  201. /package/dist/{builder/graph → runtime}/types.js.map +0 -0
package/README.md CHANGED
@@ -1,153 +1,56 @@
1
- # Flowcraft: A Workflow Framework
1
+ # Flowcraft
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/flowcraft.svg)](https://www.npmjs.com/package/flowcraft)
3
+ [![NPM Version](https://img.shields.io/npm/v/flowcraft.svg)](https://www.npmjs.com/package/flowcraft)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Codecov](https://img.shields.io/codecov/c/github/gorango/flowcraft/master)](https://codecov.io/github/gorango/flowcraft)
5
6
 
6
- Build complex, multi-step processes with a lightweight, composable, and type-safe TypeScript framework. Model everything from simple sequences to dynamic AI agents, running in-memory or across distributed systems.
7
+ Build complex, multi-step processes with a lightweight, composable, and type-safe approach. Model complex business processes, data pipelines, ETL workflows, or AI agents and scale from in-memory scripts to distributed systems without changing the core business logic.
7
8
 
8
- **[Read the Friendly Manual »](https://gorango.github.io/flowcraft/guide/)**
9
-
10
- ## Features
9
+ ## Key Features
11
10
 
12
11
  - **Zero Dependencies**: Lightweight and dependency-free, ensuring a small footprint and easy integration.
13
- - **Composable & Reusable**: Define workflows by chaining nodes or declaratively embedding other flows as nodes.
14
- - **Type-Safe by Default**: Strong typing for workflow definitions, shared state, and node parameters.
15
- - **Async First**: Built on an asynchronous foundation to handle I/O-bound tasks gracefully.
16
- - **Resilient & Reliable**: Built-in support for retries with configurable delays and fallback logic.
17
- - **Dynamic Graph Engine**: Construct executable workflows from declarative JSON, ideal for AI agents.
18
- - **Extensible Execution**: A pluggable Executor pattern enables in-memory or distributed flows.
19
- - **Advanced Control Flow**: Full support for conditional branching, loops, and parallel execution.
20
- - **Modern Tooling**: A fluent functional API, static graph validation, and automatic visualizations.
21
-
22
- ---
23
-
24
- Flowcraft is a lightweight, zero-dependency TypeScript framework for building complex, multi-step processes. It empowers you to model everything from simple sequential tasks to dynamic, graph-driven AI agents with a clear and composable API.
25
-
26
- At its core, Flowcraft is guided by a few key principles:
27
-
28
- 1. **Structure for Complexity**: It provides a clear way to model asynchronous processes. By breaking logic into discrete `Node`s with a defined lifecycle, you can turn tangled promise chains and `async/await` blocks into maintainable, testable graphs.
29
- 2. **Start Simple, Scale Gracefully**: You can start with an in-memory workflow in a single file. As your needs grow, the architecture allows you to scale up to a robust, distributed system using message queues—**without changing your core business logic**.
30
- 3. **Composability is Key**: A `Flow` is just a specialized `Node`. This simple but powerful concept means entire workflows can be treated as building blocks, allowing you to create highly modular and reusable systems.
31
-
32
- ## The Two Paths of Flowcraft
33
-
34
- Flowcraft is designed to cater to two primary use cases, and the documentation is structured to guide you down the path that best fits your needs:
35
-
36
- ### 1. Programmatic Workflows
37
-
38
- This is the path for developers who want to build and manage workflows directly within their application's code. Using a fluent, chainable API and functional helpers, you can quickly define, test, and run complex processes in-memory.
39
-
40
- **Choose this path if you are:**
41
-
42
- - Building background jobs for a web application.
43
- - Creating complex, multi-step data processing pipelines.
44
- - Looking for a structured way to manage complex `async/await` logic.
45
-
46
- **[Learn how to build Programmatic Workflows »](https://gorango.github.io/flowcraft/guide/programmatic/basics.html)**
47
-
48
- ### 2. Declarative Workflows (for Scale)
49
-
50
- This is the path for architects and developers building dynamic, data-driven, or distributed systems. You define your workflow's structure as a declarative data format (like JSON), and the `GraphBuilder` "compiles" it into an executable, serializable `Blueprint`.
51
-
52
- **Choose this path if you are:**
53
-
54
- - Building a system where workflows are defined by users or stored in a database.
55
- - Creating a runtime for dynamic AI agents.
56
- - Architecting a distributed system where tasks are executed by a pool of workers.
57
-
58
- **[Learn how to build Declarative Workflows »](https://gorango.github.io/flowcraft/guide/declarative/basics.html)**
59
-
60
- ---
61
-
62
- ## Learn by Example
63
-
64
- > [!TIP]
65
- > The best way to learn is by exploring the included sandbox examples. They are ordered by complexity, each demonstrating a new feature of the core engine.
66
-
67
- ### 1. Basic Sequential Flow: Article Writer
68
-
69
- A simple, linear workflow that demonstrates the core concepts of creating a sequence of nodes to perform a multi-step task.
70
-
71
- ```mermaid
72
- graph LR
73
- A[Generate Outline] --> B[Write Content]
74
- B --> C[Apply Style]
12
+ - **Declarative Workflows**: Define workflows as serializable objects with nodes and edges.
13
+ - **Unopinionated Logic**: Nodes can be simple functions or structured classes, supporting any logic.
14
+ - **Progressive Scalability**: Run in-memory or scale to distributed systems using the same blueprint.
15
+ - **Resilient Execution**: Built-in support for retries, fallbacks, timeouts, and graceful cancellation.
16
+ - **Advanced Patterns**: Includes batch processing and loop constructs for complex workflows.
17
+ - **Extensibility**: Pluggable loggers, evaluators, serializers, and middleware for custom behavior.
18
+ - **Static Analysis**: Tools to detect cycles, validate blueprints, and generate visual diagrams.
19
+ - **Type-Safe API**: Fully typed with TypeScript for a robust developer experience.
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install flowcraft
75
25
  ```
76
26
 
77
- - **Demonstrates**: `Node` chaining, passing data via `Context`.
78
- - **[Explore the Basic example »](https://github.com/gorango/flowcraft/tree/main/sandbox/1.basic/)**
79
-
80
- ### 2. Conditional Branching: Research Agent
27
+ ## Usage
81
28
 
82
- A simple agent that uses a loop and conditional branching to decide whether to search the web for information or answer a question based on the current context.
29
+ ```typescript
30
+ import { createFlow, FlowRuntime } from './index'
83
31
 
84
- ```mermaid
85
- graph TD
86
- A{Decide Action} -->|"search"| B[Search Web]
87
- A -->|"answer"| C[Answer Question]
88
- B --> A
89
- ```
90
-
91
- - **Demonstrates**: Conditional branching, creating loops, and building simple state machines.
92
- - **[Explore the Research Agent example »](https://github.com/gorango/flowcraft/tree/main/sandbox/2.research/)**
32
+ const flow = createFlow('simple-workflow')
33
+ .node('start', async () => ({ output: 42 }))
34
+ .node('double', async ({ input }) => ({ output: input * 2 }), { inputs: 'start' })
35
+ .edge('start', 'double')
36
+ .toBlueprint()
93
37
 
94
- ### 3. Parallel Batch Processing: Document Translator
38
+ const runtime = new FlowRuntime({
39
+ registry: flow.getFunctionRegistry(),
40
+ })
95
41
 
96
- A practical example that translates a document into multiple languages concurrently using `ParallelBatchFlow` for a massive performance boost on I/O-bound tasks.
42
+ async function run() {
43
+ const result = await runtime.run(flow, {})
44
+ console.log(result) // { context: { start: 42, double: 84 }, status: 'completed' }
45
+ }
97
46
 
98
- ```mermaid
99
- graph TD
100
- A[Load README.md] --> B["ParallelBatchFlow"]
101
- B -- "Chinese" --> T1[TranslateNode]
102
- B -- "Spanish" --> T2[TranslateNode]
103
- B -- "Japanese" --> T3[TranslateNode]
104
- T1 & T2 & T3 --> S[Save Files]
47
+ run()
105
48
  ```
106
49
 
107
- - **Demonstrates**: High-throughput concurrent processing for data-parallel tasks.
108
- - **[Explore the Parallel Translation example »](https://github.com/gorango/flowcraft/tree/main/sandbox/3.parallel/)**
109
-
110
- ### 4. Dynamic Graph Engine: AI Agent Runtime
111
-
112
- A powerful runtime that executes complex, graph-based AI workflows defined in simple JSON-like objects. This shows how to build highly dynamic and modular AI agent systems.
113
-
114
- ```mermaid
115
- graph TD
116
- A(User Post) --> B[check_pii] & C[check_hate_speech] & D[check_spam]
117
- B & C & D --> E{triage_post}
118
- E -- action_ban --> F["Sub-Workflow: Ban User"]
119
- E -- action_approve --> G[approve_post_branch]
120
- ```
121
-
122
- - **Demonstrates**:
123
- - Type-safe graph construction from declarative definitions using `GraphBuilder`.
124
- - Parallel fan-in and fan-out.
125
- - Reusable, data-driven nodes and complex sub-workflow composition.
126
- - **[Explore the Dynamic AI Agent example »](https://github.com/gorango/flowcraft/tree/main/sandbox/4.dag/)**
127
-
128
- ### 5. Distributed Execution: AI Agent with BullMQ
129
-
130
- This example takes the same type-safe graph definition from the previous example and runs it in a distributed environment using a custom `BullMQExecutor`, demonstrating a client-worker architecture for scalable background jobs.
131
-
132
- - **Demonstrates**:
133
- - A pluggable `IExecutor` for distributed workflows.
134
- - How business logic (the graph) remains unchanged when the execution environment changes.
135
- - **[Explore the Distributed AI Agent example »](https://github.com/gorango/flowcraft/tree/main/sandbox/5.distributed/)**
136
-
137
- ### 6. Advanced RAG Agent: Complex Data & Serialization
138
-
139
- A complete Retrieval-Augmented Generation (RAG) agent that ingests a document, creates embeddings, performs a vector search, and synthesizes an answer, showcasing a sophisticated, data-driven AI workflow.
140
-
141
- - **Demonstrates**:
142
- - A full, practical RAG pipeline with custom nodes.
143
- - Handling complex data types (`Map`, `Date`, etc.) in the `Context`.
144
- - Robust serialization (using `superjson`) for reliable state management.
145
- - **[Explore the RAG Agent example »](https://github.com/gorango/flowcraft/tree/main/sandbox/6.rag/)**
146
-
147
50
  ## Documentation
148
51
 
149
- For a deep dive into all features, patterns, and APIs, please see the **[complete Flowcraft documentation](https://gorango.github.io/flowcraft/guide/)**.
52
+ For a complete overview all features, patterns, examples, and APIs, please see the **[Flowcraft documentation](https://flowcraft.js.org/)**.
150
53
 
151
- ---
54
+ ## License
152
55
 
153
- Licensed under the [MIT License](https://github.com/gorango/flowcraft/tree/main/LICENSE).
56
+ Flowcraft is licensed under the [MIT License](LICENSE).
@@ -0,0 +1,43 @@
1
+ import { W as WorkflowBlueprint } from './types-CZN_FcB6.js';
2
+
3
+ /**
4
+ * A list of cycles found in the graph. Each cycle is an array of node IDs.
5
+ */
6
+ type Cycles = string[][];
7
+ /**
8
+ * Analysis result for a workflow blueprint
9
+ */
10
+ interface BlueprintAnalysis {
11
+ /** Cycles found in the graph */
12
+ cycles: Cycles;
13
+ /** Node IDs that have no incoming edges (start nodes) */
14
+ startNodeIds: string[];
15
+ /** Node IDs that have no outgoing edges (terminal nodes) */
16
+ terminalNodeIds: string[];
17
+ /** Total number of nodes */
18
+ nodeCount: number;
19
+ /** Total number of edges */
20
+ edgeCount: number;
21
+ /** Whether the graph is a valid DAG (no cycles) */
22
+ isDag: boolean;
23
+ }
24
+ /**
25
+ * Analyzes a workflow blueprint to detect cycles.
26
+ * @param blueprint The WorkflowBlueprint object containing nodes and edges.
27
+ * @returns An array of cycles found. Each cycle is represented as an array of node IDs.
28
+ */
29
+ declare function checkForCycles(blueprint: WorkflowBlueprint): Cycles;
30
+ /**
31
+ * Generates Mermaid diagram syntax from a WorkflowBlueprint
32
+ * @param blueprint The WorkflowBlueprint object containing nodes and edges
33
+ * @returns Mermaid syntax string for the flowchart
34
+ */
35
+ declare function generateMermaid(blueprint: WorkflowBlueprint): string;
36
+ /**
37
+ * Analyzes a workflow blueprint and returns comprehensive analysis
38
+ * @param blueprint The WorkflowBlueprint object containing nodes and edges
39
+ * @returns Analysis result with cycles, start nodes, terminal nodes, and other metrics
40
+ */
41
+ declare function analyzeBlueprint(blueprint: WorkflowBlueprint): BlueprintAnalysis;
42
+
43
+ export { type BlueprintAnalysis, type Cycles, analyzeBlueprint, checkForCycles, generateMermaid };
@@ -0,0 +1,3 @@
1
+ export { analyzeBlueprint, checkForCycles, generateMermaid } from './chunk-M23P46ZL.js';
2
+ //# sourceMappingURL=analysis.js.map
3
+ //# sourceMappingURL=analysis.js.map
@@ -0,0 +1,3 @@
1
+
2
+ //# sourceMappingURL=chunk-55J6XMHW.js.map
3
+ //# sourceMappingURL=chunk-55J6XMHW.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-7XUN3OQT.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-55J6XMHW.js"}
@@ -0,0 +1,123 @@
1
+ import { isNodeClass } from './chunk-DSZSR7UE.js';
2
+
3
+ // src/flow.ts
4
+ var Flow = class {
5
+ blueprint;
6
+ functionRegistry;
7
+ loopControllerIds;
8
+ constructor(id) {
9
+ this.blueprint = { id, nodes: [], edges: [] };
10
+ this.functionRegistry = /* @__PURE__ */ new Map();
11
+ this.loopControllerIds = /* @__PURE__ */ new Map();
12
+ }
13
+ node(id, implementation, options) {
14
+ let usesKey;
15
+ if (isNodeClass(implementation)) {
16
+ usesKey = implementation.name && implementation.name !== "BaseNode" ? implementation.name : `class_${globalThis.crypto.randomUUID()}`;
17
+ this.functionRegistry.set(usesKey, implementation);
18
+ } else {
19
+ usesKey = `fn_${globalThis.crypto.randomUUID()}`;
20
+ this.functionRegistry.set(usesKey, implementation);
21
+ }
22
+ const nodeDef = { id, uses: usesKey, ...options };
23
+ this.blueprint.nodes.push(nodeDef);
24
+ return this;
25
+ }
26
+ edge(source, target, options) {
27
+ const edgeDef = { source, target, ...options };
28
+ this.blueprint.edges.push(edgeDef);
29
+ return this;
30
+ }
31
+ /**
32
+ * Creates a batch processing pattern.
33
+ * It takes an input array, runs a worker node on each item in parallel, and gathers the results.
34
+ * @param id The base ID for this batch operation.
35
+ * @param worker The node implementation to run on each item.
36
+ * @param options Configuration for the batch operation.
37
+ * @param options.inputKey The key in the context that holds the input array for the batch.
38
+ * @param options.outputKey The key in the context where the array of results will be stored.
39
+ * @returns The Flow instance for chaining.
40
+ */
41
+ batch(id, worker, options) {
42
+ const { inputKey, outputKey } = options;
43
+ const scatterId = `${id}_scatter`;
44
+ const gatherId = `${id}_gather`;
45
+ let workerUsesKey;
46
+ if (isNodeClass(worker)) {
47
+ workerUsesKey = worker.name && worker.name !== "BaseNode" ? worker.name : `class_batch_worker_${globalThis.crypto.randomUUID()}`;
48
+ this.functionRegistry.set(workerUsesKey, worker);
49
+ } else {
50
+ workerUsesKey = `fn_batch_worker_${globalThis.crypto.randomUUID()}`;
51
+ this.functionRegistry.set(workerUsesKey, worker);
52
+ }
53
+ this.blueprint.nodes.push({
54
+ id: scatterId,
55
+ uses: "batch-scatter",
56
+ // This is a special, built-in node type
57
+ inputs: inputKey,
58
+ params: { workerUsesKey, outputKey, gatherNodeId: gatherId }
59
+ });
60
+ this.blueprint.nodes.push({
61
+ id: gatherId,
62
+ uses: "batch-gather",
63
+ // built-in node type
64
+ params: { outputKey },
65
+ config: { joinStrategy: "all" }
66
+ // Important: Must wait for all scattered jobs
67
+ });
68
+ this.edge(scatterId, gatherId);
69
+ return this;
70
+ }
71
+ /**
72
+ * Creates a loop pattern in the workflow graph.
73
+ * @param id A unique identifier for the loop construct.
74
+ * @param options Defines the start, end, and continuation condition of the loop.
75
+ * @param options.startNodeId The ID of the first node inside the loop body.
76
+ * @param options.endNodeId The ID of the last node inside the loop body.
77
+ * @param options.condition An expression that, if true, causes the loop to run again.
78
+ */
79
+ loop(id, options) {
80
+ const { startNodeId, endNodeId, condition } = options;
81
+ const controllerId = `${id}-loop`;
82
+ this.loopControllerIds.set(id, controllerId);
83
+ this.blueprint.nodes.push({
84
+ id: controllerId,
85
+ uses: "loop-controller",
86
+ // Special built-in node type
87
+ params: { condition },
88
+ config: { joinStrategy: "any" }
89
+ });
90
+ this.edge(endNodeId, controllerId);
91
+ this.edge(controllerId, startNodeId, { action: "continue", transform: `context.${endNodeId}` });
92
+ const startNode = this.blueprint.nodes.find((n) => n.id === startNodeId);
93
+ if (startNode)
94
+ startNode.config = { ...startNode.config, joinStrategy: "any" };
95
+ const endNode = this.blueprint.nodes.find((n) => n.id === endNodeId);
96
+ if (endNode)
97
+ endNode.config = { ...endNode.config, joinStrategy: "any" };
98
+ return this;
99
+ }
100
+ getLoopControllerId(id) {
101
+ const controllerId = this.loopControllerIds.get(id);
102
+ if (!controllerId) {
103
+ throw new Error(`Loop with id '${id}' not found. Ensure you have defined it using the .loop() method.`);
104
+ }
105
+ return controllerId;
106
+ }
107
+ toBlueprint() {
108
+ if (!this.blueprint.nodes || this.blueprint.nodes.length === 0) {
109
+ throw new Error("Cannot build a blueprint with no nodes.");
110
+ }
111
+ return this.blueprint;
112
+ }
113
+ getFunctionRegistry() {
114
+ return this.functionRegistry;
115
+ }
116
+ };
117
+ function createFlow(id) {
118
+ return new Flow(id);
119
+ }
120
+
121
+ export { Flow, createFlow };
122
+ //# sourceMappingURL=chunk-6DNEDIIT.js.map
123
+ //# sourceMappingURL=chunk-6DNEDIIT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/flow.ts"],"names":[],"mappings":"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","file":"chunk-6DNEDIIT.js","sourcesContent":["import type { EdgeDefinition, NodeClass, NodeDefinition, NodeFunction, WorkflowBlueprint } from './types'\nimport { isNodeClass } from './node'\n\n/**\n * A fluent API for programmatically constructing a WorkflowBlueprint.\n */\nexport class Flow<\n\tTContext extends Record<string, any> = Record<string, any>,\n\tTDependencies extends Record<string, any> = Record<string, any>,\n> {\n\tprivate blueprint: Partial<WorkflowBlueprint>\n\tprivate functionRegistry: Map<string, NodeFunction | NodeClass>\n\tprivate loopControllerIds: Map<string, string>\n\n\tconstructor(id: string) {\n\t\tthis.blueprint = { id, nodes: [], edges: [] }\n\t\tthis.functionRegistry = new Map()\n\t\tthis.loopControllerIds = new Map()\n\t}\n\n\tnode(\n\t\tid: string,\n\t\timplementation: NodeFunction<TContext, TDependencies> | NodeClass,\n\t\toptions?: Omit<NodeDefinition, 'id' | 'uses'>,\n\t): this {\n\t\tlet usesKey: string\n\n\t\tif (isNodeClass(implementation)) {\n\t\t\tusesKey = (implementation.name && implementation.name !== 'BaseNode')\n\t\t\t\t? implementation.name\n\t\t\t\t: `class_${globalThis.crypto.randomUUID()}`\n\t\t\tthis.functionRegistry.set(usesKey, implementation)\n\t\t}\n\t\telse {\n\t\t\tusesKey = `fn_${globalThis.crypto.randomUUID()}`\n\t\t\tthis.functionRegistry.set(usesKey, implementation as NodeFunction)\n\t\t}\n\n\t\tconst nodeDef: NodeDefinition = { id, uses: usesKey, ...options }\n\t\tthis.blueprint.nodes!.push(nodeDef)\n\t\treturn this\n\t}\n\n\tedge(source: string, target: string, options?: Omit<EdgeDefinition, 'source' | 'target'>): this {\n\t\tconst edgeDef: EdgeDefinition = { source, target, ...options }\n\t\tthis.blueprint.edges!.push(edgeDef)\n\t\treturn this\n\t}\n\n\t/**\n\t * Creates a batch processing pattern.\n\t * It takes an input array, runs a worker node on each item in parallel, and gathers the results.\n\t * @param id The base ID for this batch operation.\n\t * @param worker The node implementation to run on each item.\n\t * @param options Configuration for the batch operation.\n\t * @param options.inputKey The key in the context that holds the input array for the batch.\n\t * @param options.outputKey The key in the context where the array of results will be stored.\n\t * @returns The Flow instance for chaining.\n\t */\n\tbatch(id: string, worker: NodeFunction<TContext, TDependencies> | NodeClass, options: {\n\t\t/** The key in the context that holds the input array for the batch. */\n\t\tinputKey: string\n\t\t/** The key in the context where the array of results will be stored. */\n\t\toutputKey: string\n\t}): this {\n\t\tconst { inputKey, outputKey } = options\n\t\tconst scatterId = `${id}_scatter`\n\t\tconst gatherId = `${id}_gather`\n\n\t\t// Register the user's worker implementation under a unique key.\n\t\tlet workerUsesKey: string\n\t\tif (isNodeClass(worker)) {\n\t\t\tworkerUsesKey = (worker.name && worker.name !== 'BaseNode') ? worker.name : `class_batch_worker_${globalThis.crypto.randomUUID()}`\n\t\t\tthis.functionRegistry.set(workerUsesKey, worker)\n\t\t}\n\t\telse {\n\t\t\tworkerUsesKey = `fn_batch_worker_${globalThis.crypto.randomUUID()}`\n\t\t\tthis.functionRegistry.set(workerUsesKey, worker as NodeFunction)\n\t\t}\n\n\t\t// Scatter Node: A built-in node that takes an array and dynamically schedules worker nodes.\n\t\tthis.blueprint.nodes!.push({\n\t\t\tid: scatterId,\n\t\t\tuses: 'batch-scatter', // This is a special, built-in node type\n\t\t\tinputs: inputKey,\n\t\t\tparams: { workerUsesKey, outputKey, gatherNodeId: gatherId },\n\t\t})\n\n\t\t// Gather Node: A built-in node that waits for all workers to finish and collects the results.\n\t\tthis.blueprint.nodes!.push({\n\t\t\tid: gatherId,\n\t\t\tuses: 'batch-gather', // built-in node type\n\t\t\tparams: { outputKey },\n\t\t\tconfig: { joinStrategy: 'all' }, // Important: Must wait for all scattered jobs\n\t\t})\n\n\t\t// Edge to connect the scatter and gather nodes. The orchestrator will manage the dynamic workers.\n\t\tthis.edge(scatterId, gatherId)\n\n\t\treturn this\n\t}\n\n\t/**\n\t * Creates a loop pattern in the workflow graph.\n\t * @param id A unique identifier for the loop construct.\n\t * @param options Defines the start, end, and continuation condition of the loop.\n\t * @param options.startNodeId The ID of the first node inside the loop body.\n\t * @param options.endNodeId The ID of the last node inside the loop body.\n\t * @param options.condition An expression that, if true, causes the loop to run again.\n\t */\n\tloop(id: string, options: {\n\t\t/** The ID of the first node inside the loop body. */\n\t\tstartNodeId: string\n\t\t/** The ID of the last node inside the loop body. */\n\t\tendNodeId: string\n\t\t/** An expression that, if true, causes the loop to run again. */\n\t\tcondition: string\n\t}): this {\n\t\tconst { startNodeId, endNodeId, condition } = options\n\t\tconst controllerId = `${id}-loop`\n\n\t\t// Store the generated ID against the user-provided loop ID\n\t\tthis.loopControllerIds.set(id, controllerId)\n\n\t\t// Add the controller node, which evaluates the loop condition.\n\t\t// Set joinStrategy='any' to allow re-execution on each loop iteration\n\t\tthis.blueprint.nodes!.push({\n\t\t\tid: controllerId,\n\t\t\tuses: 'loop-controller', // Special built-in node type\n\t\t\tparams: { condition },\n\t\t\tconfig: { joinStrategy: 'any' },\n\t\t})\n\n\t\t// Connect the end of the loop body to the controller.\n\t\tthis.edge(endNodeId, controllerId)\n\n\t\t// Connect the controller back to the start of the loop if the condition is met.\n\t\t// Use a transform to pass the end node's value to the start node for the next iteration.\n\t\tthis.edge(controllerId, startNodeId, { action: 'continue', transform: `context.${endNodeId}` })\n\n\t\t// Set the start and end nodes to use 'any' join strategy so they can re-execute\n\t\t// Start node: executes when either its initial predecessor OR the loop controller completes\n\t\t// End node: needs to re-execute on each loop iteration\n\t\tconst startNode = this.blueprint.nodes!.find(n => n.id === startNodeId)\n\t\tif (startNode)\n\t\t\tstartNode.config = { ...startNode.config, joinStrategy: 'any' }\n\n\t\tconst endNode = this.blueprint.nodes!.find(n => n.id === endNodeId)\n\t\tif (endNode)\n\t\t\tendNode.config = { ...endNode.config, joinStrategy: 'any' }\n\n\t\treturn this\n\t}\n\n\tgetLoopControllerId(id: string): string {\n\t\tconst controllerId = this.loopControllerIds.get(id)\n\t\tif (!controllerId) {\n\t\t\tthrow new Error(`Loop with id '${id}' not found. Ensure you have defined it using the .loop() method.`)\n\t\t}\n\t\treturn controllerId\n\t}\n\n\ttoBlueprint(): WorkflowBlueprint {\n\t\tif (!this.blueprint.nodes || this.blueprint.nodes.length === 0) {\n\t\t\tthrow new Error('Cannot build a blueprint with no nodes.')\n\t\t}\n\t\treturn this.blueprint as WorkflowBlueprint\n\t}\n\n\tgetFunctionRegistry() {\n\t\treturn this.functionRegistry\n\t}\n}\n\n/**\n * Helper function to create a new Flow builder instance.\n */\nexport function createFlow<\n\tTContext extends Record<string, any> = Record<string, any>,\n\tTDependencies extends Record<string, any> = Record<string, any>,\n>(id: string): Flow<TContext, TDependencies> {\n\treturn new Flow(id)\n}\n"]}
@@ -0,0 +1,100 @@
1
+ import { CancelledWorkflowError, FatalNodeExecutionError } from './chunk-WXT3YEWU.js';
2
+
3
+ // src/runtime/executors.ts
4
+ var FunctionNodeExecutor = class {
5
+ constructor(implementation, maxRetries, eventBus) {
6
+ this.implementation = implementation;
7
+ this.maxRetries = maxRetries;
8
+ this.eventBus = eventBus;
9
+ }
10
+ async execute(nodeDef, context, executionId, signal) {
11
+ let lastError;
12
+ for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
13
+ try {
14
+ signal?.throwIfAborted();
15
+ const result = await this.implementation(context);
16
+ if (attempt > 1) {
17
+ context.dependencies.logger.info(`Node execution succeeded after retry`, { nodeId: nodeDef.id, attempt, executionId });
18
+ }
19
+ return result;
20
+ } catch (error) {
21
+ lastError = error;
22
+ if (error instanceof DOMException && error.name === "AbortError") {
23
+ throw new CancelledWorkflowError("Workflow cancelled");
24
+ }
25
+ if (error instanceof FatalNodeExecutionError)
26
+ break;
27
+ if (attempt < this.maxRetries) {
28
+ context.dependencies.logger.warn(`Node execution failed, retrying`, { nodeId: nodeDef.id, attempt, maxRetries: this.maxRetries, error: error instanceof Error ? error.message : String(error), executionId });
29
+ await this.eventBus.emit("node:retry", { blueprintId: context.dependencies.blueprint?.id || "", nodeId: nodeDef.id, attempt, executionId });
30
+ } else {
31
+ context.dependencies.logger.error(`Node execution failed after all retries`, { nodeId: nodeDef.id, attempts: this.maxRetries, error: error instanceof Error ? error.message : String(error), executionId });
32
+ }
33
+ }
34
+ }
35
+ throw lastError;
36
+ }
37
+ };
38
+ var ClassNodeExecutor = class {
39
+ constructor(implementation, maxRetries, eventBus) {
40
+ this.implementation = implementation;
41
+ this.maxRetries = maxRetries;
42
+ this.eventBus = eventBus;
43
+ }
44
+ async execute(nodeDef, context, executionId, signal) {
45
+ const instance = new this.implementation(nodeDef.params || {});
46
+ try {
47
+ signal?.throwIfAborted();
48
+ const prepResult = await instance.prep(context);
49
+ let execResult;
50
+ let lastError;
51
+ for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
52
+ try {
53
+ signal?.throwIfAborted();
54
+ execResult = await instance.exec(prepResult, context);
55
+ lastError = void 0;
56
+ if (attempt > 1) {
57
+ context.dependencies.logger.info(`Node execution succeeded after retry`, { nodeId: nodeDef.id, attempt, executionId });
58
+ }
59
+ break;
60
+ } catch (error) {
61
+ lastError = error;
62
+ if (error instanceof DOMException && error.name === "AbortError") {
63
+ throw new CancelledWorkflowError("Workflow cancelled");
64
+ }
65
+ if (error instanceof FatalNodeExecutionError)
66
+ break;
67
+ if (attempt < this.maxRetries) {
68
+ context.dependencies.logger.warn(`Node execution failed, retrying`, { nodeId: nodeDef.id, attempt, maxRetries: this.maxRetries, error: error instanceof Error ? error.message : String(error), executionId });
69
+ await this.eventBus.emit("node:retry", { blueprintId: context.dependencies.blueprint?.id || "", nodeId: nodeDef.id, attempt, executionId });
70
+ } else {
71
+ context.dependencies.logger.error(`Node execution failed after all retries`, { nodeId: nodeDef.id, attempts: this.maxRetries, error: error instanceof Error ? error.message : String(error), executionId });
72
+ }
73
+ }
74
+ }
75
+ if (lastError) {
76
+ signal?.throwIfAborted();
77
+ execResult = await instance.fallback(lastError, context);
78
+ }
79
+ signal?.throwIfAborted();
80
+ return await instance.post(execResult, context);
81
+ } catch (error) {
82
+ if (error instanceof DOMException && error.name === "AbortError") {
83
+ throw new CancelledWorkflowError("Workflow cancelled");
84
+ }
85
+ throw error;
86
+ }
87
+ }
88
+ };
89
+ var BuiltInNodeExecutor = class {
90
+ constructor(executeBuiltIn) {
91
+ this.executeBuiltIn = executeBuiltIn;
92
+ }
93
+ async execute(nodeDef, context) {
94
+ return this.executeBuiltIn(nodeDef, context.context);
95
+ }
96
+ };
97
+
98
+ export { BuiltInNodeExecutor, ClassNodeExecutor, FunctionNodeExecutor };
99
+ //# sourceMappingURL=chunk-734J4PTM.js.map
100
+ //# sourceMappingURL=chunk-734J4PTM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/executors.ts"],"names":[],"mappings":"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","file":"chunk-734J4PTM.js","sourcesContent":["import type { BaseNode } from '../node'\nimport type { ContextImplementation, IEventBus, NodeContext, NodeDefinition, NodeFunction, NodeResult } from '../types'\nimport { CancelledWorkflowError, FatalNodeExecutionError } from '../errors'\n\nexport interface ExecutionStrategy {\n\texecute: (\n\t\tnodeDef: NodeDefinition,\n\t\tcontext: NodeContext<any, any>,\n\t\texecutionId?: string,\n\t\tsignal?: AbortSignal,\n\t) => Promise<NodeResult>\n}\n\nexport class FunctionNodeExecutor implements ExecutionStrategy {\n\tconstructor(\n\t\tprivate implementation: NodeFunction,\n\t\tprivate maxRetries: number,\n\t\tprivate eventBus: IEventBus,\n\t) { }\n\n\tasync execute(\n\t\tnodeDef: NodeDefinition,\n\t\tcontext: NodeContext<any, any>,\n\t\texecutionId?: string,\n\t\tsignal?: AbortSignal,\n\t): Promise<NodeResult> {\n\t\tlet lastError: any\n\t\tfor (let attempt = 1; attempt <= this.maxRetries; attempt++) {\n\t\t\ttry {\n\t\t\t\tsignal?.throwIfAborted()\n\t\t\t\tconst result = await this.implementation(context)\n\t\t\t\tif (attempt > 1) {\n\t\t\t\t\tcontext.dependencies.logger.info(`Node execution succeeded after retry`, { nodeId: nodeDef.id, attempt, executionId })\n\t\t\t\t}\n\t\t\t\treturn result\n\t\t\t}\n\t\t\tcatch (error) {\n\t\t\t\tlastError = error\n\t\t\t\tif (error instanceof DOMException && error.name === 'AbortError') {\n\t\t\t\t\tthrow new CancelledWorkflowError('Workflow cancelled')\n\t\t\t\t}\n\t\t\t\tif (error instanceof FatalNodeExecutionError)\n\t\t\t\t\tbreak\n\t\t\t\tif (attempt < this.maxRetries) {\n\t\t\t\t\tcontext.dependencies.logger.warn(`Node execution failed, retrying`, { nodeId: nodeDef.id, attempt, maxRetries: this.maxRetries, error: error instanceof Error ? error.message : String(error), executionId })\n\t\t\t\t\tawait this.eventBus.emit('node:retry', { blueprintId: context.dependencies.blueprint?.id || '', nodeId: nodeDef.id, attempt, executionId })\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tcontext.dependencies.logger.error(`Node execution failed after all retries`, { nodeId: nodeDef.id, attempts: this.maxRetries, error: error instanceof Error ? error.message : String(error), executionId })\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthrow lastError\n\t}\n}\n\nexport class ClassNodeExecutor implements ExecutionStrategy {\n\tconstructor(\n\t\tprivate implementation: typeof BaseNode,\n\t\tprivate maxRetries: number,\n\t\tprivate eventBus: IEventBus,\n\t) { }\n\n\tasync execute(\n\t\tnodeDef: NodeDefinition,\n\t\tcontext: NodeContext<any, any>,\n\t\texecutionId?: string,\n\t\tsignal?: AbortSignal,\n\t): Promise<NodeResult> {\n\t\tconst instance = new (this.implementation as new (params: Record<string, any>) => BaseNode)(nodeDef.params || {})\n\t\ttry {\n\t\t\tsignal?.throwIfAborted()\n\t\t\tconst prepResult = await instance.prep(context)\n\t\t\tlet execResult: Omit<NodeResult, 'error'>\n\t\t\tlet lastError: any\n\t\t\tfor (let attempt = 1; attempt <= this.maxRetries; attempt++) {\n\t\t\t\ttry {\n\t\t\t\t\tsignal?.throwIfAborted()\n\t\t\t\t\texecResult = await instance.exec(prepResult, context)\n\t\t\t\t\tlastError = undefined\n\t\t\t\t\tif (attempt > 1) {\n\t\t\t\t\t\tcontext.dependencies.logger.info(`Node execution succeeded after retry`, { nodeId: nodeDef.id, attempt, executionId })\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcatch (error) {\n\t\t\t\t\tlastError = error\n\t\t\t\t\tif (error instanceof DOMException && error.name === 'AbortError') {\n\t\t\t\t\t\tthrow new CancelledWorkflowError('Workflow cancelled')\n\t\t\t\t\t}\n\t\t\t\t\tif (error instanceof FatalNodeExecutionError)\n\t\t\t\t\t\tbreak\n\t\t\t\t\tif (attempt < this.maxRetries) {\n\t\t\t\t\t\tcontext.dependencies.logger.warn(`Node execution failed, retrying`, { nodeId: nodeDef.id, attempt, maxRetries: this.maxRetries, error: error instanceof Error ? error.message : String(error), executionId })\n\t\t\t\t\t\tawait this.eventBus.emit('node:retry', { blueprintId: context.dependencies.blueprint?.id || '', nodeId: nodeDef.id, attempt, executionId })\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tcontext.dependencies.logger.error(`Node execution failed after all retries`, { nodeId: nodeDef.id, attempts: this.maxRetries, error: error instanceof Error ? error.message : String(error), executionId })\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (lastError) {\n\t\t\t\tsignal?.throwIfAborted()\n\t\t\t\texecResult = await instance.fallback(lastError, context)\n\t\t\t}\n\t\t\tsignal?.throwIfAborted()\n\t\t\treturn await instance.post(execResult!, context)\n\t\t}\n\t\tcatch (error) {\n\t\t\tif (error instanceof DOMException && error.name === 'AbortError') {\n\t\t\t\tthrow new CancelledWorkflowError('Workflow cancelled')\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\t}\n}\n\nexport class BuiltInNodeExecutor implements ExecutionStrategy {\n\tconstructor(\n\t\tprivate executeBuiltIn: (nodeDef: NodeDefinition, context: ContextImplementation<any>) => Promise<NodeResult>,\n\t) { }\n\n\tasync execute(\n\t\tnodeDef: NodeDefinition,\n\t\tcontext: NodeContext<any, any>,\n\t): Promise<NodeResult> {\n\t\treturn this.executeBuiltIn(nodeDef, context.context as ContextImplementation<any>)\n\t}\n}\n"]}
@@ -0,0 +1,40 @@
1
+ // src/node.ts
2
+ function isNodeClass(impl) {
3
+ return typeof impl === "function" && !!impl.prototype?.exec;
4
+ }
5
+ var BaseNode = class {
6
+ /**
7
+ * @param params Static parameters for this node instance, passed from the blueprint.
8
+ */
9
+ constructor(params) {
10
+ this.params = params;
11
+ }
12
+ /**
13
+ * Phase 1: Gathers and prepares data for execution. This phase is NOT retried on failure.
14
+ * @param context The node's execution context.
15
+ * @returns The data needed for the `exec` phase.
16
+ */
17
+ async prep(context) {
18
+ return context.input;
19
+ }
20
+ /**
21
+ * Phase 3: Processes the result and saves state. This phase is NOT retried.
22
+ * @param execResult The successful result from the `exec` or `fallback` phase.
23
+ * @param _context The node's execution context.
24
+ */
25
+ async post(execResult, _context) {
26
+ return execResult;
27
+ }
28
+ /**
29
+ * An optional safety net that runs if all `exec` retries fail.
30
+ * @param error The final error from the last `exec` attempt.
31
+ * @param _context The node's execution context.
32
+ */
33
+ async fallback(error, _context) {
34
+ throw error;
35
+ }
36
+ };
37
+
38
+ export { BaseNode, isNodeClass };
39
+ //# sourceMappingURL=chunk-DSZSR7UE.js.map
40
+ //# sourceMappingURL=chunk-DSZSR7UE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/node.ts"],"names":[],"mappings":";AAKO,SAAS,YAAY,IAAA,EAA8B;AACzD,EAAA,OAAO,OAAO,IAAA,KAAS,UAAA,IAAc,CAAC,CAAC,KAAK,SAAA,EAAW,IAAA;AACxD;AAOO,IAAe,WAAf,MAGL;AAAA;AAAA;AAAA;AAAA,EAID,YAAsB,MAAA,EAA6B;AAA7B,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA,EAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOrD,MAAM,KAAK,OAAA,EAA6D;AACvE,IAAA,OAAO,OAAA,CAAQ,KAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAM,IAAA,CAAK,UAAA,EAAuC,QAAA,EAAqE;AACtH,IAAA,OAAO,UAAA;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,QAAA,CAAS,KAAA,EAAc,QAAA,EAAoF;AAEhH,IAAA,MAAM,KAAA;AAAA,EACP;AACD","file":"chunk-DSZSR7UE.js","sourcesContent":["/** eslint-disable unused-imports/no-unused-vars */\n\nimport type { NodeClass, NodeContext, NodeResult, RuntimeDependencies } from './types'\n\n/** A type guard to reliably distinguish a NodeClass from a NodeFunction. */\nexport function isNodeClass(impl: any): impl is NodeClass {\n\treturn typeof impl === 'function' && !!impl.prototype?.exec\n}\n\n/**\n * A structured, class-based node for complex logic with a safe, granular lifecycle.\n * This class is generic, allowing implementations to specify the exact context\n * and dependency types they expect.\n */\nexport abstract class BaseNode<\n\tTContext extends Record<string, any> = Record<string, any>,\n\tTDependencies extends RuntimeDependencies = RuntimeDependencies,\n> {\n\t/**\n\t * @param params Static parameters for this node instance, passed from the blueprint.\n\t */\n\tconstructor(protected params: Record<string, any>) { }\n\n\t/**\n\t * Phase 1: Gathers and prepares data for execution. This phase is NOT retried on failure.\n\t * @param context The node's execution context.\n\t * @returns The data needed for the `exec` phase.\n\t */\n\tasync prep(context: NodeContext<TContext, TDependencies>): Promise<any> {\n\t\treturn context.input\n\t}\n\n\t/**\n\t * Phase 2: Performs the core, isolated logic. This is the ONLY phase that is retried.\n\t * @param prepResult The data returned from the `prep` phase.\n\t * @param context The node's execution context.\n\t */\n\tabstract exec(prepResult: any, context: NodeContext<TContext, TDependencies>): Promise<Omit<NodeResult, 'error'>>\n\n\t/**\n\t * Phase 3: Processes the result and saves state. This phase is NOT retried.\n\t * @param execResult The successful result from the `exec` or `fallback` phase.\n\t * @param _context The node's execution context.\n\t */\n\tasync post(execResult: Omit<NodeResult, 'error'>, _context: NodeContext<TContext, TDependencies>): Promise<NodeResult> {\n\t\treturn execResult\n\t}\n\n\t/**\n\t * An optional safety net that runs if all `exec` retries fail.\n\t * @param error The final error from the last `exec` attempt.\n\t * @param _context The node's execution context.\n\t */\n\tasync fallback(error: Error, _context: NodeContext<TContext, TDependencies>): Promise<Omit<NodeResult, 'error'>> {\n\t\t// By default, re-throw the error, failing the node.\n\t\tthrow error\n\t}\n}\n"]}
@@ -0,0 +1,22 @@
1
+ // src/evaluator.ts
2
+ var SimpleEvaluator = class {
3
+ evaluate(expression, context) {
4
+ try {
5
+ const validIdentifierRegex = /^[a-z_$][\w$]*$/i;
6
+ const validKeys = Object.keys(context).filter((key) => validIdentifierRegex.test(key));
7
+ const validContext = {};
8
+ for (const key of validKeys) {
9
+ validContext[key] = context[key];
10
+ }
11
+ const sandbox = new Function(...validKeys, `return ${expression}`);
12
+ return sandbox(...validKeys.map((k) => validContext[k]));
13
+ } catch (error) {
14
+ console.error(`Error evaluating expression "${expression}":`, error);
15
+ return void 0;
16
+ }
17
+ }
18
+ };
19
+
20
+ export { SimpleEvaluator };
21
+ //# sourceMappingURL=chunk-GTZC6PQI.js.map
22
+ //# sourceMappingURL=chunk-GTZC6PQI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/evaluator.ts"],"names":[],"mappings":";AAiBO,IAAM,kBAAN,MAA4C;AAAA,EAClD,QAAA,CAAS,YAAoB,OAAA,EAAmC;AAC/D,IAAA,IAAI;AAEH,MAAA,MAAM,oBAAA,GAAuB,kBAAA;AAC7B,MAAA,MAAM,SAAA,GAAY,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA,CAAE,OAAO,CAAA,GAAA,KAAO,oBAAA,CAAqB,IAAA,CAAK,GAAG,CAAC,CAAA;AACnF,MAAA,MAAM,eAAoC,EAAC;AAC3C,MAAA,KAAA,MAAW,OAAO,SAAA,EAAW;AAC5B,QAAA,YAAA,CAAa,GAAG,CAAA,GAAI,OAAA,CAAQ,GAAG,CAAA;AAAA,MAChC;AAIA,MAAA,MAAM,UAAU,IAAI,QAAA,CAAS,GAAG,SAAA,EAAW,CAAA,OAAA,EAAU,UAAU,CAAA,CAAE,CAAA;AACjE,MAAA,OAAO,OAAA,CAAQ,GAAG,SAAA,CAAU,GAAA,CAAI,OAAK,YAAA,CAAa,CAAC,CAAC,CAAC,CAAA;AAAA,IACtD,SACO,KAAA,EAAO;AACb,MAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,6BAAA,EAAgC,UAAU,CAAA,EAAA,CAAA,EAAM,KAAK,CAAA;AAEnE,MAAA,OAAO,MAAA;AAAA,IACR;AAAA,EACD;AACD","file":"chunk-GTZC6PQI.js","sourcesContent":["import type { IEvaluator } from './types'\n\n/**\n * A simple, safe, placeholder expression evaluator.\n * It provides a sandboxed environment for evaluating edge conditions and transforms.\n *\n * @warning This implementation uses `new Function()` which, while sandboxed from the global\n * scope, can be a security risk if expressions are provided by end-users. It is NOT\n * recommended for production systems. Please replace this with a more robust and secure\n * library like `jsep` by providing your own implementation in the runtime options.\n *\n * This implementation can only access properties on a single context object.\n * Example expressions:\n * - \"result.output.status === 'SUCCESS'\"\n * - \"context.user.isAdmin\"\n * - \"input.value * 100\"\n */\nexport class SimpleEvaluator implements IEvaluator {\n\tevaluate(expression: string, context: Record<string, any>): any {\n\t\ttry {\n\t\t\t// Filter out keys that aren't valid JavaScript identifiers\n\t\t\tconst validIdentifierRegex = /^[a-z_$][\\w$]*$/i\n\t\t\tconst validKeys = Object.keys(context).filter(key => validIdentifierRegex.test(key))\n\t\t\tconst validContext: Record<string, any> = {}\n\t\t\tfor (const key of validKeys) {\n\t\t\t\tvalidContext[key] = context[key]\n\t\t\t}\n\n\t\t\t// Creates a function that is sandboxed to only the keys of the `context` object.\n\t\t\t// It prevents access to global scope (e.g., `window`, `process`).\n\t\t\tconst sandbox = new Function(...validKeys, `return ${expression}`) // eslint-disable-line no-new-func\n\t\t\treturn sandbox(...validKeys.map(k => validContext[k]))\n\t\t}\n\t\tcatch (error) {\n\t\t\tconsole.error(`Error evaluating expression \"${expression}\":`, error)\n\t\t\t// In case of a syntax error or other issue, default to a \"falsy\" value.\n\t\t\treturn undefined\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,3 @@
1
+
2
+ //# sourceMappingURL=chunk-HMR2GEGE.js.map
3
+ //# sourceMappingURL=chunk-HMR2GEGE.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-F2RSES6P.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-HMR2GEGE.js"}
@@ -0,0 +1,27 @@
1
+ // src/sanitizer.ts
2
+ function sanitizeBlueprint(raw) {
3
+ const nodes = raw.nodes?.map((node) => ({
4
+ id: node.id,
5
+ uses: node.uses,
6
+ params: node.params,
7
+ inputs: node.inputs,
8
+ config: node.config
9
+ })) || [];
10
+ const edges = raw.edges?.map((edge) => ({
11
+ source: edge.source,
12
+ target: edge.target,
13
+ action: edge.action,
14
+ condition: edge.condition,
15
+ transform: edge.transform
16
+ })) || [];
17
+ return {
18
+ id: raw.id,
19
+ nodes,
20
+ edges,
21
+ metadata: raw.metadata
22
+ };
23
+ }
24
+
25
+ export { sanitizeBlueprint };
26
+ //# sourceMappingURL=chunk-J3RNCPED.js.map
27
+ //# sourceMappingURL=chunk-J3RNCPED.js.map