@timo9378/flow2code 0.1.9 → 0.2.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +15 -2
  3. package/dist/cli.js +74 -7
  4. package/dist/compiler.cjs +32 -2
  5. package/dist/compiler.d.cts +6 -0
  6. package/dist/compiler.d.ts +6 -0
  7. package/dist/compiler.js +32 -2
  8. package/dist/server.d.ts +1 -1
  9. package/dist/server.js +1227 -1010
  10. package/out/404.html +1 -1
  11. package/out/__next.__PAGE__.txt +4 -4
  12. package/out/__next._full.txt +13 -13
  13. package/out/__next._head.txt +4 -4
  14. package/out/__next._index.txt +6 -6
  15. package/out/__next._tree.txt +2 -2
  16. package/out/_next/static/chunks/05328cd26bdc795c.js +176 -0
  17. package/out/_next/static/chunks/06e01c846ae01892.js +1 -0
  18. package/out/_next/static/chunks/1011f174944c0ca2.js +70 -0
  19. package/out/_next/static/chunks/1570e9ba5f1b44ed.js +5 -0
  20. package/out/_next/static/chunks/6167fccccde2e675.css +1 -0
  21. package/out/_next/static/chunks/{b112c2f519e4b429.js → 7cd04052abfadac1.js} +1 -1
  22. package/out/_next/static/chunks/8091c1216a95d294.js +1 -0
  23. package/out/_next/static/chunks/98d53aae29c36c6b.js +1 -0
  24. package/out/_next/static/chunks/a6dad97d9634a72d.js.map +1 -1
  25. package/out/_next/static/chunks/{b163b5d7cccbcf42.js → b05daf00cdc6058f.js} +1 -1
  26. package/out/_next/static/chunks/b3419ee3e3a616d9.js +1 -0
  27. package/out/_next/static/chunks/{acf223168ac429f7.js → be40d79540010a0d.js} +1 -1
  28. package/out/_next/static/chunks/{turbopack-576234c945ffdc44.js → turbopack-9da9810f42c97265.js} +1 -1
  29. package/out/_not-found/__next._full.txt +11 -11
  30. package/out/_not-found/__next._head.txt +4 -4
  31. package/out/_not-found/__next._index.txt +6 -6
  32. package/out/_not-found/__next._not-found/__PAGE__.txt +2 -2
  33. package/out/_not-found/__next._not-found.txt +3 -3
  34. package/out/_not-found/__next._tree.txt +2 -2
  35. package/out/_not-found.html +1 -1
  36. package/out/_not-found.txt +11 -11
  37. package/out/index.html +2 -2
  38. package/out/index.txt +13 -13
  39. package/package.json +130 -124
  40. package/out/_next/static/chunks/0bc0a50347ee5f3c.js +0 -51
  41. package/out/_next/static/chunks/58bf94a9d7047ec0.js +0 -125
  42. package/out/_next/static/chunks/6b84376656bd9887.js +0 -1
  43. package/out/_next/static/chunks/83ab8820627f8bfe.css +0 -1
  44. package/out/_next/static/chunks/ab8888d4b78b94be.js +0 -5
  45. package/out/_next/static/chunks/b6e8711267bccbbd.js +0 -1
  46. package/out/_next/static/chunks/fbca595129527827.js +0 -1
  47. package/scripts/publish-all.sh +0 -56
  48. /package/out/_next/static/{Ma0MmC8j1mxpQbtLwNajF → dSp6-CaehEDKVU9OSJABu}/_buildManifest.js +0 -0
  49. /package/out/_next/static/{Ma0MmC8j1mxpQbtLwNajF → dSp6-CaehEDKVU9OSJABu}/_clientMiddlewareManifest.json +0 -0
  50. /package/out/_next/static/{Ma0MmC8j1mxpQbtLwNajF → dSp6-CaehEDKVU9OSJABu}/_ssgManifest.js +0 -0
package/dist/server.js CHANGED
@@ -1,20 +1,24 @@
1
1
  #!/usr/bin/env node
2
-
3
- // src/server/index.ts
4
- import { createServer } from "http";
5
- import { readFile, stat } from "fs/promises";
6
- import { join as join2, extname, dirname as dirname2, resolve as resolve2 } from "path";
7
- import { fileURLToPath } from "url";
8
- import { existsSync as existsSync2 } from "fs";
9
-
10
- // src/lib/compiler/compiler.ts
11
- import { Project } from "ts-morph";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
+ };
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
12
11
 
13
12
  // src/lib/ir/types.ts
14
- var CURRENT_IR_VERSION = "1.0.0";
13
+ var CURRENT_IR_VERSION;
14
+ var init_types = __esm({
15
+ "src/lib/ir/types.ts"() {
16
+ "use strict";
17
+ CURRENT_IR_VERSION = "1.0.0";
18
+ }
19
+ });
15
20
 
16
21
  // src/lib/ir/migrations/engine.ts
17
- var migrations = [];
18
22
  function migrateIR(raw, targetVersion = CURRENT_IR_VERSION) {
19
23
  const applied = [];
20
24
  let current = { ...raw };
@@ -51,14 +55,30 @@ function migrateIR(raw, targetVersion = CURRENT_IR_VERSION) {
51
55
  function needsMigration(version, targetVersion = CURRENT_IR_VERSION) {
52
56
  return version !== targetVersion;
53
57
  }
54
- var MigrationError = class extends Error {
55
- constructor(message, fromVersion, targetVersion) {
56
- super(message);
57
- this.fromVersion = fromVersion;
58
- this.targetVersion = targetVersion;
59
- this.name = "MigrationError";
58
+ var migrations, MigrationError;
59
+ var init_engine = __esm({
60
+ "src/lib/ir/migrations/engine.ts"() {
61
+ "use strict";
62
+ init_types();
63
+ migrations = [];
64
+ MigrationError = class extends Error {
65
+ constructor(message, fromVersion, targetVersion) {
66
+ super(message);
67
+ this.fromVersion = fromVersion;
68
+ this.targetVersion = targetVersion;
69
+ this.name = "MigrationError";
70
+ }
71
+ };
60
72
  }
61
- };
73
+ });
74
+
75
+ // src/lib/ir/migrations/index.ts
76
+ var init_migrations = __esm({
77
+ "src/lib/ir/migrations/index.ts"() {
78
+ "use strict";
79
+ init_engine();
80
+ }
81
+ });
62
82
 
63
83
  // src/lib/ir/validator.ts
64
84
  function validateFlowIR(ir) {
@@ -185,14 +205,38 @@ function validateFlowIR(ir) {
185
205
  });
186
206
  }
187
207
  }
208
+ for (const edge of workingIR.edges) {
209
+ const sourceNode = workingNodeMap.get(edge.sourceNodeId);
210
+ const targetNode = workingNodeMap.get(edge.targetNodeId);
211
+ if (!sourceNode || !targetNode) continue;
212
+ const sourcePort = sourceNode.outputs?.find((p) => p.id === edge.sourcePortId);
213
+ const targetPort = targetNode.inputs?.find((p) => p.id === edge.targetPortId);
214
+ if (!sourcePort || !targetPort) continue;
215
+ if (!isTypeCompatible(sourcePort.dataType, targetPort.dataType)) {
216
+ errors.push({
217
+ code: "TYPE_MISMATCH",
218
+ message: `Type mismatch on edge "${edge.id}": output "${sourcePort.label}" (${sourcePort.dataType}) \u2192 input "${targetPort.label}" (${targetPort.dataType})`,
219
+ edgeId: edge.id,
220
+ severity: "warning"
221
+ });
222
+ }
223
+ }
188
224
  return {
189
- valid: errors.length === 0,
225
+ valid: errors.filter((e) => e.severity !== "warning" && e.severity !== "info").length === 0,
190
226
  errors,
191
227
  migrated,
192
228
  migratedIR: migrated ? workingIR : void 0,
193
229
  migrationLog
194
230
  };
195
231
  }
232
+ function isTypeCompatible(source, target) {
233
+ if (source === target) return true;
234
+ if (source === "any" || target === "any") return true;
235
+ if (target === "object" && source === "array") return true;
236
+ if (target === "string" && source === "number") return true;
237
+ if (target === "number" && source === "string") return true;
238
+ return false;
239
+ }
196
240
  function detectCycles(nodes, edges) {
197
241
  const errors = [];
198
242
  const adjacency = /* @__PURE__ */ new Map();
@@ -238,6 +282,13 @@ function detectCycles(nodes, edges) {
238
282
  }
239
283
  return errors;
240
284
  }
285
+ var init_validator = __esm({
286
+ "src/lib/ir/validator.ts"() {
287
+ "use strict";
288
+ init_types();
289
+ init_migrations();
290
+ }
291
+ });
241
292
 
242
293
  // src/lib/ir/topological-sort.ts
243
294
  function buildGraph(nodes, edges) {
@@ -310,6 +361,11 @@ function topologicalSort(ir) {
310
361
  dependents
311
362
  };
312
363
  }
364
+ var init_topological_sort = __esm({
365
+ "src/lib/ir/topological-sort.ts"() {
366
+ "use strict";
367
+ }
368
+ });
313
369
 
314
370
  // src/lib/compiler/expression-parser.ts
315
371
  function parseExpression(expr, context) {
@@ -460,8 +516,6 @@ function resolveInputRef(path, context) {
460
516
  `Expression parser error: Node "${context.currentNodeId}" has no input connected`
461
517
  );
462
518
  }
