UNPKG

@liyown/flow-engine

Version:

一个基于JavaScript的无状态工作流引擎框架,支持可视化拖拽、DSL定义、断点继续、自动重试等高级功能

3 lines (2 loc) 33.5 kB
(function(l,w){typeof exports=="object"&&typeof module<"u"?w(exports,require("events"),require("uuid")):typeof define=="function"&&define.amd?define(["exports","events","uuid"],w):(l=typeof globalThis<"u"?globalThis:l||self,w(l.FlowEngine={},l.events,l.uuid))})(this,function(l,w,I){"use strict";class S{static createWorkflow(e){var t,r,i,s;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:((i=e.global)==null?void 0:i.context)||{},variables:((s=e.global)==null?void 0:s.variables)||{}},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 ${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 b{constructor(e,t={}){this.workflowId=e,this.executionId=this.generateExecutionId(),this.startTime=Date.now(),this.status="running",this.globalContext={},this.stepResults=new Map,this.variables=new Map,this.initialData=t,this.currentStep=null,this.completedSteps=new Set,this.failedSteps=new Set,this.skippedSteps=new Set,this.errors=[],this.executionHistory=[],this.breakpoints=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 b(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 m{async execute(e,t){return this.handler(e,t)}getMetadata(){return this.metadata}}class v extends m{constructor(){super(...arguments),this.name="http",this.handler=async(e,t)=>{const{url:r,method:i="GET",headers:s={},body:n}=e;try{return await(await fetch(r,{method:i,headers:{"Content-Type":"application/json",...s},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 x{static convert(e,t){const r=[];let i=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 s=Array.isArray(t.type)?t.type.filter(n=>n!=="null")[0]||t.type[0]:t.type;switch(s){case"string":i=this.convertToString(e,r);break;case"number":i=this.convertToNumber(e,r);break;case"integer":i=this.convertToInteger(e,r);break;case"boolean":i=this.convertToBoolean(e,r);break;case"array":i=this.convertToArray(e,t,r);break;case"object":i=this.convertToObject(e,t,r);break;case"date":case"datetime":i=this.convertToDate(e,r);break;default:return r.push(`不支持转换到类型: ${s}`),{success:!1,value:e,errors:r}}return s==="integer"&&typeof e=="number"&&!Number.isInteger(e)&&(r.length=0),r.length>0?{success:!1,value:e,errors:r}:{success:!0,value:i,errors:[]}}catch(s){return r.push(`转换过程中出错: ${s instanceof Error?s.message:String(s)}`),{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 i=Math.trunc(r);return i!==r&&typeof e=="number"&&console.warn(`数字 ${r} 被截断为整数 ${i}`),i}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 i=JSON.parse(e);if(Array.isArray(i))return i}catch{return e.split(",").map(i=>i.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 i=JSON.parse(e);return typeof i=="object"&&i!==null&&!Array.isArray(i)?i:(r.push(`解析的JSON不是对象: ${e}`),{})}catch(i){return r.push(`无法将字符串解析为JSON对象: ${i instanceof Error?i.message:String(i)}`),{}}if(Array.isArray(e))try{const i={};for(let s=0;s<e.length;s+=2)if(s+1<e.length){const n=String(e[s]);i[n]=e[s+1]}return i}catch(i){return r.push(`无法将数组转换为对象: ${i instanceof Error?i.message:String(i)}`),{}}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}" 解析为日期`),new Date):r}if(typeof e=="number"){const r=new Date(e);return isNaN(r.getTime())?(t.push(`无法将数字 ${e} 转换为日期`),new Date):r}return t.push(`无法将类型 ${typeof e} 转换为日期`),new Date}}class k{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(i){r.push(`验证过程中出错: ${i instanceof Error?i.message:String(i)}`)}return{valid:r.length===0,errors:r}}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(i=>this.matchType(r,i)):this.matchType(r,t)}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 i=0;i<Math.min(e.length,t.items.length);i++){const s=t.items[i],n=this.validate(e[i],s);n.valid||r.push(`数组索引 ${i} 验证失败: ${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 i=t.items.length;i<e.length;i++){const s=this.validate(e[i],t.additionalItems);s.valid||r.push(`额外数组项索引 ${i} 验证失败: ${s.errors.join(", ")}`)}}else for(let i=0;i<e.length;i++){const s=this.validate(e[i],t.items);s.valid||r.push(`数组索引 ${i} 验证失败: ${s.errors.join(", ")}`)}}static validateObject(e,t,r){const i=Object.keys(e);if(t.required)for(const s of t.required)s in e||r.push(`缺少必需属性: ${s}`);if(t.minProperties!==void 0&&i.length<t.minProperties&&r.push(`对象属性数量 ${i.length} 小于最小数量 ${t.minProperties}`),t.maxProperties!==void 0&&i.length>t.maxProperties&&r.push(`对象属性数量 ${i.length} 大于最大数量 ${t.maxProperties}`),t.properties){for(const[s,n]of Object.entries(t.properties))if(s in e){const o=this.validate(e[s],n);o.valid||r.push(`属性 "${s}" 验证失败: ${o.errors.join(", ")}`)}}if(t.additionalProperties===!1){const s=t.properties?Object.keys(t.properties):[],n=i.filter(o=>!s.includes(o));n.length>0&&r.push(`对象包含额外属性: ${n.join(", ")}`)}else if(typeof t.additionalProperties=="object"){const s=t.properties?Object.keys(t.properties):[],n=i.filter(o=>!s.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 s=new Date(e);if(!isNaN(s.getTime()))return}catch{}if(typeof e!="string"||isNaN(Date.parse(String(e)))){r.push(`值 ${e} 不是有效的日期`);return}const i=new Date(String(e));if(t.minimum!==void 0){const s=new Date(t.minimum);i<s&&r.push(`日期早于最小日期 ${s.toISOString()}`)}if(t.maximum!==void 0){const s=new Date(t.maximum);i>s&&r.push(`日期晚于最大日期 ${s.toISOString()}`)}}}class j extends m{constructor(){super(...arguments),this.name="typeConvert",this.handler=async(e,t)=>{const{value:r,targetSchema:i,validateAfterConversion:s=!0,throwOnError:n=!1}=e;if(!i)throw new Error("缺少必需参数: targetSchema");const o=x.convert(r,i);if(!o.success&&n)throw new Error(`类型转换失败: ${o.errors.join("; ")}`);let u={valid:!0,errors:[]};if(s&&o.success&&(u=k.validate(o.value,i),!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 N extends m{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 O extends m{constructor(){super(...arguments),this.name="log",this.handler=async e=>{const{message:t,level:r="info",data:i}=e;switch(r){case"error":console.error(t,i);break;case"warn":console.warn(t,i);break;case"debug":console.debug(t,i);break;case"info":default:console.info(t,i)}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 A extends m{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 T(){return[new v,new j,new N,new O,new A]}class D{constructor(){this.handlers=new Map,this.metadata=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=T();for(const t of e)this.register(t.name,async(r,i)=>await t.execute(r,i),t.metadata)}async executeHandler(e,t,r){const i=this.get(e);if(!i)throw new Error(`Handler not found: ${e}`);return await i(t,r)}}class y{static mapInput(e,t,r){if(!t||Object.keys(t).length===0)return e;const i={};for(const[s,n]of Object.entries(t))i[s]=this.evaluateExpression(n,{input:e,context:r.globalContext,variables:Object.fromEntries(r.variables),stepResults:this.mapToObject(r.stepResults)});return i}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),i=this.getNestedValue(t,r);return i===void 0&&console.warn(`在作用域中未找到路径: ${e}`),i}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,i)=>{const s=this.getNestedValue(t,i.trim());return s!==void 0?String(s):r})}static evaluateFunction(e,t,r){var s;const i=t.map(n=>this.evaluateExpression(n,r));switch(e){case"now":return Date.now();case"uuid":return this.generateUUID();case"length":return i[0]===void 0||i[0]===null?0:typeof i[0]!="string"&&!Array.isArray(i[0])?(console.warn(`函数 "length" 的参数必须是字符串或数组,但收到: ${typeof i[0]}`),0):((s=i[0])==null?void 0:s.length)||0;case"upper":return typeof i[0]!="string"?(console.warn(`函数 "upper" 的参数必须是字符串,但收到: ${typeof i[0]}`),String(i[0])):String(i[0]).toUpperCase();case"lower":return typeof i[0]!="string"?(console.warn(`函数 "lower" 的参数必须是字符串,但收到: ${typeof i[0]}`),String(i[0])):String(i[0]).toLowerCase();case"sum":return Array.isArray(i[0])?i[0].reduce((n,o)=>{const u=Number(o);return isNaN(u)?(console.warn(`函数 "sum" 在累加时遇到非数字值: ${o}`),n):n+u},0):i.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((i,s)=>{if(!(i==null||typeof i!="object"))return i[s]},e);return r!==void 0&&console.log(`DataMapper: 获取路径 ${t} 的值 ${r},类型为 ${typeof r}`),r}static mapToObject(e){const t={};for(const[r,i]of e.entries())t[r]=i;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 P{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:y.mapToObject(t.stepResults)};try{return this.safeEval(e,r)}catch(i){return console.warn("Condition evaluation failed:",i),!1}}static evaluateConditionObject(e,t){const{operator:r,left:i,right:s,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(i,t)===this.getValue(s,t);case"ne":return this.getValue(i,t)!==this.getValue(s,t);case"gt":return this.getValue(i,t)>this.getValue(s,t);case"gte":return this.getValue(i,t)>=this.getValue(s,t);case"lt":return this.getValue(i,t)<this.getValue(s,t);case"lte":return this.getValue(i,t)<=this.getValue(s,t);case"contains":return String(this.getValue(i,t)).includes(String(this.getValue(s,t)));case"in":{const o=this.getValue(s,t);return Array.isArray(o)&&o.includes(this.getValue(i,t))}default:return console.warn(`未知的条件操作符: ${r}`),!1}}static getValue(e,t){return typeof e=="string"&&e.startsWith("$")?y.evaluateExpression(e,{context:t.globalContext,variables:Object.fromEntries(t.variables),stepResults:y.mapToObject(t.stepResults)}):e}static safeEval(e,t){const r=e.replace(/\$(\w+\.?\w*)/g,(i,s)=>JSON.stringify(y.getNestedValue(t,s)));try{return new Function("scope",`return Boolean(${r})`)(t)}catch(i){return console.error(`在 safeEval 中执行表达式 "${e}" (清理后为 "${r}") 时出错:`,i),!1}}}class C{constructor(e={}){this.handlerRegistry=new D,this.executionStore=e.executionStore||new Map,this.eventEmitter=e.eventEmitter||new w.EventEmitter,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(i,s)=>await t(i,s),r)}async execute(e,t={},r={}){var n;const i="id"in e?e:S.createWorkflow(e),s=new b(i.id,t);Object.assign(s.globalContext,((n=i.global)==null?void 0:n.context)||{}),r.breakpoints&&r.breakpoints.forEach(o=>s.breakpoints.add(o)),this.executionStore.set(s.executionId,s);try{this.emitEvent("workflow.started",{context:s,workflow:i});const o=this.buildDependencyGraph(i.steps);console.log("依赖图构建完成",{graph:o});const u=await this.executeWorkflow(i,s,o);return console.log("工作流执行完成",{result:u}),s.status="completed",s.endTime=Date.now(),this.emitEvent("workflow.completed",{context:s,workflow:i,result:u}),{executionId:s.executionId,status:s.status,result:u,context:s.serialize()}}catch(o){throw s.status="failed",s.endTime=Date.now(),s.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:s,workflow:i,error:o}),console.error(`工作流 ${s.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=new Map;for(const r of e)t.set(r.id,{step:r,dependencies:r.dependsOn||[],dependents:[]});for(const[r,i]of t.entries())for(const s of i.dependencies){const n=t.get(s);n&&n.dependents.push(r)}return t}async executeWorkflow(e,t,r){const i=[],s=new Set,n=new Set,o={},u=Array.from(r.values()).filter(f=>f.dependencies.length===0).map(f=>f.step);console.log("入口步骤",{entrySteps:u});for(const f of u)i.push(f);for(;i.length>0||s.size>0;){if(t.isPaused){console.log("工作流暂停",{context:t});break}const f=i.filter(a=>!s.has(a.id)&&(a.dependsOn||[]).every(c=>n.has(c)));if(f.length===0&&s.size===0&&i.length===0){console.log("所有步骤执行完毕或没有可执行的步骤,退出循环");break}if(f.length===0&&s.size>0){await new Promise(a=>setTimeout(a,50));continue}f.length===0&&i.length>0&&s.size===0&&console.warn("执行队列中没有就绪的步骤,但队列不为空且无正在执行的步骤。可能存在依赖问题。",{executionQueue:i.map(a=>a.id),executing:Array.from(s),completed:Array.from(n)});const g=f.map(async a=>{s.add(a.id);try{const c=await this.executeStep(a,t,e);o[a.id]=c,t.setStepResult(a.id,c),t.completedSteps.add(a.id),n.add(a.id);const h=Array.from(r.values()).filter(p=>p.dependencies.includes(a.id)).map(p=>p.step).filter(p=>!i.includes(p)&&!s.has(p.id)&&!n.has(p.id));i.push(...h)}catch(c){if(t.failedSteps.add(a.id),t.errors.push({stepId:a.id,message:c instanceof Error?c.message:String(c),stack:c instanceof Error?c.stack:void 0,timestamp:Date.now()}),a.onError==="throw")throw c;if(a.onError==="continue"){console.warn(`步骤 ${a.id} 执行失败,但错误处理策略为 'continue'。错误:`,c instanceof Error?c.message:String(c)),t.setStepResult(a.id,{error:c instanceof Error?c.message:String(c),continued:!0}),n.add(a.id);const h=Array.from(r.values()).filter(p=>p.dependencies.includes(a.id)).map(p=>p.step).filter(p=>!i.includes(p)&&!s.has(p.id)&&!n.has(p.id));i.push(...h)}else if(a.onError==="retry")throw c}finally{s.delete(a.id)}});for(const a of f){const c=i.findIndex(h=>h.id===a.id);c>-1&&i.splice(c,1)}g.length>0&&await Promise.race(g)}return o}async executeStep(e,t,r){var f,g,a,c;if(t.currentStep=e.id,this.emitEvent("step.started",{step:e,context:t}),e.condition&&!P.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 i=y.mapInput(t.initialData,e.inputMapping||{},t),s=e.input||((f=this.handlerRegistry.getMetadata(e.handler))==null?void 0:f.inputSchema);if(s){const h=k.validate(i,s);if(!h.valid){const p=`步骤 "${e.id}" 的输入数据验证失败: ${h.errors.join("; ")}`;throw this.emitEvent("step.validation_failed",{step:e,context:t,errors:h.errors,inputData:i}),new Error(p)}}const n=((g=e.retry)==null?void 0:g.maxRetries)||0,o=((a=e.retry)==null?void 0:a.delay)||1e3;let u=null;for(let h=0;h<=n;h++)try{const p=e.timeout||((c=r.global)==null?void 0:c.timeout)||this.config.defaultTimeout,E=new Promise((B,L)=>{setTimeout(()=>L(new Error(`Step timeout: ${e.id}`)),p)}),V=this.handlerRegistry.executeHandler(e.handler,i,t),R=await Promise.race([V,E]);return this.emitEvent("step.completed",{step:e,context:t,result:R}),R}catch(p){u=p,h<n&&(this.emitEvent("step.retry",{step:e,context:t,error:p,attempt:h+1,maxRetries:n}),await new Promise(E=>setTimeout(E,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)}getAvailableHandlers(){return this.handlerRegistry.getAllMetadata()}getHandlerMetadata(e){return this.handlerRegistry.getMetadata(e)}getWorkflowStepsInfo(e){return e.steps.map(t=>{var i;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:(i=t.metadata)==null?void 0:i.description,handlerMetadata:r}})}}class H{constructor(){this.workflow={id:I.v4(),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 $(e);return this.workflow.steps.push(t),this}updateStep(e,t){if(!this.workflow.steps)return this;const r=this.workflow.steps.findIndex(i=>i.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 i=this.workflow.steps.find(o=>o.id===e),s=this.workflow.steps.find(o=>o.id===t);if(!i)throw new Error(`依赖的源步骤不存在: ${e}`);if(!s)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(i=>i.id===t);r&&r.dependsOn&&(r.dependsOn=r.dependsOn.filter(i=>i!==e))}return this.workflow.dependencies&&(this.workflow.dependencies=this.workflow.dependencies.filter(r=>!(r.from===e&&r.to===t))),this}setInputSchema(e){return this.workflow.input=e,this}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(i=>i.id);if(new Set(t).size!==t.length){const i=t.filter((s,n)=>t.indexOf(s)!==n);e.push(`存在重复的步骤ID: ${i.join(", ")}`)}for(const i of this.workflow.steps)if(i.dependsOn)for(const s of i.dependsOn)t.includes(s)||e.push(`步骤 ${i.id} 依赖不存在的步骤: ${s}`);this.hasCyclicDependency()&&e.push("检测到循环依赖")}return{valid:e.length===0,errors:e}}hasCyclicDependency(){if(!this.workflow.steps)return!1;const e=new Map;for(const s of this.workflow.steps)e.set(s.id,s.dependsOn||[]);const t=new Set,r=new Set,i=s=>{if(r.has(s))return!0;if(t.has(s))return!1;t.add(s),r.add(s);const n=e.get(s)||[];for(const o of n)if(i(o))return!0;return r.delete(s),!1};for(const s of e.keys())if(i(s))return!0;return!1}build(){const e=this.validate();if(!e.valid)throw new Error(`工作流验证失败: ${e.errors.join(", ")}`);return S.createWorkflow(this.workflow)}toJSON(){return JSON.stringify(this.workflow,null,2)}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 M={maxConcurrentExecutions:10,defaultTimeout:3e4,enableBreakpoints:!1,persistExecution:!1};l.BaseNode=m,l.ConditionEvaluator=P,l.DEFAULT_CONFIG=M,l.DataMapper=y,l.DelayNode=N,l.ExecutionContext=b,l.HttpNode=v,l.LogNode=O,l.NoopNode=A,l.SchemaValidator=k,l.StepDefinition=$,l.StepHandlerRegistry=D,l.TypeConvertNode=j,l.TypeConverter=x,l.WorkflowBuilder=H,l.WorkflowDSL=S,l.WorkflowEngine=C,l.getBuiltinNodes=T,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})}); //# sourceMappingURL=flow-engine.umd.js.map