@liyown/flow-engine
Version:
一个基于JavaScript的无状态工作流引擎框架,支持可视化拖拽、DSL定义、断点继续、自动重试等高级功能
1,437 lines (1,436 loc) • 48.3 kB
JavaScript
import { EventEmitter as $ } from "events";
import { v4 as v } from "uuid";
class S {
static createWorkflow(e) {
var t, r, s, i;
return {
id: e.id || this.generateId(),
name: e.name || "",
version: e.version || "1.0.0",
description: e.description,
// 全局配置
global: {
timeout: ((t = e.global) == null ? void 0 : t.timeout) || 3e4,
retryPolicy: ((r = e.global) == null ? void 0 : r.retryPolicy) || {
maxRetries: 3,
delay: 1e3
},
context: ((s = e.global) == null ? void 0 : s.context) || {},
variables: ((i = e.global) == null ? void 0 : i.variables) || {}
},
// 输入输出Schema
input: e.input || { type: "object", properties: {} },
output: e.output || { type: "object", properties: {} },
// 步骤定义
steps: e.steps || [],
// 依赖关系
dependencies: e.dependencies || [],
// 条件分支
conditions: e.conditions || [],
// 错误处理
errorHandlers: e.errorHandlers || [],
// 元数据
metadata: e.metadata || {}
};
}
static generateId() {
return `workflow_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
}
}
class j {
constructor(e) {
this.id = e.id, this.name = e.name, this.type = e.type, this.handler = e.handler, this.input = e.input || { type: "object" }, this.output = e.output || { type: "object" }, this.inputMapping = e.inputMapping || {}, this.retry = e.retry || { maxRetries: 0, delay: 1e3 }, this.timeout = e.timeout || 1e4, this.condition = e.condition, this.dependsOn = e.dependsOn || [], this.parallel = e.parallel || !1, this.loop = e.loop, this.onError = e.onError || "throw", this.metadata = e.metadata || {};
}
}
class g {
constructor(e, t = {}) {
this.workflowId = e, this.executionId = this.generateExecutionId(), this.startTime = Date.now(), this.status = "running", this.globalContext = {}, this.stepResults = /* @__PURE__ */ new Map(), this.variables = /* @__PURE__ */ new Map(), this.initialData = t, this.currentStep = null, this.completedSteps = /* @__PURE__ */ new Set(), this.failedSteps = /* @__PURE__ */ new Set(), this.skippedSteps = /* @__PURE__ */ new Set(), this.errors = [], this.executionHistory = [], this.breakpoints = /* @__PURE__ */ new Set(), this.isPaused = !1;
}
generateExecutionId() {
return `exec_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
}
setStepResult(e, t) {
this.stepResults.set(e, {
result: t,
timestamp: Date.now(),
executionTime: Date.now() - this.startTime
});
}
getStepResult(e) {
return this.stepResults.get(e);
}
addHistoryRecord(e) {
this.executionHistory.push({
...e,
timestamp: Date.now()
});
}
serialize() {
return {
workflowId: this.workflowId,
executionId: this.executionId,
startTime: this.startTime,
endTime: this.endTime,
status: this.status,
globalContext: this.globalContext,
stepResults: Object.fromEntries(this.stepResults),
variables: Object.fromEntries(this.variables),
initialData: this.initialData,
currentStep: this.currentStep,
completedSteps: Array.from(this.completedSteps),
failedSteps: Array.from(this.failedSteps),
skippedSteps: Array.from(this.skippedSteps),
errors: this.errors,
executionHistory: this.executionHistory,
breakpoints: Array.from(this.breakpoints),
isPaused: this.isPaused
};
}
static deserialize(e) {
const t = new g(e.workflowId, e.initialData);
return t.executionId = e.executionId, t.startTime = e.startTime, t.endTime = e.endTime, t.status = e.status, t.globalContext = e.globalContext, t.initialData = e.initialData, t.currentStep = e.currentStep, t.errors = e.errors, t.executionHistory = e.executionHistory, t.isPaused = e.isPaused, t.stepResults = new Map(Object.entries(e.stepResults)), t.variables = new Map(Object.entries(e.variables)), t.completedSteps = new Set(e.completedSteps), t.failedSteps = new Set(e.failedSteps), t.skippedSteps = new Set(e.skippedSteps), t.breakpoints = new Set(e.breakpoints), t;
}
}
class y {
/**
* 执行节点处理器
*/
async execute(e, t) {
return this.handler(e, t);
}
/**
* 获取节点元数据
*/
getMetadata() {
return this.metadata;
}
}
class A extends y {
constructor() {
super(...arguments), this.name = "http", this.handler = async (e, t) => {
const { url: r, method: s = "GET", headers: i = {}, body: n } = e;
try {
return await (await fetch(r, {
method: s,
headers: { "Content-Type": "application/json", ...i },
body: n ? JSON.stringify(n) : void 0
})).json();
} catch (o) {
throw new Error(`HTTP request failed: ${o.message}`);
}
}, this.metadata = {
name: this.name,
description: "发送HTTP请求到外部API",
category: "网络",
displayName: "HTTP请求",
inputSchema: {
type: "object",
properties: {
url: {
type: "string",
format: "uri",
description: "请求的目标URL"
},
method: {
type: "string",
enum: ["GET", "POST", "PUT", "DELETE", "PATCH"],
default: "GET",
description: "HTTP请求方法"
},
headers: {
type: "object",
additionalProperties: { type: "string" },
description: "HTTP请求头"
},
body: {
type: "object",
description: "请求体(用于POST, PUT, PATCH等方法)"
}
},
required: ["url"]
},
outputSchema: {
type: "object",
description: "HTTP请求的响应数据"
},
examples: [
{
name: "获取用户数据",
input: {
url: "https://api.example.com/users/1",
method: "GET"
}
}
]
};
}
}
class N {
/**
* 将数据转换为符合目标Schema的格式
* @param value 要转换的数据
* @param targetSchema 目标Schema
* @returns 转换结果
*/
static convert(e, t) {
const r = [];
let s = e;
try {
if (e === null)
return Array.isArray(t.type) && t.type.includes("null") ? { success: !0, value: null, errors: [] } : t.type === "null" ? { success: !0, value: null, errors: [] } : (r.push(`无法将null转换为 ${t.type}`), { success: !1, value: e, errors: r });
if (e === void 0)
return t.default !== void 0 ? { success: !0, value: t.default, errors: [] } : (r.push(`无法将undefined转换为 ${t.type}`), { success: !1, value: e, errors: r });
const i = Array.isArray(t.type) ? t.type.filter((n) => n !== "null")[0] || t.type[0] : t.type;
switch (i) {
case "string":
s = this.convertToString(e, r);
break;
case "number":
s = this.convertToNumber(e, r);
break;
case "integer":
s = this.convertToInteger(e, r);
break;
case "boolean":
s = this.convertToBoolean(e, r);
break;
case "array":
s = this.convertToArray(e, t, r);
break;
case "object":
s = this.convertToObject(e, t, r);
break;
case "date":
case "datetime":
s = this.convertToDate(e, r);
break;
default:
return r.push(`不支持转换到类型: ${i}`), { success: !1, value: e, errors: r };
}
return i === "integer" && typeof e == "number" && !Number.isInteger(e) && (r.length = 0), r.length > 0 ? { success: !1, value: e, errors: r } : { success: !0, value: s, errors: [] };
} catch (i) {
return r.push(`转换过程中出错: ${i instanceof Error ? i.message : String(i)}`), { success: !1, value: e, errors: r };
}
}
/**
* 转换为字符串
*/
static convertToString(e, t) {
if (typeof e == "string")
return e;
if (e == null)
return t.push("无法将null或undefined转换为字符串"), "";
if (typeof e == "object")
try {
return JSON.stringify(e);
} catch (r) {
return t.push(`无法将对象转换为JSON字符串: ${r instanceof Error ? r.message : String(r)}`), String(e);
}
return String(e);
}
/**
* 转换为数字
*/
static convertToNumber(e, t) {
if (typeof e == "number")
return e;
if (typeof e == "string") {
const r = Number(e);
return isNaN(r) ? (t.push(`无法将字符串 "${e}" 转换为数字`), 0) : r;
}
return typeof e == "boolean" ? e ? 1 : 0 : e instanceof Date ? e.getTime() : (t.push(`无法将类型 ${typeof e} 转换为数字`), 0);
}
/**
* 转换为整数
*/
static convertToInteger(e, t) {
if (typeof e == "number" && Number.isInteger(e))
return e;
let r = e;
if (typeof e != "number" && (r = this.convertToNumber(e, t)), t.length > 0)
return 0;
const s = Math.trunc(r);
return s !== r && typeof e == "number" && console.warn(`数字 ${r} 被截断为整数 ${s}`), s;
}
/**
* 转换为布尔值
*/
static convertToBoolean(e, t) {
if (typeof e == "boolean")
return e;
if (typeof e == "string") {
const r = e.toLowerCase().trim();
return ["true", "yes", "1", "on"].includes(r) ? !0 : (["false", "no", "0", "off"].includes(r) || t.push(`无法将字符串 "${e}" 转换为布尔值`), !1);
}
return typeof e == "number" ? e !== 0 : (t.push(`无法将类型 ${typeof e} 转换为布尔值`), !1);
}
/**
* 转换为数组
*/
static convertToArray(e, t, r) {
if (Array.isArray(e))
return e;
if (typeof e == "string")
try {
const s = JSON.parse(e);
if (Array.isArray(s))
return s;
} catch {
return e.split(",").map((s) => s.trim());
}
return [e];
}
/**
* 转换为对象
*/
static convertToObject(e, t, r) {
if (typeof e == "object" && e !== null && !Array.isArray(e))
return e;
if (typeof e == "string")
try {
const s = JSON.parse(e);
return typeof s == "object" && s !== null && !Array.isArray(s) ? s : (r.push(`解析的JSON不是对象: ${e}`), {});
} catch (s) {
return r.push(`无法将字符串解析为JSON对象: ${s instanceof Error ? s.message : String(s)}`), {};
}
if (Array.isArray(e))
try {
const s = {};
for (let i = 0; i < e.length; i += 2)
if (i + 1 < e.length) {
const n = String(e[i]);
s[n] = e[i + 1];
}
return s;
} catch (s) {
return r.push(`无法将数组转换为对象: ${s instanceof Error ? s.message : String(s)}`), {};
}
return r.push(`无法将类型 ${typeof e} 转换为对象`), {};
}
/**
* 转换为日期
*/
static convertToDate(e, t) {
if (e instanceof Date)
return e;
if (typeof e == "string") {
const r = new Date(e);
return isNaN(r.getTime()) ? (t.push(`无法将字符串 "${e}" 解析为日期`), /* @__PURE__ */ new Date()) : r;
}
if (typeof e == "number") {
const r = new Date(e);
return isNaN(r.getTime()) ? (t.push(`无法将数字 ${e} 转换为日期`), /* @__PURE__ */ new Date()) : r;
}
return t.push(`无法将类型 ${typeof e} 转换为日期`), /* @__PURE__ */ new Date();
}
}
class k {
/**
* 验证数据是否符合Schema
* @param data 要验证的数据
* @param schema Schema定义
* @returns 验证结果
*/
static validate(e, t) {
const r = [];
try {
if (!this.validateType(e, t.type))
return r.push(`类型不匹配: 期望 ${t.type},实际为 ${typeof e}`), { valid: !1, errors: r };
switch (this.getPrimaryType(t.type)) {
case "string":
this.validateString(e, t, r);
break;
case "number":
case "integer":
this.validateNumber(e, t, r);
break;
case "boolean":
break;
case "array":
this.validateArray(e, t, r);
break;
case "object":
this.validateObject(e, t, r);
break;
case "date":
case "datetime":
this.validateDate(e, t, r);
break;
}
t.enum && !t.enum.includes(e) && r.push(`值 ${e} 不在允许的枚举值 [${t.enum.join(", ")}] 中`);
} catch (s) {
r.push(`验证过程中出错: ${s instanceof Error ? s.message : String(s)}`);
}
return {
valid: r.length === 0,
errors: r
};
}
/**
* 获取主要类型(如果是类型数组,返回第一个非null类型)
*/
static getPrimaryType(e) {
if (Array.isArray(e)) {
const t = e.filter((r) => r !== "null");
return t.length > 0 ? t[0] : e[0];
}
return e;
}
/**
* 验证类型是否匹配
*/
static validateType(e, t) {
if (e === null)
return Array.isArray(t) && t.includes("null");
const r = typeof e;
if (Array.isArray(e) && (t === "array" || Array.isArray(t) && t.includes("array")) || (e instanceof Date || typeof e == "string" && !isNaN(Date.parse(e))) && (t === "date" || t === "datetime" || Array.isArray(t) && (t.includes("date") || t.includes("datetime"))))
return !0;
if (r === "number") {
if (t === "number" || t === "integer")
return !(t === "integer" && !Number.isInteger(e));
if (Array.isArray(t) && (t.includes("number") || t.includes("integer")))
return t.includes("integer") && !Number.isInteger(e) ? t.includes("number") : !0;
}
return Array.isArray(t) ? t.some((s) => this.matchType(r, s)) : this.matchType(r, t);
}
/**
* 匹配JavaScript类型和Schema类型
*/
static matchType(e, t) {
switch (t) {
case "string":
return e === "string";
case "number":
return e === "number";
case "integer":
return e === "number";
case "boolean":
return e === "boolean";
case "object":
return e === "object" && !Array.isArray(e);
case "array":
return Array.isArray(e);
default:
return !1;
}
}
/**
* 验证字符串
*/
static validateString(e, t, r) {
if (t.minLength !== void 0 && e.length < t.minLength && r.push(`字符串长度 ${e.length} 小于最小长度 ${t.minLength}`), t.maxLength !== void 0 && e.length > t.maxLength && r.push(`字符串长度 ${e.length} 大于最大长度 ${t.maxLength}`), t.pattern)
try {
new RegExp(t.pattern).test(e) || r.push(`字符串不匹配模式 ${t.pattern}`);
} catch {
r.push(`无效的正则表达式模式: ${t.pattern}`);
}
if (t.format)
switch (t.format) {
case "email":
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e) || r.push("值不是有效的电子邮件格式");
break;
case "uri":
try {
new URL(e);
} catch {
r.push("值不是有效的URI格式");
}
break;
}
}
/**
* 验证数字
*/
static validateNumber(e, t, r) {
t.type === "integer" && !Number.isInteger(e) && r.push(`值 ${e} 不是整数`), t.multipleOf !== void 0 && e % t.multipleOf !== 0 && r.push(`值 ${e} 不是 ${t.multipleOf} 的倍数`), t.maximum !== void 0 && e > t.maximum && r.push(`值 ${e} 大于最大值 ${t.maximum}`), t.exclusiveMaximum !== void 0 && e >= t.exclusiveMaximum && r.push(`值 ${e} 大于或等于独占最大值 ${t.exclusiveMaximum}`), t.minimum !== void 0 && e < t.minimum && r.push(`值 ${e} 小于最小值 ${t.minimum}`), t.exclusiveMinimum !== void 0 && e <= t.exclusiveMinimum && r.push(`值 ${e} 小于或等于独占最小值 ${t.exclusiveMinimum}`);
}
/**
* 验证数组
*/
static validateArray(e, t, r) {
if (t.minItems !== void 0 && e.length < t.minItems && r.push(`数组长度 ${e.length} 小于最小长度 ${t.minItems}`), t.maxItems !== void 0 && e.length > t.maxItems && r.push(`数组长度 ${e.length} 大于最大长度 ${t.maxItems}`), t.uniqueItems && new Set(e).size !== e.length && r.push("数组包含重复项,但要求唯一项"), t.items)
if (Array.isArray(t.items)) {
for (let s = 0; s < Math.min(e.length, t.items.length); s++) {
const i = t.items[s], n = this.validate(e[s], i);
n.valid || r.push(`数组索引 ${s} 验证失败: ${n.errors.join(", ")}`);
}
if (e.length > t.items.length && t.additionalItems === !1)
r.push("数组包含额外项,但不允许额外项");
else if (e.length > t.items.length && typeof t.additionalItems == "object")
for (let s = t.items.length; s < e.length; s++) {
const i = this.validate(e[s], t.additionalItems);
i.valid || r.push(`额外数组项索引 ${s} 验证失败: ${i.errors.join(", ")}`);
}
} else
for (let s = 0; s < e.length; s++) {
const i = this.validate(e[s], t.items);
i.valid || r.push(`数组索引 ${s} 验证失败: ${i.errors.join(", ")}`);
}
}
/**
* 验证对象
*/
static validateObject(e, t, r) {
const s = Object.keys(e);
if (t.required)
for (const i of t.required)
i in e || r.push(`缺少必需属性: ${i}`);
if (t.minProperties !== void 0 && s.length < t.minProperties && r.push(`对象属性数量 ${s.length} 小于最小数量 ${t.minProperties}`), t.maxProperties !== void 0 && s.length > t.maxProperties && r.push(`对象属性数量 ${s.length} 大于最大数量 ${t.maxProperties}`), t.properties) {
for (const [i, n] of Object.entries(t.properties))
if (i in e) {
const o = this.validate(e[i], n);
o.valid || r.push(`属性 "${i}" 验证失败: ${o.errors.join(", ")}`);
}
}
if (t.additionalProperties === !1) {
const i = t.properties ? Object.keys(t.properties) : [], n = s.filter((o) => !i.includes(o));
n.length > 0 && r.push(`对象包含额外属性: ${n.join(", ")}`);
} else if (typeof t.additionalProperties == "object") {
const i = t.properties ? Object.keys(t.properties) : [], n = s.filter((o) => !i.includes(o));
for (const o of n) {
const u = this.validate(e[o], t.additionalProperties);
u.valid || r.push(`额外属性 "${o}" 验证失败: ${u.errors.join(", ")}`);
}
}
}
/**
* 验证日期
*/
static validateDate(e, t, r) {
if (e instanceof Date)
return;
if (typeof e == "string")
try {
const i = new Date(e);
if (!isNaN(i.getTime()))
return;
} catch {
}
if (typeof e != "string" || isNaN(Date.parse(String(e)))) {
r.push(`值 ${e} 不是有效的日期`);
return;
}
const s = new Date(String(e));
if (t.minimum !== void 0) {
const i = new Date(t.minimum);
s < i && r.push(`日期早于最小日期 ${i.toISOString()}`);
}
if (t.maximum !== void 0) {
const i = new Date(t.maximum);
s > i && r.push(`日期晚于最大日期 ${i.toISOString()}`);
}
}
}
class O extends y {
constructor() {
super(...arguments), this.name = "typeConvert", this.handler = async (e, t) => {
const { value: r, targetSchema: s, validateAfterConversion: i = !0, throwOnError: n = !1 } = e;
if (!s)
throw new Error("缺少必需参数: targetSchema");
const o = N.convert(r, s);
if (!o.success && n)
throw new Error(`类型转换失败: ${o.errors.join("; ")}`);
let u = { valid: !0, errors: [] };
if (i && o.success && (u = k.validate(o.value, s), !u.valid && n))
throw new Error(`类型验证失败: ${u.errors.join("; ")}`);
return {
originalValue: r,
convertedValue: o.value,
conversionSuccess: o.success,
conversionErrors: o.errors,
validationSuccess: u.valid,
validationErrors: u.errors,
isValid: o.success && u.valid
};
}, this.metadata = {
name: this.name,
description: "将数据转换为指定的类型并验证",
category: "数据处理",
displayName: "类型转换",
inputSchema: {
type: "object",
properties: {
value: {
description: "要转换的值",
type: ["string", "number", "boolean", "object", "array", "null"]
},
targetSchema: {
type: "object",
description: "目标Schema定义"
},
validateAfterConversion: {
type: "boolean",
description: "是否在转换后验证",
default: !0
},
throwOnError: {
type: "boolean",
description: "转换或验证失败时是否抛出错误",
default: !1
}
},
required: ["value", "targetSchema"]
},
outputSchema: {
type: "object",
properties: {
originalValue: {
description: "原始值",
type: ["string", "number", "boolean", "object", "array", "null"]
},
convertedValue: {
description: "转换后的值",
type: ["string", "number", "boolean", "object", "array", "null"]
},
conversionSuccess: {
type: "boolean",
description: "转换是否成功"
},
conversionErrors: {
type: "array",
items: { type: "string" },
description: "转换错误列表"
},
validationSuccess: {
type: "boolean",
description: "验证是否成功"
},
validationErrors: {
type: "array",
items: { type: "string" },
description: "验证错误列表"
},
isValid: {
type: "boolean",
description: "转换和验证是否都成功"
}
}
},
examples: [
{
name: "将字符串转换为数字",
input: {
value: "123",
targetSchema: { type: "number" }
}
},
{
name: "将字符串转换为日期",
input: {
value: "2023-01-01",
targetSchema: { type: "date" }
}
}
]
};
}
}
class T extends y {
constructor() {
super(...arguments), this.name = "delay", this.handler = async (e) => {
const { duration: t = 1e3 } = e;
return await new Promise((r) => setTimeout(r, t)), { delayed: !0, duration: t };
}, this.metadata = {
name: this.name,
description: "延迟执行指定的毫秒数",
category: "工具",
displayName: "延迟",
inputSchema: {
type: "object",
properties: {
duration: {
type: "number",
description: "延迟时间(毫秒)",
default: 1e3
}
}
},
outputSchema: {
type: "object",
properties: {
delayed: { type: "boolean" },
duration: { type: "number" }
}
}
};
}
}
class P extends y {
constructor() {
super(...arguments), this.name = "log", this.handler = async (e) => {
const { message: t, level: r = "info", data: s } = e;
switch (r) {
case "error":
console.error(t, s);
break;
case "warn":
console.warn(t, s);
break;
case "debug":
console.debug(t, s);
break;
case "info":
default:
console.info(t, s);
}
return { logged: !0, timestamp: Date.now() };
}, this.metadata = {
name: this.name,
description: "记录日志信息",
category: "工具",
displayName: "日志",
inputSchema: {
type: "object",
properties: {
message: { type: "string", description: "日志消息" },
level: {
type: "string",
enum: ["info", "warn", "error", "debug"],
default: "info",
description: "日志级别"
},
data: { type: "object", description: "附加数据" }
},
required: ["message"]
},
outputSchema: {
type: "object",
properties: {
logged: { type: "boolean" },
timestamp: { type: "number" }
}
}
};
}
}
class D extends y {
constructor() {
super(...arguments), this.name = "noop", this.handler = async () => ({ executed: !0 }), this.metadata = {
name: this.name,
description: "不执行任何操作的处理器",
category: "工具",
displayName: "空操作",
inputSchema: { type: "object" },
outputSchema: {
type: "object",
properties: {
executed: { type: "boolean" }
}
}
};
}
}
function R() {
return [
new A(),
new O(),
new T(),
new P(),
new D()
];
}
class I {
constructor() {
this.handlers = /* @__PURE__ */ new Map(), this.metadata = /* @__PURE__ */ new Map(), this.registerBuiltinHandlers();
}
/**
* 注册步骤处理器
*/
register(e, t, r) {
this.handlers.set(e, t), r && this.registerMetadata(e, {
name: e,
description: r.description || `Handler for ${e}`,
inputSchema: r.inputSchema || { type: "object", properties: {} },
outputSchema: r.outputSchema || {
type: "object",
properties: {}
},
category: r.category,
icon: r.icon,
displayName: r.displayName || e,
examples: r.examples || []
});
}
/**
* 注册处理器元数据
*/
registerMetadata(e, t) {
this.metadata.set(e, t);
}
/**
* 获取处理器元数据
*/
getMetadata(e) {
return this.metadata.get(e);
}
/**
* 获取所有处理器元数据
*/
getAllMetadata() {
return Array.from(this.metadata.values());
}
/**
* 获取步骤处理器
*/
get(e) {
return this.handlers.get(e);
}
/**
* 检查处理器是否存在
*/
has(e) {
return this.handlers.has(e);
}
/**
* 注册内置处理器
*/
registerBuiltinHandlers() {
const e = R();
for (const t of e)
this.register(t.name, async (r, s) => await t.execute(r, s), t.metadata);
}
/**
* 执行处理器
*/
async executeHandler(e, t, r) {
const s = this.get(e);
if (!s)
throw new Error(`Handler not found: ${e}`);
return await s(t, r);
}
}
class m {
static mapInput(e, t, r) {
if (!t || Object.keys(t).length === 0)
return e;
const s = {};
for (const [i, n] of Object.entries(t))
s[i] = this.evaluateExpression(n, {
input: e,
context: r.globalContext,
variables: Object.fromEntries(r.variables),
stepResults: this.mapToObject(r.stepResults)
});
return s;
}
static evaluateExpression(e, t) {
return typeof e == "string" ? e.startsWith("$") ? this.evaluateJSONPath(e, t) : e : typeof e == "object" && e !== null ? this.evaluateComplexExpression(e, t) : e;
}
static evaluateJSONPath(e, t) {
const r = e.substring(1), s = this.getNestedValue(t, r);
return s === void 0 && console.warn(`在作用域中未找到路径: ${e}`), s;
}
static evaluateComplexExpression(e, t) {
return e.type === "concat" ? e.values.map((r) => this.evaluateExpression(r, t)).join(e.separator || "") : e.type === "template" ? this.evaluateTemplate(e.template, t) : e.type === "function" ? this.evaluateFunction(e.name, e.args, t) : e;
}
static evaluateTemplate(e, t) {
return e.replace(/\{\{([^}]+)\}\}/g, (r, s) => {
const i = this.getNestedValue(t, s.trim());
return i !== void 0 ? String(i) : r;
});
}
static evaluateFunction(e, t, r) {
var i;
const s = t.map((n) => this.evaluateExpression(n, r));
switch (e) {
case "now":
return Date.now();
case "uuid":
return this.generateUUID();
case "length":
return s[0] === void 0 || s[0] === null ? 0 : typeof s[0] != "string" && !Array.isArray(s[0]) ? (console.warn(`函数 "length" 的参数必须是字符串或数组,但收到: ${typeof s[0]}`), 0) : ((i = s[0]) == null ? void 0 : i.length) || 0;
case "upper":
return typeof s[0] != "string" ? (console.warn(`函数 "upper" 的参数必须是字符串,但收到: ${typeof s[0]}`), String(s[0])) : String(s[0]).toUpperCase();
case "lower":
return typeof s[0] != "string" ? (console.warn(`函数 "lower" 的参数必须是字符串,但收到: ${typeof s[0]}`), String(s[0])) : String(s[0]).toLowerCase();
case "sum":
return Array.isArray(s[0]) ? s[0].reduce((n, o) => {
const u = Number(o);
return isNaN(u) ? (console.warn(`函数 "sum" 在累加时遇到非数字值: ${o}`), n) : n + u;
}, 0) : s.reduce((n, o) => {
const u = Number(o);
return isNaN(u) ? (console.warn(`函数 "sum" 在累加时遇到非数字值: ${o}`), n) : n + u;
}, 0);
default:
throw new Error(`未知函数: ${e}`);
}
}
static getNestedValue(e, t) {
const r = t.split(".").reduce((s, i) => {
if (!(s == null || typeof s != "object"))
return s[i];
}, e);
return r !== void 0 && console.log(`DataMapper: 获取路径 ${t} 的值 ${r},类型为 ${typeof r}`), r;
}
static mapToObject(e) {
const t = {};
for (const [r, s] of e.entries())
t[r] = s;
return t;
}
static generateUUID() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(e) {
const t = Math.random() * 16 | 0;
return (e === "x" ? t : t & 3 | 8).toString(16);
});
}
}
class C {
static evaluate(e, t) {
return e ? typeof e == "string" ? this.evaluateExpression(e, t) : typeof e == "object" ? this.evaluateConditionObject(e, t) : !!e : !0;
}
static evaluateExpression(e, t) {
const r = {
context: t.globalContext,
variables: Object.fromEntries(t.variables),
stepResults: m.mapToObject(t.stepResults)
};
try {
return this.safeEval(e, r);
} catch (s) {
return console.warn("Condition evaluation failed:", s), !1;
}
}
static evaluateConditionObject(e, t) {
const { operator: r, left: s, right: i, conditions: n } = e;
switch (r) {
case "and":
return (n == null ? void 0 : n.every((o) => this.evaluate(o, t))) ?? !1;
case "or":
return (n == null ? void 0 : n.some((o) => this.evaluate(o, t))) ?? !1;
case "not":
return !this.evaluate(n == null ? void 0 : n[0], t);
case "eq":
return this.getValue(s, t) === this.getValue(i, t);
case "ne":
return this.getValue(s, t) !== this.getValue(i, t);
case "gt":
return this.getValue(s, t) > this.getValue(i, t);
case "gte":
return this.getValue(s, t) >= this.getValue(i, t);
case "lt":
return this.getValue(s, t) < this.getValue(i, t);
case "lte":
return this.getValue(s, t) <= this.getValue(i, t);
case "contains":
return String(this.getValue(s, t)).includes(String(this.getValue(i, t)));
case "in": {
const o = this.getValue(i, t);
return Array.isArray(o) && o.includes(this.getValue(s, t));
}
default:
return console.warn(`未知的条件操作符: ${r}`), !1;
}
}
static getValue(e, t) {
return typeof e == "string" && e.startsWith("$") ? m.evaluateExpression(e, {
context: t.globalContext,
variables: Object.fromEntries(t.variables),
stepResults: m.mapToObject(t.stepResults)
}) : e;
}
static safeEval(e, t) {
const r = e.replace(/\$(\w+\.?\w*)/g, (s, i) => JSON.stringify(m.getNestedValue(t, i)));
try {
return new Function("scope", `return Boolean(${r})`)(t);
} catch (s) {
return console.error(`在 safeEval 中执行表达式 "${e}" (清理后为 "${r}") 时出错:`, s), !1;
}
}
}
class J {
constructor(e = {}) {
this.handlerRegistry = new I(), this.executionStore = e.executionStore || /* @__PURE__ */ new Map(), this.eventEmitter = e.eventEmitter || new $(), this.config = {
maxConcurrentExecutions: e.maxConcurrentExecutions || 10,
defaultTimeout: e.defaultTimeout || 3e4,
enableBreakpoints: e.enableBreakpoints || !1,
persistExecution: e.persistExecution || !1
};
}
/**
* 注册步骤处理器
*/
registerHandler(e, t, r) {
this.handlerRegistry.register(e, async (s, i) => await t(s, i), r);
}
/**
* 执行工作流
*/
async execute(e, t = {}, r = {}) {
var n;
const s = "id" in e ? e : S.createWorkflow(e), i = new g(s.id, t);
Object.assign(i.globalContext, ((n = s.global) == null ? void 0 : n.context) || {}), r.breakpoints && r.breakpoints.forEach((o) => i.breakpoints.add(o)), this.executionStore.set(i.executionId, i);
try {
this.emitEvent("workflow.started", { context: i, workflow: s });
const o = this.buildDependencyGraph(s.steps);
console.log("依赖图构建完成", { graph: o });
const u = await this.executeWorkflow(s, i, o);
return console.log("工作流执行完成", { result: u }), i.status = "completed", i.endTime = Date.now(), this.emitEvent("workflow.completed", { context: i, workflow: s, result: u }), {
executionId: i.executionId,
status: i.status,
result: u,
context: i.serialize()
};
} catch (o) {
throw i.status = "failed", i.endTime = Date.now(), i.errors.push({
message: o instanceof Error ? o.message : String(o),
stack: o instanceof Error ? o.stack : void 0,
timestamp: Date.now()
}), this.emitEvent("workflow.failed", { context: i, workflow: s, error: o }), console.error(`工作流 ${i.executionId} 执行失败:`, o), o;
}
}
/**
* 从断点继续执行
*/
async resume(e) {
const t = this.executionStore.get(e);
if (!t)
throw new Error(`Execution not found: ${e}`);
if (t.status !== "paused")
throw new Error(`Execution is not paused: ${e}`);
return t.status = "running", t.isPaused = !1, this.emitEvent("workflow.resumed", { context: t }), { status: "resumed", executionId: e };
}
/**
* 暂停执行
*/
async pause(e) {
const t = this.executionStore.get(e);
if (!t)
throw new Error(`Execution not found: ${e}`);
return t.status = "paused", t.isPaused = !0, this.emitEvent("workflow.paused", { context: t }), { status: "paused", executionId: e };
}
/**
* 取消执行
*/
async cancel(e) {
const t = this.executionStore.get(e);
if (!t)
throw new Error(`Execution not found: ${e}`);
return t.status = "cancelled", this.emitEvent("workflow.cancelled", { context: t }), { status: "cancelled", executionId: e };
}
/**
* 获取执行状态
*/
getExecutionStatus(e) {
const t = this.executionStore.get(e);
return t ? {
executionId: t.executionId,
status: t.status,
startTime: t.startTime,
endTime: t.endTime,
currentStep: t.currentStep,
completedSteps: Array.from(t.completedSteps),
failedSteps: Array.from(t.failedSteps),
errors: t.errors
} : null;
}
/**
* 构建依赖图
*/
buildDependencyGraph(e) {
const t = /* @__PURE__ */ new Map();
for (const r of e)
t.set(r.id, {
step: r,
dependencies: r.dependsOn || [],
dependents: []
});
for (const [r, s] of t.entries())
for (const i of s.dependencies) {
const n = t.get(i);
n && n.dependents.push(r);
}
return t;
}
/**
* 执行工作流
*/
async executeWorkflow(e, t, r) {
const s = [], i = /* @__PURE__ */ new Set(), n = /* @__PURE__ */ new Set(), o = {}, u = Array.from(r.values()).filter((d) => d.dependencies.length === 0).map((d) => d.step);
console.log("入口步骤", { entrySteps: u });
for (const d of u)
s.push(d);
for (; s.length > 0 || i.size > 0; ) {
if (t.isPaused) {
console.log("工作流暂停", { context: t });
break;
}
const d = s.filter((a) => !i.has(a.id) && (a.dependsOn || []).every((l) => n.has(l)));
if (d.length === 0 && i.size === 0 && s.length === 0) {
console.log("所有步骤执行完毕或没有可执行的步骤,退出循环");
break;
}
if (d.length === 0 && i.size > 0) {
await new Promise((a) => setTimeout(a, 50));
continue;
}
d.length === 0 && s.length > 0 && i.size === 0 && console.warn("执行队列中没有就绪的步骤,但队列不为空且无正在执行的步骤。可能存在依赖问题。", {
executionQueue: s.map((a) => a.id),
executing: Array.from(i),
completed: Array.from(n)
});
const h = d.map(async (a) => {
i.add(a.id);
try {
const l = await this.executeStep(a, t, e);
o[a.id] = l, t.setStepResult(a.id, l), t.completedSteps.add(a.id), n.add(a.id);
const f = Array.from(r.values()).filter((p) => p.dependencies.includes(a.id)).map((p) => p.step).filter((p) => !s.includes(p) && !i.has(p.id) && !n.has(p.id));
s.push(...f);
} catch (l) {
if (t.failedSteps.add(a.id), t.errors.push({
stepId: a.id,
message: l instanceof Error ? l.message : String(l),
stack: l instanceof Error ? l.stack : void 0,
timestamp: Date.now()
}), a.onError === "throw")
throw l;
if (a.onError === "continue") {
console.warn(`步骤 ${a.id} 执行失败,但错误处理策略为 'continue'。错误:`, l instanceof Error ? l.message : String(l)), t.setStepResult(a.id, {
error: l instanceof Error ? l.message : String(l),
continued: !0
}), n.add(a.id);
const f = Array.from(r.values()).filter((p) => p.dependencies.includes(a.id)).map((p) => p.step).filter((p) => !s.includes(p) && !i.has(p.id) && !n.has(p.id));
s.push(...f);
} else if (a.onError === "retry")
throw l;
} finally {
i.delete(a.id);
}
});
for (const a of d) {
const l = s.findIndex((f) => f.id === a.id);
l > -1 && s.splice(l, 1);
}
h.length > 0 && await Promise.race(h);
}
return o;
}
/**
* 执行单个步骤
*/
async executeStep(e, t, r) {
var d, h, a, l;
if (t.currentStep = e.id, this.emitEvent("step.started", { step: e, context: t }), e.condition && !C.evaluate(e.condition, t))
return t.skippedSteps.add(e.id), this.emitEvent("step.skipped", { step: e, context: t, reason: "condition" }), null;
if (t.breakpoints.has(e.id))
return t.isPaused = !0, t.status = "paused", this.emitEvent("step.breakpoint", { step: e, context: t }), null;
const s = m.mapInput(t.initialData, e.inputMapping || {}, t), i = e.input || ((d = this.handlerRegistry.getMetadata(e.handler)) == null ? void 0 : d.inputSchema);
if (i) {
const f = k.validate(s, i);
if (!f.valid) {
const p = `步骤 "${e.id}" 的输入数据验证失败: ${f.errors.join("; ")}`;
throw this.emitEvent("step.validation_failed", {
step: e,
context: t,
errors: f.errors,
inputData: s
}), new Error(p);
}
}
const n = ((h = e.retry) == null ? void 0 : h.maxRetries) || 0, o = ((a = e.retry) == null ? void 0 : a.delay) || 1e3;
let u = null;
for (let f = 0; f <= n; f++)
try {
const p = e.timeout || ((l = r.global) == null ? void 0 : l.timeout) || this.config.defaultTimeout, w = new Promise((H, E) => {
setTimeout(() => E(new Error(`Step timeout: ${e.id}`)), p);
}), x = this.handlerRegistry.executeHandler(e.handler, s, t), b = await Promise.race([
x,
w
]);
return this.emitEvent("step.completed", {
step: e,
context: t,
result: b
}), b;
} catch (p) {
u = p, f < n && (this.emitEvent("step.retry", {
step: e,
context: t,
error: p,
attempt: f + 1,
maxRetries: n
}), await new Promise((w) => setTimeout(w, o)));
}
throw this.emitEvent("step.failed", { step: e, context: t, error: u }), u;
}
/**
* 发送事件
*/
emitEvent(e, t) {
this.eventEmitter.emit(e, { detail: t });
}
/**
* 添加事件监听器
*/
on(e, t) {
this.eventEmitter.on(e, t);
}
/**
* 移除事件监听器
*/
off(e, t) {
this.eventEmitter.off(e, t);
}
/**
* 获取所有可用的处理器元数据
* @returns 所有注册的处理器元数据列表
*/
getAvailableHandlers() {
return this.handlerRegistry.getAllMetadata();
}
/**
* 获取特定处理器的元数据
* @param handlerName 处理器名称
* @returns 处理器元数据,如果不存在返回undefined
*/
getHandlerMetadata(e) {
return this.handlerRegistry.getMetadata(e);
}
/**
* 获取工作流步骤的详细信息(包括输入输出Schema)
* @param workflowDefinition 工作流定义
* @returns 工作流步骤的详细信息
*/
getWorkflowStepsInfo(e) {
return e.steps.map((t) => {
var s;
const r = this.handlerRegistry.getMetadata(t.handler);
return {
id: t.id,
name: t.name,
type: t.type,
handler: t.handler,
inputSchema: t.input || (r == null ? void 0 : r.inputSchema) || { type: "object", properties: {} },
outputSchema: t.output || (r == null ? void 0 : r.outputSchema) || { type: "object", properties: {} },
description: (s = t.metadata) == null ? void 0 : s.description,
handlerMetadata: r
};
});
}
}
class L {
constructor() {
this.workflow = {
id: v(),
name: "",
version: "1.0.0",
description: "",
global: {
timeout: 3e4,
retryPolicy: { maxRetries: 3, delay: 1e3 },
context: {},
variables: {}
},
input: { type: "object", properties: {} },
output: { type: "object", properties: {} },
steps: [],
dependencies: [],
conditions: [],
errorHandlers: [],
metadata: {}
};
}
/**
* 设置基本信息
*/
setBasicInfo(e) {
return this.workflow.name = e.name, e.description && (this.workflow.description = e.description), e.version && (this.workflow.version = e.version), e.id && (this.workflow.id = e.id), this;
}
/**
* 设置全局配置
*/
setGlobalConfig(e) {
return this.workflow.global || (this.workflow.global = {}), e.timeout && (this.workflow.global.timeout = e.timeout), e.retryPolicy && (this.workflow.global.retryPolicy = e.retryPolicy), e.context && (this.workflow.global.context = {
...this.workflow.global.context,
...e.context
}), e.variables && (this.workflow.global.variables = {
...this.workflow.global.variables,
...e.variables
}), this;
}
/**
* 添加步骤
*/
addStep(e) {
this.workflow.steps || (this.workflow.steps = []);
const t = new j(e);
return this.workflow.steps.push(t), this;
}
/**
* 更新步骤
*/
updateStep(e, t) {
if (!this.workflow.steps)
return this;
const r = this.workflow.steps.findIndex((s) => s.id === e);
return r !== -1 && (this.workflow.steps[r] = {
...this.workflow.steps[r],
...t
}), this;
}
/**
* 删除步骤
*/
removeStep(e) {
return this.workflow.steps ? (this.workflow.steps = this.workflow.steps.filter((t) => t.id !== e), this) : this;
}
/**
* 添加依赖关系
*/
addDependency(e, t, r) {
if (!this.workflow.steps)
throw new Error("工作流中没有任何步骤,无法添加依赖");
const s = this.workflow.steps.find((o) => o.id === e), i = this.workflow.steps.find((o) => o.id === t);
if (!s)
throw new Error(`依赖的源步骤不存在: ${e}`);
if (!i)
throw new Error(`依赖的目标步骤不存在: ${t}`);
const n = this.workflow.steps.find((o) => o.id === t);
return n && (n.dependsOn || (n.dependsOn = []), n.dependsOn.includes(e) || n.dependsOn.push(e)), this.workflow.dependencies || (this.workflow.dependencies = []), this.workflow.dependencies.push({
from: e,
to: t,
type: r
}), this;
}
/**
* 移除依赖关系
*/
removeDependency(e, t) {
if (this.workflow.steps) {
const r = this.workflow.steps.find((s) => s.id === t);
r && r.dependsOn && (r.dependsOn = r.dependsOn.filter((s) => s !== e));
}
return this.workflow.dependencies && (this.workflow.dependencies = this.workflow.dependencies.filter((r) => !(r.from === e && r.to === t))), this;
}
/**
* 设置输入Schema
*/
setInputSchema(e) {
return this.workflow.input = e, this;
}
/**
* 设置输出Schema
*/
setOutputSchema(e) {
return this.workflow.output = e, this;
}
/**
* 添加条件规则
*/
addConditionRule(e) {
return this.workflow.conditions || (this.workflow.conditions = []), this.workflow.conditions.push(e), this;
}
/**
* 添加错误处理器
*/
addErrorHandler(e) {
return this.workflow.errorHandlers || (this.workflow.errorHandlers = []), this.workflow.errorHandlers.push(e), this;
}
/**
* 验证工作流
*/
validate() {
const e = [];
if (this.workflow.name || e.push("工作流名称是必需的"), !this.workflow.steps || this.workflow.steps.length === 0)
e.push("至少需要一个步骤");
else {
const t = this.workflow.steps.map((s) => s.id);
if (new Set(t).size !== t.length) {
const s = t.filter((i, n) => t.indexOf(i) !== n);
e.push(`存在重复的步骤ID: ${s.join(", ")}`);
}
for (const s of this.workflow.steps)
if (s.dependsOn)
for (const i of s.dependsOn)
t.includes(i) || e.push(`步骤 ${s.id} 依赖不存在的步骤: ${i}`);
this.hasCyclicDependency() && e.push("检测到循环依赖");
}
return {
valid: e.length === 0,
errors: e
};
}
/**
* 检查循环依赖
*/
hasCyclicDependency() {
if (!this.workflow.steps)
return !1;
const e = /* @__PURE__ */ new Map();
for (const i of this.workflow.steps)
e.set(i.id, i.dependsOn || []);
const t = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set(), s = (i) => {
if (r.has(i))
return !0;
if (t.has(i))
return !1;
t.add(i), r.add(i);
const n = e.get(i) || [];
for (const o of n)
if (s(o))
return !0;
return r.delete(i), !1;
};
for (const i of e.keys())
if (s(i))
return !0;
return !1;
}
/**
* 构建工作流
*/
build() {
const e = this.validate();
if (!e.valid)
throw new Error(`工作流验证失败: ${e.errors.join(", ")}`);
return S.createWorkflow(this.workflow);
}
/**
* 导出为JSON字符串
*/
toJSON() {
return JSON.stringify(this.workflow, null, 2);
}
/**
* 从JSON导入
*/
fromJSON(e) {
let t;
if (typeof e == "string")
try {
t = JSON.parse(e);
} catch (r) {
throw new Error(`无效的JSON字符串: ${r.message}`);
}
else
t = e;
return this.workflow = { ...this.workflow, ...t }, this;
}
}
const B = {
maxConcurrentExecutions: 10,
defaultTimeout: 3e4,
enableBreakpoints: !1,
persistExecution: !1
};
export {
y as BaseNode,
C as ConditionEvaluator,
B as DEFAULT_CONFIG,
m as DataMapper,
T as DelayNode,
g as ExecutionContext,
A as HttpNode,
P as LogNode,
D as NoopNode,
k as SchemaValidator,
j as StepDefinition,
I as StepHandlerRegistry,
O as TypeConvertNode,
N as TypeConverter,
L as WorkflowBuilder,
S as WorkflowDSL,
J as WorkflowEngine,
R as getBuiltinNodes
};
//# sourceMappingURL=flow-engine.es.js.map