next-workflow-builder 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/chunk-QMJQ5NK5.js +42 -0
- package/dist/client/index.js +16 -16
- package/dist/handler-YTQRRHEK.js +1 -0
- package/dist/server/api/index.js +10 -10
- package/dist/styles.css +3 -0
- package/package.json +1 -1
- package/dist/chunk-HB2H2PVI.js +0 -42
- package/dist/handler-NWAMWKXW.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# next-workflow-builder
|
|
2
2
|
|
|
3
|
+
## 0.7.1
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- Add cancel execution support — stop a running workflow from the UI "Runs" tab, via API (`POST /workflows/executions/[executionId]/cancel`), or MCP `cancel_execution` tool
|
|
8
|
+
- Cooperative cancellation in workflow executor — checks DB status before each node execution, skips remaining steps if cancelled
|
|
9
|
+
|
|
10
|
+
### Improvements
|
|
11
|
+
|
|
12
|
+
- Migrate MCP server tools from deprecated `server.tool()` to `server.registerTool()` API
|
|
13
|
+
|
|
3
14
|
## 0.7.0
|
|
4
15
|
|
|
5
16
|
### Features
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import{j as q,m as L}from"./chunk-DMHGXYVW.js";import{a as Z,b as J}from"./chunk-IEOZJAW2.js";import{b as $}from"./chunk-6UXAINJQ.js";import{l as M,m as z}from"./chunk-BNX2SV7E.js";import{r as V,t as U}from"./chunk-QRG4O4PE.js";import{k as P,o as j,p as B,q as H}from"./chunk-5J6TNMJG.js";async function fe(e){let r=Z();if(r.getUser)return r.getUser(e);let o=await J.api.getSession({headers:e.headers});return o?.user?{id:o.user.id,email:o.user.email??void 0,name:o.user.name??void 0}:null}import{eq as re}from"drizzle-orm";import{readdir as ne,readFile as se}from"fs/promises";import{join as ie}from"path";import{eq as K}from"drizzle-orm";import"server-only";function Y(e){return{success:!0,data:e.triggerData}}async function O(e){"use step";return e._workflowComplete?(await B(e._workflowComplete),{success:!0,data:{}}):H(e,()=>Promise.resolve(Y(e)))}O.maxRetries=0;var D={"Database Query":{importer:()=>import("./database-query-OHFQUPLV.js"),stepFunction:"databaseQueryStep"},"HTTP Request":{importer:()=>import("./http-request-EHJHOTNA.js"),stepFunction:"httpRequestStep"},Condition:{importer:()=>import("./condition-CFAA7UDI.js"),stepFunction:"conditionStep"},Loop:{importer:()=>import("./loop-5LPVY452.js"),stepFunction:"loopStep"},Switch:{importer:()=>import("./switch-ZPVREROE.js"),stepFunction:"switchStep"},Merge:{importer:()=>import("./merge-HYBHX22D.js"),stepFunction:"mergeStep"}};function G(e,r){if(e===void 0||e==="")return;let o=/\{\{@([^:]+):([^}]+)\}\}/g,n=[...e.matchAll(o)];if(n.length===0)return e;function s(i,a){let u=i.replace(/[^a-zA-Z0-9]/g,"_"),d=r[u];if(!d)return;let w=a.indexOf(".");if(w===-1)return d.data;if(d.data===null||d.data===void 0)return;let x=a.substring(w+1).split("."),f=d.data,b=x[0];f&&typeof f=="object"&&"success"in f&&"data"in f&&b!=="success"&&b!=="data"&&b!=="error"&&!(b in f)&&(f=f.data);for(let W of x)if(f&&typeof f=="object")f=f[W];else return;return f}return n.length===1&&n[0][0]===e?s(n[0][1],n[0][2]):e.replace(o,(i,a,u)=>{let d=s(a,u);return d==null?"":typeof d=="object"?JSON.stringify(d):String(d)})}function ee(e,r){let o=e.dataType||"string",n=e.operator,s=e.leftValue,i=e.rightValue,a=G(s,r),u=G(i,r);return console.log("[Condition] Evaluating:",{dataType:o,operator:n,leftResolved:a,rightResolved:u}),{result:L(o,n,a,u),resolvedValues:{leftValue:a,rightValue:u}}}async function te(e){let{actionType:r,config:o,outputs:n,context:s}=e,i={...o,_context:s};if(r==="Condition"){let w=D.Condition,k=await w.importer(),{result:x,resolvedValues:f}=ee(o,n);return console.log("[Condition] Final result:",x),await k[w.stepFunction]({condition:x,dataType:o.dataType,operator:o.operator,leftValue:f.leftValue,rightValue:f.rightValue,_context:s})}let a=D[r];if(a){let k=(await a.importer())[a.stepFunction];return await k(i)}let{getStepImporter:u}=await import("virtual:workflow-builder-step-registry"),d=u(r);if(d){let k=(await d.importer())[d.stepFunction];return k?await k(i):{success:!1,error:`Step function "${d.stepFunction}" not found in module for action "${r}". Check that the plugin exports the correct function name.`}}return{success:!1,error:`Unknown action type: "${r}". This action is not registered in the plugin system. Available system actions: ${Object.keys(D).join(", ")}.`}}function oe(e,r){let o={};for(let[n,s]of Object.entries(e))if(typeof s=="string"){let i=s,a=/\{\{@([^:]+):([^}]+)\}\}/g;i=i.replace(a,(u,d,w)=>{let k=d.replace(/[^a-zA-Z0-9]/g,"_"),x=r[k];if(!x)return u;let f=w.indexOf(".");if(f===-1){let t=x.data;return t==null?"":typeof t=="object"?JSON.stringify(t):String(t)}if(x.data===null||x.data===void 0)return"";let W=w.substring(f+1).split("."),p=x.data,R=W[0];p&&typeof p=="object"&&"success"in p&&"data"in p&&R!=="success"&&R!=="data"&&R!=="error"&&!(R in p)&&(p=p.data);for(let t of W)if(p&&typeof p=="object")p=p[t];else return"";return p==null?"":typeof p=="object"?JSON.stringify(p):String(p)}),o[n]=i}else o[n]=s;return o}async function Q(e){"use workflow";console.log("[Workflow Executor] Starting workflow execution");let{nodes:r,edges:o,triggerInput:n={},executionId:s,workflowId:i}=e;console.log("[Workflow Executor] Input:",{nodeCount:r.length,edgeCount:o.length,hasExecutionId:!!s,workflowId:i||"none"});let a={},u={},d=new Map(r.map(t=>[t.id,t])),w=new Map,k=new Map;for(let t of o){let g=w.get(t.source)||[];g.push(t.target),w.set(t.source,g);let c=k.get(t.target)||[];c.push(t.source),k.set(t.target,c)}let x=new Set(o.map(t=>t.target)),f=r.filter(t=>t.data.type==="trigger"&&!x.has(t.id));console.log("[Workflow Executor] Found",f.length,"trigger nodes");let{getActionLabel:b}=await import("virtual:workflow-builder-step-registry");function W(t){if(t.data.label)return t.data.label;if(t.data.type==="action"){let g=t.data.config?.actionType;if(g){let c=b(g);if(c)return c}return"Action"}return t.data.type==="trigger"?t.data.config?.triggerType||"Trigger":t.data.type}async function p(){return s?(await j.query.workflowExecutions.findFirst({where:K(P.id,s),columns:{status:!0}}))?.status==="cancelled":!1}async function R(t,g=new Set){if(console.log("[Workflow Executor] Executing node:",t),await p()){console.log("[Workflow Executor] Execution cancelled, stopping");return}if(g.has(t)){console.log("[Workflow Executor] Node already visited, skipping");return}g.add(t);let c=d.get(t);if(!c){console.log("[Workflow Executor] Node not found:",t);return}if(c.data.enabled===!1){console.log("[Workflow Executor] Skipping disabled node:",t);let l=t.replace(/[^a-zA-Z0-9]/g,"_");a[l]={label:c.data.label||t,data:null};let v=w.get(t)||[];await Promise.all(v.map(h=>R(h,g)));return}try{let l;if(c.data.type==="trigger"){console.log("[Workflow Executor] Executing trigger node");let h=c.data.config||{},m=h.triggerType,y={triggered:!0,timestamp:Date.now()};if(m==="Webhook"&&h.webhookMockRequest&&(!n||Object.keys(n).length===0))try{let S=JSON.parse(h.webhookMockRequest);y={...y,...S},console.log("[Workflow Executor] Using webhook mock request data:",S)}catch(S){console.error("[Workflow Executor] Failed to parse webhook mock request:",S)}else n&&Object.keys(n).length>0&&(y={...y,...n});let C={executionId:s,nodeId:c.id,nodeName:W(c),nodeType:c.data.type},T=await O({triggerData:y,_context:C});l={success:T.success,data:T.data}}else if(c.data.type==="action"){let h=c.data.config||{},m=h.actionType;if(console.log("[Workflow Executor] Executing action node:",m),!m){l={success:!1,error:`Action node "${c.data.label||c.id}" has no action type configured`},u[t]=l;return}let y=oe(h,a),C={executionId:s,nodeId:c.id,nodeName:W(c),nodeType:m},T={},S=k.get(t)||[];for(let A of S){let F=A.replace(/[^a-zA-Z0-9]/g,"_"),I=a[F];if(I?.data&&typeof I.data=="object"){let N=I.data;"success"in N&&"data"in N&&N.data&&typeof N.data=="object"&&(N=N.data);for(let[_,X]of Object.entries(N))_!=="success"&&_!=="error"&&(T[_]=X)}}console.log("[Workflow Executor] Calling executeActionStep");let E=await te({actionType:m,config:{...T,...y},outputs:a,context:C});if(console.log("[Workflow Executor] Step result received:",{hasResult:!!E,resultType:typeof E}),E&&typeof E=="object"&&"success"in E&&E.success===!1){let A=E,F=typeof A.error=="string"?A.error:A.error?.message||`Step "${m}" in node "${c.data.label||c.id}" failed without a specific error message.`;console.error(`[Workflow Executor] Step "${m}" failed:`,F),l={success:!1,error:F}}else l={success:!0,data:E}}else console.log("[Workflow Executor] Unknown node type:",c.data.type),l={success:!1,error:`Unknown node type "${c.data.type}" in node "${c.data.label||c.id}". Expected "trigger" or "action".`};u[t]=l;let v=t.replace(/[^a-zA-Z0-9]/g,"_");if(a[v]={label:c.data.label||t,data:l.data},console.log("[Workflow Executor] Node execution completed:",{nodeId:t,success:l.success}),l.success)if(c.data.type==="action"&&c.data.config?.actionType==="Condition"){let m=l.data?.condition;if(console.log("[Workflow Executor] Condition node result:",m),m===!0){let y=w.get(t)||[];console.log("[Workflow Executor] Condition is true, executing",y.length,"next nodes in parallel"),await Promise.all(y.map(C=>R(C,g)))}else console.log("[Workflow Executor] Condition is false, skipping next nodes")}else{let m=w.get(t)||[];console.log("[Workflow Executor] Executing",m.length,"next nodes in parallel"),await Promise.all(m.map(y=>R(y,g)))}}catch(l){console.error("[Workflow Executor] Error executing node:",t,l);let h={success:!1,error:await $(l)};u[t]=h}}try{console.log("[Workflow Executor] Starting execution from trigger nodes");let t=Date.now();await Promise.all(f.map(l=>R(l.id)));let g=Object.values(u).every(l=>l.success),c=Date.now()-t;if(console.log("[Workflow Executor] Workflow execution completed:",{success:g,resultCount:Object.keys(u).length,duration:c}),s&&!await p())try{await O({triggerData:{},_workflowComplete:{executionId:s,status:g?"success":"error",output:Object.values(u).at(-1)?.data,error:Object.values(u).find(l=>!l.success)?.error,startTime:t}}),console.log("[Workflow Executor] Updated execution record")}catch(l){console.error("[Workflow Executor] Failed to update execution record:",l)}return{success:g,results:u,outputs:a}}catch(t){console.error("[Workflow Executor] Fatal error during workflow execution:",t);let g=await $(t);if(s)try{await O({triggerData:{},_workflowComplete:{executionId:s,status:"error",error:g,startTime:Date.now()}})}catch(c){console.error("[Workflow Executor] Failed to log error:",c)}return{success:!1,results:u,outputs:a,error:g}}}var Fe={"Access-Control-Allow-Origin":"*","Access-Control-Allow-Methods":"POST, OPTIONS","Access-Control-Allow-Headers":"Content-Type, Authorization"};function je(e){let o=new URL(e.url).pathname,n="/api/workflow-builder/",s=o.indexOf(n);if(s===-1){let a=o.indexOf("/api/");return a===-1?[]:o.slice(a+5).split("/").filter(Boolean)}return o.slice(s+n.length).split("/").filter(Boolean)}function Ie(e,r){return new Request(r,{method:e.method,headers:e.headers,body:e.body,duplex:"half"})}async function _e(e,r,o,n,s){try{await Q({nodes:o,edges:n,triggerInput:s,executionId:e,workflowId:r})}catch(i){console.error("[Workflow Execute] Error during execution:",i),await j.update(P).set({status:"error",error:i instanceof Error?i.message:"Unknown error",completedAt:new Date}).where(re(P.id,e))}}function $e(e){let r={updatedAt:new Date};return e.name!==void 0&&(r.name=e.name),e.description!==void 0&&(r.description=e.description),e.nodes!==void 0&&(r.nodes=e.nodes),e.edges!==void 0&&(r.edges=e.edges),e.visibility!==void 0&&(r.visibility=e.visibility),r}function De(e){return e.map(r=>{let o={...r};if(o.data&&typeof o.data=="object"&&o.data!==null){let n={...o.data};if(n.config&&typeof n.config=="object"&&n.config!==null){let{integrationId:s,...i}=n.config;n.config=i}o.data=n}return o})}async function ae(e,r=e){let o={},n=await ne(e,{withFileTypes:!0});for(let s of n){let i=ie(e,s.name);if(s.isDirectory()){let a=await ae(i,r);Object.assign(o,a)}else if(s.isFile()){let a=await se(i,"utf-8"),u=i.substring(r.length+1);o[u]=a}}return o}function Ve(e){let r={},n=`${e.name.replace(M,"").split(z).map((a,u)=>u===0?a.toLowerCase():a.charAt(0).toUpperCase()+a.slice(1).toLowerCase()).join("")||"execute"}Workflow`,s=q(e.name,e.nodes,e.edges,{functionName:n}),i=ce(e.name);return r[`workflows/${i}.ts`]=s,r[`app/api/workflows/${i}/route.ts`]=`import { start } from 'workflow/api';
|
|
2
|
+
import { ${n} } from '@/workflows/${i}';
|
|
3
|
+
import { NextResponse } from 'next/server';
|
|
4
|
+
|
|
5
|
+
export async function POST(request: Request) {
|
|
6
|
+
try {
|
|
7
|
+
const body = await request.json();
|
|
8
|
+
|
|
9
|
+
// Start the workflow execution
|
|
10
|
+
await start(${n}, [body]);
|
|
11
|
+
|
|
12
|
+
return NextResponse.json({
|
|
13
|
+
success: true,
|
|
14
|
+
message: 'Workflow started successfully',
|
|
15
|
+
});
|
|
16
|
+
} catch (error) {
|
|
17
|
+
return NextResponse.json(
|
|
18
|
+
{
|
|
19
|
+
success: false,
|
|
20
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
21
|
+
},
|
|
22
|
+
{ status: 500 }
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
`,r["app/page.tsx"]=`export default function Home() {
|
|
27
|
+
return (
|
|
28
|
+
<main className="p-8">
|
|
29
|
+
<h1 className="text-2xl font-bold mb-4">Workflow: ${e.name}</h1>
|
|
30
|
+
<p className="mb-4 text-gray-600">API endpoint:</p>
|
|
31
|
+
<ul className="list-disc pl-6 space-y-2">
|
|
32
|
+
<li>
|
|
33
|
+
<a href="/api/workflows/${i}" className="text-blue-600 hover:underline">
|
|
34
|
+
/api/workflows/${i}
|
|
35
|
+
</a>
|
|
36
|
+
</li>
|
|
37
|
+
</ul>
|
|
38
|
+
</main>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
`,r}function Ue(e){let r=e.filter(o=>o.data.type==="action").map(o=>o.data.config?.actionType).filter(Boolean);return V(r)}function qe(){let e=["# Add your environment variables here"];e.push(""),e.push("# For database integrations"),e.push("DATABASE_URL=your_database_url");let r=U(),o={};for(let n of r){let s=n.name.split("_")[0];o[s]||(o[s]=[]),o[s].push(n)}for(let[n,s]of Object.entries(o)){e.push(`# For ${n.charAt(0)+n.slice(1).toLowerCase()} integration`);for(let i of s)e.push(`${i.name}=your_${i.name.toLowerCase()}`);e.push("")}return e.join(`
|
|
42
|
+
`)}function ce(e){return e.toLowerCase().replace(/[^a-z0-9]/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")}export{fe as a,Fe as b,je as c,Ie as d,_e as e,$e as f,De as g,ae as h,Ve as i,Ue as j,qe as k,ce as l};
|