UNPKG

@liyown/flow-engine

Version:

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

3 lines (2 loc) 33.4 kB
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const I=require("events"),C=require("uuid");class b{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)||{}},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 x{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=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 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 m{async execute(e,t){return this.handler(e,t)}getMetadata(){return this.metadata}}class E extends m{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 ${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}" 解析为日期`),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 S{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}}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)}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 v extends m{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=$.convert(r,s);if(!o.success&&n)throw new Error(`类型转换失败: ${o.errors.join("; ")}`);let u={valid:!0,errors:[]};if(i&&o.success&&(u=S.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 j 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 N extends m{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 O 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 A(){return[new E,new v,new j,new N,new O]}class T{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=A();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 h{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 D{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:h.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("$")?h.evaluateExpression(e,{context:t.globalContext,variables:Object.fromEntries(t.variables),stepResults:h.mapToObject(t.stepResults)}):e}static safeEval(e,t){const r=e.replace(/\$(\w+\.?\w*)/g,(s,i)=>JSON.stringify(h.getNestedValue(t,i)));try{return new Function("scope",`return Boolean(${r})`)(t)}catch(s){return console.error(`在 safeEval 中执行表达式 "${e}" (清理后为 "${r}") 时出错:`,s),!1}}}class H{constructor(e={}){this.handlerRegistry=new T,this.executionStore=e.executionStore||new Map,this.eventEmitter=e.eventEmitter||new I.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(s,i)=>await t(s,i),r)}async execute(e,t={},r={}){var n;const s="id"in e?e:b.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=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=new Set,n=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 y=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)}y.length>0&&await Promise.race(y)}return o}async executeStep(e,t,r){var d,y,a,l;if(t.currentStep=e.id,this.emitEvent("step.started",{step:e,context:t}),e.condition&&!D.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=h.mapInput(t.initialData,e.inputMapping||{},t),i=e.input||((d=this.handlerRegistry.getMetadata(e.handler))==null?void 0:d.inputSchema);if(i){const f=S.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=((y=e.retry)==null?void 0:y.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((L,R)=>{setTimeout(()=>R(new Error(`Step timeout: ${e.id}`)),p)}),P=this.handlerRegistry.executeHandler(e.handler,s,t),k=await Promise.race([P,w]);return this.emitEvent("step.completed",{step:e,context:t,result:k}),k}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)}getAvailableHandlers(){return this.handlerRegistry.getAllMetadata()}getHandlerMetadata(e){return this.handlerRegistry.getMetadata(e)}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 M{constructor(){this.workflow={id:C.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 x(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}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(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=new Map;for(const i of this.workflow.steps)e.set(i.id,i.dependsOn||[]);const t=new Set,r=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 b.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 V={maxConcurrentExecutions:10,defaultTimeout:3e4,enableBreakpoints:!1,persistExecution:!1};exports.BaseNode=m;exports.ConditionEvaluator=D;exports.DEFAULT_CONFIG=V;exports.DataMapper=h;exports.DelayNode=j;exports.ExecutionContext=g;exports.HttpNode=E;exports.LogNode=N;exports.NoopNode=O;exports.SchemaValidator=S;exports.StepDefinition=x;exports.StepHandlerRegistry=T;exports.TypeConvertNode=v;exports.TypeConverter=$;exports.WorkflowBuilder=M;exports.WorkflowDSL=b;exports.WorkflowEngine=H;exports.getBuiltinNodes=A; //# sourceMappingURL=flow-engine.cjs.js.map