next-workflow-builder 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1162 @@
1
+ import {
2
+ findActionById,
3
+ flattenConfigFields
4
+ } from "./chunk-Z3BJJYHM.js";
5
+
6
+ // src/client/lib/workflow-codegen-shared.ts
7
+ var TEMPLATE_PATTERN = /\{\{([^}]+)\}\}/g;
8
+ var WHITESPACE_PATTERN = /\s+/;
9
+ var NON_ALPHANUMERIC_PATTERN = /[^a-zA-Z0-9]/g;
10
+ var ARRAY_INDEX_PATTERN = /^([^[]+)\[(\d+)\]$/;
11
+ var VALID_IDENTIFIER_PATTERN = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
12
+ var NUMBER_START_PATTERN = /^[0-9]/;
13
+ function findNodeReferences(template) {
14
+ const refs = /* @__PURE__ */ new Set();
15
+ if (!template || typeof template !== "string") {
16
+ return refs;
17
+ }
18
+ let match;
19
+ while ((match = TEMPLATE_PATTERN.exec(template)) !== null) {
20
+ const expression = match[1].trim();
21
+ if (expression.startsWith("@")) {
22
+ const withoutAt = expression.substring(1);
23
+ const colonIndex = withoutAt.indexOf(":");
24
+ if (colonIndex !== -1) {
25
+ const nodeId = withoutAt.substring(0, colonIndex);
26
+ refs.add(nodeId);
27
+ }
28
+ } else if (expression.startsWith("$")) {
29
+ const withoutDollar = expression.substring(1);
30
+ const parts = withoutDollar.split(".");
31
+ if (parts.length > 0) {
32
+ refs.add(parts[0]);
33
+ }
34
+ }
35
+ }
36
+ return refs;
37
+ }
38
+ function extractRefsFromConfigValue(value) {
39
+ const refs = /* @__PURE__ */ new Set();
40
+ if (typeof value === "string") {
41
+ const foundRefs = findNodeReferences(value);
42
+ for (const ref of foundRefs) {
43
+ refs.add(ref);
44
+ }
45
+ }
46
+ return refs;
47
+ }
48
+ function analyzeNodeUsage(nodes) {
49
+ const usedNodes = /* @__PURE__ */ new Set();
50
+ for (const node of nodes) {
51
+ if (node.data.type !== "action") {
52
+ continue;
53
+ }
54
+ const config = node.data.config || {};
55
+ for (const value of Object.values(config)) {
56
+ const refs = extractRefsFromConfigValue(value);
57
+ for (const ref of refs) {
58
+ usedNodes.add(ref);
59
+ }
60
+ }
61
+ }
62
+ return usedNodes;
63
+ }
64
+ function buildEdgeMap(edges) {
65
+ const edgesBySource = /* @__PURE__ */ new Map();
66
+ for (const edge of edges) {
67
+ const targets = edgesBySource.get(edge.source) || [];
68
+ targets.push(edge.target);
69
+ edgesBySource.set(edge.source, targets);
70
+ }
71
+ return edgesBySource;
72
+ }
73
+ function findTriggerNodes(nodes, edges) {
74
+ const nodesWithIncoming = new Set(edges.map((e) => e.target));
75
+ return nodes.filter(
76
+ (node) => node.data.type === "trigger" && !nodesWithIncoming.has(node.id)
77
+ );
78
+ }
79
+ function buildAccessPath(fieldPath) {
80
+ return fieldPath.split(".").map((part) => {
81
+ const arrayMatch = ARRAY_INDEX_PATTERN.exec(part);
82
+ if (arrayMatch) {
83
+ return `.${arrayMatch[1]}[${arrayMatch[2]}]`;
84
+ }
85
+ return `.${part}`;
86
+ }).join("");
87
+ }
88
+ function toFriendlyVarName(label, actionType) {
89
+ const baseName = label || actionType || "result";
90
+ const camelCase = baseName.split(WHITESPACE_PATTERN).map((word, index) => {
91
+ const cleaned = word.replace(NON_ALPHANUMERIC_PATTERN, "");
92
+ if (!cleaned) {
93
+ return "";
94
+ }
95
+ if (index === 0) {
96
+ return cleaned.toLowerCase();
97
+ }
98
+ return cleaned.charAt(0).toUpperCase() + cleaned.slice(1).toLowerCase();
99
+ }).filter((word) => word.length > 0).join("");
100
+ return `${camelCase}Result`;
101
+ }
102
+ function removeInvisibleChars(str) {
103
+ return str.replace(/\u00a0/g, " ").replace(/[\u2000-\u200B\u2028\u2029]/g, " ");
104
+ }
105
+ function escapeForTemplateLiteral(str) {
106
+ if (!str) {
107
+ return "";
108
+ }
109
+ return str.replace(/\\/g, "\\\\").replace(/`/g, "\\`");
110
+ }
111
+ function sanitizeFunctionName(name) {
112
+ return name.replace(/[^a-zA-Z0-9]/g, "_").replace(NUMBER_START_PATTERN, "_$&").replace(/_+/g, "_");
113
+ }
114
+ function sanitizeStepName(name) {
115
+ const result = name.split(WHITESPACE_PATTERN).filter((word) => word.length > 0).map((word, index) => {
116
+ const cleaned = word.replace(/[^a-zA-Z0-9]/g, "");
117
+ if (!cleaned) {
118
+ return "";
119
+ }
120
+ if (index === 0) {
121
+ return cleaned.toLowerCase();
122
+ }
123
+ return cleaned.charAt(0).toUpperCase() + cleaned.slice(1).toLowerCase();
124
+ }).filter((word) => word.length > 0).join("");
125
+ if (!result || result.length === 0) {
126
+ return "unnamedStep";
127
+ }
128
+ const sanitized = result.replace(NUMBER_START_PATTERN, "_$&");
129
+ return `${sanitized}Step`;
130
+ }
131
+ function sanitizeVarName(id) {
132
+ return id.replace(/[^a-zA-Z0-9]/g, "_");
133
+ }
134
+ function toTypeScriptLiteral(value) {
135
+ if (value === null) {
136
+ return "null";
137
+ }
138
+ if (value === void 0) {
139
+ return "undefined";
140
+ }
141
+ if (typeof value === "string") {
142
+ return JSON.stringify(value);
143
+ }
144
+ if (typeof value === "number" || typeof value === "boolean") {
145
+ return String(value);
146
+ }
147
+ if (Array.isArray(value)) {
148
+ const items = value.map((item) => toTypeScriptLiteral(item));
149
+ return `[${items.join(", ")}]`;
150
+ }
151
+ if (typeof value === "object") {
152
+ const entries = Object.entries(value).map(([key, val]) => {
153
+ const keyStr = VALID_IDENTIFIER_PATTERN.test(key) ? key : JSON.stringify(key);
154
+ return `${keyStr}: ${toTypeScriptLiteral(val)}`;
155
+ });
156
+ return `{${entries.join(", ")}}`;
157
+ }
158
+ return String(value);
159
+ }
160
+ var SYSTEM_STEP_INFO = {
161
+ "Database Query": {
162
+ functionName: "databaseQueryStep",
163
+ importPath: "./steps/database-query-step"
164
+ },
165
+ "HTTP Request": {
166
+ functionName: "httpRequestStep",
167
+ importPath: "./steps/http-request-step"
168
+ },
169
+ Condition: {
170
+ functionName: "conditionStep",
171
+ importPath: "./steps/condition-step"
172
+ }
173
+ };
174
+ function getStepInfo(actionType) {
175
+ const systemInfo = SYSTEM_STEP_INFO[actionType];
176
+ if (systemInfo) {
177
+ return systemInfo;
178
+ }
179
+ const action = findActionById(actionType);
180
+ if (action) {
181
+ return {
182
+ functionName: action.stepFunction,
183
+ // Convert plugin's stepImportPath to generated code import path
184
+ // Plugin uses "send-email", generated code uses "./steps/send-email-step"
185
+ importPath: `./steps/${action.stepImportPath}-step`
186
+ };
187
+ }
188
+ return {
189
+ functionName: "unknownStep",
190
+ importPath: "./steps/unknown-step"
191
+ };
192
+ }
193
+
194
+ // src/client/lib/workflow-codegen.ts
195
+ var CONST_ASSIGNMENT_PATTERN = /^(\s*)(const\s+\w+\s*=\s*)(.*)$/;
196
+ function generateWorkflowCode(nodes, edges, options = {}) {
197
+ const { functionName = "executeWorkflow" } = options;
198
+ const usedNodeOutputs = analyzeNodeUsage(nodes);
199
+ const imports = /* @__PURE__ */ new Set();
200
+ const nodeMap = new Map(nodes.map((n) => [n.id, n]));
201
+ const edgesBySource = /* @__PURE__ */ new Map();
202
+ for (const edge of edges) {
203
+ const targets = edgesBySource.get(edge.source) || [];
204
+ targets.push(edge.target);
205
+ edgesBySource.set(edge.source, targets);
206
+ }
207
+ const nodesWithIncoming = new Set(edges.map((e) => e.target));
208
+ const triggerNodes = nodes.filter(
209
+ (node) => node.data.type === "trigger" && !nodesWithIncoming.has(node.id)
210
+ );
211
+ const inputIsUsed = triggerNodes.some(
212
+ (trigger) => usedNodeOutputs.has(trigger.id)
213
+ );
214
+ const codeLines = [];
215
+ const visited = /* @__PURE__ */ new Set();
216
+ const functionSignature = inputIsUsed ? `export async function ${functionName}<TInput>(input: TInput) {` : `export async function ${functionName}() {`;
217
+ codeLines.push(functionSignature);
218
+ codeLines.push(` "use workflow";`);
219
+ codeLines.push("");
220
+ const nodeIdToVarName = /* @__PURE__ */ new Map();
221
+ const usedVarNames = /* @__PURE__ */ new Set();
222
+ for (const node of nodes) {
223
+ let varName;
224
+ if (node.data.type === "action") {
225
+ const actionType = node.data.config?.actionType;
226
+ const label = node.data.label || "";
227
+ const baseVarName = toFriendlyVarName(label, actionType);
228
+ varName = baseVarName;
229
+ let counter = 1;
230
+ while (usedVarNames.has(varName)) {
231
+ varName = `${baseVarName}${counter}`;
232
+ counter += 1;
233
+ }
234
+ usedVarNames.add(varName);
235
+ } else {
236
+ varName = "input";
237
+ }
238
+ nodeIdToVarName.set(node.id, varName);
239
+ }
240
+ function processAtFormat(trimmed, match) {
241
+ const withoutAt = trimmed.substring(1);
242
+ const colonIndex = withoutAt.indexOf(":");
243
+ if (colonIndex === -1) {
244
+ return match;
245
+ }
246
+ const nodeId = withoutAt.substring(0, colonIndex);
247
+ const rest = withoutAt.substring(colonIndex + 1);
248
+ const dotIndex = rest.indexOf(".");
249
+ const fieldPath = dotIndex !== -1 ? rest.substring(dotIndex + 1) : "";
250
+ const varName = nodeIdToVarName.get(nodeId);
251
+ if (!varName) {
252
+ return match;
253
+ }
254
+ if (!fieldPath) {
255
+ return `\${${varName}}`;
256
+ }
257
+ const accessPath = buildAccessPath(fieldPath);
258
+ return `\${${varName}${accessPath}}`;
259
+ }
260
+ function processDollarFormat(trimmed, match) {
261
+ const withoutDollar = trimmed.substring(1);
262
+ const parts = withoutDollar.split(".");
263
+ const nodeId = parts[0];
264
+ const fieldPath = parts.slice(1).join(".");
265
+ const varName = nodeIdToVarName.get(nodeId);
266
+ if (!varName) {
267
+ return match;
268
+ }
269
+ if (!fieldPath) {
270
+ return `\${${varName}}`;
271
+ }
272
+ const accessPath = buildAccessPath(fieldPath);
273
+ return `\${${varName}${accessPath}}`;
274
+ }
275
+ function processAtFormatForExpression(trimmed, match) {
276
+ const withoutAt = trimmed.substring(1);
277
+ const colonIndex = withoutAt.indexOf(":");
278
+ if (colonIndex === -1) {
279
+ return match;
280
+ }
281
+ const nodeId = withoutAt.substring(0, colonIndex);
282
+ const rest = withoutAt.substring(colonIndex + 1);
283
+ const dotIndex = rest.indexOf(".");
284
+ const fieldPath = dotIndex !== -1 ? rest.substring(dotIndex + 1) : "";
285
+ const varName = nodeIdToVarName.get(nodeId);
286
+ if (!varName) {
287
+ return match;
288
+ }
289
+ if (!fieldPath) {
290
+ return varName;
291
+ }
292
+ const accessPath = buildAccessPath(fieldPath);
293
+ return `${varName}${accessPath}`;
294
+ }
295
+ function processDollarFormatForExpression(trimmed, match) {
296
+ const withoutDollar = trimmed.substring(1);
297
+ const parts = withoutDollar.split(".");
298
+ const nodeId = parts[0];
299
+ const fieldPath = parts.slice(1).join(".");
300
+ const varName = nodeIdToVarName.get(nodeId);
301
+ if (!varName) {
302
+ return match;
303
+ }
304
+ if (!fieldPath) {
305
+ return varName;
306
+ }
307
+ const accessPath = buildAccessPath(fieldPath);
308
+ return `${varName}${accessPath}`;
309
+ }
310
+ function convertTemplateToJS(template) {
311
+ if (!template || typeof template !== "string") {
312
+ return template;
313
+ }
314
+ return template.replace(TEMPLATE_PATTERN, (match, expression) => {
315
+ const trimmed = expression.trim();
316
+ if (trimmed.startsWith("@")) {
317
+ return processAtFormat(trimmed, match);
318
+ }
319
+ if (trimmed.startsWith("$")) {
320
+ return processDollarFormat(trimmed, match);
321
+ }
322
+ return match;
323
+ });
324
+ }
325
+ function convertConditionToJS(condition) {
326
+ if (!condition || typeof condition !== "string") {
327
+ return condition;
328
+ }
329
+ const cleaned = removeInvisibleChars(condition);
330
+ const converted = cleaned.replace(TEMPLATE_PATTERN, (match, expression) => {
331
+ const trimmed = expression.trim();
332
+ if (trimmed.startsWith("@")) {
333
+ return processAtFormatForExpression(trimmed, match);
334
+ }
335
+ if (trimmed.startsWith("$")) {
336
+ return processDollarFormatForExpression(trimmed, match);
337
+ }
338
+ return match;
339
+ });
340
+ return removeInvisibleChars(converted);
341
+ }
342
+ function generateEmailActionCode(node, indent, varName) {
343
+ const stepInfo = getStepInfo("Send Email");
344
+ imports.add(
345
+ `import { ${stepInfo.functionName} } from '${stepInfo.importPath}';`
346
+ );
347
+ const config = node.data.config || {};
348
+ const emailTo = config.emailTo || "user@example.com";
349
+ const emailSubject = config.emailSubject || "Notification";
350
+ const emailBody = config.emailBody || "No content";
351
+ const convertedEmailTo = convertTemplateToJS(emailTo);
352
+ const convertedSubject = convertTemplateToJS(emailSubject);
353
+ const convertedBody = convertTemplateToJS(emailBody);
354
+ const hasTemplateRefs = (str) => str.includes("${");
355
+ const escapeForOuterTemplate = (str) => str.replace(/\$\{/g, "$${");
356
+ const emailToValue = hasTemplateRefs(convertedEmailTo) ? `\`${escapeForOuterTemplate(convertedEmailTo).replace(/`/g, "\\`")}\`` : `'${emailTo.replace(/'/g, "\\'")}'`;
357
+ const subjectValue = hasTemplateRefs(convertedSubject) ? `\`${escapeForOuterTemplate(convertedSubject).replace(/`/g, "\\`")}\`` : `'${emailSubject.replace(/'/g, "\\'")}'`;
358
+ const bodyValue = hasTemplateRefs(convertedBody) ? `\`${escapeForOuterTemplate(convertedBody).replace(/`/g, "\\`")}\`` : `'${emailBody.replace(/'/g, "\\'")}'`;
359
+ return [
360
+ `${indent}const ${varName} = await ${stepInfo.functionName}({`,
361
+ `${indent} emailTo: ${emailToValue},`,
362
+ `${indent} emailSubject: ${subjectValue},`,
363
+ `${indent} emailBody: ${bodyValue},`,
364
+ `${indent}});`
365
+ ];
366
+ }
367
+ function generateTicketActionCode(node, indent, varName) {
368
+ const stepInfo = getStepInfo("Create Ticket");
369
+ imports.add(
370
+ `import { ${stepInfo.functionName} } from '${stepInfo.importPath}';`
371
+ );
372
+ const config = node.data.config || {};
373
+ const ticketTitle = config.ticketTitle || "New Ticket";
374
+ const ticketDescription = config.ticketDescription || "";
375
+ const convertedTitle = convertTemplateToJS(ticketTitle);
376
+ const convertedDescription = convertTemplateToJS(ticketDescription);
377
+ const hasTemplateRefs = (str) => str.includes("${");
378
+ const escapeForOuterTemplate = (str) => str.replace(/\$\{/g, "$${");
379
+ const titleValue = hasTemplateRefs(convertedTitle) ? `\`${escapeForOuterTemplate(convertedTitle).replace(/`/g, "\\`")}\`` : `'${ticketTitle.replace(/'/g, "\\'")}'`;
380
+ const descValue = hasTemplateRefs(convertedDescription) ? `\`${escapeForOuterTemplate(convertedDescription).replace(/`/g, "\\`")}\`` : `'${ticketDescription.replace(/'/g, "\\'")}'`;
381
+ return [
382
+ `${indent}const ${varName} = await ${stepInfo.functionName}({`,
383
+ `${indent} ticketTitle: ${titleValue},`,
384
+ `${indent} ticketDescription: ${descValue},`,
385
+ `${indent}});`
386
+ ];
387
+ }
388
+ function generateDatabaseActionCode(node, indent, varName) {
389
+ const stepInfo = getStepInfo("Database Query");
390
+ imports.add(
391
+ `import { ${stepInfo.functionName} } from '${stepInfo.importPath}';`
392
+ );
393
+ const config = node.data.config || {};
394
+ const dbQuery = config.dbQuery || "";
395
+ const dataSource = config.dataSource || "";
396
+ const tableName = config.dbTable || config.tableName || "your_table";
397
+ const lines = [
398
+ `${indent}const ${varName} = await ${stepInfo.functionName}({`
399
+ ];
400
+ if (dataSource) {
401
+ lines.push(`${indent} dataSource: { name: "${dataSource}" },`);
402
+ } else {
403
+ lines.push(`${indent} dataSource: {},`);
404
+ }
405
+ if (dbQuery) {
406
+ const convertedQuery = convertTemplateToJS(dbQuery);
407
+ const hasTemplateRefs = convertedQuery.includes("${");
408
+ const escapeForOuterTemplate = (str) => str.replace(/\$\{/g, "$${");
409
+ const queryValue = hasTemplateRefs ? `\`${escapeForOuterTemplate(convertedQuery).replace(/`/g, "\\`")}\`` : `\`${dbQuery.replace(/`/g, "\\`")}\``;
410
+ lines.push(`${indent} query: ${queryValue},`);
411
+ } else {
412
+ lines.push(`${indent} query: "${tableName}",`);
413
+ }
414
+ lines.push(`${indent}});`);
415
+ return lines;
416
+ }
417
+ function generateHTTPActionCode(node, indent, varName) {
418
+ const stepInfo = getStepInfo("HTTP Request");
419
+ imports.add(
420
+ `import { ${stepInfo.functionName} } from '${stepInfo.importPath}';`
421
+ );
422
+ const config = node.data.config || {};
423
+ const endpoint = config.endpoint || "https://api.example.com/endpoint";
424
+ const method = config.httpMethod || "POST";
425
+ return [
426
+ `${indent}const ${varName} = await ${stepInfo.functionName}({`,
427
+ `${indent} url: '${endpoint}',`,
428
+ `${indent} method: '${method}',`,
429
+ `${indent} body: {},`,
430
+ `${indent}});`
431
+ ];
432
+ }
433
+ function processAiSchema(aiSchema) {
434
+ if (!aiSchema) {
435
+ return null;
436
+ }
437
+ try {
438
+ const parsedSchema = JSON.parse(aiSchema);
439
+ const schemaWithoutIds = Array.isArray(parsedSchema) ? parsedSchema.map((field) => {
440
+ const { id: _id, ...rest } = field;
441
+ return rest;
442
+ }) : parsedSchema;
443
+ return toTypeScriptLiteral(schemaWithoutIds);
444
+ } catch {
445
+ return null;
446
+ }
447
+ }
448
+ function generatePromptValue(aiPrompt) {
449
+ const convertedPrompt = convertTemplateToJS(aiPrompt);
450
+ const hasTemplateRefs = convertedPrompt.includes("${");
451
+ const escapeForOuterTemplate = (str) => str.replace(/\$\{/g, "$${");
452
+ if (hasTemplateRefs) {
453
+ return `\`${escapeForOuterTemplate(convertedPrompt).replace(/`/g, "\\`")}\``;
454
+ }
455
+ return `\`${aiPrompt.replace(/`/g, "\\`")}\``;
456
+ }
457
+ function generateAiTextActionCode(node, indent, varName) {
458
+ const stepInfo = getStepInfo("Generate Text");
459
+ imports.add(
460
+ `import { ${stepInfo.functionName} } from '${stepInfo.importPath}';`
461
+ );
462
+ const config = node.data.config || {};
463
+ const aiPrompt = config.aiPrompt || "Generate a summary";
464
+ const aiModel = config.aiModel || "meta/llama-4-scout";
465
+ const aiFormat = config.aiFormat || "text";
466
+ const aiSchema = config.aiSchema;
467
+ const promptValue = generatePromptValue(aiPrompt);
468
+ const lines = [
469
+ `${indent}// Generate text using AI`,
470
+ `${indent}const ${varName} = await ${stepInfo.functionName}({`,
471
+ `${indent} model: "${aiModel}",`,
472
+ `${indent} prompt: ${promptValue},`
473
+ ];
474
+ if (aiFormat === "object") {
475
+ lines.push(`${indent} format: "object",`);
476
+ const schemaString = processAiSchema(aiSchema);
477
+ if (schemaString) {
478
+ lines.push(`${indent} schema: ${schemaString},`);
479
+ }
480
+ }
481
+ lines.push(`${indent}});`);
482
+ return lines;
483
+ }
484
+ function generateAiImageActionCode(node, indent, varName) {
485
+ imports.add(
486
+ "import { experimental_generateImage as generateImage } from 'ai';"
487
+ );
488
+ const imagePrompt = node.data.config?.imagePrompt || "A beautiful landscape";
489
+ const imageModel = node.data.config?.imageModel || "google/imagen-4.0-generate";
490
+ return [
491
+ `${indent}// Generate image using AI`,
492
+ `${indent}const ${varName} = await generateImage({`,
493
+ `${indent} model: "${imageModel}",`,
494
+ `${indent} prompt: \`${imagePrompt}\`,`,
495
+ `${indent} size: "1024x1024",`,
496
+ `${indent}});`
497
+ ];
498
+ }
499
+ function generateSlackActionCode(node, indent, varName) {
500
+ const stepInfo = getStepInfo("Send Slack Message");
501
+ imports.add(
502
+ `import { ${stepInfo.functionName} } from '${stepInfo.importPath}';`
503
+ );
504
+ const config = node.data.config || {};
505
+ const slackChannel = config.slackChannel || "#general";
506
+ const slackMessage = config.slackMessage || "Message content";
507
+ const convertedChannel = convertTemplateToJS(slackChannel);
508
+ const convertedMessage = convertTemplateToJS(slackMessage);
509
+ const hasTemplateRefs = (str) => str.includes("${");
510
+ const escapeForOuterTemplate = (str) => str.replace(/\$\{/g, "$${");
511
+ const channelValue = hasTemplateRefs(convertedChannel) ? `\`${escapeForOuterTemplate(convertedChannel).replace(/`/g, "\\`")}\`` : `"${slackChannel}"`;
512
+ const messageValue = hasTemplateRefs(convertedMessage) ? `\`${escapeForOuterTemplate(convertedMessage).replace(/`/g, "\\`")}\`` : `"${slackMessage}"`;
513
+ return [
514
+ `${indent}const ${varName} = await ${stepInfo.functionName}({`,
515
+ `${indent} slackChannel: ${channelValue},`,
516
+ `${indent} slackMessage: ${messageValue},`,
517
+ `${indent}});`
518
+ ];
519
+ }
520
+ function formatTemplateValue(value) {
521
+ const converted = convertTemplateToJS(value);
522
+ const hasTemplateRefs = converted.includes("${");
523
+ const escaped = converted.replace(/\$\{/g, "$${").replace(/`/g, "\\`");
524
+ return hasTemplateRefs ? `\`${escaped}\`` : `\`${value.replace(/`/g, "\\`")}\``;
525
+ }
526
+ function generateFirecrawlActionCode(node, indent, varName) {
527
+ const actionType = node.data.config?.actionType;
528
+ const stepInfo = getStepInfo(actionType);
529
+ imports.add(
530
+ `import { ${stepInfo.functionName} } from '${stepInfo.importPath}';`
531
+ );
532
+ const config = node.data.config || {};
533
+ const url = config.url || "";
534
+ const query = config.query || "";
535
+ const limit = config.limit ? Number(config.limit) : void 0;
536
+ const lines = [
537
+ `${indent}const ${varName} = await ${stepInfo.functionName}({`
538
+ ];
539
+ if (url) {
540
+ lines.push(`${indent} url: ${formatTemplateValue(url)},`);
541
+ }
542
+ if (query) {
543
+ lines.push(`${indent} query: ${formatTemplateValue(query)},`);
544
+ }
545
+ if (limit) {
546
+ lines.push(`${indent} limit: ${limit},`);
547
+ }
548
+ lines.push(`${indent}});`);
549
+ return lines;
550
+ }
551
+ function generateV0CreateChatActionCode(node, indent, varName) {
552
+ const stepInfo = getStepInfo("Create Chat");
553
+ imports.add(
554
+ `import { ${stepInfo.functionName} } from '${stepInfo.importPath}';`
555
+ );
556
+ const config = node.data.config || {};
557
+ const message = config.message || "";
558
+ const system = config.system || "";
559
+ const lines = [
560
+ `${indent}const ${varName} = await ${stepInfo.functionName}({`,
561
+ `${indent} message: ${formatTemplateValue(message)},`
562
+ ];
563
+ if (system) {
564
+ lines.push(`${indent} system: ${formatTemplateValue(system)},`);
565
+ }
566
+ lines.push(`${indent}});`);
567
+ return lines;
568
+ }
569
+ function generateV0SendMessageActionCode(node, indent, varName) {
570
+ const stepInfo = getStepInfo("Send Message");
571
+ imports.add(
572
+ `import { ${stepInfo.functionName} } from '${stepInfo.importPath}';`
573
+ );
574
+ const config = node.data.config || {};
575
+ const chatId = config.chatId || "";
576
+ const message = config.message || "";
577
+ const lines = [
578
+ `${indent}const ${varName} = await ${stepInfo.functionName}({`,
579
+ `${indent} chatId: ${formatTemplateValue(chatId)},`,
580
+ `${indent} message: ${formatTemplateValue(message)},`,
581
+ `${indent}});`
582
+ ];
583
+ return lines;
584
+ }
585
+ function formatFieldValue(fieldType, value, indent, key) {
586
+ const fieldTypeFormatters = {
587
+ "template-input": () => `${indent} ${key}: ${formatTemplateValue(String(value))},`,
588
+ "template-textarea": () => `${indent} ${key}: ${formatTemplateValue(String(value))},`,
589
+ number: () => `${indent} ${key}: ${value},`,
590
+ select: () => `${indent} ${key}: "${value}",`,
591
+ "schema-builder": () => `${indent} ${key}: ${JSON.stringify(value)},`
592
+ };
593
+ const formatter = fieldTypeFormatters[fieldType];
594
+ return formatter ? formatter() : `${indent} ${key}: "${value}",`;
595
+ }
596
+ function generatePluginActionCode(node, actionType, indent, varName) {
597
+ const action = findActionById(actionType);
598
+ if (!action) {
599
+ return null;
600
+ }
601
+ const stepInfo = getStepInfo(actionType);
602
+ imports.add(
603
+ `import { ${stepInfo.functionName} } from '${stepInfo.importPath}';`
604
+ );
605
+ const config = node.data.config || {};
606
+ const configFields = flattenConfigFields(action.configFields);
607
+ const paramLines = [];
608
+ for (const field of configFields) {
609
+ const value = config[field.key];
610
+ if (value === void 0 || value === null || value === "") {
611
+ continue;
612
+ }
613
+ paramLines.push(formatFieldValue(field.type, value, indent, field.key));
614
+ }
615
+ const lines = [];
616
+ if (paramLines.length > 0) {
617
+ lines.push(
618
+ `${indent}const ${varName} = await ${stepInfo.functionName}({`
619
+ );
620
+ lines.push(...paramLines);
621
+ lines.push(`${indent}});`);
622
+ } else {
623
+ lines.push(
624
+ `${indent}const ${varName} = await ${stepInfo.functionName}({});`
625
+ );
626
+ }
627
+ return lines;
628
+ }
629
+ function generateActionNodeCode(node, nodeId, indent, varName) {
630
+ const actionType = node.data.config?.actionType;
631
+ const actionLabel = node.data.label || actionType || "Unknown Action";
632
+ const lines = [`${indent}// Action: ${actionLabel}`];
633
+ if (node.data.description) {
634
+ lines.push(`${indent}// ${node.data.description}`);
635
+ }
636
+ const outputIsUsed = usedNodeOutputs.has(nodeId);
637
+ function processAwaitLine(line) {
638
+ const match = CONST_ASSIGNMENT_PATTERN.exec(line);
639
+ if (match) {
640
+ const [, lineIndent, , rest] = match;
641
+ return `${lineIndent}${rest}`;
642
+ }
643
+ return line;
644
+ }
645
+ function processConstLine(line) {
646
+ const match = CONST_ASSIGNMENT_PATTERN.exec(line);
647
+ if (match) {
648
+ const [, lineIndent, , rest] = match;
649
+ return `${lineIndent}void ${rest}`;
650
+ }
651
+ return line;
652
+ }
653
+ function removeVariableAssignment(actionLines) {
654
+ const result = [];
655
+ for (const line of actionLines) {
656
+ if (line.includes("await")) {
657
+ result.push(processAwaitLine(line));
658
+ } else if (line.trim().startsWith("const") && line.includes("{")) {
659
+ result.push(processConstLine(line));
660
+ } else {
661
+ result.push(line);
662
+ }
663
+ }
664
+ return result;
665
+ }
666
+ const wrapActionCall = (actionLines) => {
667
+ if (outputIsUsed) {
668
+ return actionLines;
669
+ }
670
+ return removeVariableAssignment(actionLines);
671
+ };
672
+ if (actionType === "Generate Text") {
673
+ lines.push(
674
+ ...wrapActionCall(generateAiTextActionCode(node, indent, varName))
675
+ );
676
+ } else if (actionType === "Generate Image") {
677
+ lines.push(
678
+ ...wrapActionCall(generateAiImageActionCode(node, indent, varName))
679
+ );
680
+ } else if (actionType === "Send Email") {
681
+ lines.push(
682
+ ...wrapActionCall(generateEmailActionCode(node, indent, varName))
683
+ );
684
+ } else if (actionType === "Send Slack Message") {
685
+ lines.push(
686
+ ...wrapActionCall(generateSlackActionCode(node, indent, varName))
687
+ );
688
+ } else if (actionType === "Create Ticket") {
689
+ lines.push(
690
+ ...wrapActionCall(generateTicketActionCode(node, indent, varName))
691
+ );
692
+ } else if (actionType === "Scrape" || actionType === "Search") {
693
+ lines.push(
694
+ ...wrapActionCall(generateFirecrawlActionCode(node, indent, varName))
695
+ );
696
+ } else if (actionType === "Create Chat") {
697
+ lines.push(
698
+ ...wrapActionCall(generateV0CreateChatActionCode(node, indent, varName))
699
+ );
700
+ } else if (actionType === "Send Message") {
701
+ lines.push(
702
+ ...wrapActionCall(
703
+ generateV0SendMessageActionCode(node, indent, varName)
704
+ )
705
+ );
706
+ } else if (actionType === "Database Query") {
707
+ lines.push(
708
+ ...wrapActionCall(generateDatabaseActionCode(node, indent, varName))
709
+ );
710
+ } else if (actionType === "HTTP Request") {
711
+ lines.push(
712
+ ...wrapActionCall(generateHTTPActionCode(node, indent, varName))
713
+ );
714
+ } else {
715
+ const pluginCode = generatePluginActionCode(
716
+ node,
717
+ actionType,
718
+ indent,
719
+ varName
720
+ );
721
+ if (pluginCode) {
722
+ lines.push(...wrapActionCall(pluginCode));
723
+ } else if (outputIsUsed) {
724
+ lines.push(`${indent}// TODO: Implement action type "${actionType}"`);
725
+ lines.push(
726
+ `${indent}const ${varName} = { status: 'pending', actionType: "${actionType}" };`
727
+ );
728
+ } else {
729
+ lines.push(`${indent}// TODO: Implement action type "${actionType}"`);
730
+ lines.push(
731
+ `${indent}void ({ status: 'pending', actionType: "${actionType}" });`
732
+ );
733
+ }
734
+ }
735
+ return lines;
736
+ }
737
+ function generateConditionNodeCode(node, nodeId, indent) {
738
+ const lines = [`${indent}// Condition: ${node.data.label}`];
739
+ if (node.data.description) {
740
+ lines.push(`${indent}// ${node.data.description}`);
741
+ }
742
+ const condition = node.data.config?.condition;
743
+ const nextNodes = edgesBySource.get(nodeId) || [];
744
+ if (nextNodes.length > 0) {
745
+ const trueNode = nextNodes[0];
746
+ const falseNode = nextNodes[1];
747
+ const convertedCondition = condition ? convertConditionToJS(condition) : "true";
748
+ lines.push(`${indent}if (${convertedCondition}) {`);
749
+ if (trueNode) {
750
+ const trueNodeCode = generateNodeCode(trueNode, `${indent} `);
751
+ lines.push(...trueNodeCode);
752
+ }
753
+ if (falseNode) {
754
+ lines.push(`${indent}} else {`);
755
+ const falseNodeCode = generateNodeCode(falseNode, `${indent} `);
756
+ lines.push(...falseNodeCode);
757
+ }
758
+ lines.push(`${indent}}`);
759
+ }
760
+ return lines;
761
+ }
762
+ function processTriggerNode(nodeId, indent) {
763
+ const nextNodes = edgesBySource.get(nodeId) || [];
764
+ const lines = generateParallelNodeCode(nextNodes, indent);
765
+ return { lines, wasSkipped: true };
766
+ }
767
+ function processActionNode(node, nodeId, varName, indent) {
768
+ const lines = [];
769
+ const actionType = node.data.config?.actionType;
770
+ if (actionType === "Condition") {
771
+ lines.push(...generateConditionNodeCode(node, nodeId, indent));
772
+ return lines;
773
+ }
774
+ lines.push(...generateActionNodeCode(node, nodeId, indent, varName));
775
+ return lines;
776
+ }
777
+ function generateBranchCode(nodeId, indent, branchVisited) {
778
+ if (branchVisited.has(nodeId)) {
779
+ return [];
780
+ }
781
+ branchVisited.add(nodeId);
782
+ const node = nodeMap.get(nodeId);
783
+ if (!node) {
784
+ return [];
785
+ }
786
+ const lines = [];
787
+ if (node.data.type === "action") {
788
+ const actionType = node.data.config?.actionType;
789
+ if (actionType === "Condition") {
790
+ lines.push(
791
+ ...generateConditionBranchCode(node, nodeId, indent, branchVisited)
792
+ );
793
+ } else {
794
+ lines.push(...generateActionCallCode(node, indent));
795
+ const children = edgesBySource.get(nodeId) || [];
796
+ if (children.length > 0) {
797
+ lines.push("");
798
+ lines.push(...generateChildrenCode(children, indent, branchVisited));
799
+ }
800
+ }
801
+ }
802
+ return lines;
803
+ }
804
+ function generateConditionBranchCode(node, nodeId, indent, branchVisited) {
805
+ const lines = [`${indent}// Condition: ${node.data.label}`];
806
+ const condition = node.data.config?.condition;
807
+ const nextNodes = edgesBySource.get(nodeId) || [];
808
+ if (nextNodes.length > 0) {
809
+ const convertedCondition = condition ? convertConditionToJS(condition) : "true";
810
+ lines.push(`${indent}if (${convertedCondition}) {`);
811
+ if (nextNodes[0]) {
812
+ lines.push(
813
+ ...generateBranchCode(nextNodes[0], `${indent} `, branchVisited)
814
+ );
815
+ }
816
+ if (nextNodes[1]) {
817
+ lines.push(`${indent}} else {`);
818
+ lines.push(
819
+ ...generateBranchCode(nextNodes[1], `${indent} `, branchVisited)
820
+ );
821
+ }
822
+ lines.push(`${indent}}`);
823
+ }
824
+ return lines;
825
+ }
826
+ function generateActionCallCode(node, indent) {
827
+ const actionType = node.data.config?.actionType;
828
+ const actionLabel = node.data.label || actionType || "Unknown Action";
829
+ const stepInfo = getStepInfo(actionType);
830
+ const configParams = buildActionConfigParams(node, `${indent} `);
831
+ imports.add(
832
+ `import { ${stepInfo.functionName} } from '${stepInfo.importPath}';`
833
+ );
834
+ const lines = [`${indent}// ${actionLabel}`];
835
+ if (configParams.length > 0) {
836
+ lines.push(`${indent}await ${stepInfo.functionName}({`);
837
+ lines.push(...configParams);
838
+ lines.push(`${indent}});`);
839
+ } else {
840
+ lines.push(`${indent}await ${stepInfo.functionName}({});`);
841
+ }
842
+ return lines;
843
+ }
844
+ function generateChildrenCode(childIds, indent, branchVisited) {
845
+ const unvisited = childIds.filter((id) => !branchVisited.has(id));
846
+ if (unvisited.length === 0) {
847
+ return [];
848
+ }
849
+ if (unvisited.length === 1) {
850
+ return generateBranchCode(unvisited[0], indent, branchVisited);
851
+ }
852
+ const lines = [`${indent}await Promise.all([`];
853
+ for (let i = 0; i < unvisited.length; i++) {
854
+ const childId = unvisited[i];
855
+ const isLast = i === unvisited.length - 1;
856
+ const comma = isLast ? "" : ",";
857
+ const childBranchVisited = new Set(branchVisited);
858
+ const branchCode = generateBranchCode(
859
+ childId,
860
+ `${indent} `,
861
+ childBranchVisited
862
+ );
863
+ if (branchCode.length > 0) {
864
+ lines.push(`${indent} (async () => {`);
865
+ lines.push(...branchCode);
866
+ lines.push(`${indent} })()${comma}`);
867
+ }
868
+ }
869
+ lines.push(`${indent}]);`);
870
+ return lines;
871
+ }
872
+ function generateAsyncIIFEBranch(nodeId, indent, isLast) {
873
+ const branchVisited = new Set(visited);
874
+ branchVisited.delete(nodeId);
875
+ const branchCode = generateBranchCode(
876
+ nodeId,
877
+ `${indent} `,
878
+ branchVisited
879
+ );
880
+ const comma = isLast ? "" : ",";
881
+ if (branchCode.length === 0) {
882
+ return [];
883
+ }
884
+ return [
885
+ `${indent} (async () => {`,
886
+ ...branchCode,
887
+ `${indent} })()${comma}`
888
+ ];
889
+ }
890
+ function generateParallelNodeCode(nodeIds, indent) {
891
+ if (nodeIds.length === 0) {
892
+ return [];
893
+ }
894
+ const unvisited = nodeIds.filter(
895
+ (id) => !visited.has(id) && nodeMap.get(id)?.data.type === "action"
896
+ );
897
+ if (unvisited.length === 0) {
898
+ return [];
899
+ }
900
+ if (unvisited.length === 1) {
901
+ const branchVisited = new Set(visited);
902
+ visited.add(unvisited[0]);
903
+ return generateBranchCode(unvisited[0], indent, branchVisited);
904
+ }
905
+ for (const id of unvisited) {
906
+ visited.add(id);
907
+ }
908
+ const lines = [`${indent}await Promise.all([`];
909
+ for (let i = 0; i < unvisited.length; i++) {
910
+ lines.push(
911
+ ...generateAsyncIIFEBranch(
912
+ unvisited[i],
913
+ indent,
914
+ i === unvisited.length - 1
915
+ )
916
+ );
917
+ }
918
+ lines.push(`${indent}]);`);
919
+ return lines;
920
+ }
921
+ function buildPluginConfigParams(config, actionType, indent) {
922
+ const action = findActionById(actionType);
923
+ if (!action) {
924
+ return [];
925
+ }
926
+ const params = [];
927
+ for (const field of flattenConfigFields(action.configFields)) {
928
+ const value = config[field.key];
929
+ if (value === void 0 || value === null || value === "") {
930
+ continue;
931
+ }
932
+ params.push(formatFieldValue(field.type, value, indent, field.key));
933
+ }
934
+ return params;
935
+ }
936
+ const EXCLUDED_CONFIG_KEYS = /* @__PURE__ */ new Set(["actionType", "integrationId"]);
937
+ function buildFallbackConfigParams(config, indent) {
938
+ const params = [];
939
+ for (const [key, value] of Object.entries(config)) {
940
+ if (EXCLUDED_CONFIG_KEYS.has(key) || value === void 0 || value === null) {
941
+ continue;
942
+ }
943
+ if (typeof value === "string") {
944
+ params.push(`${indent}${key}: ${formatTemplateValue(value)},`);
945
+ } else if (typeof value === "number" || typeof value === "boolean") {
946
+ params.push(`${indent}${key}: ${value},`);
947
+ } else {
948
+ params.push(`${indent}${key}: ${JSON.stringify(value)},`);
949
+ }
950
+ }
951
+ return params;
952
+ }
953
+ function buildActionConfigParams(node, indent) {
954
+ const actionType = node.data.config?.actionType;
955
+ const config = node.data.config || {};
956
+ const pluginParams = buildPluginConfigParams(config, actionType, indent);
957
+ if (pluginParams.length > 0) {
958
+ return pluginParams;
959
+ }
960
+ return buildFallbackConfigParams(config, indent);
961
+ }
962
+ function processNextNodes(nodeId, currentLines, indent) {
963
+ const nextNodes = edgesBySource.get(nodeId) || [];
964
+ const result = [...currentLines];
965
+ if (currentLines.length > 0 && nextNodes.length > 0) {
966
+ result.push("");
967
+ }
968
+ result.push(...generateParallelNodeCode(nextNodes, indent));
969
+ return result;
970
+ }
971
+ function generateNodeCode(nodeId, indent = " ") {
972
+ if (visited.has(nodeId)) {
973
+ return [`${indent}// Already processed: ${nodeId}`];
974
+ }
975
+ visited.add(nodeId);
976
+ const node = nodeMap.get(nodeId);
977
+ if (!node) {
978
+ return [];
979
+ }
980
+ const varName = nodeIdToVarName.get(nodeId) || `${node.data.type}_${nodeId.replace(/-/g, "_")}`;
981
+ let lines = [];
982
+ switch (node.data.type) {
983
+ case "trigger": {
984
+ const { lines: triggerLines, wasSkipped } = processTriggerNode(
985
+ nodeId,
986
+ indent
987
+ );
988
+ if (wasSkipped) {
989
+ return triggerLines;
990
+ }
991
+ return processNextNodes(nodeId, triggerLines, indent);
992
+ }
993
+ case "action": {
994
+ const actionLines = processActionNode(node, nodeId, varName, indent);
995
+ const actionType = node.data.config?.actionType;
996
+ if (actionType === "Condition") {
997
+ return actionLines;
998
+ }
999
+ lines = actionLines;
1000
+ break;
1001
+ }
1002
+ default:
1003
+ lines.push(`${indent}// Unknown node type: ${node.data.type}`);
1004
+ break;
1005
+ }
1006
+ return processNextNodes(nodeId, lines, indent);
1007
+ }
1008
+ if (triggerNodes.length === 0) {
1009
+ codeLines.push(" // No trigger nodes found");
1010
+ } else {
1011
+ for (const trigger of triggerNodes) {
1012
+ const triggerCode = generateNodeCode(trigger.id, " ");
1013
+ codeLines.push(...triggerCode);
1014
+ }
1015
+ }
1016
+ codeLines.push("}");
1017
+ const importStatements = Array.from(imports).join("\n");
1018
+ const code = `${importStatements}
1019
+
1020
+ ${codeLines.join("\n")}
1021
+ `;
1022
+ return {
1023
+ code,
1024
+ functionName,
1025
+ imports: Array.from(imports)
1026
+ };
1027
+ }
1028
+ function generateWorkflowModule(workflowName, nodes, edges, options = {}) {
1029
+ const { code } = generateWorkflowCode(nodes, edges, options);
1030
+ return `/**
1031
+ * Generated Workflow: ${workflowName}
1032
+ *
1033
+ * This file was automatically generated from a workflow definition.
1034
+ * DO NOT EDIT MANUALLY - regenerate from the workflow editor instead.
1035
+ */
1036
+
1037
+ ${code}
1038
+ `;
1039
+ }
1040
+
1041
+ // src/plugins/condition/index.tsx
1042
+ import { GitBranch } from "lucide-react";
1043
+ import { jsx } from "react/jsx-runtime";
1044
+ var conditionAction = {
1045
+ id: "Condition",
1046
+ label: "Condition",
1047
+ description: "Branch based on a condition",
1048
+ category: "System",
1049
+ icon: /* @__PURE__ */ jsx(GitBranch, { className: "size-12 text-pink-300", strokeWidth: 1.5 }),
1050
+ codeGenerator: `export async function conditionStep(input: {
1051
+ condition: boolean;
1052
+ }) {
1053
+ "use step";
1054
+
1055
+ // Evaluate condition
1056
+ return { condition: input.condition };
1057
+ }`
1058
+ };
1059
+
1060
+ // src/plugins/database-query/index.tsx
1061
+ import { Database } from "lucide-react";
1062
+ import { jsx as jsx2 } from "react/jsx-runtime";
1063
+ var databaseQueryAction = {
1064
+ id: "Database Query",
1065
+ label: "Database Query",
1066
+ description: "Query your database",
1067
+ category: "System",
1068
+ icon: /* @__PURE__ */ jsx2(Database, { className: "size-12 text-blue-300", strokeWidth: 1.5 }),
1069
+ codeGenerator: `export async function databaseQueryStep(input: {
1070
+ query: string;
1071
+ }) {
1072
+ "use step";
1073
+
1074
+ const databaseUrl = process.env.DATABASE_URL;
1075
+ if (!databaseUrl) {
1076
+ return { success: false, error: "DATABASE_URL environment variable is not set" };
1077
+ }
1078
+
1079
+ const postgres = await import("postgres");
1080
+ const sql = postgres.default(databaseUrl, { max: 1 });
1081
+
1082
+ try {
1083
+ const result = await sql.unsafe(input.query);
1084
+ await sql.end();
1085
+ return { success: true, rows: result, count: result.length };
1086
+ } catch (error) {
1087
+ await sql.end();
1088
+ const message = error instanceof Error ? error.message : String(error);
1089
+ return { success: false, error: \`Database query failed: \${message}\` };
1090
+ }
1091
+ }`
1092
+ };
1093
+
1094
+ // src/plugins/http-request/index.tsx
1095
+ import { Zap } from "lucide-react";
1096
+ import { jsx as jsx3 } from "react/jsx-runtime";
1097
+ var httpRequestAction = {
1098
+ id: "HTTP Request",
1099
+ label: "HTTP Request",
1100
+ description: "Make an HTTP request to any API",
1101
+ category: "System",
1102
+ icon: /* @__PURE__ */ jsx3(Zap, { className: "size-12 text-amber-300", strokeWidth: 1.5 }),
1103
+ codeGenerator: `export async function httpRequestStep(input: {
1104
+ endpoint: string;
1105
+ httpMethod: string;
1106
+ httpHeaders?: string;
1107
+ httpBody?: string;
1108
+ }) {
1109
+ "use step";
1110
+
1111
+ let headers = {};
1112
+ if (input.httpHeaders) {
1113
+ try {
1114
+ headers = JSON.parse(input.httpHeaders);
1115
+ } catch {
1116
+ // If parsing fails, use empty headers
1117
+ }
1118
+ }
1119
+
1120
+ let body: string | undefined;
1121
+ if (input.httpMethod !== "GET" && input.httpBody) {
1122
+ try {
1123
+ const parsedBody = JSON.parse(input.httpBody);
1124
+ if (Object.keys(parsedBody).length > 0) {
1125
+ body = JSON.stringify(parsedBody);
1126
+ }
1127
+ } catch {
1128
+ if (input.httpBody.trim() && input.httpBody.trim() !== "{}") {
1129
+ body = input.httpBody;
1130
+ }
1131
+ }
1132
+ }
1133
+
1134
+ const response = await fetch(input.endpoint, {
1135
+ method: input.httpMethod,
1136
+ headers,
1137
+ body,
1138
+ });
1139
+
1140
+ const contentType = response.headers.get("content-type");
1141
+ if (contentType?.includes("application/json")) {
1142
+ return await response.json();
1143
+ }
1144
+ return await response.text();
1145
+ }`
1146
+ };
1147
+
1148
+ export {
1149
+ ARRAY_INDEX_PATTERN,
1150
+ analyzeNodeUsage,
1151
+ buildEdgeMap,
1152
+ findTriggerNodes,
1153
+ escapeForTemplateLiteral,
1154
+ sanitizeFunctionName,
1155
+ sanitizeStepName,
1156
+ sanitizeVarName,
1157
+ generateWorkflowCode,
1158
+ generateWorkflowModule,
1159
+ conditionAction,
1160
+ databaseQueryAction,
1161
+ httpRequestAction
1162
+ };