463
- var _cachedTriggerIR = null;
464
- var _cachedTriggerId = null;
465
519
  function resolveTriggerRef(path, context) {
466
520
  if (_cachedTriggerIR !== context.ir) {
467
521
  _cachedTriggerIR = context.ir;
@@ -478,17 +532,24 @@ function resolveTriggerRef(path, context) {
478
532
  }
479
533
  return "undefined";
480
534
  }
481
- var ExpressionParseError = class extends Error {
482
- constructor(message, expression, position) {
483
- super(message);
484
- this.expression = expression;
485
- this.position = position;
486
- this.name = "ExpressionParseError";
535
+ var _cachedTriggerIR, _cachedTriggerId, ExpressionParseError;
536
+ var init_expression_parser = __esm({
537
+ "src/lib/compiler/expression-parser.ts"() {
538
+ "use strict";
539
+ _cachedTriggerIR = null;
540
+ _cachedTriggerId = null;
541
+ ExpressionParseError = class extends Error {
542
+ constructor(message, expression, position) {
543
+ super(message);
544
+ this.expression = expression;
545
+ this.position = position;
546
+ this.name = "ExpressionParseError";
547
+ }
548
+ };
487
549
  }
488
- };
550
+ });
489
551
 
490
552
  // src/lib/compiler/platforms/types.ts
491
- var platformRegistry = /* @__PURE__ */ new Map();
492
553
  function registerPlatform(name, factory) {
493
554
  platformRegistry.set(name, factory);
494
555
  }
@@ -501,519 +562,557 @@ function getPlatform(name) {
501
562
  }
502
563
  return factory();
503
564
  }
565
+ var platformRegistry;
566
+ var init_types2 = __esm({
567
+ "src/lib/compiler/platforms/types.ts"() {
568
+ "use strict";
569
+ platformRegistry = /* @__PURE__ */ new Map();
570
+ }
571
+ });
504
572
 
505
573
  // src/lib/compiler/platforms/nextjs.ts
506
- var NextjsPlatform = class {
507
- name = "nextjs";
508
- generateImports(sourceFile, trigger, _context) {
509
- if (trigger.nodeType !== "http_webhook" /* HTTP_WEBHOOK */) return;
510
- const params = trigger.params;
511
- const isGetOrDelete = ["GET", "DELETE"].includes(params.method);
512
- sourceFile.addImportDeclaration({
513
- namedImports: isGetOrDelete ? ["NextRequest", "NextResponse"] : ["NextResponse"],
514
- moduleSpecifier: "next/server"
515
- });
516
- }
517
- generateFunction(sourceFile, trigger, _context, bodyGenerator) {
518
- switch (trigger.nodeType) {
519
- case "http_webhook" /* HTTP_WEBHOOK */:
520
- this.generateHttpFunction(sourceFile, trigger, bodyGenerator);
521
- break;
522
- case "cron_job" /* CRON_JOB */:
523
- this.generateCronFunction(sourceFile, trigger, bodyGenerator);
524
- break;
525
- case "manual" /* MANUAL */:
526
- this.generateManualFunction(sourceFile, trigger, bodyGenerator);
527
- break;
528
- default:
529
- throw new Error(`Unsupported trigger type: ${trigger.nodeType}`);
530
- }
531
- }
532
- generateResponse(writer, bodyExpr, statusCode, headers) {
533
- if (headers && Object.keys(headers).length > 0) {
534
- writer.writeLine(
535
- `throw new EarlyResponse(NextResponse.json(${bodyExpr}, { status: ${statusCode}, headers: ${JSON.stringify(headers)} }));`
536
- );
537
- } else {
538
- writer.writeLine(
539
- `throw new EarlyResponse(NextResponse.json(${bodyExpr}, { status: ${statusCode} }));`
540
- );
541
- }
542
- }
543
- generateErrorResponse(writer) {
544
- writer.write("if (error instanceof EarlyResponse) ").block(() => {
545
- writer.writeLine("return error.response;");
546
- });
547
- writer.writeLine('console.error("Workflow failed:", error);');
548
- writer.writeLine(
549
- 'return NextResponse.json({ error: error instanceof Error ? error.message : "Internal Server Error" }, { status: 500 });'
550
- );
551
- }
552
- getOutputFilePath(trigger) {
553
- if (trigger.nodeType === "http_webhook" /* HTTP_WEBHOOK */) {
554
- const params = trigger.params;
555
- const routePath = params.routePath.replace(/^\//, "");
556
- return `src/app/${routePath}/route.ts`;
557
- }
558
- if (trigger.nodeType === "cron_job" /* CRON_JOB */) {
559
- const params = trigger.params;
560
- return `src/lib/cron/${params.functionName}.ts`;
561
- }
562
- if (trigger.nodeType === "manual" /* MANUAL */) {
563
- const params = trigger.params;
564
- return `src/lib/functions/${params.functionName}.ts`;
565
- }
566
- return "src/generated/flow.ts";
567
- }
568
- getImplicitDependencies() {
569
- return [];
570
- }
571
- generateTriggerInit(writer, trigger, context) {
572
- const varName = context.symbolTable.getVarName(trigger.id);
573
- switch (trigger.nodeType) {
574
- case "http_webhook" /* HTTP_WEBHOOK */: {
574
+ var NextjsPlatform;
575
+ var init_nextjs = __esm({
576
+ "src/lib/compiler/platforms/nextjs.ts"() {
577
+ "use strict";
578
+ NextjsPlatform = class {
579
+ name = "nextjs";
580
+ generateImports(sourceFile, trigger, _context) {
581
+ if (trigger.nodeType !== "http_webhook" /* HTTP_WEBHOOK */) return;
575
582
  const params = trigger.params;
576
583
  const isGetOrDelete = ["GET", "DELETE"].includes(params.method);
577
- if (isGetOrDelete) {
578
- writer.writeLine("const searchParams = req.nextUrl.searchParams;");
584
+ sourceFile.addImportDeclaration({
585
+ namedImports: isGetOrDelete ? ["NextRequest", "NextResponse"] : ["NextResponse"],
586
+ moduleSpecifier: "next/server"
587
+ });
588
+ }
589
+ generateFunction(sourceFile, trigger, _context, bodyGenerator) {
590
+ switch (trigger.nodeType) {
591
+ case "http_webhook" /* HTTP_WEBHOOK */:
592
+ this.generateHttpFunction(sourceFile, trigger, bodyGenerator);
593
+ break;
594
+ case "cron_job" /* CRON_JOB */:
595
+ this.generateCronFunction(sourceFile, trigger, bodyGenerator);
596
+ break;
597
+ case "manual" /* MANUAL */:
598
+ this.generateManualFunction(sourceFile, trigger, bodyGenerator);
599
+ break;
600
+ default:
601
+ throw new Error(`Unsupported trigger type: ${trigger.nodeType}`);
602
+ }
603
+ }
604
+ generateResponse(writer, bodyExpr, statusCode, headers) {
605
+ if (headers && Object.keys(headers).length > 0) {
579
606
  writer.writeLine(
580
- "const query = Object.fromEntries(searchParams.entries());"
607
+ `throw new EarlyResponse(NextResponse.json(${bodyExpr}, { status: ${statusCode}, headers: ${JSON.stringify(headers)} }));`
581
608
  );
582
- writer.writeLine(`const ${varName} = { query, url: req.url };`);
583
- writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
584
- } else if (params.parseBody && ["POST", "PUT", "PATCH"].includes(params.method)) {
585
- writer.writeLine("let body: unknown;");
586
- writer.write("try ").block(() => {
587
- writer.writeLine("body = await req.json();");
588
- });
589
- writer.write(" catch ").block(() => {
590
- writer.writeLine(
591
- 'return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 });'
592
- );
593
- });
594
- writer.writeLine(`const ${varName} = { body, url: req.url };`);
595
- writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
596
609
  } else {
597
- writer.writeLine(`const ${varName} = { url: req.url };`);
598
- writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
610
+ writer.writeLine(
611
+ `throw new EarlyResponse(NextResponse.json(${bodyExpr}, { status: ${statusCode} }));`
612
+ );
599
613
  }
600
- break;
601
614
  }
602
- case "cron_job" /* CRON_JOB */: {
615
+ generateErrorResponse(writer) {
616
+ writer.write("if (error instanceof EarlyResponse) ").block(() => {
617
+ writer.writeLine("return error.response;");
618
+ });
619
+ writer.writeLine('console.error("Workflow failed:", error);');
603
620
  writer.writeLine(
604
- `const ${varName} = { triggeredAt: new Date().toISOString() };`
621
+ 'return NextResponse.json({ error: error instanceof Error ? error.message : "Internal Server Error" }, { status: 500 });'
605
622
  );
606
- writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
607
- break;
608
623
  }
609
- case "manual" /* MANUAL */: {
610
- const params = trigger.params;
611
- if (params.args.length > 0) {
612
- const argsObj = params.args.map((a) => a.name).join(", ");
613
- writer.writeLine(`const ${varName} = { ${argsObj} };`);
614
- writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
624
+ getOutputFilePath(trigger) {
625
+ if (trigger.nodeType === "http_webhook" /* HTTP_WEBHOOK */) {
626
+ const params = trigger.params;
627
+ const routePath = params.routePath.replace(/^\//, "");
628
+ return `src/app/${routePath}/route.ts`;
615
629
  }
616
- break;
630
+ if (trigger.nodeType === "cron_job" /* CRON_JOB */) {
631
+ const params = trigger.params;
632
+ return `src/lib/cron/${params.functionName}.ts`;
633
+ }
634
+ if (trigger.nodeType === "manual" /* MANUAL */) {
635
+ const params = trigger.params;
636
+ return `src/lib/functions/${params.functionName}.ts`;
637
+ }
638
+ return "src/generated/flow.ts";
617
639
  }
618
- }
619
- }
620
- // ── Private ──
621
- generateHttpFunction(sourceFile, trigger, bodyGenerator) {
622
- const params = trigger.params;
623
- const isGetOrDelete = ["GET", "DELETE"].includes(params.method);
624
- const funcDecl = sourceFile.addFunction({
625
- name: params.method,
626
- isAsync: true,
627
- isExported: true,
628
- parameters: [
629
- { name: "req", type: isGetOrDelete ? "NextRequest" : "Request" }
630
- ]
631
- });
632
- sourceFile.insertStatements(funcDecl.getChildIndex(), (writer) => {
633
- writer.writeLine("class EarlyResponse extends Error {");
634
- writer.writeLine(" constructor(public response: Response) { super(); }");
635
- writer.writeLine("}");
636
- writer.blankLine();
637
- });
638
- funcDecl.addStatements((writer) => {
639
- writer.write("try ").block(() => {
640
- bodyGenerator(writer);
641
- });
642
- writer.write(" catch (error) ").block(() => {
643
- this.generateErrorResponse(writer);
644
- });
645
- });
646
- }
647
- generateCronFunction(sourceFile, trigger, bodyGenerator) {
648
- const params = trigger.params;
649
- sourceFile.addStatements(`// @schedule ${params.schedule}`);
650
- const funcDecl = sourceFile.addFunction({
651
- name: params.functionName,
652
- isAsync: true,
653
- isExported: true
654
- });
655
- funcDecl.addStatements((writer) => {
656
- bodyGenerator(writer);
657
- });
658
- }
659
- generateManualFunction(sourceFile, trigger, bodyGenerator) {
660
- const params = trigger.params;
661
- const funcDecl = sourceFile.addFunction({
662
- name: params.functionName,
663
- isAsync: true,
664
- isExported: true,
665
- parameters: params.args.map((arg) => ({
666
- name: arg.name,
667
- type: arg.type
668
- }))
669
- });
670
- funcDecl.addStatements((writer) => {
671
- bodyGenerator(writer);
672
- });
640
+ getImplicitDependencies() {
641
+ return [];
642
+ }
643
+ generateTriggerInit(writer, trigger, context) {
644
+ const varName = context.symbolTable.getVarName(trigger.id);
645
+ switch (trigger.nodeType) {
646
+ case "http_webhook" /* HTTP_WEBHOOK */: {
647
+ const params = trigger.params;
648
+ const isGetOrDelete = ["GET", "DELETE"].includes(params.method);
649
+ if (isGetOrDelete) {
650
+ writer.writeLine("const searchParams = req.nextUrl.searchParams;");
651
+ writer.writeLine(
652
+ "const query = Object.fromEntries(searchParams.entries());"
653
+ );
654
+ writer.writeLine(`const ${varName} = { query, url: req.url };`);
655
+ writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
656
+ } else if (params.parseBody && ["POST", "PUT", "PATCH"].includes(params.method)) {
657
+ writer.writeLine("let body: unknown;");
658
+ writer.write("try ").block(() => {
659
+ writer.writeLine("body = await req.json();");
660
+ });
661
+ writer.write(" catch ").block(() => {
662
+ writer.writeLine(
663
+ 'return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 });'
664
+ );
665
+ });
666
+ writer.writeLine(`const ${varName} = { body, url: req.url };`);
667
+ writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
668
+ } else {
669
+ writer.writeLine(`const ${varName} = { url: req.url };`);
670
+ writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
671
+ }
672
+ break;
673
+ }
674
+ case "cron_job" /* CRON_JOB */: {
675
+ writer.writeLine(
676
+ `const ${varName} = { triggeredAt: new Date().toISOString() };`
677
+ );
678
+ writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
679
+ break;
680
+ }
681
+ case "manual" /* MANUAL */: {
682
+ const params = trigger.params;
683
+ if (params.args.length > 0) {
684
+ const argsObj = params.args.map((a) => a.name).join(", ");
685
+ writer.writeLine(`const ${varName} = { ${argsObj} };`);
686
+ writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
687
+ }
688
+ break;
689
+ }
690
+ }
691
+ }
692
+ // ── Private ──
693
+ generateHttpFunction(sourceFile, trigger, bodyGenerator) {
694
+ const params = trigger.params;
695
+ const isGetOrDelete = ["GET", "DELETE"].includes(params.method);
696
+ const funcDecl = sourceFile.addFunction({
697
+ name: params.method,
698
+ isAsync: true,
699
+ isExported: true,
700
+ parameters: [
701
+ { name: "req", type: isGetOrDelete ? "NextRequest" : "Request" }
702
+ ]
703
+ });
704
+ sourceFile.insertStatements(funcDecl.getChildIndex(), (writer) => {
705
+ writer.writeLine("class EarlyResponse extends Error {");
706
+ writer.writeLine(" constructor(public response: Response) { super(); }");
707
+ writer.writeLine("}");
708
+ writer.blankLine();
709
+ });
710
+ funcDecl.addStatements((writer) => {
711
+ writer.write("try ").block(() => {
712
+ bodyGenerator(writer);
713
+ });
714
+ writer.write(" catch (error) ").block(() => {
715
+ this.generateErrorResponse(writer);
716
+ });
717
+ });
718
+ }
719
+ generateCronFunction(sourceFile, trigger, bodyGenerator) {
720
+ const params = trigger.params;
721
+ sourceFile.addStatements(`// @schedule ${params.schedule}`);
722
+ const funcDecl = sourceFile.addFunction({
723
+ name: params.functionName,
724
+ isAsync: true,
725
+ isExported: true
726
+ });
727
+ funcDecl.addStatements((writer) => {
728
+ bodyGenerator(writer);
729
+ });
730
+ }
731
+ generateManualFunction(sourceFile, trigger, bodyGenerator) {
732
+ const params = trigger.params;
733
+ const funcDecl = sourceFile.addFunction({
734
+ name: params.functionName,
735
+ isAsync: true,
736
+ isExported: true,
737
+ parameters: params.args.map((arg) => ({
738
+ name: arg.name,
739
+ type: arg.type
740
+ }))
741
+ });
742
+ funcDecl.addStatements((writer) => {
743
+ bodyGenerator(writer);
744
+ });
745
+ }
746
+ };
673
747
  }
674
- };
748
+ });
675
749
 
676
750
  // src/lib/compiler/platforms/express.ts
677
- var ExpressPlatform = class {
678
- name = "express";
679
- generateImports(sourceFile, trigger, _context) {
680
- if (trigger.nodeType === "http_webhook" /* HTTP_WEBHOOK */) {
681
- sourceFile.addImportDeclaration({
682
- namedImports: ["Request", "Response"],
683
- moduleSpecifier: "express"
684
- });
685
- }
686
- }
687
- generateFunction(sourceFile, trigger, _context, bodyGenerator) {
688
- switch (trigger.nodeType) {
689
- case "http_webhook" /* HTTP_WEBHOOK */:
690
- this.generateHttpHandler(sourceFile, trigger, bodyGenerator);
691
- break;
692
- case "cron_job" /* CRON_JOB */:
693
- this.generateCronFunction(sourceFile, trigger, bodyGenerator);
694
- break;
695
- case "manual" /* MANUAL */:
696
- this.generateManualFunction(sourceFile, trigger, bodyGenerator);
697
- break;
698
- default:
699
- throw new Error(`Unsupported trigger type: ${trigger.nodeType}`);
700
- }
701
- }
702
- generateResponse(writer, bodyExpr, statusCode, headers) {
703
- if (headers && Object.keys(headers).length > 0) {
704
- for (const [key, value] of Object.entries(headers)) {
705
- writer.writeLine(`res.setHeader(${JSON.stringify(key)}, ${JSON.stringify(value)});`);
751
+ var ExpressPlatform;
752
+ var init_express = __esm({
753
+ "src/lib/compiler/platforms/express.ts"() {
754
+ "use strict";
755
+ ExpressPlatform = class {
756
+ name = "express";
757
+ generateImports(sourceFile, trigger, _context) {
758
+ if (trigger.nodeType === "http_webhook" /* HTTP_WEBHOOK */) {
759
+ sourceFile.addImportDeclaration({
760
+ namedImports: ["Request", "Response"],
761
+ moduleSpecifier: "express"
762
+ });
763
+ }
706
764
  }
707
- }
708
- writer.writeLine(`throw new EarlyResponse(() => res.status(${statusCode}).json(${bodyExpr}));`);
709
- }
710
- generateErrorResponse(writer) {
711
- writer.write("if (error instanceof EarlyResponse) ").block(() => {
712
- writer.writeLine("return error.send();");
713
- });
714
- writer.writeLine('console.error("Workflow failed:", error);');
715
- writer.writeLine(
716
- 'return res.status(500).json({ error: error instanceof Error ? error.message : "Internal Server Error" });'
717
- );
718
- }
719
- getOutputFilePath(trigger) {
720
- if (trigger.nodeType === "http_webhook" /* HTTP_WEBHOOK */) {
721
- const params = trigger.params;
722
- const routePath = params.routePath.replace(/^\//, "").replace(/\//g, "-");
723
- return `src/routes/${routePath}.ts`;
724
- }
725
- if (trigger.nodeType === "cron_job" /* CRON_JOB */) {
726
- const params = trigger.params;
727
- return `src/cron/${params.functionName}.ts`;
728
- }
729
- if (trigger.nodeType === "manual" /* MANUAL */) {
730
- const params = trigger.params;
731
- return `src/functions/${params.functionName}.ts`;
732
- }
733
- return "src/generated/flow.ts";
734
- }
735
- getImplicitDependencies() {
736
- return ["express", "@types/express"];
737
- }
738
- generateTriggerInit(writer, trigger, context) {
739
- const varName = context.symbolTable.getVarName(trigger.id);
740
- switch (trigger.nodeType) {
741
- case "http_webhook" /* HTTP_WEBHOOK */: {
742
- const params = trigger.params;
743
- const isGetOrDelete = ["GET", "DELETE"].includes(params.method);
744
- if (isGetOrDelete) {
745
- writer.writeLine(
746
- "const query = req.query as Record<string, string>;"
747
- );
748
- writer.writeLine(
749
- `const ${varName} = { query, url: req.originalUrl };`
750
- );
751
- writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
752
- } else if (params.parseBody && ["POST", "PUT", "PATCH"].includes(params.method)) {
753
- writer.writeLine("const body = req.body;");
754
- writer.writeLine(
755
- `const ${varName} = { body, url: req.originalUrl };`
756
- );
757
- writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
758
- } else {
759
- writer.writeLine(
760
- `const ${varName} = { url: req.originalUrl };`
761
- );
762
- writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
765
+ generateFunction(sourceFile, trigger, _context, bodyGenerator) {
766
+ switch (trigger.nodeType) {
767
+ case "http_webhook" /* HTTP_WEBHOOK */:
768
+ this.generateHttpHandler(sourceFile, trigger, bodyGenerator);
769
+ break;
770
+ case "cron_job" /* CRON_JOB */:
771
+ this.generateCronFunction(sourceFile, trigger, bodyGenerator);
772
+ break;
773
+ case "manual" /* MANUAL */:
774
+ this.generateManualFunction(sourceFile, trigger, bodyGenerator);
775
+ break;
776
+ default:
777
+ throw new Error(`Unsupported trigger type: ${trigger.nodeType}`);
763
778
  }
764
- break;
765
779
  }
766
- case "cron_job" /* CRON_JOB */: {
780
+ generateResponse(writer, bodyExpr, statusCode, headers) {
781
+ if (headers && Object.keys(headers).length > 0) {
782
+ for (const [key, value] of Object.entries(headers)) {
783
+ writer.writeLine(`res.setHeader(${JSON.stringify(key)}, ${JSON.stringify(value)});`);
784
+ }
785
+ }
786
+ writer.writeLine(`throw new EarlyResponse(() => res.status(${statusCode}).json(${bodyExpr}));`);
787
+ }
788
+ generateErrorResponse(writer) {
789
+ writer.write("if (error instanceof EarlyResponse) ").block(() => {
790
+ writer.writeLine("return error.send();");
791
+ });
792
+ writer.writeLine('console.error("Workflow failed:", error);');
767
793
  writer.writeLine(
768
- `const ${varName} = { triggeredAt: new Date().toISOString() };`
794
+ 'return res.status(500).json({ error: error instanceof Error ? error.message : "Internal Server Error" });'
769
795
  );
770
- writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
771
- break;
772
796
  }
773
- case "manual" /* MANUAL */: {
774
- const params = trigger.params;
775
- if (params.args.length > 0) {
776
- const argsObj = params.args.map((a) => a.name).join(", ");
777
- writer.writeLine(`const ${varName} = { ${argsObj} };`);
778
- writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
797
+ getOutputFilePath(trigger) {
798
+ if (trigger.nodeType === "http_webhook" /* HTTP_WEBHOOK */) {
799
+ const params = trigger.params;
800
+ const routePath = params.routePath.replace(/^\//, "").replace(/\//g, "-");
801
+ return `src/routes/${routePath}.ts`;
779
802
  }
780
- break;
803
+ if (trigger.nodeType === "cron_job" /* CRON_JOB */) {
804
+ const params = trigger.params;
805
+ return `src/cron/${params.functionName}.ts`;
806
+ }
807
+ if (trigger.nodeType === "manual" /* MANUAL */) {
808
+ const params = trigger.params;
809
+ return `src/functions/${params.functionName}.ts`;
810
+ }
811
+ return "src/generated/flow.ts";
781
812
  }
782
- }
783
- }
784
- // ── Private ──
785
- generateHttpHandler(sourceFile, trigger, bodyGenerator) {
786
- const params = trigger.params;
787
- const funcDecl = sourceFile.addFunction({
788
- name: `handle${params.method.charAt(0)}${params.method.slice(1).toLowerCase()}`,
789
- isAsync: true,
790
- isExported: true,
791
- parameters: [
792
- { name: "req", type: "Request" },
793
- { name: "res", type: "Response" }
794
- ]
795
- });
796
- sourceFile.insertStatements(funcDecl.getChildIndex(), (writer) => {
797
- writer.writeLine("class EarlyResponse extends Error {");
798
- writer.writeLine(" constructor(public send: () => void) { super(); }");
799
- writer.writeLine("}");
800
- writer.blankLine();
801
- });
802
- funcDecl.addStatements((writer) => {
803
- writer.write("try ").block(() => {
804
- bodyGenerator(writer);
805
- });
806
- writer.write(" catch (error) ").block(() => {
807
- this.generateErrorResponse(writer);
808
- });
809
- });
810
- }
811
- generateCronFunction(sourceFile, trigger, bodyGenerator) {
812
- const params = trigger.params;
813
- sourceFile.addStatements(`// @schedule ${params.schedule}`);
814
- const funcDecl = sourceFile.addFunction({
815
- name: params.functionName,
816
- isAsync: true,
817
- isExported: true
818
- });
819
- funcDecl.addStatements((writer) => {
820
- bodyGenerator(writer);
821
- });
822
- }
823
- generateManualFunction(sourceFile, trigger, bodyGenerator) {
824
- const params = trigger.params;
825
- const funcDecl = sourceFile.addFunction({
826
- name: params.functionName,
827
- isAsync: true,
828
- isExported: true,
829
- parameters: params.args.map((arg) => ({
830
- name: arg.name,
831
- type: arg.type
832
- }))
833
- });
834
- funcDecl.addStatements((writer) => {
835
- bodyGenerator(writer);
836
- });
837
- }
838
- };
839
-
840
- // src/lib/compiler/platforms/cloudflare.ts
841
- var CloudflarePlatform = class {
842
- name = "cloudflare";
843
- generateImports(_sourceFile, _trigger, _context) {
844
- }
845
- generateFunction(sourceFile, trigger, _context, bodyGenerator) {
846
- switch (trigger.nodeType) {
847
- case "http_webhook" /* HTTP_WEBHOOK */:
848
- this.generateFetchHandler(sourceFile, trigger, bodyGenerator);
849
- break;
850
- case "cron_job" /* CRON_JOB */:
851
- this.generateScheduledHandler(sourceFile, trigger, bodyGenerator);
852
- break;
853
- case "manual" /* MANUAL */:
854
- this.generateManualFunction(sourceFile, trigger, bodyGenerator);
855
- break;
856
- default:
857
- throw new Error(`Unsupported trigger type: ${trigger.nodeType}`);
858
- }
859
- }
860
- generateResponse(writer, bodyExpr, statusCode, headers) {
861
- const headersObj = headers && Object.keys(headers).length > 0 ? `, { status: ${statusCode}, headers: ${JSON.stringify({ "Content-Type": "application/json", ...headers })} }` : `, { status: ${statusCode}, headers: { "Content-Type": "application/json" } }`;
862
- writer.writeLine(
863
- `throw new EarlyResponse(new Response(JSON.stringify(${bodyExpr})${headersObj}));`
864
- );
865
- }
866
- generateErrorResponse(writer) {
867
- writer.write("if (error instanceof EarlyResponse) ").block(() => {
868
- writer.writeLine("return error.response;");
869
- });
870
- writer.writeLine('console.error("Workflow failed:", error);');
871
- writer.writeLine(
872
- `return new Response(JSON.stringify({ error: error instanceof Error ? error.message : "Internal Server Error" }), { status: 500, headers: { "Content-Type": "application/json" } });`
873
- );
874
- }
875
- getOutputFilePath(trigger) {
876
- if (trigger.nodeType === "http_webhook" /* HTTP_WEBHOOK */) {
877
- return "src/worker.ts";
878
- }
879
- if (trigger.nodeType === "cron_job" /* CRON_JOB */) {
880
- const params = trigger.params;
881
- return `src/scheduled/${params.functionName}.ts`;
882
- }
883
- if (trigger.nodeType === "manual" /* MANUAL */) {
884
- const params = trigger.params;
885
- return `src/functions/${params.functionName}.ts`;
886
- }
887
- return "src/generated/flow.ts";
888
- }
889
- getImplicitDependencies() {
890
- return ["@cloudflare/workers-types"];
891
- }
892
- generateTriggerInit(writer, trigger, context) {
893
- const varName = context.symbolTable.getVarName(trigger.id);
894
- switch (trigger.nodeType) {
895
- case "http_webhook" /* HTTP_WEBHOOK */: {
813
+ getImplicitDependencies() {
814
+ return ["express", "@types/express"];
815
+ }
816
+ generateTriggerInit(writer, trigger, context) {
817
+ const varName = context.symbolTable.getVarName(trigger.id);
818
+ switch (trigger.nodeType) {
819
+ case "http_webhook" /* HTTP_WEBHOOK */: {
820
+ const params = trigger.params;
821
+ const isGetOrDelete = ["GET", "DELETE"].includes(params.method);
822
+ if (isGetOrDelete) {
823
+ writer.writeLine(
824
+ "const query = req.query as Record<string, string>;"
825
+ );
826
+ writer.writeLine(
827
+ `const ${varName} = { query, url: req.originalUrl };`
828
+ );
829
+ writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
830
+ } else if (params.parseBody && ["POST", "PUT", "PATCH"].includes(params.method)) {
831
+ writer.writeLine("const body = req.body;");
832
+ writer.writeLine(
833
+ `const ${varName} = { body, url: req.originalUrl };`
834
+ );
835
+ writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
836
+ } else {
837
+ writer.writeLine(
838
+ `const ${varName} = { url: req.originalUrl };`
839
+ );
840
+ writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
841
+ }
842
+ break;
843
+ }
844
+ case "cron_job" /* CRON_JOB */: {
845
+ writer.writeLine(
846
+ `const ${varName} = { triggeredAt: new Date().toISOString() };`
847
+ );
848
+ writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
849
+ break;
850
+ }
851
+ case "manual" /* MANUAL */: {
852
+ const params = trigger.params;
853
+ if (params.args.length > 0) {
854
+ const argsObj = params.args.map((a) => a.name).join(", ");
855
+ writer.writeLine(`const ${varName} = { ${argsObj} };`);
856
+ writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
857
+ }
858
+ break;
859
+ }
860
+ }
861
+ }
862
+ // ── Private ──
863
+ generateHttpHandler(sourceFile, trigger, bodyGenerator) {
896
864
  const params = trigger.params;
897
- const isGetOrDelete = ["GET", "DELETE"].includes(params.method);
898
- if (isGetOrDelete) {
899
- writer.writeLine(
900
- "const url = new URL(request.url);"
901
- );
902
- writer.writeLine(
903
- "const query = Object.fromEntries(url.searchParams.entries());"
904
- );
905
- writer.writeLine(
906
- `const ${varName} = { query, url: request.url };`
907
- );
908
- writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
909
- } else if (params.parseBody && ["POST", "PUT", "PATCH"].includes(params.method)) {
910
- writer.writeLine("let body: unknown;");
865
+ const funcDecl = sourceFile.addFunction({
866
+ name: `handle${params.method.charAt(0)}${params.method.slice(1).toLowerCase()}`,
867
+ isAsync: true,
868
+ isExported: true,
869
+ parameters: [
870
+ { name: "req", type: "Request" },
871
+ { name: "res", type: "Response" }
872
+ ]
873
+ });
874
+ sourceFile.insertStatements(funcDecl.getChildIndex(), (writer) => {
875
+ writer.writeLine("class EarlyResponse extends Error {");
876
+ writer.writeLine(" constructor(public send: () => void) { super(); }");
877
+ writer.writeLine("}");
878
+ writer.blankLine();
879
+ });
880
+ funcDecl.addStatements((writer) => {
911
881
  writer.write("try ").block(() => {
912
- writer.writeLine("body = await request.json();");
882
+ bodyGenerator(writer);
913
883
  });
914
- writer.write(" catch ").block(() => {
915
- writer.writeLine(
916
- 'return new Response(JSON.stringify({ error: "Invalid JSON body" }), { status: 400, headers: { "Content-Type": "application/json" } });'
917
- );
884
+ writer.write(" catch (error) ").block(() => {
885
+ this.generateErrorResponse(writer);
918
886
  });
919
- writer.writeLine(
920
- `const ${varName} = { body, url: request.url };`
921
- );
922
- writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
923
- } else {
924
- writer.writeLine(
925
- `const ${varName} = { url: request.url };`
926
- );
927
- writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
887
+ });
888
+ }
889
+ generateCronFunction(sourceFile, trigger, bodyGenerator) {
890
+ const params = trigger.params;
891
+ sourceFile.addStatements(`// @schedule ${params.schedule}`);
892
+ const funcDecl = sourceFile.addFunction({
893
+ name: params.functionName,
894
+ isAsync: true,
895
+ isExported: true
896
+ });
897
+ funcDecl.addStatements((writer) => {
898
+ bodyGenerator(writer);
899
+ });
900
+ }
901
+ generateManualFunction(sourceFile, trigger, bodyGenerator) {
902
+ const params = trigger.params;
903
+ const funcDecl = sourceFile.addFunction({
904
+ name: params.functionName,
905
+ isAsync: true,
906
+ isExported: true,
907
+ parameters: params.args.map((arg) => ({
908
+ name: arg.name,
909
+ type: arg.type
910
+ }))
911
+ });
912
+ funcDecl.addStatements((writer) => {
913
+ bodyGenerator(writer);
914
+ });
915
+ }
916
+ };
917
+ }
918
+ });
919
+
920
+ // src/lib/compiler/platforms/cloudflare.ts
921
+ var CloudflarePlatform;
922
+ var init_cloudflare = __esm({
923
+ "src/lib/compiler/platforms/cloudflare.ts"() {
924
+ "use strict";
925
+ CloudflarePlatform = class {
926
+ name = "cloudflare";
927
+ generateImports(_sourceFile, _trigger, _context) {
928
+ }
929
+ generateFunction(sourceFile, trigger, _context, bodyGenerator) {
930
+ switch (trigger.nodeType) {
931
+ case "http_webhook" /* HTTP_WEBHOOK */:
932
+ this.generateFetchHandler(sourceFile, trigger, bodyGenerator);
933
+ break;
934
+ case "cron_job" /* CRON_JOB */:
935
+ this.generateScheduledHandler(sourceFile, trigger, bodyGenerator);
936
+ break;
937
+ case "manual" /* MANUAL */:
938
+ this.generateManualFunction(sourceFile, trigger, bodyGenerator);
939
+ break;
940
+ default:
941
+ throw new Error(`Unsupported trigger type: ${trigger.nodeType}`);
928
942
  }
929
- break;
930
943
  }
931
- case "cron_job" /* CRON_JOB */: {
944
+ generateResponse(writer, bodyExpr, statusCode, headers) {
945
+ const headersObj = headers && Object.keys(headers).length > 0 ? `, { status: ${statusCode}, headers: ${JSON.stringify({ "Content-Type": "application/json", ...headers })} }` : `, { status: ${statusCode}, headers: { "Content-Type": "application/json" } }`;
932
946
  writer.writeLine(
933
- `const ${varName} = { triggeredAt: new Date().toISOString() };`
947
+ `throw new EarlyResponse(new Response(JSON.stringify(${bodyExpr})${headersObj}));`
934
948
  );
935
- writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
936
- break;
937
949
  }
938
- case "manual" /* MANUAL */: {
939
- const params = trigger.params;
940
- if (params.args.length > 0) {
941
- const argsObj = params.args.map((a) => a.name).join(", ");
942
- writer.writeLine(`const ${varName} = { ${argsObj} };`);
943
- writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
950
+ generateErrorResponse(writer) {
951
+ writer.write("if (error instanceof EarlyResponse) ").block(() => {
952
+ writer.writeLine("return error.response;");
953
+ });
954
+ writer.writeLine('console.error("Workflow failed:", error);');
955
+ writer.writeLine(
956
+ `return new Response(JSON.stringify({ error: error instanceof Error ? error.message : "Internal Server Error" }), { status: 500, headers: { "Content-Type": "application/json" } });`
957
+ );
958
+ }
959
+ getOutputFilePath(trigger) {
960
+ if (trigger.nodeType === "http_webhook" /* HTTP_WEBHOOK */) {
961
+ return "src/worker.ts";
944
962
  }
945
- break;
963
+ if (trigger.nodeType === "cron_job" /* CRON_JOB */) {
964
+ const params = trigger.params;
965
+ return `src/scheduled/${params.functionName}.ts`;
966
+ }
967
+ if (trigger.nodeType === "manual" /* MANUAL */) {
968
+ const params = trigger.params;
969
+ return `src/functions/${params.functionName}.ts`;
970
+ }
971
+ return "src/generated/flow.ts";
946
972
  }
947
- }
948
- }
949
- // ── Private ──
950
- generateFetchHandler(sourceFile, trigger, bodyGenerator) {
951
- const params = trigger.params;
952
- sourceFile.addStatements(`// Cloudflare Workers handler`);
953
- const funcDecl = sourceFile.addFunction({
954
- name: "handleRequest",
955
- isAsync: true,
956
- isExported: true,
957
- parameters: [
958
- { name: "request", type: "Request" },
959
- { name: "env", type: "Env" },
960
- { name: "ctx", type: "ExecutionContext" }
961
- ]
962
- });
963
- sourceFile.insertStatements(funcDecl.getChildIndex(), (writer) => {
964
- writer.writeLine("class EarlyResponse extends Error {");
965
- writer.writeLine(" constructor(public response: Response) { super(); }");
966
- writer.writeLine("}");
967
- writer.blankLine();
968
- });
969
- funcDecl.addStatements((writer) => {
970
- writer.write("try ").block(() => {
971
- bodyGenerator(writer);
972
- });
973
- writer.write(" catch (error) ").block(() => {
974
- this.generateErrorResponse(writer);
975
- });
976
- });
977
- sourceFile.addStatements(`
973
+ getImplicitDependencies() {
974
+ return ["@cloudflare/workers-types"];
975
+ }
976
+ generateTriggerInit(writer, trigger, context) {
977
+ const varName = context.symbolTable.getVarName(trigger.id);
978
+ switch (trigger.nodeType) {
979
+ case "http_webhook" /* HTTP_WEBHOOK */: {
980
+ const params = trigger.params;
981
+ const isGetOrDelete = ["GET", "DELETE"].includes(params.method);
982
+ if (isGetOrDelete) {
983
+ writer.writeLine(
984
+ "const url = new URL(request.url);"
985
+ );
986
+ writer.writeLine(
987
+ "const query = Object.fromEntries(url.searchParams.entries());"
988
+ );
989
+ writer.writeLine(
990
+ `const ${varName} = { query, url: request.url };`
991
+ );
992
+ writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
993
+ } else if (params.parseBody && ["POST", "PUT", "PATCH"].includes(params.method)) {
994
+ writer.writeLine("let body: unknown;");
995
+ writer.write("try ").block(() => {
996
+ writer.writeLine("body = await request.json();");
997
+ });
998
+ writer.write(" catch ").block(() => {
999
+ writer.writeLine(
1000
+ 'return new Response(JSON.stringify({ error: "Invalid JSON body" }), { status: 400, headers: { "Content-Type": "application/json" } });'
1001
+ );
1002
+ });
1003
+ writer.writeLine(
1004
+ `const ${varName} = { body, url: request.url };`
1005
+ );
1006
+ writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
1007
+ } else {
1008
+ writer.writeLine(
1009
+ `const ${varName} = { url: request.url };`
1010
+ );
1011
+ writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
1012
+ }
1013
+ break;
1014
+ }
1015
+ case "cron_job" /* CRON_JOB */: {
1016
+ writer.writeLine(
1017
+ `const ${varName} = { triggeredAt: new Date().toISOString() };`
1018
+ );
1019
+ writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
1020
+ break;
1021
+ }
1022
+ case "manual" /* MANUAL */: {
1023
+ const params = trigger.params;
1024
+ if (params.args.length > 0) {
1025
+ const argsObj = params.args.map((a) => a.name).join(", ");
1026
+ writer.writeLine(`const ${varName} = { ${argsObj} };`);
1027
+ writer.writeLine(`flowState['${trigger.id}'] = ${varName};`);
1028
+ }
1029
+ break;
1030
+ }
1031
+ }
1032
+ }
1033
+ // ── Private ──
1034
+ generateFetchHandler(sourceFile, trigger, bodyGenerator) {
1035
+ const params = trigger.params;
1036
+ sourceFile.addStatements(`// Cloudflare Workers handler`);
1037
+ const funcDecl = sourceFile.addFunction({
1038
+ name: "handleRequest",
1039
+ isAsync: true,
1040
+ isExported: true,
1041
+ parameters: [
1042
+ { name: "request", type: "Request" },
1043
+ { name: "env", type: "Env" },
1044
+ { name: "ctx", type: "ExecutionContext" }
1045
+ ]
1046
+ });
1047
+ sourceFile.insertStatements(funcDecl.getChildIndex(), (writer) => {
1048
+ writer.writeLine("class EarlyResponse extends Error {");
1049
+ writer.writeLine(" constructor(public response: Response) { super(); }");
1050
+ writer.writeLine("}");
1051
+ writer.blankLine();
1052
+ });
1053
+ funcDecl.addStatements((writer) => {
1054
+ writer.write("try ").block(() => {
1055
+ bodyGenerator(writer);
1056
+ });
1057
+ writer.write(" catch (error) ").block(() => {
1058
+ this.generateErrorResponse(writer);
1059
+ });
1060
+ });
1061
+ sourceFile.addStatements(`
978
1062
  export default {
979
1063
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
980
1064
  return handleRequest(request, env, ctx);
981
1065
  },
982
1066
  };`);
1067
+ }
1068
+ generateScheduledHandler(sourceFile, trigger, bodyGenerator) {
1069
+ const params = trigger.params;
1070
+ sourceFile.addStatements(`// @schedule ${params.schedule}`);
1071
+ const funcDecl = sourceFile.addFunction({
1072
+ name: params.functionName,
1073
+ isAsync: true,
1074
+ isExported: true
1075
+ });
1076
+ funcDecl.addStatements((writer) => {
1077
+ bodyGenerator(writer);
1078
+ });
1079
+ }
1080
+ generateManualFunction(sourceFile, trigger, bodyGenerator) {
1081
+ const params = trigger.params;
1082
+ const funcDecl = sourceFile.addFunction({
1083
+ name: params.functionName,
1084
+ isAsync: true,
1085
+ isExported: true,
1086
+ parameters: params.args.map((arg) => ({
1087
+ name: arg.name,
1088
+ type: arg.type
1089
+ }))
1090
+ });
1091
+ funcDecl.addStatements((writer) => {
1092
+ bodyGenerator(writer);
1093
+ });
1094
+ }
1095
+ };
983
1096
  }
984
- generateScheduledHandler(sourceFile, trigger, bodyGenerator) {
985
- const params = trigger.params;
986
- sourceFile.addStatements(`// @schedule ${params.schedule}`);
987
- const funcDecl = sourceFile.addFunction({
988
- name: params.functionName,
989
- isAsync: true,
990
- isExported: true
991
- });
992
- funcDecl.addStatements((writer) => {
993
- bodyGenerator(writer);
994
- });
995
- }
996
- generateManualFunction(sourceFile, trigger, bodyGenerator) {
997
- const params = trigger.params;
998
- const funcDecl = sourceFile.addFunction({
999
- name: params.functionName,
1000
- isAsync: true,
1001
- isExported: true,
1002
- parameters: params.args.map((arg) => ({
1003
- name: arg.name,
1004
- type: arg.type
1005
- }))
1006
- });
1007
- funcDecl.addStatements((writer) => {
1008
- bodyGenerator(writer);
1009
- });
1010
- }
1011
- };
1097
+ });
1012
1098
 
1013
1099
  // src/lib/compiler/platforms/index.ts
1014
- registerPlatform("nextjs", () => new NextjsPlatform());
1015
- registerPlatform("express", () => new ExpressPlatform());
1016
- registerPlatform("cloudflare", () => new CloudflarePlatform());
1100
+ var init_platforms = __esm({
1101
+ "src/lib/compiler/platforms/index.ts"() {
1102
+ "use strict";
1103
+ init_types2();
1104
+ init_nextjs();
1105
+ init_express();
1106
+ init_cloudflare();
1107
+ init_types2();
1108
+ init_nextjs();
1109
+ init_express();
1110
+ init_cloudflare();
1111
+ registerPlatform("nextjs", () => new NextjsPlatform());
1112
+ registerPlatform("express", () => new ExpressPlatform());
1113
+ registerPlatform("cloudflare", () => new CloudflarePlatform());
1114
+ }
1115
+ });
1017
1116
 
1018
1117
  // src/lib/compiler/plugins/types.ts
1019
1118
  function createPluginRegistry() {
@@ -1039,10 +1138,16 @@ function createPluginRegistry() {
1039
1138
  }
1040
1139
  };
1041
1140
  }
1042
- var globalRegistry = createPluginRegistry();
1043
1141
  function getPlugin(nodeType) {
1044
1142
  return globalRegistry.get(nodeType);
1045
1143
  }
1144
+ var globalRegistry;
1145
+ var init_types3 = __esm({
1146
+ "src/lib/compiler/plugins/types.ts"() {
1147
+ "use strict";
1148
+ globalRegistry = createPluginRegistry();
1149
+ }
1150
+ });
1046
1151
 
1047
1152
  // src/lib/compiler/plugins/builtin.ts
1048
1153
  function inferTypeFromExpression(expr) {
@@ -1117,459 +1222,473 @@ function inferTypeFromCode(code, returnVar) {
1117
1222
  function escapeRegex(s) {
1118
1223
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1119
1224
  }
1120
- var httpWebhookPlugin = {
1121
- nodeType: "http_webhook" /* HTTP_WEBHOOK */,
1122
- generate: () => {
1123
- },
1124
- getOutputType(node) {
1125
- const params = node.params;
1126
- if (["GET", "DELETE"].includes(params.method)) {
1127
- return "{ query: Record<string, string>; url: string }";
1128
- }
1129
- if (params.parseBody) {
1130
- return "{ body: unknown; url: string }";
1131
- }
1132
- return "{ url: string }";
1133
- }
1134
- };
1135
- var cronJobPlugin = {
1136
- nodeType: "cron_job" /* CRON_JOB */,
1137
- generate: () => {
1138
- },
1139
- getOutputType: () => "{ triggeredAt: string }"
1140
- };
1141
- var manualPlugin = {
1142
- nodeType: "manual" /* MANUAL */,
1143
- generate: () => {
1144
- },
1145
- getOutputType: () => "Record<string, unknown>"
1146
- };
1147
- var fetchApiPlugin = {
1148
- nodeType: "fetch_api" /* FETCH_API */,
1149
- generate(node, writer, context) {
1150
- const params = node.params;
1151
- const url = context.resolveEnvVars(params.url);
1152
- writer.write("try ").block(() => {
1153
- const hasBody = params.body && ["POST", "PUT", "PATCH"].includes(params.method);
1154
- writer.writeLine(`const response = await fetch(${url}, {`);
1155
- writer.writeLine(` method: "${params.method}",`);
1156
- if (params.headers && Object.keys(params.headers).length > 0) {
1157
- writer.writeLine(` headers: ${JSON.stringify(params.headers)},`);
1158
- } else if (hasBody) {
1159
- writer.writeLine(
1160
- ` headers: { "Content-Type": "application/json" },`
1161
- );
1225
+ var httpWebhookPlugin, cronJobPlugin, manualPlugin, fetchApiPlugin, sqlQueryPlugin, redisCachePlugin, DANGEROUS_CODE_PATTERNS, customCodePlugin, callSubflowPlugin, ifElsePlugin, forLoopPlugin, tryCatchPlugin, promiseAllPlugin, declarePlugin, transformPlugin, returnResponsePlugin, builtinPlugins;
1226
+ var init_builtin = __esm({
1227
+ "src/lib/compiler/plugins/builtin.ts"() {
1228
+ "use strict";
1229
+ httpWebhookPlugin = {
1230
+ nodeType: "http_webhook" /* HTTP_WEBHOOK */,
1231
+ generate: () => {
1232
+ },
1233
+ getOutputType(node) {
1234
+ const params = node.params;
1235
+ if (["GET", "DELETE"].includes(params.method)) {
1236
+ return "{ query: Record<string, string>; url: string }";
1237
+ }
1238
+ if (params.parseBody) {
1239
+ return "{ body: unknown; url: string }";
1240
+ }
1241
+ return "{ url: string }";
1242
+ }
1243
+ };
1244
+ cronJobPlugin = {
1245
+ nodeType: "cron_job" /* CRON_JOB */,
1246
+ generate: () => {
1247
+ },
1248
+ getOutputType: () => "{ triggeredAt: string }"
1249
+ };
1250
+ manualPlugin = {
1251
+ nodeType: "manual" /* MANUAL */,
1252
+ generate: () => {
1253
+ },
1254
+ getOutputType: () => "Record<string, unknown>"
1255
+ };
1256
+ fetchApiPlugin = {
1257
+ nodeType: "fetch_api" /* FETCH_API */,
1258
+ generate(node, writer, context) {
1259
+ const params = node.params;
1260
+ const url = context.resolveEnvVars(params.url);
1261
+ writer.write("try ").block(() => {
1262
+ const hasBody = params.body && ["POST", "PUT", "PATCH"].includes(params.method);
1263
+ writer.writeLine(`const response = await fetch(${url}, {`);
1264
+ writer.writeLine(` method: "${params.method}",`);
1265
+ if (params.headers && Object.keys(params.headers).length > 0) {
1266
+ writer.writeLine(` headers: ${JSON.stringify(params.headers)},`);
1267
+ } else if (hasBody) {
1268
+ writer.writeLine(
1269
+ ` headers: { "Content-Type": "application/json" },`
1270
+ );
1271
+ }
1272
+ if (hasBody) {
1273
+ const bodyExpr = context.resolveExpression(params.body, node.id);
1274
+ if (bodyExpr.trimStart().startsWith("JSON.stringify")) {
1275
+ writer.writeLine(` body: ${bodyExpr},`);
1276
+ } else {
1277
+ writer.writeLine(` body: JSON.stringify(${bodyExpr}),`);
1278
+ }
1279
+ }
1280
+ writer.writeLine("});");
1281
+ writer.blankLine();
1282
+ writer.write("if (!response.ok) ").block(() => {
1283
+ writer.writeLine(
1284
+ `throw new Error(\`${node.label} failed: HTTP \${response.status} \${response.statusText}\`);`
1285
+ );
1286
+ });
1287
+ writer.blankLine();
1288
+ if (params.parseJson) {
1289
+ writer.writeLine(`const data = await response.json();`);
1290
+ writer.writeLine(`flowState['${node.id}'] = {`);
1291
+ writer.writeLine(` data,`);
1292
+ writer.writeLine(` status: response.status,`);
1293
+ writer.writeLine(` headers: Object.fromEntries(response.headers.entries()),`);
1294
+ writer.writeLine(`};`);
1295
+ } else {
1296
+ writer.writeLine(`flowState['${node.id}'] = response;`);
1297
+ }
1298
+ });
1299
+ writer.write(" catch (fetchError) ").block(() => {
1300
+ writer.writeLine(
1301
+ `console.error("Fetch failed for ${node.label}:", fetchError);`
1302
+ );
1303
+ writer.writeLine(`throw fetchError;`);
1304
+ });
1305
+ },
1306
+ getRequiredPackages: () => [],
1307
+ getOutputType(node) {
1308
+ const params = node.params;
1309
+ return params.parseJson ? "{ data: unknown; status: number; headers: Record<string, string> }" : "Response";
1162
1310
  }
1163
- if (hasBody) {
1164
- const bodyExpr = context.resolveExpression(params.body, node.id);
1165
- if (bodyExpr.trimStart().startsWith("JSON.stringify")) {
1166
- writer.writeLine(` body: ${bodyExpr},`);
1311
+ };
1312
+ sqlQueryPlugin = {
1313
+ nodeType: "sql_query" /* SQL_QUERY */,
1314
+ generate(node, writer) {
1315
+ const params = node.params;
1316
+ switch (params.orm) {
1317
+ case "drizzle":
1318
+ writer.writeLine(`// Drizzle ORM Query`);
1319
+ writer.writeLine(
1320
+ `const result = await db.execute(sql\`${params.query}\`);`
1321
+ );
1322
+ writer.writeLine(`flowState['${node.id}'] = result;`);
1323
+ break;
1324
+ case "prisma":
1325
+ writer.writeLine(`// Prisma Query`);
1326
+ writer.writeLine(
1327
+ `const result = await prisma.$queryRaw\`${params.query}\`;`
1328
+ );
1329
+ writer.writeLine(`flowState['${node.id}'] = result;`);
1330
+ break;
1331
+ case "raw":
1332
+ default:
1333
+ writer.writeLine(`// Raw SQL Query`);
1334
+ writer.writeLine(
1335
+ `const result = await db.query(\`${params.query}\`);`
1336
+ );
1337
+ writer.writeLine(`flowState['${node.id}'] = result;`);
1338
+ break;
1339
+ }
1340
+ },
1341
+ getRequiredPackages(node) {
1342
+ const params = node.params;
1343
+ const map = {
1344
+ drizzle: ["drizzle-orm"],
1345
+ prisma: ["@prisma/client"],
1346
+ raw: []
1347
+ };
1348
+ return map[params.orm] ?? [];
1349
+ },
1350
+ getOutputType: () => "unknown[]"
1351
+ };
1352
+ redisCachePlugin = {
1353
+ nodeType: "redis_cache" /* REDIS_CACHE */,
1354
+ generate(node, writer) {
1355
+ const params = node.params;
1356
+ const needsInterpolation = params.key.includes("${") || params.key.includes("{{");
1357
+ const keyExpr = needsInterpolation ? `\`${params.key}\`` : `"${params.key}"`;
1358
+ switch (params.operation) {
1359
+ case "get":
1360
+ writer.writeLine(
1361
+ `flowState['${node.id}'] = await redis.get(${keyExpr});`
1362
+ );
1363
+ break;
1364
+ case "set":
1365
+ if (params.ttl) {
1366
+ writer.writeLine(
1367
+ `await redis.set(${keyExpr}, ${params.value ?? "null"}, "EX", ${params.ttl});`
1368
+ );
1369
+ } else {
1370
+ writer.writeLine(
1371
+ `await redis.set(${keyExpr}, ${params.value ?? "null"});`
1372
+ );
1373
+ }
1374
+ writer.writeLine(`flowState['${node.id}'] = true;`);
1375
+ break;
1376
+ case "del":
1377
+ writer.writeLine(`await redis.del(${keyExpr});`);
1378
+ writer.writeLine(`flowState['${node.id}'] = true;`);
1379
+ break;
1380
+ }
1381
+ },
1382
+ getRequiredPackages: () => ["ioredis"],
1383
+ getOutputType(node) {
1384
+ const params = node.params;
1385
+ return params.operation === "get" ? "string | null" : "boolean";
1386
+ }
1387
+ };
1388
+ DANGEROUS_CODE_PATTERNS = [
1389
+ { pattern: /\bprocess\.exit\b/, desc: "process.exit() \u2014 terminates the Node.js process" },
1390
+ { pattern: /\bchild_process\b/, desc: "child_process \u2014 can execute arbitrary system commands" },
1391
+ { pattern: /\beval\s*\(/, desc: "eval() \u2014 dynamically executes arbitrary code" },
1392
+ { pattern: /\bnew\s+Function\s*\(/, desc: "new Function() \u2014 dynamically constructs functions" },
1393
+ { pattern: /\brequire\s*\(\s*['"]fs['"]/, desc: "require('fs') \u2014 file system access" },
1394
+ { pattern: /\bimport\s*\(\s*['"]fs['"]/, desc: "import('fs') \u2014 file system access" },
1395
+ { pattern: /\bfs\.\w*(unlink|rmdir|rm|writeFile)\b/, desc: "fs delete/write operations" }
1396
+ ];
1397
+ customCodePlugin = {
1398
+ nodeType: "custom_code" /* CUSTOM_CODE */,
1399
+ generate(node, writer, context) {
1400
+ const params = node.params;
1401
+ const warnings = [];
1402
+ for (const { pattern, desc } of DANGEROUS_CODE_PATTERNS) {
1403
+ if (pattern.test(params.code)) {
1404
+ warnings.push(desc);
1405
+ }
1406
+ }
1407
+ if (warnings.length > 0) {
1408
+ writer.writeLine(`// \u26A0\uFE0F SECURITY WARNING: This custom code uses the following dangerous APIs:`);
1409
+ for (const w of warnings) {
1410
+ writer.writeLine(`// - ${w}`);
1411
+ }
1412
+ writer.writeLine(`// Please carefully review this code before deployment.`);
1413
+ if (context && "addWarning" in context) {
1414
+ const addWarning = context.addWarning;
1415
+ addWarning?.(`[${node.id}] Custom code uses dangerous API: ${warnings.join(", ")}`);
1416
+ }
1417
+ }
1418
+ const resultVar = `custom_result_${node.id.replace(/[^a-zA-Z0-9_]/g, "_")}`;
1419
+ if (params.returnVariable) {
1420
+ writer.writeLine(`const ${resultVar} = await (async () => {`);
1167
1421
  } else {
1168
- writer.writeLine(` body: JSON.stringify(${bodyExpr}),`);
1422
+ writer.writeLine(`await (async () => {`);
1169
1423
  }
1424
+ writer.writeLine(`// Custom Code: ${node.label}`);
1425
+ const lines = params.code.split("\n");
1426
+ for (const line of lines) {
1427
+ writer.writeLine(` ${line}`);
1428
+ }
1429
+ if (params.returnVariable) {
1430
+ writer.writeLine(` if (typeof ${params.returnVariable} !== 'undefined') return ${params.returnVariable};`);
1431
+ }
1432
+ writer.writeLine(`})();`);
1433
+ if (params.returnVariable) {
1434
+ writer.writeLine(`flowState['${node.id}'] = ${resultVar};`);
1435
+ }
1436
+ },
1437
+ getOutputType(node) {
1438
+ const params = node.params;
1439
+ if (params.returnType) return params.returnType;
1440
+ if (!params.returnVariable) return "void";
1441
+ return inferTypeFromCode(params.code, params.returnVariable);
1170
1442
  }
1171
- writer.writeLine("});");
1172
- writer.blankLine();
1173
- writer.write("if (!response.ok) ").block(() => {
1443
+ };
1444
+ callSubflowPlugin = {
1445
+ nodeType: "call_subflow" /* CALL_SUBFLOW */,
1446
+ generate(node, writer, context) {
1447
+ const params = node.params;
1448
+ const existing = context.imports.get(params.flowPath);
1449
+ if (existing) {
1450
+ existing.add(params.functionName);
1451
+ } else {
1452
+ context.imports.set(params.flowPath, /* @__PURE__ */ new Set([params.functionName]));
1453
+ }
1454
+ const args = Object.entries(params.inputMapping).map(([key, expr]) => {
1455
+ const resolved = context.resolveExpression(expr, node.id);
1456
+ return `${key}: ${resolved}`;
1457
+ }).join(", ");
1174
1458
  writer.writeLine(
1175
- `throw new Error(\`${node.label} failed: HTTP \${response.status} \${response.statusText}\`);`
1459
+ `flowState['${node.id}'] = await ${params.functionName}({ ${args} });`
1176
1460
  );
1177
- });
1178
- writer.blankLine();
1179
- if (params.parseJson) {
1180
- writer.writeLine(`const data = await response.json();`);
1181
- writer.writeLine(`flowState['${node.id}'] = {`);
1182
- writer.writeLine(` data,`);
1183
- writer.writeLine(` status: response.status,`);
1184
- writer.writeLine(` headers: Object.fromEntries(response.headers.entries()),`);
1185
- writer.writeLine(`};`);
1186
- } else {
1187
- writer.writeLine(`flowState['${node.id}'] = response;`);
1461
+ },
1462
+ getOutputType(node) {
1463
+ const params = node.params;
1464
+ if (params.returnType) return params.returnType;
1465
+ return `Awaited<ReturnType<typeof ${params.functionName}>>`;
1188
1466
  }
1189
- });
1190
- writer.write(" catch (fetchError) ").block(() => {
1191
- writer.writeLine(
1192
- `console.error("Fetch failed for ${node.label}:", fetchError);`
1193
- );
1194
- writer.writeLine(`throw fetchError;`);
1195
- });
1196
- },
1197
- getRequiredPackages: () => [],
1198
- getOutputType(node) {
1199
- const params = node.params;
1200
- return params.parseJson ? "{ data: unknown; status: number; headers: Record<string, string> }" : "Response";
1201
- }
1202
- };
1203
- var sqlQueryPlugin = {
1204
- nodeType: "sql_query" /* SQL_QUERY */,
1205
- generate(node, writer) {
1206
- const params = node.params;
1207
- switch (params.orm) {
1208
- case "drizzle":
1209
- writer.writeLine(`// Drizzle ORM Query`);
1210
- writer.writeLine(
1211
- `const result = await db.execute(sql\`${params.query}\`);`
1467
+ };
1468
+ ifElsePlugin = {
1469
+ nodeType: "if_else" /* IF_ELSE */,
1470
+ generate(node, writer, context) {
1471
+ const params = node.params;
1472
+ const trueEdges = context.ir.edges.filter(
1473
+ (e) => e.sourceNodeId === node.id && e.sourcePortId === "true"
1212
1474
  );
1213
- writer.writeLine(`flowState['${node.id}'] = result;`);
1214
- break;
1215
- case "prisma":
1216
- writer.writeLine(`// Prisma Query`);
1217
- writer.writeLine(
1218
- `const result = await prisma.$queryRaw\`${params.query}\`;`
1475
+ const falseEdges = context.ir.edges.filter(
1476
+ (e) => e.sourceNodeId === node.id && e.sourcePortId === "false"
1219
1477
  );
1220
- writer.writeLine(`flowState['${node.id}'] = result;`);
1221
- break;
1222
- case "raw":
1223
- default:
1224
- writer.writeLine(`// Raw SQL Query`);
1225
- writer.writeLine(
1226
- `const result = await db.query(\`${params.query}\`);`
1478
+ const conditionExpr = context.resolveExpression(
1479
+ params.condition,
1480
+ node.id
1227
1481
  );
1228
- writer.writeLine(`flowState['${node.id}'] = result;`);
1229
- break;
1230
- }
1231
- },
1232
- getRequiredPackages(node) {
1233
- const params = node.params;
1234
- const map = {
1235
- drizzle: ["drizzle-orm"],
1236
- prisma: ["@prisma/client"],
1237
- raw: []
1482
+ writer.write(`if (${conditionExpr}) `).block(() => {
1483
+ writer.writeLine(`flowState['${node.id}'] = true;`);
1484
+ for (const edge of trueEdges) {
1485
+ const childNode = context.nodeMap.get(edge.targetNodeId);
1486
+ if (childNode) {
1487
+ context.generateChildNode(writer, childNode);
1488
+ }
1489
+ }
1490
+ });
1491
+ if (falseEdges.length > 0) {
1492
+ writer.write(" else ").block(() => {
1493
+ writer.writeLine(`flowState['${node.id}'] = false;`);
1494
+ for (const edge of falseEdges) {
1495
+ const childNode = context.nodeMap.get(edge.targetNodeId);
1496
+ if (childNode) {
1497
+ context.generateChildNode(writer, childNode);
1498
+ }
1499
+ }
1500
+ });
1501
+ }
1502
+ },
1503
+ getOutputType: () => "boolean"
1238
1504
  };
1239
- return map[params.orm] ?? [];
1240
- },
1241
- getOutputType: () => "unknown[]"
1242
- };
1243
- var redisCachePlugin = {
1244
- nodeType: "redis_cache" /* REDIS_CACHE */,
1245
- generate(node, writer) {
1246
- const params = node.params;
1247
- const needsInterpolation = params.key.includes("${") || params.key.includes("{{");
1248
- const keyExpr = needsInterpolation ? `\`${params.key}\`` : `"${params.key}"`;
1249
- switch (params.operation) {
1250
- case "get":
1251
- writer.writeLine(
1252
- `flowState['${node.id}'] = await redis.get(${keyExpr});`
1505
+ forLoopPlugin = {
1506
+ nodeType: "for_loop" /* FOR_LOOP */,
1507
+ generate(node, writer, context) {
1508
+ const params = node.params;
1509
+ const iterableExpr = context.resolveExpression(
1510
+ params.iterableExpression,
1511
+ node.id
1253
1512
  );
1254
- break;
1255
- case "set":
1256
- if (params.ttl) {
1257
- writer.writeLine(
1258
- `await redis.set(${keyExpr}, ${params.value ?? "null"}, "EX", ${params.ttl});`
1513
+ const sanitizedId = node.id.replace(/[^a-zA-Z0-9_]/g, "_");
1514
+ const scopeVar = `_scope_${sanitizedId}`;
1515
+ writer.writeLine(`const ${sanitizedId}_results: unknown[] = [];`);
1516
+ if (params.indexVariable) {
1517
+ writer.write(
1518
+ `for (const [${params.indexVariable}, ${params.itemVariable}] of (${iterableExpr}).entries()) `
1259
1519
  );
1260
1520
  } else {
1261
- writer.writeLine(
1262
- `await redis.set(${keyExpr}, ${params.value ?? "null"});`
1521
+ writer.write(
1522
+ `for (const ${params.itemVariable} of ${iterableExpr}) `
1263
1523
  );
1264
1524
  }
1265
- writer.writeLine(`flowState['${node.id}'] = true;`);
1266
- break;
1267
- case "del":
1268
- writer.writeLine(`await redis.del(${keyExpr});`);
1269
- writer.writeLine(`flowState['${node.id}'] = true;`);
1270
- break;
1271
- }
1272
- },
1273
- getRequiredPackages: () => ["ioredis"],
1274
- getOutputType(node) {
1275
- const params = node.params;
1276
- return params.operation === "get" ? "string | null" : "boolean";
1277
- }
1278
- };
1279
- var DANGEROUS_CODE_PATTERNS = [
1280
- { pattern: /\bprocess\.exit\b/, desc: "process.exit() \u2014 terminates the Node.js process" },
1281
- { pattern: /\bchild_process\b/, desc: "child_process \u2014 can execute arbitrary system commands" },
1282
- { pattern: /\beval\s*\(/, desc: "eval() \u2014 dynamically executes arbitrary code" },
1283
- { pattern: /\bnew\s+Function\s*\(/, desc: "new Function() \u2014 dynamically constructs functions" },
1284
- { pattern: /\brequire\s*\(\s*['"]fs['"]/, desc: "require('fs') \u2014 file system access" },
1285
- { pattern: /\bimport\s*\(\s*['"]fs['"]/, desc: "import('fs') \u2014 file system access" },
1286
- { pattern: /\bfs\.\w*(unlink|rmdir|rm|writeFile)\b/, desc: "fs delete/write operations" }
1287
- ];
1288
- var customCodePlugin = {
1289
- nodeType: "custom_code" /* CUSTOM_CODE */,
1290
- generate(node, writer, context) {
1291
- const params = node.params;
1292
- const warnings = [];
1293
- for (const { pattern, desc } of DANGEROUS_CODE_PATTERNS) {
1294
- if (pattern.test(params.code)) {
1295
- warnings.push(desc);
1296
- }
1297
- }
1298
- if (warnings.length > 0) {
1299
- writer.writeLine(`// \u26A0\uFE0F SECURITY WARNING: This custom code uses the following dangerous APIs:`);
1300
- for (const w of warnings) {
1301
- writer.writeLine(`// - ${w}`);
1302
- }
1303
- writer.writeLine(`// Please carefully review this code before deployment.`);
1304
- if (context && "addWarning" in context) {
1305
- const addWarning = context.addWarning;
1306
- addWarning?.(`[${node.id}] Custom code uses dangerous API: ${warnings.join(", ")}`);
1307
- }
1308
- }
1309
- const resultVar = `custom_result_${node.id.replace(/[^a-zA-Z0-9_]/g, "_")}`;
1310
- if (params.returnVariable) {
1311
- writer.writeLine(`const ${resultVar} = await (async () => {`);
1312
- } else {
1313
- writer.writeLine(`await (async () => {`);
1314
- }
1315
- writer.writeLine(`// Custom Code: ${node.label}`);
1316
- const lines = params.code.split("\n");
1317
- for (const line of lines) {
1318
- writer.writeLine(` ${line}`);
1319
- }
1320
- if (params.returnVariable) {
1321
- writer.writeLine(` if (typeof ${params.returnVariable} !== 'undefined') return ${params.returnVariable};`);
1322
- }
1323
- writer.writeLine(`})();`);
1324
- if (params.returnVariable) {
1325
- writer.writeLine(`flowState['${node.id}'] = ${resultVar};`);
1326
- }
1327
- },
1328
- getOutputType(node) {
1329
- const params = node.params;
1330
- if (params.returnType) return params.returnType;
1331
- if (!params.returnVariable) return "void";
1332
- return inferTypeFromCode(params.code, params.returnVariable);
1333
- }
1334
- };
1335
- var callSubflowPlugin = {
1336
- nodeType: "call_subflow" /* CALL_SUBFLOW */,
1337
- generate(node, writer, context) {
1338
- const params = node.params;
1339
- const existing = context.imports.get(params.flowPath);
1340
- if (existing) {
1341
- existing.add(params.functionName);
1342
- } else {
1343
- context.imports.set(params.flowPath, /* @__PURE__ */ new Set([params.functionName]));
1344
- }
1345
- const args = Object.entries(params.inputMapping).map(([key, expr]) => {
1346
- const resolved = context.resolveExpression(expr, node.id);
1347
- return `${key}: ${resolved}`;
1348
- }).join(", ");
1349
- writer.writeLine(
1350
- `flowState['${node.id}'] = await ${params.functionName}({ ${args} });`
1351
- );
1352
- },
1353
- getOutputType(node) {
1354
- const params = node.params;
1355
- if (params.returnType) return params.returnType;
1356
- return `Awaited<ReturnType<typeof ${params.functionName}>>`;
1357
- }
1358
- };
1359
- var ifElsePlugin = {
1360
- nodeType: "if_else" /* IF_ELSE */,
1361
- generate(node, writer, context) {
1362
- const params = node.params;
1363
- const trueEdges = context.ir.edges.filter(
1364
- (e) => e.sourceNodeId === node.id && e.sourcePortId === "true"
1365
- );
1366
- const falseEdges = context.ir.edges.filter(
1367
- (e) => e.sourceNodeId === node.id && e.sourcePortId === "false"
1368
- );
1369
- const conditionExpr = context.resolveExpression(
1370
- params.condition,
1371
- node.id
1372
- );
1373
- writer.write(`if (${conditionExpr}) `).block(() => {
1374
- writer.writeLine(`flowState['${node.id}'] = true;`);
1375
- for (const edge of trueEdges) {
1376
- const childNode = context.nodeMap.get(edge.targetNodeId);
1377
- if (childNode) {
1378
- context.generateChildNode(writer, childNode);
1379
- }
1380
- }
1381
- });
1382
- if (falseEdges.length > 0) {
1383
- writer.write(" else ").block(() => {
1384
- writer.writeLine(`flowState['${node.id}'] = false;`);
1385
- for (const edge of falseEdges) {
1386
- const childNode = context.nodeMap.get(edge.targetNodeId);
1387
- if (childNode) {
1388
- context.generateChildNode(writer, childNode);
1525
+ writer.block(() => {
1526
+ writer.writeLine(
1527
+ `const ${scopeVar}: Record<string, unknown> = {};`
1528
+ );
1529
+ writer.writeLine(
1530
+ `${scopeVar}['${node.id}'] = ${params.itemVariable};`
1531
+ );
1532
+ context.pushScope(node.id, scopeVar);
1533
+ const childEdges = context.ir.edges.filter(
1534
+ (e) => e.sourceNodeId === node.id && e.sourcePortId === "body"
1535
+ );
1536
+ for (const edge of childEdges) {
1537
+ const childNode = context.nodeMap.get(edge.targetNodeId);
1538
+ if (childNode) {
1539
+ context.generateChildNode(writer, childNode);
1540
+ }
1389
1541
  }
1390
- }
1391
- });
1392
- }
1393
- },
1394
- getOutputType: () => "boolean"
1395
- };
1396
- var forLoopPlugin = {
1397
- nodeType: "for_loop" /* FOR_LOOP */,
1398
- generate(node, writer, context) {
1399
- const params = node.params;
1400
- const iterableExpr = context.resolveExpression(
1401
- params.iterableExpression,
1402
- node.id
1403
- );
1404
- const sanitizedId = node.id.replace(/[^a-zA-Z0-9_]/g, "_");
1405
- const scopeVar = `_scope_${sanitizedId}`;
1406
- writer.writeLine(`const ${sanitizedId}_results: unknown[] = [];`);
1407
- if (params.indexVariable) {
1408
- writer.write(
1409
- `for (const [${params.indexVariable}, ${params.itemVariable}] of (${iterableExpr}).entries()) `
1410
- );
1411
- } else {
1412
- writer.write(
1413
- `for (const ${params.itemVariable} of ${iterableExpr}) `
1414
- );
1415
- }
1416
- writer.block(() => {
1417
- writer.writeLine(
1418
- `const ${scopeVar}: Record<string, unknown> = {};`
1419
- );
1420
- writer.writeLine(
1421
- `${scopeVar}['${node.id}'] = ${params.itemVariable};`
1422
- );
1423
- context.pushScope(node.id, scopeVar);
1424
- const childEdges = context.ir.edges.filter(
1425
- (e) => e.sourceNodeId === node.id && e.sourcePortId === "body"
1426
- );
1427
- for (const edge of childEdges) {
1428
- const childNode = context.nodeMap.get(edge.targetNodeId);
1429
- if (childNode) {
1430
- context.generateChildNode(writer, childNode);
1431
- }
1432
- }
1433
- context.popScope();
1434
- writer.writeLine(`${sanitizedId}_results.push(${params.itemVariable});`);
1435
- });
1436
- writer.writeLine(`flowState['${node.id}'] = ${sanitizedId}_results;`);
1437
- },
1438
- getOutputType: () => "unknown[]"
1439
- };
1440
- var tryCatchPlugin = {
1441
- nodeType: "try_catch" /* TRY_CATCH */,
1442
- generate(node, writer, context) {
1443
- const params = node.params;
1444
- const successEdges = context.ir.edges.filter(
1445
- (e) => e.sourceNodeId === node.id && e.sourcePortId === "success"
1446
- );
1447
- const errorEdges = context.ir.edges.filter(
1448
- (e) => e.sourceNodeId === node.id && e.sourcePortId === "error"
1449
- );
1450
- const tryScopeVar = `_scope_${node.id.replace(/[^a-zA-Z0-9_]/g, "_")}_try`;
1451
- const catchScopeVar = `_scope_${node.id.replace(/[^a-zA-Z0-9_]/g, "_")}_catch`;
1452
- writer.write("try ").block(() => {
1453
- writer.writeLine(
1454
- `const ${tryScopeVar}: Record<string, unknown> = {};`
1455
- );
1456
- context.pushScope(node.id, tryScopeVar);
1457
- for (const edge of successEdges) {
1458
- const childNode = context.nodeMap.get(edge.targetNodeId);
1459
- if (childNode) {
1460
- context.generateChildNode(writer, childNode);
1461
- }
1462
- }
1463
- context.popScope();
1464
- writer.writeLine(
1465
- `flowState['${node.id}'] = { success: true };`
1466
- );
1467
- });
1468
- writer.write(` catch (${params.errorVariable}) `).block(() => {
1469
- writer.writeLine(
1470
- `console.error("Error in ${node.label}:", ${params.errorVariable});`
1471
- );
1472
- writer.writeLine(
1473
- `const ${catchScopeVar}: Record<string, unknown> = {};`
1474
- );
1475
- writer.writeLine(
1476
- `flowState['${node.id}'] = { success: false, error: ${params.errorVariable} };`
1477
- );
1478
- context.pushScope(node.id, catchScopeVar);
1479
- for (const edge of errorEdges) {
1480
- const childNode = context.nodeMap.get(edge.targetNodeId);
1481
- if (childNode) {
1482
- context.generateChildNode(writer, childNode);
1483
- }
1484
- }
1485
- context.popScope();
1486
- });
1487
- },
1488
- getOutputType: () => "{ success: boolean; error?: unknown }"
1489
- };
1490
- var promiseAllPlugin = {
1491
- nodeType: "promise_all" /* PROMISE_ALL */,
1492
- generate(node, writer) {
1493
- writer.writeLine(`// Promise.all handled by concurrent execution`);
1494
- writer.writeLine(
1495
- `flowState['${node.id}'] = undefined; // populated by concurrent handler`
1496
- );
1497
- },
1498
- getOutputType: () => "unknown[]"
1499
- };
1500
- var declarePlugin = {
1501
- nodeType: "declare" /* DECLARE */,
1502
- generate(node, writer) {
1503
- const params = node.params;
1504
- const keyword = params.isConst ? "const" : "let";
1505
- const initialValue = params.initialValue ?? "undefined";
1506
- writer.writeLine(`${keyword} ${params.name} = ${initialValue};`);
1507
- writer.writeLine(`flowState['${node.id}'] = ${params.name};`);
1508
- },
1509
- getOutputType(node) {
1510
- const params = node.params;
1511
- return params.dataType;
1512
- }
1513
- };
1514
- var transformPlugin = {
1515
- nodeType: "transform" /* TRANSFORM */,
1516
- generate(node, writer, context) {
1517
- const params = node.params;
1518
- const expr = context.resolveExpression(params.expression, node.id);
1519
- writer.writeLine(`flowState['${node.id}'] = ${expr};`);
1520
- },
1521
- getOutputType(node) {
1522
- const params = node.params;
1523
- return inferTypeFromExpression(params.expression);
1524
- }
1525
- };
1526
- var returnResponsePlugin = {
1527
- nodeType: "return_response" /* RETURN_RESPONSE */,
1528
- generate(node, writer, context) {
1529
- const params = node.params;
1530
- const bodyExpr = context.resolveExpression(
1531
- params.bodyExpression,
1532
- node.id
1533
- );
1534
- const ctx = context;
1535
- if (ctx.__platformResponse) {
1536
- ctx.__platformResponse(writer, bodyExpr, params.statusCode, params.headers);
1537
- } else {
1538
- if (params.headers && Object.keys(params.headers).length > 0) {
1539
- writer.writeLine(
1540
- `return NextResponse.json(${bodyExpr}, { status: ${params.statusCode}, headers: ${JSON.stringify(params.headers)} });`
1542
+ context.popScope();
1543
+ writer.writeLine(`${sanitizedId}_results.push(${params.itemVariable});`);
1544
+ });
1545
+ writer.writeLine(`flowState['${node.id}'] = ${sanitizedId}_results;`);
1546
+ },
1547
+ getOutputType: () => "unknown[]"
1548
+ };
1549
+ tryCatchPlugin = {
1550
+ nodeType: "try_catch" /* TRY_CATCH */,
1551
+ generate(node, writer, context) {
1552
+ const params = node.params;
1553
+ const successEdges = context.ir.edges.filter(
1554
+ (e) => e.sourceNodeId === node.id && e.sourcePortId === "success"
1541
1555
  );
1542
- } else {
1556
+ const errorEdges = context.ir.edges.filter(
1557
+ (e) => e.sourceNodeId === node.id && e.sourcePortId === "error"
1558
+ );
1559
+ const tryScopeVar = `_scope_${node.id.replace(/[^a-zA-Z0-9_]/g, "_")}_try`;
1560
+ const catchScopeVar = `_scope_${node.id.replace(/[^a-zA-Z0-9_]/g, "_")}_catch`;
1561
+ writer.write("try ").block(() => {
1562
+ writer.writeLine(
1563
+ `const ${tryScopeVar}: Record<string, unknown> = {};`
1564
+ );
1565
+ context.pushScope(node.id, tryScopeVar);
1566
+ for (const edge of successEdges) {
1567
+ const childNode = context.nodeMap.get(edge.targetNodeId);
1568
+ if (childNode) {
1569
+ context.generateChildNode(writer, childNode);
1570
+ }
1571
+ }
1572
+ context.popScope();
1573
+ writer.writeLine(
1574
+ `flowState['${node.id}'] = { success: true };`
1575
+ );
1576
+ });
1577
+ writer.write(` catch (${params.errorVariable}) `).block(() => {
1578
+ writer.writeLine(
1579
+ `console.error("Error in ${node.label}:", ${params.errorVariable});`
1580
+ );
1581
+ writer.writeLine(
1582
+ `const ${catchScopeVar}: Record<string, unknown> = {};`
1583
+ );
1584
+ writer.writeLine(
1585
+ `flowState['${node.id}'] = { success: false, error: ${params.errorVariable} };`
1586
+ );
1587
+ context.pushScope(node.id, catchScopeVar);
1588
+ for (const edge of errorEdges) {
1589
+ const childNode = context.nodeMap.get(edge.targetNodeId);
1590
+ if (childNode) {
1591
+ context.generateChildNode(writer, childNode);
1592
+ }
1593
+ }
1594
+ context.popScope();
1595
+ });
1596
+ },
1597
+ getOutputType: () => "{ success: boolean; error?: unknown }"
1598
+ };
1599
+ promiseAllPlugin = {
1600
+ nodeType: "promise_all" /* PROMISE_ALL */,
1601
+ generate(node, writer) {
1602
+ writer.writeLine(`// Promise.all handled by concurrent execution`);
1543
1603
  writer.writeLine(
1544
- `return NextResponse.json(${bodyExpr}, { status: ${params.statusCode} });`
1604
+ `flowState['${node.id}'] = undefined; // populated by concurrent handler`
1545
1605
  );
1606
+ },
1607
+ getOutputType: () => "unknown[]"
1608
+ };
1609
+ declarePlugin = {
1610
+ nodeType: "declare" /* DECLARE */,
1611
+ generate(node, writer) {
1612
+ const params = node.params;
1613
+ const keyword = params.isConst ? "const" : "let";
1614
+ const initialValue = params.initialValue ?? "undefined";
1615
+ writer.writeLine(`${keyword} ${params.name} = ${initialValue};`);
1616
+ writer.writeLine(`flowState['${node.id}'] = ${params.name};`);
1617
+ },
1618
+ getOutputType(node) {
1619
+ const params = node.params;
1620
+ return params.dataType;
1546
1621
  }
1547
- }
1548
- },
1549
- getOutputType: () => "never"
1550
- };
1551
- var builtinPlugins = [
1552
- // Triggers
1553
- httpWebhookPlugin,
1554
- cronJobPlugin,
1555
- manualPlugin,
1556
- // Actions
1557
- fetchApiPlugin,
1558
- sqlQueryPlugin,
1559
- redisCachePlugin,
1560
- customCodePlugin,
1561
- callSubflowPlugin,
1562
- // Logic
1563
- ifElsePlugin,
1564
- forLoopPlugin,
1565
- tryCatchPlugin,
1566
- promiseAllPlugin,
1567
- // Variables
1568
- declarePlugin,
1569
- transformPlugin,
1570
- // Output
1571
- returnResponsePlugin
1572
- ];
1622
+ };
1623
+ transformPlugin = {
1624
+ nodeType: "transform" /* TRANSFORM */,
1625
+ generate(node, writer, context) {
1626
+ const params = node.params;
1627
+ const expr = context.resolveExpression(params.expression, node.id);
1628
+ writer.writeLine(`flowState['${node.id}'] = ${expr};`);
1629
+ },
1630
+ getOutputType(node) {
1631
+ const params = node.params;
1632
+ return inferTypeFromExpression(params.expression);
1633
+ }
1634
+ };
1635
+ returnResponsePlugin = {
1636
+ nodeType: "return_response" /* RETURN_RESPONSE */,
1637
+ generate(node, writer, context) {
1638
+ const params = node.params;
1639
+ const bodyExpr = context.resolveExpression(
1640
+ params.bodyExpression,
1641
+ node.id
1642
+ );
1643
+ const ctx = context;
1644
+ if (ctx.__platformResponse) {
1645
+ ctx.__platformResponse(writer, bodyExpr, params.statusCode, params.headers);
1646
+ } else {
1647
+ if (params.headers && Object.keys(params.headers).length > 0) {
1648
+ writer.writeLine(
1649
+ `return NextResponse.json(${bodyExpr}, { status: ${params.statusCode}, headers: ${JSON.stringify(params.headers)} });`
1650
+ );
1651
+ } else {
1652
+ writer.writeLine(
1653
+ `return NextResponse.json(${bodyExpr}, { status: ${params.statusCode} });`
1654
+ );
1655
+ }
1656
+ }
1657
+ },
1658
+ getOutputType: () => "never"
1659
+ };
1660
+ builtinPlugins = [
1661
+ // Triggers
1662
+ httpWebhookPlugin,
1663
+ cronJobPlugin,
1664
+ manualPlugin,
1665
+ // Actions
1666
+ fetchApiPlugin,
1667
+ sqlQueryPlugin,
1668
+ redisCachePlugin,
1669
+ customCodePlugin,
1670
+ callSubflowPlugin,
1671
+ // Logic
1672
+ ifElsePlugin,
1673
+ forLoopPlugin,
1674
+ tryCatchPlugin,
1675
+ promiseAllPlugin,
1676
+ // Variables
1677
+ declarePlugin,
1678
+ transformPlugin,
1679
+ // Output
1680
+ returnResponsePlugin
1681
+ ];
1682
+ }
1683
+ });
1684
+
1685
+ // src/lib/compiler/plugins/index.ts
1686
+ var init_plugins = __esm({
1687
+ "src/lib/compiler/plugins/index.ts"() {
1688
+ "use strict";
1689
+ init_types3();
1690
+ }
1691
+ });
1573
1692
 
1574
1693
  // src/lib/compiler/type-inference.ts
1575
1694
  function inferFlowStateTypes(ir, registry) {
@@ -1620,6 +1739,12 @@ function mapFlowDataTypeToTS(dataType) {
1620
1739
  return "unknown";
1621
1740
  }
1622
1741
  }
1742
+ var init_type_inference = __esm({
1743
+ "src/lib/compiler/type-inference.ts"() {
1744
+ "use strict";
1745
+ init_types3();
1746
+ }
1747
+ });
1623
1748
 
1624
1749
  // src/lib/compiler/symbol-table.ts
1625
1750
  function buildSymbolTable(ir) {
@@ -1665,75 +1790,89 @@ function labelToVarName(label) {
1665
1790
  return lower.charAt(0).toUpperCase() + lower.slice(1);
1666
1791
  }).join("");
1667
1792
  }
1668
- var RESERVED_WORDS = /* @__PURE__ */ new Set([
1669
- // JavaScript reserved words
1670
- "break",
1671
- "case",
1672
- "catch",
1673
- "continue",
1674
- "debugger",
1675
- "default",
1676
- "delete",
1677
- "do",
1678
- "else",
1679
- "finally",
1680
- "for",
1681
- "function",
1682
- "if",
1683
- "in",
1684
- "instanceof",
1685
- "new",
1686
- "return",
1687
- "switch",
1688
- "this",
1689
- "throw",
1690
- "try",
1691
- "typeof",
1692
- "var",
1693
- "void",
1694
- "while",
1695
- "with",
1696
- "class",
1697
- "const",
1698
- "enum",
1699
- "export",
1700
- "extends",
1701
- "import",
1702
- "super",
1703
- "implements",
1704
- "interface",
1705
- "let",
1706
- "package",
1707
- "private",
1708
- "protected",
1709
- "public",
1710
- "static",
1711
- "yield",
1712
- "await",
1713
- "async",
1714
- // Built-in global values
1715
- "undefined",
1716
- "null",
1717
- "true",
1718
- "false",
1719
- "NaN",
1720
- "Infinity",
1721
- // Common identifiers in generated code (avoid shadowing)
1722
- "req",
1723
- "res",
1724
- "body",
1725
- "query",
1726
- "data",
1727
- "result",
1728
- "response",
1729
- "error",
1730
- "flowState",
1731
- "searchParams",
1732
- "NextResponse",
1733
- "NextRequest"
1734
- ]);
1793
+ var RESERVED_WORDS;
1794
+ var init_symbol_table = __esm({
1795
+ "src/lib/compiler/symbol-table.ts"() {
1796
+ "use strict";
1797
+ RESERVED_WORDS = /* @__PURE__ */ new Set([
1798
+ // JavaScript reserved words
1799
+ "break",
1800
+ "case",
1801
+ "catch",
1802
+ "continue",
1803
+ "debugger",
1804
+ "default",
1805
+ "delete",
1806
+ "do",
1807
+ "else",
1808
+ "finally",
1809
+ "for",
1810
+ "function",
1811
+ "if",
1812
+ "in",
1813
+ "instanceof",
1814
+ "new",
1815
+ "return",
1816
+ "switch",
1817
+ "this",
1818
+ "throw",
1819
+ "try",
1820
+ "typeof",
1821
+ "var",
1822
+ "void",
1823
+ "while",
1824
+ "with",
1825
+ "class",
1826
+ "const",
1827
+ "enum",
1828
+ "export",
1829
+ "extends",
1830
+ "import",
1831
+ "super",
1832
+ "implements",
1833
+ "interface",
1834
+ "let",
1835
+ "package",
1836
+ "private",
1837
+ "protected",
1838
+ "public",
1839
+ "static",
1840
+ "yield",
1841
+ "await",
1842
+ "async",
1843
+ // Built-in global values
1844
+ "undefined",
1845
+ "null",
1846
+ "true",
1847
+ "false",
1848
+ "NaN",
1849
+ "Infinity",
1850
+ // Common identifiers in generated code (avoid shadowing)
1851
+ "req",
1852
+ "res",
1853
+ "body",
1854
+ "query",
1855
+ "data",
1856
+ "result",
1857
+ "response",
1858
+ "error",
1859
+ "flowState",
1860
+ "searchParams",
1861
+ "NextResponse",
1862
+ "NextRequest"
1863
+ ]);
1864
+ }
1865
+ });
1735
1866
 
1736
1867
  // src/lib/compiler/compiler.ts
1868
+ var compiler_exports = {};
1869
+ __export(compiler_exports, {
1870
+ compile: () => compile,
1871
+ compileWithPrettier: () => compileWithPrettier,
1872
+ formatWithPrettier: () => formatWithPrettier,
1873
+ traceLineToNode: () => traceLineToNode
1874
+ });
1875
+ import { Project } from "ts-morph";
1737
1876
  function compile(ir, options) {
1738
1877
  const pluginRegistry = createPluginRegistry();
1739
1878
  pluginRegistry.registerAll(builtinPlugins);
@@ -1811,7 +1950,7 @@ function compile(ir, options) {
1811
1950
  indentSize: 2,
1812
1951
  convertTabsToSpaces: true
1813
1952
  });
1814
- const code = sourceFile.getFullText();
1953
+ let code = sourceFile.getFullText();
1815
1954
  const filePath = platform.getOutputFilePath(trigger);
1816
1955
  collectRequiredPackages(workingIR, context);
1817
1956
  const sourceMap = buildSourceMap(code, workingIR, filePath);
@@ -1828,6 +1967,28 @@ function compile(ir, options) {
1828
1967
  sourceMap
1829
1968
  };
1830
1969
  }
1970
+ async function formatWithPrettier(code, options) {
1971
+ try {
1972
+ const prettier = await import("prettier");
1973
+ return await prettier.format(code, {
1974
+ parser: "typescript",
1975
+ printWidth: options?.printWidth ?? 100,
1976
+ tabWidth: 2,
1977
+ singleQuote: options?.singleQuote ?? true,
1978
+ trailingComma: "all",
1979
+ semi: true
1980
+ });
1981
+ } catch {
1982
+ return code;
1983
+ }
1984
+ }
1985
+ async function compileWithPrettier(ir, options) {
1986
+ const result = compile(ir, options);
1987
+ if (!result.success || !result.code) return result;
1988
+ const formatted = await formatWithPrettier(result.code);
1989
+ const sourceMap = result.sourceMap ? buildSourceMap(formatted, ir, result.filePath ?? "formatted.ts") : void 0;
1990
+ return { ...result, code: formatted, sourceMap };
1991
+ }
1831
1992
  function generateCode(sourceFile, trigger, context) {
1832
1993
  const { platform } = context;
1833
1994
  platform.generateImports(sourceFile, trigger, {
@@ -1862,11 +2023,6 @@ function generateFunctionBody(writer, trigger, context) {
1862
2023
  writer.blankLine();
1863
2024
  generateNodeChain(writer, trigger.id, context);
1864
2025
  }
1865
- var CONTROL_FLOW_PORT_MAP = {
1866
- ["if_else" /* IF_ELSE */]: /* @__PURE__ */ new Set(["true", "false"]),
1867
- ["for_loop" /* FOR_LOOP */]: /* @__PURE__ */ new Set(["body"]),
1868
- ["try_catch" /* TRY_CATCH */]: /* @__PURE__ */ new Set(["success", "error"])
1869
- };
1870
2026
  function isControlFlowEdge(edge, nodeMap) {
1871
2027
  const sourceNode = nodeMap.get(edge.sourceNodeId);
1872
2028
  if (!sourceNode) return false;
@@ -2221,8 +2377,58 @@ function buildSourceMap(code, ir, filePath) {
2221
2377
  mappings
2222
2378
  };
2223
2379
  }
2380
+ function traceLineToNode(sourceMap, line) {
2381
+ const entries = Object.entries(sourceMap.mappings).map(([nodeId, range]) => ({ nodeId, ...range })).sort((a, b) => a.startLine - b.startLine);
2382
+ let lo = 0;
2383
+ let hi = entries.length - 1;
2384
+ while (lo <= hi) {
2385
+ const mid = lo + hi >>> 1;
2386
+ const e = entries[mid];
2387
+ if (line < e.startLine) {
2388
+ hi = mid - 1;
2389
+ } else if (line > e.endLine) {
2390
+ lo = mid + 1;
2391
+ } else {
2392
+ return e;
2393
+ }
2394
+ }
2395
+ return null;
2396
+ }
2397
+ var CONTROL_FLOW_PORT_MAP;
2398
+ var init_compiler = __esm({
2399
+ "src/lib/compiler/compiler.ts"() {
2400
+ "use strict";
2401
+ init_validator();
2402
+ init_topological_sort();
2403
+ init_expression_parser();
2404
+ init_platforms();
2405
+ init_plugins();
2406
+ init_builtin();
2407
+ init_type_inference();
2408
+ init_symbol_table();
2409
+ registerPlatform("nextjs", () => new NextjsPlatform());
2410
+ registerPlatform("express", () => new ExpressPlatform());
2411
+ registerPlatform("cloudflare", () => new CloudflarePlatform());
2412
+ CONTROL_FLOW_PORT_MAP = {
2413
+ ["if_else" /* IF_ELSE */]: /* @__PURE__ */ new Set(["true", "false"]),
2414
+ ["for_loop" /* FOR_LOOP */]: /* @__PURE__ */ new Set(["body"]),
2415
+ ["try_catch" /* TRY_CATCH */]: /* @__PURE__ */ new Set(["success", "error"])
2416
+ };
2417
+ }
2418
+ });
2419
+
2420
+ // src/server/index.ts
2421
+ import { createServer } from "http";
2422
+ import { readFile, stat } from "fs/promises";
2423
+ import { join as join2, extname, dirname as dirname2, resolve as resolve2 } from "path";
2424
+ import { fileURLToPath } from "url";
2425
+ import { existsSync as existsSync2 } from "fs";
2426
+
2427
+ // src/server/handlers.ts
2428
+ init_compiler();
2224
2429
 
2225
2430
  // src/lib/compiler/decompiler.ts
2431
+ init_types();
2226
2432
  import {
2227
2433
  Project as Project2,
2228
2434
  SyntaxKind
@@ -3052,6 +3258,9 @@ function truncate(str, maxLen) {
3052
3258
  return str.slice(0, maxLen - 3) + "...";
3053
3259
  }
3054
3260
 
3261
+ // src/server/handlers.ts
3262
+ init_validator();
3263
+
3055
3264
  // src/lib/ir/security.ts
3056
3265
  var SECURITY_PATTERNS = [
3057
3266
  // ── Critical: Remote Code Execution / System Access ──
@@ -3509,7 +3718,7 @@ Return ONLY valid JSON (no markdown, no explanation). The JSON must conform to t
3509
3718
  // src/server/handlers.ts
3510
3719
  import { writeFileSync, mkdirSync, existsSync, readFileSync } from "fs";
3511
3720
  import { join, dirname, resolve } from "path";
3512
- function handleCompile(body, projectRoot) {
3721
+ async function handleCompile(body, projectRoot) {
3513
3722
  try {
3514
3723
  const ir = body.ir;
3515
3724
  const shouldWrite = body.write !== false;
@@ -3523,8 +3732,16 @@ function handleCompile(body, projectRoot) {
3523
3732
  body: { success: false, error: result.errors?.join("\n") }
3524
3733
  };
3525
3734
  }
3735
+ let finalCode = result.code;
3736
+ if (finalCode) {
3737
+ try {
3738
+ const { formatWithPrettier: formatWithPrettier2 } = await Promise.resolve().then(() => (init_compiler(), compiler_exports));
3739
+ finalCode = await formatWithPrettier2(finalCode);
3740
+ } catch {
3741
+ }
3742
+ }
3526
3743
  let writtenPath = null;
3527
- if (shouldWrite && result.filePath && result.code) {
3744
+ if (shouldWrite && result.filePath && finalCode) {
3528
3745
  const fullPath = resolve(join(projectRoot, result.filePath));
3529
3746
  const resolvedRoot = resolve(projectRoot);
3530
3747
  const sep = resolvedRoot.endsWith("/") || resolvedRoot.endsWith("\\") ? "" : process.platform === "win32" ? "\\" : "/";
@@ -3538,7 +3755,7 @@ function handleCompile(body, projectRoot) {
3538
3755
  if (!existsSync(dir)) {
3539
3756
  mkdirSync(dir, { recursive: true });
3540
3757
  }
3541
- writeFileSync(fullPath, result.code, "utf-8");
3758
+ writeFileSync(fullPath, finalCode, "utf-8");
3542
3759
  writtenPath = fullPath;
3543
3760
  if (result.sourceMap) {
3544
3761
  const mapPath = fullPath.replace(/\.ts$/, ".flow.map.json");
@@ -3565,7 +3782,7 @@ function handleCompile(body, projectRoot) {
3565
3782
  status: 200,
3566
3783
  body: {
3567
3784
  success: true,
3568
- code: result.code,
3785
+ code: finalCode,
3569
3786
  filePath: result.filePath,
3570
3787
  writtenTo: writtenPath,
3571
3788
  dependencies: result.dependencies,
@@ -3968,7 +4185,7 @@ async function handleRequest(req, res, staticDir, projectRoot) {
3968
4185
  return;
3969
4186
  }
3970
4187
  if (pathname === "/api/compile") {
3971
- const result = handleCompile(body, projectRoot);
4188
+ const result = await handleCompile(body, projectRoot);
3972
4189
  sendJson(res, result.status, result.body);
3973
4190
  return;
3974
4191
  }