@baipeng139/72flow-nodejs 1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 我奋斗去了
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,272 @@
1
+ # 72flow-nodejs
2
+
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
4
+ [![TypeScript](https://img.shields.io/badge/TypeScript-6.x-blue)](https://www.typescriptlang.org/)
5
+ [![Node.js](https://img.shields.io/badge/Node.js-18%2B-green)](https://nodejs.org/)
6
+
7
+ 72flow 工作流编排引擎的 **Node.js / TypeScript** 实现,支持在浏览器和 Node.js 双环境中运行,与 Java 后端引擎保持行为一致。
8
+
9
+ ---
10
+
11
+ ## 特性
12
+
13
+ - ✅ **多节点类型**:START、END、SCRIPT、DECISION、CONDITION、PARALLEL、LOOP、API、LLM
14
+ - ✅ **浏览器 & Node.js 双运行时**:无需修改代码,同一套引擎在两端行为一致
15
+ - ✅ **并行分支**:`PARALLEL` 节点自动并发触发分支,汇聚后继续执行
16
+ - ✅ **条件分支**:`DECISION` / `CONDITION` 节点支持 JavaScript 表达式路由
17
+ - ✅ **循环执行**:`LOOP` 节点支持数组/次数迭代,内联同步执行循环体
18
+ - ✅ **LLM 集成**:内置 OpenAI / Qwen / Claude / Ollama 兼容接口
19
+ - ✅ **事件系统**:引擎发射 `node.starting`、`node.completed`、`node.failed` 等事件
20
+ - ✅ **X6 格式解析**:内置 `@antv/x6` 画布 JSON 格式解析器,直接对接前端图形编辑器
21
+ - ✅ **ESM + CJS 双格式产物**:兼容各种打包场景
22
+
23
+ ---
24
+
25
+ ## 安装
26
+
27
+ ```bash
28
+ npm install 72flow-nodejs
29
+ ```
30
+
31
+ > 需要 Node.js **18+**(使用原生 `fetch` 和 `EventTarget`)
32
+
33
+ ---
34
+
35
+ ## 快速开始
36
+
37
+ ### 基础线性流程
38
+
39
+ ```typescript
40
+ import { FlowEngine, FlowDefinition, NodeType } from '72flow-nodejs';
41
+
42
+ const definition: FlowDefinition = {
43
+ id: 'hello-world',
44
+ name: 'Hello World',
45
+ version: '1.0',
46
+ nodes: [
47
+ { id: 'start', type: NodeType.START },
48
+ { id: 'script', type: NodeType.SCRIPT, config: { script: 'greeting = "Hello, " + name' } },
49
+ { id: 'end', type: NodeType.END },
50
+ ],
51
+ edges: [
52
+ { id: 'e1', from: 'start', to: 'script' },
53
+ { id: 'e2', from: 'script', to: 'end' },
54
+ ],
55
+ };
56
+
57
+ const engine = new FlowEngine();
58
+ const result = await engine.execute(definition, { name: 'World' });
59
+
60
+ console.log(result.status); // 'COMPLETED'
61
+ console.log(result.variables.greeting); // 'Hello, World'
62
+ ```
63
+
64
+ ### 条件分支(DECISION)
65
+
66
+ ```typescript
67
+ const definition: FlowDefinition = {
68
+ id: 'branch-demo',
69
+ name: '条件分支示例',
70
+ version: '1.0',
71
+ nodes: [
72
+ { id: 'start', type: NodeType.START },
73
+ { id: 'decision', type: NodeType.DECISION, config: { decision: { scriptCode: 'score >= 60 ? "pass" : "fail"' } } },
74
+ { id: 'pass', type: NodeType.SCRIPT, config: { script: 'result = "通过"' } },
75
+ { id: 'fail', type: NodeType.SCRIPT, config: { script: 'result = "未通过"' } },
76
+ { id: 'end', type: NodeType.END },
77
+ ],
78
+ edges: [
79
+ { id: 'e1', from: 'start', to: 'decision' },
80
+ { id: 'e2', from: 'decision', to: 'pass', condition: 'pass' },
81
+ { id: 'e3', from: 'decision', to: 'fail', condition: 'fail' },
82
+ { id: 'e4', from: 'pass', to: 'end' },
83
+ { id: 'e5', from: 'fail', to: 'end' },
84
+ ],
85
+ };
86
+
87
+ const result = await new FlowEngine().execute(definition, { score: 80 });
88
+ console.log(result.variables.result); // '通过'
89
+ ```
90
+
91
+ ### 并行分支(PARALLEL)
92
+
93
+ ```typescript
94
+ const definition: FlowDefinition = {
95
+ id: 'parallel-demo',
96
+ name: '并行流程示例',
97
+ version: '1.0',
98
+ nodes: [
99
+ { id: 'start', type: NodeType.START },
100
+ { id: 'par', type: NodeType.PARALLEL },
101
+ { id: 'taskA', type: NodeType.SCRIPT, config: { script: 'a = 1' } },
102
+ { id: 'taskB', type: NodeType.SCRIPT, config: { script: 'b = 2' } },
103
+ { id: 'join', type: NodeType.SCRIPT, config: { script: 'sum = a + b' } },
104
+ { id: 'end', type: NodeType.END },
105
+ ],
106
+ edges: [
107
+ { id: 'e1', from: 'start', to: 'par' },
108
+ { id: 'e2', from: 'par', to: 'taskA' },
109
+ { id: 'e3', from: 'par', to: 'taskB' },
110
+ { id: 'e4', from: 'taskA', to: 'join' },
111
+ { id: 'e5', from: 'taskB', to: 'join' },
112
+ { id: 'e6', from: 'join', to: 'end' },
113
+ ],
114
+ convergeMap: { par: 'join' }, // 声明汇聚关系
115
+ };
116
+
117
+ const result = await new FlowEngine().execute(definition, {});
118
+ console.log(result.variables.sum); // 3
119
+ ```
120
+
121
+ ### 监听引擎事件
122
+
123
+ ```typescript
124
+ const engine = new FlowEngine();
125
+
126
+ engine.on('node.starting', ({ nodeId }) => console.log(`▶ 开始: ${nodeId}`));
127
+ engine.on('node.completed', ({ nodeId, output }) => console.log(`✓ 完成: ${nodeId}`, output));
128
+ engine.on('node.failed', ({ nodeId, error }) => console.error(`✗ 失败: ${nodeId}`, error));
129
+
130
+ await engine.execute(definition, variables);
131
+ ```
132
+
133
+ ### 解析 X6 画布 JSON
134
+
135
+ ```typescript
136
+ import { parseX6 } from '72flow-nodejs';
137
+
138
+ // x6Json 是 @antv/x6 画布导出的 JSON 对象
139
+ const flowDefinition = parseX6(x6Json);
140
+ const result = await new FlowEngine().execute(flowDefinition, {});
141
+ ```
142
+
143
+ ---
144
+
145
+ ## 节点类型说明
146
+
147
+ | 节点类型 | 说明 | 关键配置字段 |
148
+ |-------------|--------------------------------------------------|-------------------------------------------------|
149
+ | `START` | 流程起始节点 | — |
150
+ | `END` | 流程结束节点,输出所有变量 | — |
151
+ | `SCRIPT` | 执行 JavaScript 脚本,可读写流程变量 | `config.script`(字符串) |
152
+ | `DECISION` | 运行脚本计算返回值,与出边 `condition` 字段匹配 | `config.decision.scriptCode` |
153
+ | `CONDITION` | 对每条出边独立求值布尔表达式 | `config.condition.scriptCode` |
154
+ | `PARALLEL` | 并发触发所有出边分支,需配合 `convergeMap` 使用 | `convergeMap` (流程定义级) |
155
+ | `LOOP` | 数组/次数迭代,内联执行循环体 | `config.loop.loopType` / `itemsExpr` / `itemVar`|
156
+ | `API` | 调用 HTTP 接口,结果写入 `apiResponse` 变量 | `config.api.url` / `method` / `headers` / `body`|
157
+ | `LLM` | 调用 OpenAI 兼容大语言模型接口 | `config.llm.provider` / `modelName` / `userPrompt` |
158
+
159
+ ---
160
+
161
+ ## 流程变量
162
+
163
+ - 引擎所有节点**共享同一个变量空间**(`FlowContext.variables`)
164
+ - `SCRIPT` 节点通过 `with(vars)` 语法直接读写变量,**新增的变量也会生效**
165
+ - `API` 节点完成后,响应体自动写入 `variables.apiResponse`
166
+ - `LLM` 节点完成后,模型回复写入 `variables.llmResponse`
167
+ - `LOOP` 节点每轮迭代将当前元素写入 `item`(可自定义 `itemVar`),索引写入 `index`(可自定义 `indexVar`)
168
+
169
+ ---
170
+
171
+ ## 错误处理
172
+
173
+ 节点可在 `config.error.mode` 中指定错误处理策略:
174
+
175
+ | 值 | 行为 |
176
+ |----------------|-------------------------------------|
177
+ | `"throw"` | 抛出异常,终止流程(默认) |
178
+ | `"fail"` | 标记流程失败,终止流程 |
179
+ | `"<nodeId>"` | 跳转到指定节点 ID 继续执行(兜底逻辑)|
180
+
181
+ ---
182
+
183
+ ## API 参考
184
+
185
+ ### `FlowEngine`
186
+
187
+ ```typescript
188
+ class FlowEngine {
189
+ // 执行流程定义,返回执行结果
190
+ execute(definition: FlowDefinition, variables?: Record<string, any>): Promise<FlowResult>;
191
+
192
+ // 事件监听(继承自 SimpleEmitter)
193
+ on(event: string, handler: Function): this;
194
+ once(event: string, handler: Function): this;
195
+ off(event: string, handler: Function): this;
196
+ }
197
+ ```
198
+
199
+ ### `FlowResult`
200
+
201
+ ```typescript
202
+ interface FlowResult {
203
+ executionId: string; // 本次执行唯一 ID
204
+ status: NodeStatus; // COMPLETED | FAILED | CANCELLED
205
+ output?: any; // END 节点的输出
206
+ error?: string; // 错误信息(失败时)
207
+ duration: number; // 执行耗时(ms)
208
+ startTime: number; // 开始时间戳(ms)
209
+ endTime?: number; // 结束时间戳(ms)
210
+ variables: Record<string, any>; // 最终变量快照
211
+ traces: TraceRecord[]; // 各节点执行轨迹
212
+ }
213
+ ```
214
+
215
+ ### `parseX6(x6Json)`
216
+
217
+ 将 `@antv/x6` 导出的画布 JSON 转为 `FlowDefinition`,自动规范化节点类型、loop 配置字段等。
218
+
219
+ ---
220
+
221
+ ## 开发
222
+
223
+ ```bash
224
+ # 安装依赖
225
+ npm install
226
+
227
+ # 运行测试(watch 模式)
228
+ npm run dev
229
+
230
+ # 单次运行所有测试
231
+ npm test
232
+
233
+ # 构建 ESM + CJS 产物
234
+ npm run build
235
+ ```
236
+
237
+ ### 项目结构
238
+
239
+ ```
240
+ src/
241
+ ├── index.ts # 公开导出入口
242
+ ├── types/
243
+ │ └── models.ts # 核心类型定义(FlowDefinition、NodeDef、FlowResult 等)
244
+ ├── core/
245
+ │ ├── flow-engine.ts # 流程引擎调度核心
246
+ │ ├── flow-context.ts # 执行上下文(变量、状态、轨迹)
247
+ │ └── flow-engine.test.ts # 集成测试
248
+ ├── executors/
249
+ │ └── factory.ts # 各类型节点执行器(Start/End/Script/Decision/Parallel/Loop/API/LLM)
250
+ ├── parser/
251
+ │ └── x6-parser.ts # X6 画布 JSON 解析器
252
+ └── support/
253
+ └── logger.ts # 轻量日志工具
254
+ ```
255
+
256
+ ---
257
+
258
+ ## 与 Java 引擎的差异
259
+
260
+ | 能力 | Node.js 引擎 | Java 引擎 |
261
+ |-------------------|--------------|----------------|
262
+ | SCRIPT 语言 | **JavaScript only** | JavaScript + Groovy |
263
+ | API 跨域(浏览器) | 需 Vite `/api-proxy` 代理 | 无限制 |
264
+ | 运行环境 | Node.js 18+ / 现代浏览器 | JVM 11+ |
265
+
266
+ > **注意**:在浏览器中调用 `API` 节点时,需确保 Vite dev server 已配置 `/api-proxy` 代理路由,以规避 CORS 限制。
267
+
268
+ ---
269
+
270
+ ## License
271
+
272
+ [MIT](./LICENSE)