@runtypelabs/react-flow 0.1.0 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,3249 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var react$1 = require('@xyflow/react');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+
7
+ // src/types/index.ts
8
+ var SUPPORTED_NODE_TYPES = [
9
+ "prompt",
10
+ "fetch-url",
11
+ "transform-data",
12
+ "conditional",
13
+ "send-email"
14
+ ];
15
+ function isSupportedNodeType(type) {
16
+ return SUPPORTED_NODE_TYPES.includes(type);
17
+ }
18
+
19
+ // src/utils/adapter.ts
20
+ var NODE_WIDTH = 280;
21
+ var NODE_HEIGHT = 200;
22
+ var NODE_SPACING_X = 350;
23
+ var NODE_SPACING_Y = 80;
24
+ var BRANCH_OFFSET_X = 350;
25
+ var BRANCH_OFFSET_Y = -80;
26
+ var FALSE_BRANCH_GAP = 100;
27
+ function flowStepsToNodes(steps, options) {
28
+ const {
29
+ onChange,
30
+ onDelete,
31
+ startPosition = { x: 50, y: 200 },
32
+ idPrefix = "",
33
+ parentId
34
+ } = options ?? {};
35
+ const sortedSteps = [...steps].sort((a, b) => a.order - b.order);
36
+ const nodes = [];
37
+ let currentX = startPosition.x;
38
+ startPosition.y;
39
+ for (const step of sortedSteps) {
40
+ const nodeId = idPrefix ? `${idPrefix}${step.id}` : step.id;
41
+ const nodeData = {
42
+ step,
43
+ label: step.name || getDefaultStepName(step.type),
44
+ onChange,
45
+ onDelete
46
+ };
47
+ const node = {
48
+ id: nodeId,
49
+ type: step.type,
50
+ position: { x: currentX, y: startPosition.y },
51
+ data: nodeData,
52
+ draggable: true,
53
+ selectable: true
54
+ };
55
+ if (parentId) {
56
+ node.parentId = parentId;
57
+ }
58
+ nodes.push(node);
59
+ console.log(`[flowStepsToNodes] Placed "${step.name}" (${step.type}) at x=${currentX}`);
60
+ if (step.type === "conditional" && step.config) {
61
+ const config = step.config;
62
+ const branchX = currentX + BRANCH_OFFSET_X;
63
+ const trueBranchLength = config.trueSteps?.length || 0;
64
+ const falseBranchLength = config.falseSteps?.length || 0;
65
+ const maxBranchLength = Math.max(trueBranchLength, falseBranchLength);
66
+ const trueBranchHeight = trueBranchLength * (NODE_HEIGHT + NODE_SPACING_Y);
67
+ if (config.trueSteps && config.trueSteps.length > 0) {
68
+ const trueBranchY = startPosition.y + BRANCH_OFFSET_Y;
69
+ const trueBranchNodes = flowStepsToNodes(config.trueSteps, {
70
+ onChange,
71
+ onDelete,
72
+ startPosition: {
73
+ x: branchX,
74
+ y: trueBranchY
75
+ },
76
+ idPrefix: `${nodeId}-true-`,
77
+ parentId: nodeId
78
+ });
79
+ nodes.push(...trueBranchNodes);
80
+ }
81
+ if (config.falseSteps && config.falseSteps.length > 0) {
82
+ const falseBranchY = trueBranchLength > 0 ? startPosition.y + BRANCH_OFFSET_Y + trueBranchHeight + FALSE_BRANCH_GAP : startPosition.y + NODE_HEIGHT + NODE_SPACING_Y;
83
+ const falseBranchNodes = flowStepsToNodes(config.falseSteps, {
84
+ onChange,
85
+ onDelete,
86
+ startPosition: {
87
+ x: branchX,
88
+ y: falseBranchY
89
+ },
90
+ idPrefix: `${nodeId}-false-`,
91
+ parentId: nodeId
92
+ });
93
+ nodes.push(...falseBranchNodes);
94
+ config.falseSteps.length * (NODE_HEIGHT + NODE_SPACING_Y);
95
+ }
96
+ if (maxBranchLength > 0) {
97
+ const advance = BRANCH_OFFSET_X + maxBranchLength * (NODE_WIDTH + NODE_SPACING_X);
98
+ console.log(`[flowStepsToNodes] Conditional "${step.name}" has ${maxBranchLength} branch steps, advancing currentX by ${advance}`);
99
+ currentX += advance;
100
+ console.log(`[flowStepsToNodes] After conditional, currentX = ${currentX}`);
101
+ } else {
102
+ currentX += NODE_WIDTH + NODE_SPACING_X;
103
+ }
104
+ } else {
105
+ currentX += NODE_WIDTH + NODE_SPACING_X;
106
+ }
107
+ }
108
+ return nodes;
109
+ }
110
+ function nodesToFlowSteps(nodes) {
111
+ const topLevelNodes = nodes.filter((n) => !n.parentId && !n.id.includes("-true-") && !n.id.includes("-false-"));
112
+ const sortedNodes = [...topLevelNodes].sort((a, b) => a.position.x - b.position.x);
113
+ return sortedNodes.map((node, index) => {
114
+ const step = node.data.step;
115
+ if (step.type === "conditional") {
116
+ const trueSteps = extractBranchSteps(nodes, node.id, "true");
117
+ const falseSteps = extractBranchSteps(nodes, node.id, "false");
118
+ return {
119
+ ...step,
120
+ order: index,
121
+ config: {
122
+ ...step.config,
123
+ trueSteps,
124
+ falseSteps
125
+ }
126
+ };
127
+ }
128
+ return {
129
+ ...step,
130
+ order: index
131
+ };
132
+ });
133
+ }
134
+ function extractBranchSteps(nodes, parentId, branch) {
135
+ const branchPrefix = `${parentId}-${branch}-`;
136
+ const branchNodes = nodes.filter((n) => n.id.startsWith(branchPrefix));
137
+ const sortedBranchNodes = [...branchNodes].sort((a, b) => a.position.x - b.position.x);
138
+ return sortedBranchNodes.map((node, index) => ({
139
+ ...node.data.step,
140
+ order: index
141
+ }));
142
+ }
143
+ function createEdgesFromNodes(nodes) {
144
+ const edges = [];
145
+ const isBranchNode = (n) => n.parentId || n.id.includes("-true-") || n.id.includes("-false-");
146
+ const topLevelNodes = nodes.filter((n) => !isBranchNode(n)).sort((a, b) => a.position.x - b.position.x);
147
+ for (let i = 0; i < topLevelNodes.length - 1; i++) {
148
+ const sourceNode = topLevelNodes[i];
149
+ const targetNode = topLevelNodes[i + 1];
150
+ if (sourceNode.data.step.type === "conditional") {
151
+ continue;
152
+ }
153
+ edges.push({
154
+ id: `edge-${sourceNode.id}-${targetNode.id}`,
155
+ source: sourceNode.id,
156
+ target: targetNode.id,
157
+ sourceHandle: "output",
158
+ type: "smoothstep",
159
+ animated: false,
160
+ data: { stepOrder: i }
161
+ });
162
+ }
163
+ const conditionalNodes = nodes.filter((n) => n.data.step.type === "conditional" && !isBranchNode(n));
164
+ for (const conditionalNode of conditionalNodes) {
165
+ const conditionalId = conditionalNode.id;
166
+ const conditionalIndex = topLevelNodes.findIndex((n) => n.id === conditionalId);
167
+ const nextMainStep = conditionalIndex < topLevelNodes.length - 1 ? topLevelNodes[conditionalIndex + 1] : null;
168
+ const trueBranchNodes = nodes.filter((n) => n.id.startsWith(`${conditionalId}-true-`)).sort((a, b) => a.position.x - b.position.x);
169
+ const falseBranchNodes = nodes.filter((n) => n.id.startsWith(`${conditionalId}-false-`)).sort((a, b) => a.position.x - b.position.x);
170
+ if (trueBranchNodes.length > 0) {
171
+ edges.push({
172
+ id: `edge-${conditionalId}-to-true-branch`,
173
+ source: conditionalId,
174
+ target: trueBranchNodes[0].id,
175
+ sourceHandle: "true",
176
+ type: "smoothstep",
177
+ animated: false,
178
+ label: "True",
179
+ labelStyle: { fill: "#22c55e", fontWeight: 600, fontSize: 11 },
180
+ labelBgStyle: { fill: "#f0fdf4", fillOpacity: 0.9 },
181
+ labelBgPadding: [4, 6],
182
+ labelBgBorderRadius: 4,
183
+ style: { stroke: "#22c55e", strokeWidth: 2 }
184
+ });
185
+ for (let i = 0; i < trueBranchNodes.length - 1; i++) {
186
+ edges.push({
187
+ id: `edge-true-${trueBranchNodes[i].id}-${trueBranchNodes[i + 1].id}`,
188
+ source: trueBranchNodes[i].id,
189
+ target: trueBranchNodes[i + 1].id,
190
+ sourceHandle: "output",
191
+ type: "smoothstep",
192
+ animated: false,
193
+ style: { stroke: "#22c55e", strokeWidth: 1.5 }
194
+ });
195
+ }
196
+ if (nextMainStep) {
197
+ const lastTrueNode = trueBranchNodes[trueBranchNodes.length - 1];
198
+ edges.push({
199
+ id: `edge-true-${lastTrueNode.id}-to-${nextMainStep.id}`,
200
+ source: lastTrueNode.id,
201
+ target: nextMainStep.id,
202
+ sourceHandle: "output",
203
+ type: "smoothstep",
204
+ animated: false,
205
+ style: { stroke: "#22c55e", strokeWidth: 1.5 }
206
+ });
207
+ }
208
+ } else if (nextMainStep) {
209
+ edges.push({
210
+ id: `edge-${conditionalId}-true-to-${nextMainStep.id}`,
211
+ source: conditionalId,
212
+ target: nextMainStep.id,
213
+ sourceHandle: "true",
214
+ type: "smoothstep",
215
+ animated: false,
216
+ label: "True",
217
+ labelStyle: { fill: "#22c55e", fontWeight: 600, fontSize: 11 },
218
+ labelBgStyle: { fill: "#f0fdf4", fillOpacity: 0.9 },
219
+ labelBgPadding: [4, 6],
220
+ labelBgBorderRadius: 4,
221
+ style: { stroke: "#22c55e", strokeWidth: 2 }
222
+ });
223
+ }
224
+ if (falseBranchNodes.length > 0) {
225
+ edges.push({
226
+ id: `edge-${conditionalId}-to-false-branch`,
227
+ source: conditionalId,
228
+ target: falseBranchNodes[0].id,
229
+ sourceHandle: "false",
230
+ type: "smoothstep",
231
+ animated: false,
232
+ label: "False",
233
+ labelStyle: { fill: "#ef4444", fontWeight: 600, fontSize: 11 },
234
+ labelBgStyle: { fill: "#fef2f2", fillOpacity: 0.9 },
235
+ labelBgPadding: [4, 6],
236
+ labelBgBorderRadius: 4,
237
+ style: { stroke: "#ef4444", strokeWidth: 2 }
238
+ });
239
+ for (let i = 0; i < falseBranchNodes.length - 1; i++) {
240
+ edges.push({
241
+ id: `edge-false-${falseBranchNodes[i].id}-${falseBranchNodes[i + 1].id}`,
242
+ source: falseBranchNodes[i].id,
243
+ target: falseBranchNodes[i + 1].id,
244
+ sourceHandle: "output",
245
+ type: "smoothstep",
246
+ animated: false,
247
+ style: { stroke: "#ef4444", strokeWidth: 1.5 }
248
+ });
249
+ }
250
+ if (nextMainStep) {
251
+ const lastFalseNode = falseBranchNodes[falseBranchNodes.length - 1];
252
+ edges.push({
253
+ id: `edge-false-${lastFalseNode.id}-to-${nextMainStep.id}`,
254
+ source: lastFalseNode.id,
255
+ target: nextMainStep.id,
256
+ sourceHandle: "output",
257
+ type: "smoothstep",
258
+ animated: false,
259
+ style: { stroke: "#ef4444", strokeWidth: 1.5 }
260
+ });
261
+ }
262
+ } else if (nextMainStep) {
263
+ edges.push({
264
+ id: `edge-${conditionalId}-false-to-${nextMainStep.id}`,
265
+ source: conditionalId,
266
+ target: nextMainStep.id,
267
+ sourceHandle: "false",
268
+ type: "smoothstep",
269
+ animated: false,
270
+ label: "False",
271
+ labelStyle: { fill: "#ef4444", fontWeight: 600, fontSize: 11 },
272
+ labelBgStyle: { fill: "#fef2f2", fillOpacity: 0.9 },
273
+ labelBgPadding: [4, 6],
274
+ labelBgBorderRadius: 4,
275
+ style: { stroke: "#ef4444", strokeWidth: 2 }
276
+ });
277
+ }
278
+ if (trueBranchNodes.length === 0 && falseBranchNodes.length === 0 && nextMainStep) {
279
+ edges.push({
280
+ id: `edge-${conditionalId}-to-${nextMainStep.id}`,
281
+ source: conditionalId,
282
+ target: nextMainStep.id,
283
+ sourceHandle: "output",
284
+ type: "smoothstep",
285
+ animated: false
286
+ });
287
+ }
288
+ }
289
+ return edges;
290
+ }
291
+ function getDefaultStepName(type) {
292
+ const names = {
293
+ "prompt": "AI Prompt",
294
+ "fetch-url": "Fetch URL",
295
+ "retrieve-record": "Retrieve Record",
296
+ "fetch-github": "Fetch GitHub",
297
+ "api-call": "API Call",
298
+ "transform-data": "Transform Data",
299
+ "conditional": "Conditional",
300
+ "set-variable": "Set Variable",
301
+ "upsert-record": "Upsert Record",
302
+ "send-email": "Send Email",
303
+ "send-text": "Send Text",
304
+ "send-event": "Send Event",
305
+ "send-stream": "Send Stream",
306
+ "update-record": "Update Record",
307
+ "search": "Search",
308
+ "generate-embedding": "Generate Embedding",
309
+ "vector-search": "Vector Search",
310
+ "tool-call": "Tool Call",
311
+ "wait-until": "Wait Until"
312
+ };
313
+ return names[type] || type;
314
+ }
315
+ function createDefaultStep(type, order = 0) {
316
+ const id = `step-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
317
+ const baseStep = {
318
+ id,
319
+ type,
320
+ name: getDefaultStepName(type),
321
+ order,
322
+ enabled: true
323
+ };
324
+ switch (type) {
325
+ case "prompt":
326
+ return {
327
+ ...baseStep,
328
+ config: {
329
+ mode: "instruction",
330
+ model: "",
331
+ userPrompt: "",
332
+ responseFormat: "text",
333
+ outputVariable: `${type}_result`
334
+ }
335
+ };
336
+ case "fetch-url":
337
+ return {
338
+ ...baseStep,
339
+ config: {
340
+ http: {
341
+ url: "",
342
+ method: "GET"
343
+ },
344
+ responseType: "json",
345
+ outputVariable: "fetch_result"
346
+ }
347
+ };
348
+ case "transform-data":
349
+ return {
350
+ ...baseStep,
351
+ config: {
352
+ script: "// Transform your data here\nreturn { result: input }",
353
+ outputVariable: "transform_result"
354
+ }
355
+ };
356
+ case "conditional":
357
+ return {
358
+ ...baseStep,
359
+ config: {
360
+ condition: "true",
361
+ trueSteps: [],
362
+ falseSteps: []
363
+ }
364
+ };
365
+ case "send-email":
366
+ return {
367
+ ...baseStep,
368
+ config: {
369
+ from: "no-reply@messages.runtype.com",
370
+ to: "",
371
+ subject: "",
372
+ html: "",
373
+ outputVariable: "email_result"
374
+ }
375
+ };
376
+ default:
377
+ return {
378
+ ...baseStep,
379
+ config: {
380
+ outputVariable: `${type.replace(/-/g, "_")}_result`
381
+ }
382
+ };
383
+ }
384
+ }
385
+ function generateStepId(prefix = "step") {
386
+ return `${prefix}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
387
+ }
388
+ function cloneStep(step) {
389
+ return {
390
+ ...step,
391
+ id: generateStepId(step.type),
392
+ config: JSON.parse(JSON.stringify(step.config))
393
+ };
394
+ }
395
+
396
+ // src/utils/layout.ts
397
+ var DEFAULT_NODE_WIDTH = 280;
398
+ var DEFAULT_NODE_HEIGHT = 150;
399
+ var HORIZONTAL_SPACING = 100;
400
+ var VERTICAL_SPACING = 80;
401
+ var BRANCH_OFFSET = 350;
402
+ function autoLayout(nodes, edges, options = {}) {
403
+ const {
404
+ direction = "vertical",
405
+ startPosition = { x: 400, y: 50 },
406
+ nodeWidth = DEFAULT_NODE_WIDTH,
407
+ nodeHeight = DEFAULT_NODE_HEIGHT,
408
+ horizontalSpacing = HORIZONTAL_SPACING,
409
+ verticalSpacing = VERTICAL_SPACING,
410
+ branchOffset = BRANCH_OFFSET
411
+ } = options;
412
+ const adjacencyMap = /* @__PURE__ */ new Map();
413
+ const incomingMap = /* @__PURE__ */ new Map();
414
+ for (const edge of edges) {
415
+ const existing = adjacencyMap.get(edge.source) || [];
416
+ adjacencyMap.set(edge.source, [...existing, edge.target]);
417
+ const incoming = incomingMap.get(edge.target) || [];
418
+ incomingMap.set(edge.target, [...incoming, edge.source]);
419
+ }
420
+ const rootNodes = nodes.filter((node) => {
421
+ const incoming = incomingMap.get(node.id);
422
+ return !incoming || incoming.length === 0;
423
+ });
424
+ if (rootNodes.length === 0 && nodes.length > 0) {
425
+ rootNodes.push(nodes[0]);
426
+ }
427
+ const positionedNodes = /* @__PURE__ */ new Map();
428
+ const visited = /* @__PURE__ */ new Set();
429
+ const queue = [];
430
+ let startX = startPosition.x;
431
+ for (const rootNode of rootNodes) {
432
+ queue.push({ nodeId: rootNode.id, x: startX, y: startPosition.y, depth: 0 });
433
+ startX += nodeWidth + horizontalSpacing;
434
+ }
435
+ while (queue.length > 0) {
436
+ const { nodeId, x, y, depth } = queue.shift();
437
+ if (visited.has(nodeId)) continue;
438
+ visited.add(nodeId);
439
+ positionedNodes.set(nodeId, { x, y });
440
+ const children = adjacencyMap.get(nodeId) || [];
441
+ const node = nodes.find((n) => n.id === nodeId);
442
+ const isConditional = node?.data.step.type === "conditional";
443
+ if (isConditional && children.length > 0) {
444
+ const trueBranch = children.filter((c) => c.includes("-true-"));
445
+ const falseBranch = children.filter((c) => c.includes("-false-"));
446
+ const normalChildren = children.filter((c) => !c.includes("-true-") && !c.includes("-false-"));
447
+ let trueY = y + nodeHeight + verticalSpacing;
448
+ for (const childId of trueBranch) {
449
+ if (!visited.has(childId)) {
450
+ queue.push({
451
+ nodeId: childId,
452
+ x: x + branchOffset,
453
+ y: trueY,
454
+ depth: depth + 1
455
+ });
456
+ trueY += nodeHeight + verticalSpacing;
457
+ }
458
+ }
459
+ let falseY = y + nodeHeight + verticalSpacing;
460
+ for (const childId of falseBranch) {
461
+ if (!visited.has(childId)) {
462
+ queue.push({
463
+ nodeId: childId,
464
+ x: x - branchOffset,
465
+ y: falseY,
466
+ depth: depth + 1
467
+ });
468
+ falseY += nodeHeight + verticalSpacing;
469
+ }
470
+ }
471
+ const maxBranchY = Math.max(trueY, falseY);
472
+ let childY = maxBranchY;
473
+ for (const childId of normalChildren) {
474
+ if (!visited.has(childId)) {
475
+ queue.push({
476
+ nodeId: childId,
477
+ x,
478
+ y: childY,
479
+ depth: depth + 1
480
+ });
481
+ childY += nodeHeight + verticalSpacing;
482
+ }
483
+ }
484
+ } else {
485
+ let childY = y + nodeHeight + verticalSpacing;
486
+ let childX = x;
487
+ for (let i = 0; i < children.length; i++) {
488
+ const childId = children[i];
489
+ if (!visited.has(childId)) {
490
+ if (direction === "horizontal") {
491
+ queue.push({
492
+ nodeId: childId,
493
+ x: childX + nodeWidth + horizontalSpacing,
494
+ y,
495
+ depth: depth + 1
496
+ });
497
+ childX += nodeWidth + horizontalSpacing;
498
+ } else {
499
+ queue.push({
500
+ nodeId: childId,
501
+ x,
502
+ y: childY,
503
+ depth: depth + 1
504
+ });
505
+ childY += nodeHeight + verticalSpacing;
506
+ }
507
+ }
508
+ }
509
+ }
510
+ }
511
+ return nodes.map((node) => {
512
+ const position = positionedNodes.get(node.id);
513
+ if (position) {
514
+ return {
515
+ ...node,
516
+ position
517
+ };
518
+ }
519
+ return node;
520
+ });
521
+ }
522
+ function centerNodes(nodes, viewportWidth, viewportHeight) {
523
+ if (nodes.length === 0) return nodes;
524
+ let minX = Infinity;
525
+ let maxX = -Infinity;
526
+ let minY = Infinity;
527
+ let maxY = -Infinity;
528
+ for (const node of nodes) {
529
+ minX = Math.min(minX, node.position.x);
530
+ maxX = Math.max(maxX, node.position.x + DEFAULT_NODE_WIDTH);
531
+ minY = Math.min(minY, node.position.y);
532
+ maxY = Math.max(maxY, node.position.y + DEFAULT_NODE_HEIGHT);
533
+ }
534
+ const contentWidth = maxX - minX;
535
+ const contentHeight = maxY - minY;
536
+ const offsetX = (viewportWidth - contentWidth) / 2 - minX;
537
+ const offsetY = (viewportHeight - contentHeight) / 2 - minY;
538
+ return nodes.map((node) => ({
539
+ ...node,
540
+ position: {
541
+ x: node.position.x + offsetX,
542
+ y: node.position.y + offsetY
543
+ }
544
+ }));
545
+ }
546
+ function snapToGrid(nodes, gridSize = 20) {
547
+ return nodes.map((node) => ({
548
+ ...node,
549
+ position: {
550
+ x: Math.round(node.position.x / gridSize) * gridSize,
551
+ y: Math.round(node.position.y / gridSize) * gridSize
552
+ }
553
+ }));
554
+ }
555
+ function getNodesBoundingBox(nodes) {
556
+ if (nodes.length === 0) {
557
+ return { minX: 0, maxX: 0, minY: 0, maxY: 0, width: 0, height: 0 };
558
+ }
559
+ let minX = Infinity;
560
+ let maxX = -Infinity;
561
+ let minY = Infinity;
562
+ let maxY = -Infinity;
563
+ for (const node of nodes) {
564
+ minX = Math.min(minX, node.position.x);
565
+ maxX = Math.max(maxX, node.position.x + DEFAULT_NODE_WIDTH);
566
+ minY = Math.min(minY, node.position.y);
567
+ maxY = Math.max(maxY, node.position.y + DEFAULT_NODE_HEIGHT);
568
+ }
569
+ return {
570
+ minX,
571
+ maxX,
572
+ minY,
573
+ maxY,
574
+ width: maxX - minX,
575
+ height: maxY - minY
576
+ };
577
+ }
578
+
579
+ // src/hooks/useRuntypeFlow.ts
580
+ function useRuntypeFlow(options) {
581
+ const {
582
+ client,
583
+ flowId: initialFlowId,
584
+ initialName = "",
585
+ initialDescription = "",
586
+ initialSteps = [],
587
+ onChange,
588
+ autoLayoutOnLoad = true
589
+ } = options;
590
+ const [flowId, setFlowId] = react.useState(initialFlowId || null);
591
+ const [flowName, setFlowName] = react.useState(initialName);
592
+ const [flowDescription, setFlowDescription] = react.useState(initialDescription);
593
+ const [isLoading, setIsLoading] = react.useState(false);
594
+ const [isSaving, setIsSaving] = react.useState(false);
595
+ const [error, setError] = react.useState(null);
596
+ const [hasUnsavedChanges, setHasUnsavedChanges] = react.useState(false);
597
+ const [nodes, setNodes, onNodesChange] = react$1.useNodesState([]);
598
+ const [edges, setEdges, onEdgesChange] = react$1.useEdgesState([]);
599
+ const lastSavedState = react.useRef("");
600
+ const handleStepChange = react.useCallback(
601
+ (stepId, updates) => {
602
+ setNodes(
603
+ (nds) => nds.map((node) => {
604
+ if (node.id === stepId) {
605
+ return {
606
+ ...node,
607
+ data: {
608
+ ...node.data,
609
+ step: {
610
+ ...node.data.step,
611
+ ...updates,
612
+ config: updates.config ? { ...node.data.step.config, ...updates.config } : node.data.step.config
613
+ }
614
+ }
615
+ };
616
+ }
617
+ return node;
618
+ })
619
+ );
620
+ setHasUnsavedChanges(true);
621
+ },
622
+ [setNodes]
623
+ );
624
+ const handleStepDelete = react.useCallback(
625
+ (stepId) => {
626
+ setNodes((nds) => nds.filter((node) => node.id !== stepId));
627
+ setEdges(
628
+ (eds) => eds.filter((edge) => edge.source !== stepId && edge.target !== stepId)
629
+ );
630
+ setHasUnsavedChanges(true);
631
+ },
632
+ [setNodes, setEdges]
633
+ );
634
+ const handleConnect = react.useCallback(
635
+ (connection) => {
636
+ setEdges((eds) => react$1.addEdge({ ...connection, type: "smoothstep" }, eds));
637
+ setHasUnsavedChanges(true);
638
+ },
639
+ [setEdges]
640
+ );
641
+ const loadFlow = react.useCallback(
642
+ async (id) => {
643
+ setIsLoading(true);
644
+ setError(null);
645
+ try {
646
+ const flow = await client.flows.get(id);
647
+ const stepsResponse = await client.flowSteps.getByFlow(id);
648
+ const steps = Array.isArray(stepsResponse) ? stepsResponse : [];
649
+ let newNodes = flowStepsToNodes(steps, {
650
+ onChange: handleStepChange,
651
+ onDelete: handleStepDelete
652
+ });
653
+ if (autoLayoutOnLoad) {
654
+ const newEdges2 = createEdgesFromNodes(newNodes);
655
+ newNodes = autoLayout(newNodes, newEdges2);
656
+ }
657
+ const newEdges = createEdgesFromNodes(newNodes);
658
+ setFlowId(id);
659
+ setFlowName(flow.name || "");
660
+ setFlowDescription(flow.description || "");
661
+ setNodes(newNodes);
662
+ setEdges(newEdges);
663
+ setHasUnsavedChanges(false);
664
+ lastSavedState.current = JSON.stringify(nodesToFlowSteps(newNodes));
665
+ } catch (err) {
666
+ setError(err instanceof Error ? err : new Error("Failed to load flow"));
667
+ throw err;
668
+ } finally {
669
+ setIsLoading(false);
670
+ }
671
+ },
672
+ [client, handleStepChange, handleStepDelete, autoLayoutOnLoad, setNodes, setEdges]
673
+ );
674
+ const saveFlow = react.useCallback(async () => {
675
+ if (!flowId) {
676
+ throw new Error("No flow ID. Use createFlow() to create a new flow first.");
677
+ }
678
+ setIsSaving(true);
679
+ setError(null);
680
+ try {
681
+ const steps = nodesToFlowSteps(nodes);
682
+ await client.flows.update(flowId, {
683
+ name: flowName,
684
+ description: flowDescription
685
+ });
686
+ const existingSteps = await client.flowSteps.getByFlow(flowId);
687
+ for (const step of existingSteps) {
688
+ await client.flowSteps.delete(step.id);
689
+ }
690
+ for (const step of steps) {
691
+ await client.flowSteps.create({
692
+ flowId,
693
+ type: step.type,
694
+ name: step.name,
695
+ order: step.order,
696
+ enabled: step.enabled,
697
+ config: step.config
698
+ });
699
+ }
700
+ setHasUnsavedChanges(false);
701
+ lastSavedState.current = JSON.stringify(steps);
702
+ return {
703
+ id: flowId,
704
+ name: flowName,
705
+ description: flowDescription,
706
+ steps
707
+ };
708
+ } catch (err) {
709
+ setError(err instanceof Error ? err : new Error("Failed to save flow"));
710
+ throw err;
711
+ } finally {
712
+ setIsSaving(false);
713
+ }
714
+ }, [flowId, flowName, flowDescription, nodes, client]);
715
+ const createFlow = react.useCallback(
716
+ async (name, description) => {
717
+ setIsSaving(true);
718
+ setError(null);
719
+ try {
720
+ const flow = await client.flows.create({
721
+ name,
722
+ description,
723
+ prompts: []
724
+ });
725
+ setFlowId(flow.id);
726
+ setFlowName(name);
727
+ setFlowDescription(description || "");
728
+ setNodes([]);
729
+ setEdges([]);
730
+ setHasUnsavedChanges(false);
731
+ lastSavedState.current = "[]";
732
+ return {
733
+ id: flow.id,
734
+ name,
735
+ description,
736
+ steps: []
737
+ };
738
+ } catch (err) {
739
+ setError(err instanceof Error ? err : new Error("Failed to create flow"));
740
+ throw err;
741
+ } finally {
742
+ setIsSaving(false);
743
+ }
744
+ },
745
+ [client, setNodes, setEdges]
746
+ );
747
+ const deleteStep = react.useCallback(
748
+ (stepId) => {
749
+ handleStepDelete(stepId);
750
+ },
751
+ [handleStepDelete]
752
+ );
753
+ const updateStep = react.useCallback(
754
+ (stepId, updates) => {
755
+ handleStepChange(stepId, updates);
756
+ },
757
+ [handleStepChange]
758
+ );
759
+ const addStep = react.useCallback(
760
+ (type, position) => {
761
+ const newStep = createDefaultStep(type, nodes.length);
762
+ const newNode = {
763
+ id: newStep.id,
764
+ type: newStep.type,
765
+ position: position || { x: 400, y: nodes.length * 230 + 50 },
766
+ data: {
767
+ step: newStep,
768
+ label: newStep.name,
769
+ onChange: handleStepChange,
770
+ onDelete: handleStepDelete
771
+ },
772
+ draggable: true,
773
+ selectable: true
774
+ };
775
+ setNodes((nds) => [...nds, newNode]);
776
+ if (nodes.length > 0) {
777
+ const lastNode = nodes[nodes.length - 1];
778
+ setEdges((eds) => [
779
+ ...eds,
780
+ {
781
+ id: `edge-${lastNode.id}-${newNode.id}`,
782
+ source: lastNode.id,
783
+ target: newNode.id,
784
+ type: "smoothstep"
785
+ }
786
+ ]);
787
+ }
788
+ setHasUnsavedChanges(true);
789
+ },
790
+ [nodes, setNodes, setEdges, handleStepChange, handleStepDelete]
791
+ );
792
+ react.useEffect(() => {
793
+ if (initialFlowId) {
794
+ loadFlow(initialFlowId);
795
+ } else if (initialSteps.length > 0) {
796
+ let newNodes = flowStepsToNodes(initialSteps, {
797
+ onChange: handleStepChange,
798
+ onDelete: handleStepDelete
799
+ });
800
+ if (autoLayoutOnLoad) {
801
+ const newEdges2 = createEdgesFromNodes(newNodes);
802
+ newNodes = autoLayout(newNodes, newEdges2);
803
+ }
804
+ const newEdges = createEdgesFromNodes(newNodes);
805
+ setNodes(newNodes);
806
+ setEdges(newEdges);
807
+ }
808
+ }, []);
809
+ react.useEffect(() => {
810
+ onChange?.(nodes, edges);
811
+ }, [nodes, edges, onChange]);
812
+ react.useEffect(() => {
813
+ const currentState = JSON.stringify(nodesToFlowSteps(nodes));
814
+ if (lastSavedState.current && currentState !== lastSavedState.current) {
815
+ setHasUnsavedChanges(true);
816
+ }
817
+ }, [nodes]);
818
+ return {
819
+ // React Flow state
820
+ nodes,
821
+ edges,
822
+ onNodesChange,
823
+ onEdgesChange,
824
+ onConnect: handleConnect,
825
+ // Flow metadata
826
+ flowName,
827
+ flowDescription,
828
+ flowId,
829
+ setFlowName,
830
+ setFlowDescription,
831
+ // API operations
832
+ loadFlow,
833
+ saveFlow,
834
+ createFlow,
835
+ deleteStep,
836
+ updateStep,
837
+ addStep,
838
+ // Status
839
+ isLoading,
840
+ isSaving,
841
+ error,
842
+ hasUnsavedChanges
843
+ };
844
+ }
845
+ var promptValidation = {
846
+ validate: (step) => {
847
+ const errors = [];
848
+ const config = step.config;
849
+ if (!config.model) {
850
+ errors.push({
851
+ stepId: step.id,
852
+ field: "model",
853
+ message: "Model is required"
854
+ });
855
+ }
856
+ if (!config.userPrompt?.trim()) {
857
+ errors.push({
858
+ stepId: step.id,
859
+ field: "userPrompt",
860
+ message: "User prompt is required"
861
+ });
862
+ }
863
+ if (!config.outputVariable?.trim()) {
864
+ errors.push({
865
+ stepId: step.id,
866
+ field: "outputVariable",
867
+ message: "Output variable is required"
868
+ });
869
+ }
870
+ return errors;
871
+ }
872
+ };
873
+ var fetchUrlValidation = {
874
+ validate: (step) => {
875
+ const errors = [];
876
+ const config = step.config;
877
+ if (!config.http?.url?.trim()) {
878
+ errors.push({
879
+ stepId: step.id,
880
+ field: "http.url",
881
+ message: "URL is required"
882
+ });
883
+ } else {
884
+ const url = config.http.url;
885
+ if (!url.startsWith("http://") && !url.startsWith("https://") && !url.includes("{{")) {
886
+ errors.push({
887
+ stepId: step.id,
888
+ field: "http.url",
889
+ message: "URL must start with http:// or https://"
890
+ });
891
+ }
892
+ }
893
+ if (!config.outputVariable?.trim()) {
894
+ errors.push({
895
+ stepId: step.id,
896
+ field: "outputVariable",
897
+ message: "Output variable is required"
898
+ });
899
+ }
900
+ return errors;
901
+ }
902
+ };
903
+ var transformDataValidation = {
904
+ validate: (step) => {
905
+ const errors = [];
906
+ const config = step.config;
907
+ if (!config.script?.trim()) {
908
+ errors.push({
909
+ stepId: step.id,
910
+ field: "script",
911
+ message: "Script is required"
912
+ });
913
+ }
914
+ if (!config.outputVariable?.trim()) {
915
+ errors.push({
916
+ stepId: step.id,
917
+ field: "outputVariable",
918
+ message: "Output variable is required"
919
+ });
920
+ }
921
+ return errors;
922
+ }
923
+ };
924
+ var conditionalValidation = {
925
+ validate: (step, allSteps) => {
926
+ const errors = [];
927
+ const config = step.config;
928
+ if (!config.condition?.trim()) {
929
+ errors.push({
930
+ stepId: step.id,
931
+ field: "condition",
932
+ message: "Condition is required"
933
+ });
934
+ }
935
+ if (config.trueSteps && config.trueSteps.length > 0) {
936
+ for (const nestedStep of config.trueSteps) {
937
+ const nestedErrors = validateStep(nestedStep, allSteps);
938
+ errors.push(
939
+ ...nestedErrors.map((e) => ({
940
+ ...e,
941
+ message: `True branch: ${e.message}`
942
+ }))
943
+ );
944
+ }
945
+ }
946
+ if (config.falseSteps && config.falseSteps.length > 0) {
947
+ for (const nestedStep of config.falseSteps) {
948
+ const nestedErrors = validateStep(nestedStep, allSteps);
949
+ errors.push(
950
+ ...nestedErrors.map((e) => ({
951
+ ...e,
952
+ message: `False branch: ${e.message}`
953
+ }))
954
+ );
955
+ }
956
+ }
957
+ return errors;
958
+ }
959
+ };
960
+ var sendEmailValidation = {
961
+ validate: (step) => {
962
+ const errors = [];
963
+ const config = step.config;
964
+ if (!config.to?.trim()) {
965
+ errors.push({
966
+ stepId: step.id,
967
+ field: "to",
968
+ message: "Recipient (To) is required"
969
+ });
970
+ } else {
971
+ const to = config.to;
972
+ if (!to.includes("@") && !to.includes("{{")) {
973
+ errors.push({
974
+ stepId: step.id,
975
+ field: "to",
976
+ message: "Invalid email address"
977
+ });
978
+ }
979
+ }
980
+ if (!config.subject?.trim()) {
981
+ errors.push({
982
+ stepId: step.id,
983
+ field: "subject",
984
+ message: "Subject is required"
985
+ });
986
+ }
987
+ if (!config.html?.trim() && !config.text?.trim()) {
988
+ errors.push({
989
+ stepId: step.id,
990
+ field: "html",
991
+ message: "Email content (HTML or text) is required"
992
+ });
993
+ }
994
+ if (!config.outputVariable?.trim()) {
995
+ errors.push({
996
+ stepId: step.id,
997
+ field: "outputVariable",
998
+ message: "Output variable is required"
999
+ });
1000
+ }
1001
+ return errors;
1002
+ }
1003
+ };
1004
+ var outputVariableWarning = {
1005
+ check: (step, allSteps) => {
1006
+ const warnings = [];
1007
+ const config = step.config;
1008
+ if (config.outputVariable) {
1009
+ const duplicates = allSteps.filter(
1010
+ (s) => s.id !== step.id && s.config.outputVariable === config.outputVariable
1011
+ );
1012
+ if (duplicates.length > 0) {
1013
+ warnings.push({
1014
+ stepId: step.id,
1015
+ field: "outputVariable",
1016
+ message: `Output variable "${config.outputVariable}" is also used by another step`
1017
+ });
1018
+ }
1019
+ }
1020
+ return warnings;
1021
+ }
1022
+ };
1023
+ var emptyBranchWarning = {
1024
+ check: (step) => {
1025
+ const warnings = [];
1026
+ if (step.type === "conditional") {
1027
+ const config = step.config;
1028
+ if (!config.trueSteps || config.trueSteps.length === 0) {
1029
+ warnings.push({
1030
+ stepId: step.id,
1031
+ field: "trueSteps",
1032
+ message: "True branch has no steps"
1033
+ });
1034
+ }
1035
+ if (!config.falseSteps || config.falseSteps.length === 0) {
1036
+ warnings.push({
1037
+ stepId: step.id,
1038
+ field: "falseSteps",
1039
+ message: "False branch has no steps"
1040
+ });
1041
+ }
1042
+ }
1043
+ return warnings;
1044
+ }
1045
+ };
1046
+ var validationRules = {
1047
+ prompt: promptValidation,
1048
+ "fetch-url": fetchUrlValidation,
1049
+ "transform-data": transformDataValidation,
1050
+ conditional: conditionalValidation,
1051
+ "send-email": sendEmailValidation
1052
+ };
1053
+ var warningRules = [outputVariableWarning, emptyBranchWarning];
1054
+ function validateStep(step, allSteps) {
1055
+ const errors = [];
1056
+ if (!step.name?.trim()) {
1057
+ errors.push({
1058
+ stepId: step.id,
1059
+ field: "name",
1060
+ message: "Step name is required"
1061
+ });
1062
+ }
1063
+ const rule = validationRules[step.type];
1064
+ if (rule) {
1065
+ errors.push(...rule.validate(step, allSteps));
1066
+ }
1067
+ return errors;
1068
+ }
1069
+ function checkWarnings(step, allSteps) {
1070
+ const warnings = [];
1071
+ for (const rule of warningRules) {
1072
+ warnings.push(...rule.check(step, allSteps));
1073
+ }
1074
+ return warnings;
1075
+ }
1076
+ function useFlowValidation(options) {
1077
+ const { steps: providedSteps, nodes } = options;
1078
+ const steps = react.useMemo(() => {
1079
+ if (providedSteps) return providedSteps;
1080
+ if (nodes) return nodes.map((n) => n.data.step);
1081
+ return [];
1082
+ }, [providedSteps, nodes]);
1083
+ const result = react.useMemo(() => {
1084
+ const errors = [];
1085
+ const warnings = [];
1086
+ for (const step of steps) {
1087
+ errors.push(...validateStep(step, steps));
1088
+ warnings.push(...checkWarnings(step, steps));
1089
+ }
1090
+ return {
1091
+ isValid: errors.length === 0,
1092
+ errors,
1093
+ warnings
1094
+ };
1095
+ }, [steps]);
1096
+ const validateStepFn = react.useCallback(
1097
+ (step) => validateStep(step, steps),
1098
+ [steps]
1099
+ );
1100
+ const isStepValid = react.useCallback(
1101
+ (stepId) => {
1102
+ return !result.errors.some((e) => e.stepId === stepId);
1103
+ },
1104
+ [result.errors]
1105
+ );
1106
+ const getStepErrors = react.useCallback(
1107
+ (stepId) => {
1108
+ return result.errors.filter((e) => e.stepId === stepId);
1109
+ },
1110
+ [result.errors]
1111
+ );
1112
+ const getStepWarnings = react.useCallback(
1113
+ (stepId) => {
1114
+ return result.warnings.filter((w) => w.stepId === stepId);
1115
+ },
1116
+ [result.warnings]
1117
+ );
1118
+ return {
1119
+ result,
1120
+ validateStep: validateStepFn,
1121
+ isStepValid,
1122
+ getStepErrors,
1123
+ getStepWarnings
1124
+ };
1125
+ }
1126
+ var styles = {
1127
+ container: (selected) => ({
1128
+ minWidth: "280px",
1129
+ maxWidth: "320px",
1130
+ backgroundColor: "#ffffff",
1131
+ borderRadius: "12px",
1132
+ border: selected ? "2px solid #6366f1" : "1px solid #e5e7eb",
1133
+ boxShadow: selected ? "0 0 0 2px rgba(99, 102, 241, 0.2), 0 4px 6px -1px rgba(0, 0, 0, 0.1)" : "0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)",
1134
+ overflow: "hidden",
1135
+ transition: "border-color 0.15s ease, box-shadow 0.15s ease"
1136
+ }),
1137
+ header: (color) => ({
1138
+ display: "flex",
1139
+ alignItems: "center",
1140
+ gap: "8px",
1141
+ padding: "10px 12px",
1142
+ backgroundColor: color,
1143
+ borderBottom: "1px solid rgba(0, 0, 0, 0.05)"
1144
+ }),
1145
+ iconWrapper: {
1146
+ display: "flex",
1147
+ alignItems: "center",
1148
+ justifyContent: "center",
1149
+ width: "28px",
1150
+ height: "28px",
1151
+ borderRadius: "6px",
1152
+ backgroundColor: "rgba(255, 255, 255, 0.9)",
1153
+ color: "#374151"
1154
+ },
1155
+ headerContent: {
1156
+ flex: 1,
1157
+ minWidth: 0
1158
+ },
1159
+ typeLabel: {
1160
+ fontSize: "10px",
1161
+ fontWeight: 600,
1162
+ textTransform: "uppercase",
1163
+ letterSpacing: "0.05em",
1164
+ color: "rgba(0, 0, 0, 0.5)",
1165
+ marginBottom: "2px"
1166
+ },
1167
+ stepName: {
1168
+ fontSize: "13px",
1169
+ fontWeight: 600,
1170
+ color: "#1f2937",
1171
+ overflow: "hidden",
1172
+ textOverflow: "ellipsis",
1173
+ whiteSpace: "nowrap"
1174
+ },
1175
+ body: {
1176
+ padding: "12px"
1177
+ },
1178
+ handle: {
1179
+ width: "12px",
1180
+ height: "12px",
1181
+ borderRadius: "50%",
1182
+ border: "2px solid #ffffff"
1183
+ },
1184
+ targetHandle: {
1185
+ backgroundColor: "#6366f1"
1186
+ },
1187
+ sourceHandle: {
1188
+ backgroundColor: "#10b981"
1189
+ },
1190
+ deleteButton: {
1191
+ padding: "4px",
1192
+ borderRadius: "4px",
1193
+ backgroundColor: "transparent",
1194
+ border: "none",
1195
+ cursor: "pointer",
1196
+ color: "#9ca3af",
1197
+ display: "flex",
1198
+ alignItems: "center",
1199
+ justifyContent: "center",
1200
+ transition: "color 0.15s ease, background-color 0.15s ease"
1201
+ },
1202
+ enabledBadge: (enabled) => ({
1203
+ display: "inline-flex",
1204
+ alignItems: "center",
1205
+ padding: "2px 6px",
1206
+ borderRadius: "4px",
1207
+ fontSize: "10px",
1208
+ fontWeight: 500,
1209
+ backgroundColor: enabled ? "rgba(16, 185, 129, 0.1)" : "rgba(239, 68, 68, 0.1)",
1210
+ color: enabled ? "#059669" : "#dc2626"
1211
+ })
1212
+ };
1213
+ var NODE_HEADER_COLORS = {
1214
+ prompt: "#f3e8ff",
1215
+ // Purple tint
1216
+ "fetch-url": "#dbeafe",
1217
+ // Blue tint
1218
+ "transform-data": "#fef3c7",
1219
+ // Amber tint
1220
+ conditional: "#fce7f3",
1221
+ // Pink tint
1222
+ "send-email": "#d1fae5",
1223
+ // Green tint
1224
+ default: "#f3f4f6"
1225
+ // Gray tint
1226
+ };
1227
+ var BaseNode = react.memo(function BaseNode2({
1228
+ data,
1229
+ selected = false,
1230
+ id,
1231
+ typeLabel,
1232
+ icon,
1233
+ headerColor,
1234
+ showSourceHandle = true,
1235
+ showTargetHandle = true,
1236
+ additionalSourceHandles,
1237
+ children
1238
+ }) {
1239
+ const { step, onChange, onDelete } = data;
1240
+ const color = headerColor || NODE_HEADER_COLORS[step.type] || NODE_HEADER_COLORS.default;
1241
+ const handleDelete = (e) => {
1242
+ e.stopPropagation();
1243
+ onDelete?.(id);
1244
+ };
1245
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.container(selected), children: [
1246
+ showTargetHandle && /* @__PURE__ */ jsxRuntime.jsx(
1247
+ react$1.Handle,
1248
+ {
1249
+ type: "target",
1250
+ position: react$1.Position.Left,
1251
+ style: { ...styles.handle, ...styles.targetHandle }
1252
+ }
1253
+ ),
1254
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.header(color), children: [
1255
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.iconWrapper, children: icon }),
1256
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.headerContent, children: [
1257
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.typeLabel, children: typeLabel }),
1258
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.stepName, title: step.name, children: step.name || "Untitled Step" })
1259
+ ] }),
1260
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
1261
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.enabledBadge(step.enabled), children: step.enabled ? "Active" : "Disabled" }),
1262
+ onDelete && /* @__PURE__ */ jsxRuntime.jsx(
1263
+ "button",
1264
+ {
1265
+ style: styles.deleteButton,
1266
+ onClick: handleDelete,
1267
+ title: "Delete step",
1268
+ onMouseEnter: (e) => {
1269
+ e.currentTarget.style.backgroundColor = "rgba(239, 68, 68, 0.1)";
1270
+ e.currentTarget.style.color = "#dc2626";
1271
+ },
1272
+ onMouseLeave: (e) => {
1273
+ e.currentTarget.style.backgroundColor = "transparent";
1274
+ e.currentTarget.style.color = "#9ca3af";
1275
+ },
1276
+ children: /* @__PURE__ */ jsxRuntime.jsx(DeleteIcon, {})
1277
+ }
1278
+ )
1279
+ ] })
1280
+ ] }),
1281
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.body, className: "nodrag", children }),
1282
+ showSourceHandle && /* @__PURE__ */ jsxRuntime.jsx(
1283
+ react$1.Handle,
1284
+ {
1285
+ type: "source",
1286
+ position: react$1.Position.Right,
1287
+ id: "output",
1288
+ style: { ...styles.handle, ...styles.sourceHandle }
1289
+ }
1290
+ ),
1291
+ additionalSourceHandles?.map((handle) => /* @__PURE__ */ jsxRuntime.jsx(
1292
+ react$1.Handle,
1293
+ {
1294
+ type: "source",
1295
+ position: handle.position,
1296
+ id: handle.id,
1297
+ style: {
1298
+ ...styles.handle,
1299
+ backgroundColor: handle.color || "#10b981",
1300
+ ...handle.style
1301
+ }
1302
+ },
1303
+ handle.id
1304
+ ))
1305
+ ] });
1306
+ });
1307
+ var DeleteIcon = () => /* @__PURE__ */ jsxRuntime.jsxs(
1308
+ "svg",
1309
+ {
1310
+ width: "14",
1311
+ height: "14",
1312
+ viewBox: "0 0 24 24",
1313
+ fill: "none",
1314
+ stroke: "currentColor",
1315
+ strokeWidth: "2",
1316
+ strokeLinecap: "round",
1317
+ strokeLinejoin: "round",
1318
+ children: [
1319
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 6h18" }),
1320
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }),
1321
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" })
1322
+ ]
1323
+ }
1324
+ );
1325
+ var BrainIcon = () => /* @__PURE__ */ jsxRuntime.jsxs(
1326
+ "svg",
1327
+ {
1328
+ width: "16",
1329
+ height: "16",
1330
+ viewBox: "0 0 24 24",
1331
+ fill: "none",
1332
+ stroke: "currentColor",
1333
+ strokeWidth: "2",
1334
+ strokeLinecap: "round",
1335
+ strokeLinejoin: "round",
1336
+ children: [
1337
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z" }),
1338
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 5a3 3 0 1 1 5.997.125 4 4 0 0 1 2.526 5.77 4 4 0 0 1-.556 6.588A4 4 0 1 1 12 18Z" }),
1339
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M15 13a4.5 4.5 0 0 1-3-4 4.5 4.5 0 0 1-3 4" }),
1340
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M17.599 6.5a3 3 0 0 0 .399-1.375" }),
1341
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6.003 5.125A3 3 0 0 0 6.401 6.5" }),
1342
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3.477 10.896a4 4 0 0 1 .585-.396" }),
1343
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19.938 10.5a4 4 0 0 1 .585.396" }),
1344
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 18a4 4 0 0 1-1.967-.516" }),
1345
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19.967 17.484A4 4 0 0 1 18 18" })
1346
+ ]
1347
+ }
1348
+ );
1349
+ var GlobeIcon = () => /* @__PURE__ */ jsxRuntime.jsxs(
1350
+ "svg",
1351
+ {
1352
+ width: "16",
1353
+ height: "16",
1354
+ viewBox: "0 0 24 24",
1355
+ fill: "none",
1356
+ stroke: "currentColor",
1357
+ strokeWidth: "2",
1358
+ strokeLinecap: "round",
1359
+ strokeLinejoin: "round",
1360
+ children: [
1361
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10" }),
1362
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" }),
1363
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 12h20" })
1364
+ ]
1365
+ }
1366
+ );
1367
+ var CodeIcon = () => /* @__PURE__ */ jsxRuntime.jsxs(
1368
+ "svg",
1369
+ {
1370
+ width: "16",
1371
+ height: "16",
1372
+ viewBox: "0 0 24 24",
1373
+ fill: "none",
1374
+ stroke: "currentColor",
1375
+ strokeWidth: "2",
1376
+ strokeLinecap: "round",
1377
+ strokeLinejoin: "round",
1378
+ children: [
1379
+ /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "16 18 22 12 16 6" }),
1380
+ /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "8 6 2 12 8 18" })
1381
+ ]
1382
+ }
1383
+ );
1384
+ var GitBranchIcon = () => /* @__PURE__ */ jsxRuntime.jsxs(
1385
+ "svg",
1386
+ {
1387
+ width: "16",
1388
+ height: "16",
1389
+ viewBox: "0 0 24 24",
1390
+ fill: "none",
1391
+ stroke: "currentColor",
1392
+ strokeWidth: "2",
1393
+ strokeLinecap: "round",
1394
+ strokeLinejoin: "round",
1395
+ children: [
1396
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "6", y1: "3", x2: "6", y2: "15" }),
1397
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "18", cy: "6", r: "3" }),
1398
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "6", cy: "18", r: "3" }),
1399
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 9a9 9 0 0 1-9 9" })
1400
+ ]
1401
+ }
1402
+ );
1403
+ var MailIcon = () => /* @__PURE__ */ jsxRuntime.jsxs(
1404
+ "svg",
1405
+ {
1406
+ width: "16",
1407
+ height: "16",
1408
+ viewBox: "0 0 24 24",
1409
+ fill: "none",
1410
+ stroke: "currentColor",
1411
+ strokeWidth: "2",
1412
+ strokeLinecap: "round",
1413
+ strokeLinejoin: "round",
1414
+ children: [
1415
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { width: "20", height: "16", x: "2", y: "4", rx: "2" }),
1416
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" })
1417
+ ]
1418
+ }
1419
+ );
1420
+ var styles2 = {
1421
+ field: {
1422
+ marginBottom: "12px"
1423
+ },
1424
+ label: {
1425
+ display: "block",
1426
+ fontSize: "11px",
1427
+ fontWeight: 600,
1428
+ color: "#6b7280",
1429
+ marginBottom: "4px",
1430
+ textTransform: "uppercase",
1431
+ letterSpacing: "0.03em"
1432
+ },
1433
+ input: {
1434
+ width: "100%",
1435
+ padding: "8px 10px",
1436
+ fontSize: "12px",
1437
+ border: "1px solid #e5e7eb",
1438
+ borderRadius: "6px",
1439
+ backgroundColor: "#f9fafb",
1440
+ color: "#1f2937",
1441
+ outline: "none",
1442
+ transition: "border-color 0.15s ease, box-shadow 0.15s ease"
1443
+ },
1444
+ textarea: {
1445
+ width: "100%",
1446
+ padding: "8px 10px",
1447
+ fontSize: "12px",
1448
+ border: "1px solid #e5e7eb",
1449
+ borderRadius: "6px",
1450
+ backgroundColor: "#f9fafb",
1451
+ color: "#1f2937",
1452
+ outline: "none",
1453
+ resize: "vertical",
1454
+ minHeight: "60px",
1455
+ fontFamily: "inherit",
1456
+ transition: "border-color 0.15s ease, box-shadow 0.15s ease"
1457
+ },
1458
+ select: {
1459
+ width: "100%",
1460
+ padding: "8px 10px",
1461
+ fontSize: "12px",
1462
+ border: "1px solid #e5e7eb",
1463
+ borderRadius: "6px",
1464
+ backgroundColor: "#f9fafb",
1465
+ color: "#1f2937",
1466
+ outline: "none",
1467
+ cursor: "pointer"
1468
+ },
1469
+ row: {
1470
+ display: "flex",
1471
+ gap: "8px"
1472
+ },
1473
+ modeBadge: (isAgent) => ({
1474
+ display: "inline-flex",
1475
+ alignItems: "center",
1476
+ padding: "2px 8px",
1477
+ borderRadius: "12px",
1478
+ fontSize: "10px",
1479
+ fontWeight: 600,
1480
+ backgroundColor: isAgent ? "#dbeafe" : "#f3e8ff",
1481
+ color: isAgent ? "#1d4ed8" : "#7c3aed",
1482
+ textTransform: "uppercase",
1483
+ letterSpacing: "0.05em"
1484
+ }),
1485
+ preview: {
1486
+ fontSize: "11px",
1487
+ color: "#6b7280",
1488
+ backgroundColor: "#f3f4f6",
1489
+ padding: "8px",
1490
+ borderRadius: "6px",
1491
+ fontFamily: "monospace",
1492
+ whiteSpace: "pre-wrap",
1493
+ wordBreak: "break-word",
1494
+ maxHeight: "80px",
1495
+ overflow: "auto"
1496
+ }
1497
+ };
1498
+ var PromptNode = react.memo(function PromptNode2(props) {
1499
+ const { data, selected, id } = props;
1500
+ const { step, onChange } = data;
1501
+ const config = step.config;
1502
+ const [isExpanded, setIsExpanded] = react.useState(false);
1503
+ const handleChange = react.useCallback(
1504
+ (field, value) => {
1505
+ onChange?.(id, {
1506
+ config: {
1507
+ ...config,
1508
+ [field]: value
1509
+ }
1510
+ });
1511
+ },
1512
+ [id, config, onChange]
1513
+ );
1514
+ const handleNameChange = react.useCallback(
1515
+ (e) => {
1516
+ onChange?.(id, { name: e.target.value });
1517
+ },
1518
+ [id, onChange]
1519
+ );
1520
+ const isAgentMode = config.mode === "agent";
1521
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1522
+ BaseNode,
1523
+ {
1524
+ data,
1525
+ selected,
1526
+ id,
1527
+ typeLabel: "AI Prompt",
1528
+ icon: /* @__PURE__ */ jsxRuntime.jsx(BrainIcon, {}),
1529
+ headerColor: NODE_HEADER_COLORS.prompt,
1530
+ children: [
1531
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles2.field, children: [
1532
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles2.label, children: "Step Name" }),
1533
+ /* @__PURE__ */ jsxRuntime.jsx(
1534
+ "input",
1535
+ {
1536
+ style: styles2.input,
1537
+ value: step.name,
1538
+ onChange: handleNameChange,
1539
+ placeholder: "Enter step name",
1540
+ onKeyDown: (e) => e.stopPropagation(),
1541
+ onFocus: (e) => {
1542
+ e.target.style.borderColor = "#6366f1";
1543
+ e.target.style.boxShadow = "0 0 0 2px rgba(99, 102, 241, 0.1)";
1544
+ },
1545
+ onBlur: (e) => {
1546
+ e.target.style.borderColor = "#e5e7eb";
1547
+ e.target.style.boxShadow = "none";
1548
+ }
1549
+ }
1550
+ )
1551
+ ] }),
1552
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles2.field, children: [
1553
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "4px" }, children: [
1554
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles2.label, children: "Mode" }),
1555
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles2.modeBadge(isAgentMode), children: isAgentMode ? "Agent" : "Instruction" })
1556
+ ] }),
1557
+ /* @__PURE__ */ jsxRuntime.jsxs(
1558
+ "select",
1559
+ {
1560
+ style: styles2.select,
1561
+ value: config.mode || "instruction",
1562
+ onChange: (e) => handleChange("mode", e.target.value),
1563
+ onKeyDown: (e) => e.stopPropagation(),
1564
+ children: [
1565
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "instruction", children: "Instruction Mode" }),
1566
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "agent", children: "Agent Mode" })
1567
+ ]
1568
+ }
1569
+ )
1570
+ ] }),
1571
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles2.field, children: [
1572
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles2.label, children: "Model" }),
1573
+ /* @__PURE__ */ jsxRuntime.jsx(
1574
+ "input",
1575
+ {
1576
+ style: styles2.input,
1577
+ value: config.model || "",
1578
+ onChange: (e) => handleChange("model", e.target.value),
1579
+ placeholder: "e.g., gpt-4, claude-3-sonnet",
1580
+ onKeyDown: (e) => e.stopPropagation()
1581
+ }
1582
+ )
1583
+ ] }),
1584
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles2.field, children: [
1585
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles2.label, children: "User Prompt" }),
1586
+ /* @__PURE__ */ jsxRuntime.jsx(
1587
+ "textarea",
1588
+ {
1589
+ style: styles2.textarea,
1590
+ value: config.userPrompt || "",
1591
+ onChange: (e) => handleChange("userPrompt", e.target.value),
1592
+ placeholder: "Enter your prompt...",
1593
+ rows: 3,
1594
+ onKeyDown: (e) => e.stopPropagation()
1595
+ }
1596
+ )
1597
+ ] }),
1598
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1599
+ config.systemPrompt !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles2.field, children: [
1600
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles2.label, children: "System Prompt" }),
1601
+ /* @__PURE__ */ jsxRuntime.jsx(
1602
+ "textarea",
1603
+ {
1604
+ style: styles2.textarea,
1605
+ value: config.systemPrompt || "",
1606
+ onChange: (e) => handleChange("systemPrompt", e.target.value),
1607
+ placeholder: "System instructions...",
1608
+ rows: 2,
1609
+ onKeyDown: (e) => e.stopPropagation()
1610
+ }
1611
+ )
1612
+ ] }),
1613
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles2.row, children: [
1614
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...styles2.field, flex: 1 }, children: [
1615
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles2.label, children: "Response Format" }),
1616
+ /* @__PURE__ */ jsxRuntime.jsxs(
1617
+ "select",
1618
+ {
1619
+ style: styles2.select,
1620
+ value: config.responseFormat || "text",
1621
+ onChange: (e) => handleChange("responseFormat", e.target.value),
1622
+ onKeyDown: (e) => e.stopPropagation(),
1623
+ children: [
1624
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "text", children: "Text" }),
1625
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "json", children: "JSON" }),
1626
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "markdown", children: "Markdown" }),
1627
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "html", children: "HTML" })
1628
+ ]
1629
+ }
1630
+ )
1631
+ ] }),
1632
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...styles2.field, flex: 1 }, children: [
1633
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles2.label, children: "Temperature" }),
1634
+ /* @__PURE__ */ jsxRuntime.jsx(
1635
+ "input",
1636
+ {
1637
+ style: styles2.input,
1638
+ type: "number",
1639
+ min: "0",
1640
+ max: "2",
1641
+ step: "0.1",
1642
+ value: config.temperature ?? 0.7,
1643
+ onChange: (e) => handleChange("temperature", parseFloat(e.target.value)),
1644
+ onKeyDown: (e) => e.stopPropagation()
1645
+ }
1646
+ )
1647
+ ] })
1648
+ ] }),
1649
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles2.field, children: [
1650
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles2.label, children: "Output Variable" }),
1651
+ /* @__PURE__ */ jsxRuntime.jsx(
1652
+ "input",
1653
+ {
1654
+ style: styles2.input,
1655
+ value: config.outputVariable || "",
1656
+ onChange: (e) => handleChange("outputVariable", e.target.value),
1657
+ placeholder: "result",
1658
+ onKeyDown: (e) => e.stopPropagation()
1659
+ }
1660
+ )
1661
+ ] })
1662
+ ] }),
1663
+ /* @__PURE__ */ jsxRuntime.jsx(
1664
+ "button",
1665
+ {
1666
+ onClick: () => setIsExpanded(!isExpanded),
1667
+ style: {
1668
+ width: "100%",
1669
+ padding: "6px",
1670
+ fontSize: "11px",
1671
+ color: "#6366f1",
1672
+ backgroundColor: "transparent",
1673
+ border: "1px dashed #e5e7eb",
1674
+ borderRadius: "6px",
1675
+ cursor: "pointer",
1676
+ marginTop: "4px"
1677
+ },
1678
+ children: isExpanded ? "Show Less" : "Show More Options"
1679
+ }
1680
+ )
1681
+ ]
1682
+ }
1683
+ );
1684
+ });
1685
+ var styles3 = {
1686
+ field: {
1687
+ marginBottom: "12px"
1688
+ },
1689
+ label: {
1690
+ display: "block",
1691
+ fontSize: "11px",
1692
+ fontWeight: 600,
1693
+ color: "#6b7280",
1694
+ marginBottom: "4px",
1695
+ textTransform: "uppercase",
1696
+ letterSpacing: "0.03em"
1697
+ },
1698
+ input: {
1699
+ width: "100%",
1700
+ padding: "8px 10px",
1701
+ fontSize: "12px",
1702
+ border: "1px solid #e5e7eb",
1703
+ borderRadius: "6px",
1704
+ backgroundColor: "#f9fafb",
1705
+ color: "#1f2937",
1706
+ outline: "none",
1707
+ transition: "border-color 0.15s ease, box-shadow 0.15s ease"
1708
+ },
1709
+ textarea: {
1710
+ width: "100%",
1711
+ padding: "8px 10px",
1712
+ fontSize: "12px",
1713
+ border: "1px solid #e5e7eb",
1714
+ borderRadius: "6px",
1715
+ backgroundColor: "#f9fafb",
1716
+ color: "#1f2937",
1717
+ outline: "none",
1718
+ resize: "vertical",
1719
+ minHeight: "60px",
1720
+ fontFamily: "monospace",
1721
+ transition: "border-color 0.15s ease, box-shadow 0.15s ease"
1722
+ },
1723
+ select: {
1724
+ width: "100%",
1725
+ padding: "8px 10px",
1726
+ fontSize: "12px",
1727
+ border: "1px solid #e5e7eb",
1728
+ borderRadius: "6px",
1729
+ backgroundColor: "#f9fafb",
1730
+ color: "#1f2937",
1731
+ outline: "none",
1732
+ cursor: "pointer"
1733
+ },
1734
+ row: {
1735
+ display: "flex",
1736
+ gap: "8px"
1737
+ },
1738
+ methodBadge: (method) => {
1739
+ const colors = {
1740
+ GET: { bg: "#d1fae5", text: "#059669" },
1741
+ POST: { bg: "#dbeafe", text: "#1d4ed8" },
1742
+ PUT: { bg: "#fef3c7", text: "#d97706" },
1743
+ DELETE: { bg: "#fee2e2", text: "#dc2626" },
1744
+ PATCH: { bg: "#e0e7ff", text: "#4f46e5" }
1745
+ };
1746
+ const color = colors[method] || colors.GET;
1747
+ return {
1748
+ display: "inline-flex",
1749
+ alignItems: "center",
1750
+ padding: "2px 8px",
1751
+ borderRadius: "4px",
1752
+ fontSize: "10px",
1753
+ fontWeight: 700,
1754
+ backgroundColor: color.bg,
1755
+ color: color.text,
1756
+ fontFamily: "monospace"
1757
+ };
1758
+ },
1759
+ urlPreview: {
1760
+ fontSize: "11px",
1761
+ color: "#6b7280",
1762
+ backgroundColor: "#f3f4f6",
1763
+ padding: "6px 8px",
1764
+ borderRadius: "4px",
1765
+ fontFamily: "monospace",
1766
+ wordBreak: "break-all",
1767
+ marginTop: "4px"
1768
+ }
1769
+ };
1770
+ var FetchUrlNode = react.memo(function FetchUrlNode2(props) {
1771
+ const { data, selected, id } = props;
1772
+ const { step, onChange } = data;
1773
+ const config = step.config;
1774
+ const [isExpanded, setIsExpanded] = react.useState(false);
1775
+ const handleChange = react.useCallback(
1776
+ (field, value) => {
1777
+ if (field.startsWith("http.")) {
1778
+ const httpField = field.replace("http.", "");
1779
+ onChange?.(id, {
1780
+ config: {
1781
+ ...config,
1782
+ http: {
1783
+ ...config.http,
1784
+ [httpField]: value
1785
+ }
1786
+ }
1787
+ });
1788
+ } else {
1789
+ onChange?.(id, {
1790
+ config: {
1791
+ ...config,
1792
+ [field]: value
1793
+ }
1794
+ });
1795
+ }
1796
+ },
1797
+ [id, config, onChange]
1798
+ );
1799
+ const handleNameChange = react.useCallback(
1800
+ (e) => {
1801
+ onChange?.(id, { name: e.target.value });
1802
+ },
1803
+ [id, onChange]
1804
+ );
1805
+ const method = config.http?.method || "GET";
1806
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1807
+ BaseNode,
1808
+ {
1809
+ data,
1810
+ selected,
1811
+ id,
1812
+ typeLabel: "Fetch URL",
1813
+ icon: /* @__PURE__ */ jsxRuntime.jsx(GlobeIcon, {}),
1814
+ headerColor: NODE_HEADER_COLORS["fetch-url"],
1815
+ children: [
1816
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles3.field, children: [
1817
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles3.label, children: "Step Name" }),
1818
+ /* @__PURE__ */ jsxRuntime.jsx(
1819
+ "input",
1820
+ {
1821
+ style: styles3.input,
1822
+ value: step.name,
1823
+ onChange: handleNameChange,
1824
+ placeholder: "Enter step name",
1825
+ onKeyDown: (e) => {
1826
+ e.stopPropagation();
1827
+ }
1828
+ }
1829
+ )
1830
+ ] }),
1831
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles3.field, children: [
1832
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "4px" }, children: [
1833
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles3.label, children: "Method" }),
1834
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles3.methodBadge(method), children: method })
1835
+ ] }),
1836
+ /* @__PURE__ */ jsxRuntime.jsxs(
1837
+ "select",
1838
+ {
1839
+ style: styles3.select,
1840
+ value: method,
1841
+ onChange: (e) => handleChange("http.method", e.target.value),
1842
+ onKeyDown: (e) => e.stopPropagation(),
1843
+ children: [
1844
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "GET", children: "GET" }),
1845
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "POST", children: "POST" }),
1846
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "PUT", children: "PUT" }),
1847
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "DELETE", children: "DELETE" }),
1848
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "PATCH", children: "PATCH" })
1849
+ ]
1850
+ }
1851
+ )
1852
+ ] }),
1853
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles3.field, children: [
1854
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles3.label, children: "URL" }),
1855
+ /* @__PURE__ */ jsxRuntime.jsx(
1856
+ "input",
1857
+ {
1858
+ style: styles3.input,
1859
+ value: config.http?.url || "",
1860
+ onChange: (e) => handleChange("http.url", e.target.value),
1861
+ placeholder: "https://api.example.com/endpoint",
1862
+ onKeyDown: (e) => e.stopPropagation()
1863
+ }
1864
+ ),
1865
+ config.http?.url && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles3.urlPreview, children: config.http.url })
1866
+ ] }),
1867
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1868
+ (method === "POST" || method === "PUT" || method === "PATCH") && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles3.field, children: [
1869
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles3.label, children: "Request Body" }),
1870
+ /* @__PURE__ */ jsxRuntime.jsx(
1871
+ "textarea",
1872
+ {
1873
+ style: styles3.textarea,
1874
+ value: config.http?.body || "",
1875
+ onChange: (e) => handleChange("http.body", e.target.value),
1876
+ placeholder: '{"key": "value"}',
1877
+ rows: 3,
1878
+ onKeyDown: (e) => e.stopPropagation()
1879
+ }
1880
+ )
1881
+ ] }),
1882
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles3.field, children: [
1883
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles3.label, children: "Headers (JSON)" }),
1884
+ /* @__PURE__ */ jsxRuntime.jsx(
1885
+ "textarea",
1886
+ {
1887
+ style: styles3.textarea,
1888
+ value: config.http?.headers ? JSON.stringify(config.http.headers, null, 2) : "",
1889
+ onChange: (e) => {
1890
+ try {
1891
+ const headers = JSON.parse(e.target.value);
1892
+ handleChange("http.headers", headers);
1893
+ } catch {
1894
+ }
1895
+ },
1896
+ placeholder: '{"Content-Type": "application/json"}',
1897
+ rows: 2,
1898
+ onKeyDown: (e) => e.stopPropagation()
1899
+ }
1900
+ )
1901
+ ] }),
1902
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles3.row, children: [
1903
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...styles3.field, flex: 1 }, children: [
1904
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles3.label, children: "Response Type" }),
1905
+ /* @__PURE__ */ jsxRuntime.jsxs(
1906
+ "select",
1907
+ {
1908
+ style: styles3.select,
1909
+ value: config.responseType || "json",
1910
+ onChange: (e) => handleChange("responseType", e.target.value),
1911
+ onKeyDown: (e) => e.stopPropagation(),
1912
+ children: [
1913
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "json", children: "JSON" }),
1914
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "text", children: "Text" }),
1915
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "xml", children: "XML" })
1916
+ ]
1917
+ }
1918
+ )
1919
+ ] }),
1920
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...styles3.field, flex: 1 }, children: [
1921
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles3.label, children: "On Error" }),
1922
+ /* @__PURE__ */ jsxRuntime.jsxs(
1923
+ "select",
1924
+ {
1925
+ style: styles3.select,
1926
+ value: config.errorHandling || "fail",
1927
+ onChange: (e) => handleChange("errorHandling", e.target.value),
1928
+ onKeyDown: (e) => e.stopPropagation(),
1929
+ children: [
1930
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "fail", children: "Fail" }),
1931
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "continue", children: "Continue" }),
1932
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "default", children: "Use Default" })
1933
+ ]
1934
+ }
1935
+ )
1936
+ ] })
1937
+ ] }),
1938
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles3.field, children: [
1939
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles3.label, children: "Output Variable" }),
1940
+ /* @__PURE__ */ jsxRuntime.jsx(
1941
+ "input",
1942
+ {
1943
+ style: styles3.input,
1944
+ value: config.outputVariable || "",
1945
+ onChange: (e) => handleChange("outputVariable", e.target.value),
1946
+ placeholder: "api_response",
1947
+ onKeyDown: (e) => e.stopPropagation()
1948
+ }
1949
+ )
1950
+ ] })
1951
+ ] }),
1952
+ /* @__PURE__ */ jsxRuntime.jsx(
1953
+ "button",
1954
+ {
1955
+ onClick: () => setIsExpanded(!isExpanded),
1956
+ style: {
1957
+ width: "100%",
1958
+ padding: "6px",
1959
+ fontSize: "11px",
1960
+ color: "#6366f1",
1961
+ backgroundColor: "transparent",
1962
+ border: "1px dashed #e5e7eb",
1963
+ borderRadius: "6px",
1964
+ cursor: "pointer",
1965
+ marginTop: "4px"
1966
+ },
1967
+ children: isExpanded ? "Show Less" : "Show More Options"
1968
+ }
1969
+ )
1970
+ ]
1971
+ }
1972
+ );
1973
+ });
1974
+ var styles4 = {
1975
+ field: {
1976
+ marginBottom: "12px"
1977
+ },
1978
+ label: {
1979
+ display: "block",
1980
+ fontSize: "11px",
1981
+ fontWeight: 600,
1982
+ color: "#6b7280",
1983
+ marginBottom: "4px",
1984
+ textTransform: "uppercase",
1985
+ letterSpacing: "0.03em"
1986
+ },
1987
+ input: {
1988
+ width: "100%",
1989
+ padding: "8px 10px",
1990
+ fontSize: "12px",
1991
+ border: "1px solid #e5e7eb",
1992
+ borderRadius: "6px",
1993
+ backgroundColor: "#f9fafb",
1994
+ color: "#1f2937",
1995
+ outline: "none",
1996
+ transition: "border-color 0.15s ease, box-shadow 0.15s ease"
1997
+ },
1998
+ codeArea: {
1999
+ width: "100%",
2000
+ padding: "10px",
2001
+ fontSize: "11px",
2002
+ border: "1px solid #e5e7eb",
2003
+ borderRadius: "6px",
2004
+ backgroundColor: "#1e1e1e",
2005
+ color: "#d4d4d4",
2006
+ outline: "none",
2007
+ resize: "vertical",
2008
+ minHeight: "100px",
2009
+ fontFamily: '"Fira Code", "Monaco", "Consolas", monospace',
2010
+ lineHeight: 1.5,
2011
+ tabSize: 2
2012
+ },
2013
+ select: {
2014
+ width: "100%",
2015
+ padding: "8px 10px",
2016
+ fontSize: "12px",
2017
+ border: "1px solid #e5e7eb",
2018
+ borderRadius: "6px",
2019
+ backgroundColor: "#f9fafb",
2020
+ color: "#1f2937",
2021
+ outline: "none",
2022
+ cursor: "pointer"
2023
+ },
2024
+ row: {
2025
+ display: "flex",
2026
+ gap: "8px"
2027
+ },
2028
+ languageBadge: (language) => {
2029
+ const colors = {
2030
+ javascript: { bg: "#fef3c7", text: "#d97706" },
2031
+ typescript: { bg: "#dbeafe", text: "#1d4ed8" },
2032
+ python: { bg: "#d1fae5", text: "#059669" }
2033
+ };
2034
+ const color = colors[language] || colors.javascript;
2035
+ return {
2036
+ display: "inline-flex",
2037
+ alignItems: "center",
2038
+ padding: "2px 8px",
2039
+ borderRadius: "4px",
2040
+ fontSize: "10px",
2041
+ fontWeight: 600,
2042
+ backgroundColor: color.bg,
2043
+ color: color.text,
2044
+ textTransform: "capitalize"
2045
+ };
2046
+ },
2047
+ lineNumbers: {
2048
+ display: "flex",
2049
+ flexDirection: "column",
2050
+ alignItems: "flex-end",
2051
+ paddingRight: "8px",
2052
+ marginRight: "8px",
2053
+ borderRight: "1px solid #3f3f46",
2054
+ color: "#6b7280",
2055
+ fontSize: "11px",
2056
+ fontFamily: '"Fira Code", "Monaco", "Consolas", monospace',
2057
+ lineHeight: 1.5,
2058
+ userSelect: "none"
2059
+ },
2060
+ codePreview: {
2061
+ fontSize: "10px",
2062
+ color: "#9ca3af",
2063
+ marginTop: "4px"
2064
+ }
2065
+ };
2066
+ var CodeNode = react.memo(function CodeNode2(props) {
2067
+ const { data, selected, id } = props;
2068
+ const { step, onChange } = data;
2069
+ const config = step.config;
2070
+ const [isExpanded, setIsExpanded] = react.useState(false);
2071
+ const handleChange = react.useCallback(
2072
+ (field, value) => {
2073
+ onChange?.(id, {
2074
+ config: {
2075
+ ...config,
2076
+ [field]: value
2077
+ }
2078
+ });
2079
+ },
2080
+ [id, config, onChange]
2081
+ );
2082
+ const handleNameChange = react.useCallback(
2083
+ (e) => {
2084
+ onChange?.(id, { name: e.target.value });
2085
+ },
2086
+ [id, onChange]
2087
+ );
2088
+ const language = config.language || "javascript";
2089
+ const lineCount = (config.script || "").split("\n").length;
2090
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2091
+ BaseNode,
2092
+ {
2093
+ data,
2094
+ selected,
2095
+ id,
2096
+ typeLabel: "Run Code",
2097
+ icon: /* @__PURE__ */ jsxRuntime.jsx(CodeIcon, {}),
2098
+ headerColor: NODE_HEADER_COLORS["transform-data"],
2099
+ children: [
2100
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.field, children: [
2101
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles4.label, children: "Step Name" }),
2102
+ /* @__PURE__ */ jsxRuntime.jsx(
2103
+ "input",
2104
+ {
2105
+ style: styles4.input,
2106
+ value: step.name,
2107
+ onChange: handleNameChange,
2108
+ placeholder: "Enter step name",
2109
+ onKeyDown: (e) => e.stopPropagation()
2110
+ }
2111
+ )
2112
+ ] }),
2113
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.field, children: [
2114
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "4px" }, children: [
2115
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles4.label, children: "Code" }),
2116
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles4.languageBadge(language), children: language })
2117
+ ] }),
2118
+ /* @__PURE__ */ jsxRuntime.jsx(
2119
+ "textarea",
2120
+ {
2121
+ style: styles4.codeArea,
2122
+ value: config.script || "",
2123
+ onChange: (e) => handleChange("script", e.target.value),
2124
+ placeholder: `// Write your ${language} code here
2125
+ return { result: input }`,
2126
+ spellCheck: false,
2127
+ onKeyDown: (e) => e.stopPropagation()
2128
+ }
2129
+ ),
2130
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.codePreview, children: [
2131
+ lineCount,
2132
+ " line",
2133
+ lineCount !== 1 ? "s" : ""
2134
+ ] })
2135
+ ] }),
2136
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2137
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.row, children: [
2138
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...styles4.field, flex: 1 }, children: [
2139
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles4.label, children: "Language" }),
2140
+ /* @__PURE__ */ jsxRuntime.jsxs(
2141
+ "select",
2142
+ {
2143
+ style: styles4.select,
2144
+ value: language,
2145
+ onChange: (e) => handleChange("language", e.target.value),
2146
+ onKeyDown: (e) => e.stopPropagation(),
2147
+ children: [
2148
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "javascript", children: "JavaScript" }),
2149
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "typescript", children: "TypeScript" }),
2150
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "python", children: "Python" })
2151
+ ]
2152
+ }
2153
+ )
2154
+ ] }),
2155
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...styles4.field, flex: 1 }, children: [
2156
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles4.label, children: "Sandbox" }),
2157
+ /* @__PURE__ */ jsxRuntime.jsxs(
2158
+ "select",
2159
+ {
2160
+ style: styles4.select,
2161
+ value: config.sandboxProvider || "quickjs",
2162
+ onChange: (e) => handleChange("sandboxProvider", e.target.value),
2163
+ onKeyDown: (e) => e.stopPropagation(),
2164
+ children: [
2165
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "quickjs", children: "QuickJS (Fast)" }),
2166
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "daytona", children: "Daytona (Full)" })
2167
+ ]
2168
+ }
2169
+ )
2170
+ ] })
2171
+ ] }),
2172
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.field, children: [
2173
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles4.label, children: "On Error" }),
2174
+ /* @__PURE__ */ jsxRuntime.jsxs(
2175
+ "select",
2176
+ {
2177
+ style: styles4.select,
2178
+ value: config.errorHandling || "fail",
2179
+ onChange: (e) => handleChange("errorHandling", e.target.value),
2180
+ onKeyDown: (e) => e.stopPropagation(),
2181
+ children: [
2182
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "fail", children: "Fail" }),
2183
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "continue", children: "Continue" }),
2184
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "default", children: "Use Default" })
2185
+ ]
2186
+ }
2187
+ )
2188
+ ] }),
2189
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.field, children: [
2190
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles4.label, children: "Output Variable" }),
2191
+ /* @__PURE__ */ jsxRuntime.jsx(
2192
+ "input",
2193
+ {
2194
+ style: styles4.input,
2195
+ value: config.outputVariable || "",
2196
+ onChange: (e) => handleChange("outputVariable", e.target.value),
2197
+ placeholder: "transform_result",
2198
+ onKeyDown: (e) => e.stopPropagation()
2199
+ }
2200
+ )
2201
+ ] })
2202
+ ] }),
2203
+ /* @__PURE__ */ jsxRuntime.jsx(
2204
+ "button",
2205
+ {
2206
+ onClick: () => setIsExpanded(!isExpanded),
2207
+ style: {
2208
+ width: "100%",
2209
+ padding: "6px",
2210
+ fontSize: "11px",
2211
+ color: "#6366f1",
2212
+ backgroundColor: "transparent",
2213
+ border: "1px dashed #e5e7eb",
2214
+ borderRadius: "6px",
2215
+ cursor: "pointer",
2216
+ marginTop: "4px"
2217
+ },
2218
+ children: isExpanded ? "Show Less" : "Show More Options"
2219
+ }
2220
+ )
2221
+ ]
2222
+ }
2223
+ );
2224
+ });
2225
+ var styles5 = {
2226
+ field: {
2227
+ marginBottom: "12px"
2228
+ },
2229
+ label: {
2230
+ display: "block",
2231
+ fontSize: "11px",
2232
+ fontWeight: 600,
2233
+ color: "#6b7280",
2234
+ marginBottom: "4px",
2235
+ textTransform: "uppercase",
2236
+ letterSpacing: "0.03em"
2237
+ },
2238
+ input: {
2239
+ width: "100%",
2240
+ padding: "8px 10px",
2241
+ fontSize: "12px",
2242
+ border: "1px solid #e5e7eb",
2243
+ borderRadius: "6px",
2244
+ backgroundColor: "#f9fafb",
2245
+ color: "#1f2937",
2246
+ outline: "none",
2247
+ transition: "border-color 0.15s ease, box-shadow 0.15s ease"
2248
+ },
2249
+ conditionArea: {
2250
+ width: "100%",
2251
+ padding: "10px",
2252
+ fontSize: "12px",
2253
+ border: "1px solid #e5e7eb",
2254
+ borderRadius: "6px",
2255
+ backgroundColor: "#fef7ee",
2256
+ color: "#92400e",
2257
+ outline: "none",
2258
+ resize: "vertical",
2259
+ minHeight: "60px",
2260
+ fontFamily: '"Fira Code", "Monaco", "Consolas", monospace',
2261
+ lineHeight: 1.5
2262
+ },
2263
+ branchInfo: {
2264
+ display: "flex",
2265
+ gap: "12px",
2266
+ marginTop: "8px"
2267
+ },
2268
+ branchCard: (type) => ({
2269
+ flex: 1,
2270
+ padding: "10px",
2271
+ borderRadius: "8px",
2272
+ backgroundColor: type === "true" ? "#d1fae5" : "#fee2e2",
2273
+ border: `1px solid ${type === "true" ? "#a7f3d0" : "#fecaca"}`
2274
+ }),
2275
+ branchLabel: (type) => ({
2276
+ fontSize: "10px",
2277
+ fontWeight: 700,
2278
+ textTransform: "uppercase",
2279
+ letterSpacing: "0.05em",
2280
+ color: type === "true" ? "#059669" : "#dc2626",
2281
+ marginBottom: "4px"
2282
+ }),
2283
+ branchCount: {
2284
+ fontSize: "18px",
2285
+ fontWeight: 700,
2286
+ color: "#1f2937"
2287
+ },
2288
+ branchCountLabel: {
2289
+ fontSize: "10px",
2290
+ color: "#6b7280"
2291
+ },
2292
+ helpText: {
2293
+ fontSize: "10px",
2294
+ color: "#9ca3af",
2295
+ marginTop: "4px",
2296
+ fontStyle: "italic"
2297
+ }
2298
+ };
2299
+ var ConditionalNode = react.memo(function ConditionalNode2(props) {
2300
+ const { data, selected, id } = props;
2301
+ const { step, onChange } = data;
2302
+ const config = step.config;
2303
+ const [isExpanded, setIsExpanded] = react.useState(false);
2304
+ const handleChange = react.useCallback(
2305
+ (field, value) => {
2306
+ onChange?.(id, {
2307
+ config: {
2308
+ ...config,
2309
+ [field]: value
2310
+ }
2311
+ });
2312
+ },
2313
+ [id, config, onChange]
2314
+ );
2315
+ const handleNameChange = react.useCallback(
2316
+ (e) => {
2317
+ onChange?.(id, { name: e.target.value });
2318
+ },
2319
+ [id, onChange]
2320
+ );
2321
+ const trueStepsCount = config.trueSteps?.length || 0;
2322
+ const falseStepsCount = config.falseSteps?.length || 0;
2323
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2324
+ BaseNode,
2325
+ {
2326
+ data,
2327
+ selected,
2328
+ id,
2329
+ typeLabel: "Conditional",
2330
+ icon: /* @__PURE__ */ jsxRuntime.jsx(GitBranchIcon, {}),
2331
+ headerColor: NODE_HEADER_COLORS.conditional,
2332
+ showSourceHandle: false,
2333
+ additionalSourceHandles: [
2334
+ {
2335
+ id: "true",
2336
+ position: react$1.Position.Right,
2337
+ label: "True",
2338
+ color: "#22c55e",
2339
+ style: { top: "40%" }
2340
+ },
2341
+ {
2342
+ id: "false",
2343
+ position: react$1.Position.Right,
2344
+ label: "False",
2345
+ color: "#ef4444",
2346
+ style: { top: "60%" }
2347
+ }
2348
+ ],
2349
+ children: [
2350
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.field, children: [
2351
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles5.label, children: "Step Name" }),
2352
+ /* @__PURE__ */ jsxRuntime.jsx(
2353
+ "input",
2354
+ {
2355
+ style: styles5.input,
2356
+ value: step.name,
2357
+ onChange: handleNameChange,
2358
+ placeholder: "Enter step name",
2359
+ onKeyDown: (e) => e.stopPropagation()
2360
+ }
2361
+ )
2362
+ ] }),
2363
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.field, children: [
2364
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles5.label, children: "Condition (JavaScript)" }),
2365
+ /* @__PURE__ */ jsxRuntime.jsx(
2366
+ "textarea",
2367
+ {
2368
+ style: styles5.conditionArea,
2369
+ value: config.condition || "",
2370
+ onChange: (e) => handleChange("condition", e.target.value),
2371
+ placeholder: "user_type === 'premium'",
2372
+ spellCheck: false,
2373
+ onKeyDown: (e) => e.stopPropagation()
2374
+ }
2375
+ ),
2376
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.helpText, children: [
2377
+ "Access variables directly: ",
2378
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: "variable_name" }),
2379
+ ", ",
2380
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: "_record.metadata.field" })
2381
+ ] })
2382
+ ] }),
2383
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.branchInfo, children: [
2384
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.branchCard("true"), children: [
2385
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.branchLabel("true"), children: [
2386
+ /* @__PURE__ */ jsxRuntime.jsx(TrueIcon, {}),
2387
+ " True Branch"
2388
+ ] }),
2389
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.branchCount, children: trueStepsCount }),
2390
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.branchCountLabel, children: [
2391
+ "step",
2392
+ trueStepsCount !== 1 ? "s" : ""
2393
+ ] })
2394
+ ] }),
2395
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.branchCard("false"), children: [
2396
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.branchLabel("false"), children: [
2397
+ /* @__PURE__ */ jsxRuntime.jsx(FalseIcon, {}),
2398
+ " False Branch"
2399
+ ] }),
2400
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.branchCount, children: falseStepsCount }),
2401
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.branchCountLabel, children: [
2402
+ "step",
2403
+ falseStepsCount !== 1 ? "s" : ""
2404
+ ] })
2405
+ ] })
2406
+ ] }),
2407
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: "12px" }, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.field, children: [
2408
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles5.label, children: "Condition Examples" }),
2409
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: "11px", color: "#6b7280", lineHeight: 1.6 }, children: [
2410
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2411
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: "status === 'active'" }),
2412
+ " - Check equality"
2413
+ ] }),
2414
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2415
+ /* @__PURE__ */ jsxRuntime.jsxs("code", { children: [
2416
+ "count ",
2417
+ ">",
2418
+ " 10"
2419
+ ] }),
2420
+ " - Numeric comparison"
2421
+ ] }),
2422
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2423
+ /* @__PURE__ */ jsxRuntime.jsxs("code", { children: [
2424
+ "data && data.length ",
2425
+ ">",
2426
+ " 0"
2427
+ ] }),
2428
+ " - Check array"
2429
+ ] }),
2430
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2431
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: "_record.metadata.type === 'premium'" }),
2432
+ " - API input"
2433
+ ] })
2434
+ ] })
2435
+ ] }) }),
2436
+ /* @__PURE__ */ jsxRuntime.jsx(
2437
+ "button",
2438
+ {
2439
+ onClick: () => setIsExpanded(!isExpanded),
2440
+ style: {
2441
+ width: "100%",
2442
+ padding: "6px",
2443
+ fontSize: "11px",
2444
+ color: "#6366f1",
2445
+ backgroundColor: "transparent",
2446
+ border: "1px dashed #e5e7eb",
2447
+ borderRadius: "6px",
2448
+ cursor: "pointer",
2449
+ marginTop: "12px"
2450
+ },
2451
+ children: isExpanded ? "Hide Examples" : "Show Examples"
2452
+ }
2453
+ )
2454
+ ]
2455
+ }
2456
+ );
2457
+ });
2458
+ var TrueIcon = () => /* @__PURE__ */ jsxRuntime.jsx(
2459
+ "svg",
2460
+ {
2461
+ width: "12",
2462
+ height: "12",
2463
+ viewBox: "0 0 24 24",
2464
+ fill: "none",
2465
+ stroke: "currentColor",
2466
+ strokeWidth: "2",
2467
+ strokeLinecap: "round",
2468
+ strokeLinejoin: "round",
2469
+ style: { display: "inline", marginRight: "4px", verticalAlign: "middle" },
2470
+ children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "20 6 9 17 4 12" })
2471
+ }
2472
+ );
2473
+ var FalseIcon = () => /* @__PURE__ */ jsxRuntime.jsxs(
2474
+ "svg",
2475
+ {
2476
+ width: "12",
2477
+ height: "12",
2478
+ viewBox: "0 0 24 24",
2479
+ fill: "none",
2480
+ stroke: "currentColor",
2481
+ strokeWidth: "2",
2482
+ strokeLinecap: "round",
2483
+ strokeLinejoin: "round",
2484
+ style: { display: "inline", marginRight: "4px", verticalAlign: "middle" },
2485
+ children: [
2486
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
2487
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
2488
+ ]
2489
+ }
2490
+ );
2491
+ var styles6 = {
2492
+ field: {
2493
+ marginBottom: "12px"
2494
+ },
2495
+ label: {
2496
+ display: "block",
2497
+ fontSize: "11px",
2498
+ fontWeight: 600,
2499
+ color: "#6b7280",
2500
+ marginBottom: "4px",
2501
+ textTransform: "uppercase",
2502
+ letterSpacing: "0.03em"
2503
+ },
2504
+ input: {
2505
+ width: "100%",
2506
+ padding: "8px 10px",
2507
+ fontSize: "12px",
2508
+ border: "1px solid #e5e7eb",
2509
+ borderRadius: "6px",
2510
+ backgroundColor: "#f9fafb",
2511
+ color: "#1f2937",
2512
+ outline: "none",
2513
+ transition: "border-color 0.15s ease, box-shadow 0.15s ease"
2514
+ },
2515
+ textarea: {
2516
+ width: "100%",
2517
+ padding: "8px 10px",
2518
+ fontSize: "12px",
2519
+ border: "1px solid #e5e7eb",
2520
+ borderRadius: "6px",
2521
+ backgroundColor: "#f9fafb",
2522
+ color: "#1f2937",
2523
+ outline: "none",
2524
+ resize: "vertical",
2525
+ minHeight: "80px",
2526
+ fontFamily: "inherit",
2527
+ transition: "border-color 0.15s ease, box-shadow 0.15s ease"
2528
+ },
2529
+ select: {
2530
+ width: "100%",
2531
+ padding: "8px 10px",
2532
+ fontSize: "12px",
2533
+ border: "1px solid #e5e7eb",
2534
+ borderRadius: "6px",
2535
+ backgroundColor: "#f9fafb",
2536
+ color: "#1f2937",
2537
+ outline: "none",
2538
+ cursor: "pointer"
2539
+ },
2540
+ row: {
2541
+ display: "flex",
2542
+ gap: "8px"
2543
+ },
2544
+ emailPreview: {
2545
+ backgroundColor: "#f8fafc",
2546
+ border: "1px solid #e2e8f0",
2547
+ borderRadius: "8px",
2548
+ padding: "10px",
2549
+ marginTop: "8px"
2550
+ },
2551
+ previewHeader: {
2552
+ fontSize: "10px",
2553
+ color: "#64748b",
2554
+ marginBottom: "4px"
2555
+ },
2556
+ previewValue: {
2557
+ fontSize: "12px",
2558
+ color: "#1e293b",
2559
+ fontWeight: 500,
2560
+ marginBottom: "8px",
2561
+ wordBreak: "break-all"
2562
+ },
2563
+ variableHint: {
2564
+ display: "inline-flex",
2565
+ alignItems: "center",
2566
+ padding: "2px 6px",
2567
+ borderRadius: "4px",
2568
+ fontSize: "10px",
2569
+ backgroundColor: "#f0f9ff",
2570
+ color: "#0369a1",
2571
+ fontFamily: "monospace",
2572
+ marginRight: "4px",
2573
+ marginTop: "4px"
2574
+ }
2575
+ };
2576
+ var SendEmailNode = react.memo(function SendEmailNode2(props) {
2577
+ const { data, selected, id } = props;
2578
+ const { step, onChange } = data;
2579
+ const config = step.config;
2580
+ const [isExpanded, setIsExpanded] = react.useState(false);
2581
+ const handleChange = react.useCallback(
2582
+ (field, value) => {
2583
+ onChange?.(id, {
2584
+ config: {
2585
+ ...config,
2586
+ [field]: value
2587
+ }
2588
+ });
2589
+ },
2590
+ [id, config, onChange]
2591
+ );
2592
+ const handleNameChange = react.useCallback(
2593
+ (e) => {
2594
+ onChange?.(id, { name: e.target.value });
2595
+ },
2596
+ [id, onChange]
2597
+ );
2598
+ const hasVariables = (value) => /\{\{[\w._]+\}\}/.test(value);
2599
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2600
+ BaseNode,
2601
+ {
2602
+ data,
2603
+ selected,
2604
+ id,
2605
+ typeLabel: "Send Email",
2606
+ icon: /* @__PURE__ */ jsxRuntime.jsx(MailIcon, {}),
2607
+ headerColor: NODE_HEADER_COLORS["send-email"],
2608
+ children: [
2609
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.field, children: [
2610
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles6.label, children: "Step Name" }),
2611
+ /* @__PURE__ */ jsxRuntime.jsx(
2612
+ "input",
2613
+ {
2614
+ style: styles6.input,
2615
+ value: step.name,
2616
+ onChange: handleNameChange,
2617
+ placeholder: "Enter step name",
2618
+ onKeyDown: (e) => e.stopPropagation()
2619
+ }
2620
+ )
2621
+ ] }),
2622
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.field, children: [
2623
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles6.label, children: "To" }),
2624
+ /* @__PURE__ */ jsxRuntime.jsx(
2625
+ "input",
2626
+ {
2627
+ style: styles6.input,
2628
+ value: config.to || "",
2629
+ onChange: (e) => handleChange("to", e.target.value),
2630
+ placeholder: "recipient@example.com or {{_record.metadata.email}}",
2631
+ onKeyDown: (e) => e.stopPropagation()
2632
+ }
2633
+ ),
2634
+ hasVariables(config.to || "") && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles6.variableHint, children: "Uses variable" })
2635
+ ] }),
2636
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.field, children: [
2637
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles6.label, children: "Subject" }),
2638
+ /* @__PURE__ */ jsxRuntime.jsx(
2639
+ "input",
2640
+ {
2641
+ style: styles6.input,
2642
+ value: config.subject || "",
2643
+ onChange: (e) => handleChange("subject", e.target.value),
2644
+ placeholder: "Your subject line",
2645
+ onKeyDown: (e) => e.stopPropagation()
2646
+ }
2647
+ )
2648
+ ] }),
2649
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.field, children: [
2650
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles6.label, children: "HTML Content" }),
2651
+ /* @__PURE__ */ jsxRuntime.jsx(
2652
+ "textarea",
2653
+ {
2654
+ style: styles6.textarea,
2655
+ value: config.html || "",
2656
+ onChange: (e) => handleChange("html", e.target.value),
2657
+ placeholder: "<p>Your email content...</p>\n\nUse {{variable}} for dynamic content",
2658
+ rows: 4,
2659
+ onKeyDown: (e) => e.stopPropagation()
2660
+ }
2661
+ )
2662
+ ] }),
2663
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2664
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.field, children: [
2665
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles6.label, children: "From" }),
2666
+ /* @__PURE__ */ jsxRuntime.jsx(
2667
+ "input",
2668
+ {
2669
+ style: styles6.input,
2670
+ value: config.from || "",
2671
+ onChange: (e) => handleChange("from", e.target.value),
2672
+ placeholder: "no-reply@messages.runtype.com",
2673
+ onKeyDown: (e) => e.stopPropagation()
2674
+ }
2675
+ )
2676
+ ] }),
2677
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.row, children: [
2678
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...styles6.field, flex: 1 }, children: [
2679
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles6.label, children: "CC" }),
2680
+ /* @__PURE__ */ jsxRuntime.jsx(
2681
+ "input",
2682
+ {
2683
+ style: styles6.input,
2684
+ value: config.cc || "",
2685
+ onChange: (e) => handleChange("cc", e.target.value),
2686
+ placeholder: "cc@example.com",
2687
+ onKeyDown: (e) => e.stopPropagation()
2688
+ }
2689
+ )
2690
+ ] }),
2691
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...styles6.field, flex: 1 }, children: [
2692
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles6.label, children: "BCC" }),
2693
+ /* @__PURE__ */ jsxRuntime.jsx(
2694
+ "input",
2695
+ {
2696
+ style: styles6.input,
2697
+ value: config.bcc || "",
2698
+ onChange: (e) => handleChange("bcc", e.target.value),
2699
+ placeholder: "bcc@example.com",
2700
+ onKeyDown: (e) => e.stopPropagation()
2701
+ }
2702
+ )
2703
+ ] })
2704
+ ] }),
2705
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.field, children: [
2706
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles6.label, children: "Reply To" }),
2707
+ /* @__PURE__ */ jsxRuntime.jsx(
2708
+ "input",
2709
+ {
2710
+ style: styles6.input,
2711
+ value: config.replyTo || "",
2712
+ onChange: (e) => handleChange("replyTo", e.target.value),
2713
+ placeholder: "reply@example.com",
2714
+ onKeyDown: (e) => e.stopPropagation()
2715
+ }
2716
+ )
2717
+ ] }),
2718
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.field, children: [
2719
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles6.label, children: "Plain Text (Fallback)" }),
2720
+ /* @__PURE__ */ jsxRuntime.jsx(
2721
+ "textarea",
2722
+ {
2723
+ style: styles6.textarea,
2724
+ value: config.text || "",
2725
+ onChange: (e) => handleChange("text", e.target.value),
2726
+ placeholder: "Plain text version of your email...",
2727
+ rows: 2,
2728
+ onKeyDown: (e) => e.stopPropagation()
2729
+ }
2730
+ )
2731
+ ] }),
2732
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.row, children: [
2733
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...styles6.field, flex: 1 }, children: [
2734
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles6.label, children: "On Error" }),
2735
+ /* @__PURE__ */ jsxRuntime.jsxs(
2736
+ "select",
2737
+ {
2738
+ style: styles6.select,
2739
+ value: config.errorHandling || "fail",
2740
+ onChange: (e) => handleChange("errorHandling", e.target.value),
2741
+ onKeyDown: (e) => e.stopPropagation(),
2742
+ children: [
2743
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "fail", children: "Fail" }),
2744
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "continue", children: "Continue" }),
2745
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "default", children: "Use Default" })
2746
+ ]
2747
+ }
2748
+ )
2749
+ ] }),
2750
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...styles6.field, flex: 1 }, children: [
2751
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles6.label, children: "Output Variable" }),
2752
+ /* @__PURE__ */ jsxRuntime.jsx(
2753
+ "input",
2754
+ {
2755
+ style: styles6.input,
2756
+ value: config.outputVariable || "",
2757
+ onChange: (e) => handleChange("outputVariable", e.target.value),
2758
+ placeholder: "email_result",
2759
+ onKeyDown: (e) => e.stopPropagation()
2760
+ }
2761
+ )
2762
+ ] })
2763
+ ] })
2764
+ ] }),
2765
+ (config.to || config.subject) && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.emailPreview, children: [
2766
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.previewHeader, children: "Preview" }),
2767
+ config.to && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.previewValue, children: [
2768
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "To:" }),
2769
+ " ",
2770
+ config.to
2771
+ ] }),
2772
+ config.subject && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.previewValue, children: [
2773
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "Subject:" }),
2774
+ " ",
2775
+ config.subject
2776
+ ] })
2777
+ ] }),
2778
+ /* @__PURE__ */ jsxRuntime.jsx(
2779
+ "button",
2780
+ {
2781
+ onClick: () => setIsExpanded(!isExpanded),
2782
+ style: {
2783
+ width: "100%",
2784
+ padding: "6px",
2785
+ fontSize: "11px",
2786
+ color: "#6366f1",
2787
+ backgroundColor: "transparent",
2788
+ border: "1px dashed #e5e7eb",
2789
+ borderRadius: "6px",
2790
+ cursor: "pointer",
2791
+ marginTop: "8px"
2792
+ },
2793
+ children: isExpanded ? "Show Less" : "Show More Options"
2794
+ }
2795
+ )
2796
+ ]
2797
+ }
2798
+ );
2799
+ });
2800
+ var styles7 = {
2801
+ container: {
2802
+ width: "100%",
2803
+ height: "100%",
2804
+ position: "relative"
2805
+ },
2806
+ toolbar: {
2807
+ display: "flex",
2808
+ alignItems: "center",
2809
+ gap: "8px",
2810
+ padding: "8px 12px",
2811
+ backgroundColor: "#ffffff",
2812
+ borderRadius: "8px",
2813
+ boxShadow: "0 2px 8px rgba(0, 0, 0, 0.1)",
2814
+ border: "1px solid #e5e7eb"
2815
+ },
2816
+ toolbarButton: {
2817
+ display: "flex",
2818
+ alignItems: "center",
2819
+ gap: "6px",
2820
+ padding: "8px 12px",
2821
+ fontSize: "12px",
2822
+ fontWeight: 500,
2823
+ backgroundColor: "#f9fafb",
2824
+ border: "1px solid #e5e7eb",
2825
+ borderRadius: "6px",
2826
+ cursor: "pointer",
2827
+ color: "#374151",
2828
+ transition: "all 0.15s ease"
2829
+ },
2830
+ toolbarButtonPrimary: {
2831
+ backgroundColor: "#6366f1",
2832
+ borderColor: "#6366f1",
2833
+ color: "#ffffff"
2834
+ },
2835
+ toolbarDivider: {
2836
+ width: "1px",
2837
+ height: "24px",
2838
+ backgroundColor: "#e5e7eb",
2839
+ margin: "0 4px"
2840
+ },
2841
+ statusPanel: {
2842
+ display: "flex",
2843
+ alignItems: "center",
2844
+ gap: "8px",
2845
+ padding: "8px 12px",
2846
+ backgroundColor: "#ffffff",
2847
+ borderRadius: "8px",
2848
+ boxShadow: "0 2px 8px rgba(0, 0, 0, 0.1)",
2849
+ border: "1px solid #e5e7eb",
2850
+ fontSize: "12px",
2851
+ color: "#6b7280"
2852
+ },
2853
+ statusBadge: (isValid) => ({
2854
+ display: "inline-flex",
2855
+ alignItems: "center",
2856
+ padding: "2px 8px",
2857
+ borderRadius: "12px",
2858
+ fontSize: "10px",
2859
+ fontWeight: 600,
2860
+ backgroundColor: isValid ? "#d1fae5" : "#fee2e2",
2861
+ color: isValid ? "#059669" : "#dc2626"
2862
+ }),
2863
+ addStepMenu: {
2864
+ position: "absolute",
2865
+ top: "100%",
2866
+ left: 0,
2867
+ marginTop: "4px",
2868
+ backgroundColor: "#ffffff",
2869
+ borderRadius: "8px",
2870
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
2871
+ border: "1px solid #e5e7eb",
2872
+ padding: "4px",
2873
+ zIndex: 1e3,
2874
+ minWidth: "200px"
2875
+ },
2876
+ addStepMenuItem: {
2877
+ display: "flex",
2878
+ alignItems: "center",
2879
+ gap: "8px",
2880
+ padding: "8px 12px",
2881
+ fontSize: "12px",
2882
+ color: "#374151",
2883
+ backgroundColor: "transparent",
2884
+ border: "none",
2885
+ borderRadius: "4px",
2886
+ cursor: "pointer",
2887
+ width: "100%",
2888
+ textAlign: "left",
2889
+ transition: "background-color 0.15s ease"
2890
+ },
2891
+ flowNameInput: {
2892
+ padding: "6px 10px",
2893
+ fontSize: "14px",
2894
+ fontWeight: 600,
2895
+ border: "1px solid transparent",
2896
+ borderRadius: "4px",
2897
+ backgroundColor: "transparent",
2898
+ color: "#1f2937",
2899
+ outline: "none",
2900
+ transition: "border-color 0.15s ease, background-color 0.15s ease",
2901
+ minWidth: "200px"
2902
+ },
2903
+ unsavedBadge: {
2904
+ display: "inline-flex",
2905
+ alignItems: "center",
2906
+ padding: "2px 6px",
2907
+ borderRadius: "4px",
2908
+ fontSize: "10px",
2909
+ fontWeight: 500,
2910
+ backgroundColor: "#fef3c7",
2911
+ color: "#d97706"
2912
+ }
2913
+ };
2914
+ var nodeTypes = {
2915
+ prompt: PromptNode,
2916
+ "fetch-url": FetchUrlNode,
2917
+ "transform-data": CodeNode,
2918
+ conditional: ConditionalNode,
2919
+ "send-email": SendEmailNode,
2920
+ // Default node for unsupported types
2921
+ default: DefaultNode
2922
+ };
2923
+ function DefaultNode(props) {
2924
+ const { data, selected, id } = props;
2925
+ return /* @__PURE__ */ jsxRuntime.jsx(
2926
+ BaseNode,
2927
+ {
2928
+ data,
2929
+ selected,
2930
+ id,
2931
+ typeLabel: data.step.type,
2932
+ icon: /* @__PURE__ */ jsxRuntime.jsx(BrainIcon, {}),
2933
+ headerColor: NODE_HEADER_COLORS.default,
2934
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "12px", color: "#6b7280" }, children: "This step type is not yet fully supported in the visual editor." })
2935
+ }
2936
+ );
2937
+ }
2938
+ var STEP_TYPE_OPTIONS = [
2939
+ {
2940
+ type: "prompt",
2941
+ label: "AI Prompt",
2942
+ icon: /* @__PURE__ */ jsxRuntime.jsx(PromptIcon, {}),
2943
+ color: NODE_HEADER_COLORS.prompt
2944
+ },
2945
+ {
2946
+ type: "fetch-url",
2947
+ label: "Fetch URL",
2948
+ icon: /* @__PURE__ */ jsxRuntime.jsx(GlobeIcon2, {}),
2949
+ color: NODE_HEADER_COLORS["fetch-url"]
2950
+ },
2951
+ {
2952
+ type: "transform-data",
2953
+ label: "Run Code",
2954
+ icon: /* @__PURE__ */ jsxRuntime.jsx(CodeIcon2, {}),
2955
+ color: NODE_HEADER_COLORS["transform-data"]
2956
+ },
2957
+ {
2958
+ type: "conditional",
2959
+ label: "Conditional",
2960
+ icon: /* @__PURE__ */ jsxRuntime.jsx(BranchIcon, {}),
2961
+ color: NODE_HEADER_COLORS.conditional
2962
+ },
2963
+ {
2964
+ type: "send-email",
2965
+ label: "Send Email",
2966
+ icon: /* @__PURE__ */ jsxRuntime.jsx(MailIcon2, {}),
2967
+ color: NODE_HEADER_COLORS["send-email"]
2968
+ }
2969
+ ];
2970
+ function RuntypeFlowEditor({
2971
+ client,
2972
+ flowId,
2973
+ initialName = "Untitled Flow",
2974
+ initialDescription = "",
2975
+ initialSteps = [],
2976
+ onSave,
2977
+ onChange,
2978
+ onStepSelect,
2979
+ showToolbar = true,
2980
+ readOnly = false,
2981
+ className
2982
+ }) {
2983
+ const [showAddMenu, setShowAddMenu] = react.useState(false);
2984
+ const [selectedNode, setSelectedNode] = react.useState(null);
2985
+ const {
2986
+ nodes,
2987
+ edges,
2988
+ onNodesChange,
2989
+ onEdgesChange,
2990
+ onConnect,
2991
+ flowName,
2992
+ setFlowName,
2993
+ saveFlow,
2994
+ addStep,
2995
+ isLoading,
2996
+ isSaving,
2997
+ error,
2998
+ hasUnsavedChanges
2999
+ } = useRuntypeFlow({
3000
+ client,
3001
+ flowId,
3002
+ initialName,
3003
+ initialDescription,
3004
+ initialSteps,
3005
+ onChange,
3006
+ autoLayoutOnLoad: true
3007
+ });
3008
+ const { result: validationResult } = useFlowValidation({ nodes });
3009
+ const handleSave = react.useCallback(async () => {
3010
+ try {
3011
+ const savedFlow = await saveFlow();
3012
+ onSave?.(savedFlow);
3013
+ } catch (err) {
3014
+ console.error("Failed to save flow:", err);
3015
+ }
3016
+ }, [saveFlow, onSave]);
3017
+ const handleAddStep = react.useCallback(
3018
+ (type) => {
3019
+ addStep(type);
3020
+ setShowAddMenu(false);
3021
+ },
3022
+ [addStep]
3023
+ );
3024
+ const handleNodeClick = react.useCallback(
3025
+ (_, node) => {
3026
+ setSelectedNode(node);
3027
+ onStepSelect?.(node.data.step);
3028
+ },
3029
+ [onStepSelect]
3030
+ );
3031
+ const handlePaneClick = react.useCallback(() => {
3032
+ setSelectedNode(null);
3033
+ onStepSelect?.(null);
3034
+ }, [onStepSelect]);
3035
+ const minimapNodeColor = react.useCallback((node) => {
3036
+ return NODE_HEADER_COLORS[node.data.step.type] || NODE_HEADER_COLORS.default;
3037
+ }, []);
3038
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.container, className, children: [
3039
+ /* @__PURE__ */ jsxRuntime.jsxs(
3040
+ react$1.ReactFlow,
3041
+ {
3042
+ nodes,
3043
+ edges,
3044
+ onNodesChange: readOnly ? void 0 : onNodesChange,
3045
+ onEdgesChange: readOnly ? void 0 : onEdgesChange,
3046
+ onConnect: readOnly ? void 0 : onConnect,
3047
+ onNodeClick: handleNodeClick,
3048
+ onPaneClick: handlePaneClick,
3049
+ nodeTypes,
3050
+ fitView: true,
3051
+ fitViewOptions: { padding: 0.2 },
3052
+ snapToGrid: true,
3053
+ snapGrid: [20, 20],
3054
+ connectionLineType: react$1.ConnectionLineType.SmoothStep,
3055
+ defaultEdgeOptions: {
3056
+ type: "smoothstep",
3057
+ animated: false
3058
+ },
3059
+ proOptions: { hideAttribution: true },
3060
+ children: [
3061
+ /* @__PURE__ */ jsxRuntime.jsx(react$1.Background, { variant: react$1.BackgroundVariant.Dots, gap: 20, size: 1, color: "#d1d5db" }),
3062
+ /* @__PURE__ */ jsxRuntime.jsx(react$1.Controls, { showInteractive: !readOnly }),
3063
+ /* @__PURE__ */ jsxRuntime.jsx(
3064
+ react$1.MiniMap,
3065
+ {
3066
+ nodeColor: minimapNodeColor,
3067
+ nodeStrokeWidth: 3,
3068
+ zoomable: true,
3069
+ pannable: true,
3070
+ style: {
3071
+ backgroundColor: "#f9fafb",
3072
+ border: "1px solid #e5e7eb",
3073
+ borderRadius: "8px"
3074
+ }
3075
+ }
3076
+ ),
3077
+ showToolbar && /* @__PURE__ */ jsxRuntime.jsx(react$1.Panel, { position: "top-left", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.toolbar, children: [
3078
+ /* @__PURE__ */ jsxRuntime.jsx(
3079
+ "input",
3080
+ {
3081
+ style: styles7.flowNameInput,
3082
+ value: flowName,
3083
+ onChange: (e) => setFlowName(e.target.value),
3084
+ placeholder: "Flow name...",
3085
+ disabled: readOnly,
3086
+ onFocus: (e) => {
3087
+ e.target.style.borderColor = "#6366f1";
3088
+ e.target.style.backgroundColor = "#ffffff";
3089
+ },
3090
+ onBlur: (e) => {
3091
+ e.target.style.borderColor = "transparent";
3092
+ e.target.style.backgroundColor = "transparent";
3093
+ }
3094
+ }
3095
+ ),
3096
+ hasUnsavedChanges && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles7.unsavedBadge, children: "Unsaved" }),
3097
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.toolbarDivider }),
3098
+ !readOnly && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative" }, children: [
3099
+ /* @__PURE__ */ jsxRuntime.jsxs(
3100
+ "button",
3101
+ {
3102
+ style: styles7.toolbarButton,
3103
+ onClick: () => setShowAddMenu(!showAddMenu),
3104
+ onMouseEnter: (e) => {
3105
+ e.currentTarget.style.backgroundColor = "#f3f4f6";
3106
+ e.currentTarget.style.borderColor = "#d1d5db";
3107
+ },
3108
+ onMouseLeave: (e) => {
3109
+ e.currentTarget.style.backgroundColor = "#f9fafb";
3110
+ e.currentTarget.style.borderColor = "#e5e7eb";
3111
+ },
3112
+ children: [
3113
+ /* @__PURE__ */ jsxRuntime.jsx(PlusIcon, {}),
3114
+ " Add Step"
3115
+ ]
3116
+ }
3117
+ ),
3118
+ showAddMenu && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.addStepMenu, children: STEP_TYPE_OPTIONS.map((option) => /* @__PURE__ */ jsxRuntime.jsxs(
3119
+ "button",
3120
+ {
3121
+ style: styles7.addStepMenuItem,
3122
+ onClick: () => handleAddStep(option.type),
3123
+ onMouseEnter: (e) => {
3124
+ e.currentTarget.style.backgroundColor = option.color;
3125
+ },
3126
+ onMouseLeave: (e) => {
3127
+ e.currentTarget.style.backgroundColor = "transparent";
3128
+ },
3129
+ children: [
3130
+ option.icon,
3131
+ option.label
3132
+ ]
3133
+ },
3134
+ option.type
3135
+ )) })
3136
+ ] }),
3137
+ !readOnly && flowId && /* @__PURE__ */ jsxRuntime.jsx(
3138
+ "button",
3139
+ {
3140
+ style: { ...styles7.toolbarButton, ...styles7.toolbarButtonPrimary },
3141
+ onClick: handleSave,
3142
+ disabled: isSaving || !hasUnsavedChanges,
3143
+ onMouseEnter: (e) => {
3144
+ if (!isSaving && hasUnsavedChanges) {
3145
+ e.currentTarget.style.backgroundColor = "#4f46e5";
3146
+ }
3147
+ },
3148
+ onMouseLeave: (e) => {
3149
+ e.currentTarget.style.backgroundColor = "#6366f1";
3150
+ },
3151
+ children: isSaving ? "Saving..." : "Save"
3152
+ }
3153
+ )
3154
+ ] }) }),
3155
+ /* @__PURE__ */ jsxRuntime.jsx(react$1.Panel, { position: "top-right", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.statusPanel, children: [
3156
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles7.statusBadge(validationResult.isValid), children: validationResult.isValid ? "Valid" : `${validationResult.errors.length} Error(s)` }),
3157
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
3158
+ nodes.length,
3159
+ " steps"
3160
+ ] }),
3161
+ isLoading && /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Loading..." }),
3162
+ error && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { color: "#dc2626" }, children: [
3163
+ "Error: ",
3164
+ error.message
3165
+ ] })
3166
+ ] }) })
3167
+ ]
3168
+ }
3169
+ ),
3170
+ showAddMenu && /* @__PURE__ */ jsxRuntime.jsx(
3171
+ "div",
3172
+ {
3173
+ style: {
3174
+ position: "fixed",
3175
+ top: 0,
3176
+ left: 0,
3177
+ right: 0,
3178
+ bottom: 0,
3179
+ zIndex: 999
3180
+ },
3181
+ onClick: () => setShowAddMenu(false)
3182
+ }
3183
+ )
3184
+ ] });
3185
+ }
3186
+ function PlusIcon() {
3187
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
3188
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
3189
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
3190
+ ] });
3191
+ }
3192
+ function PromptIcon() {
3193
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
3194
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z" }),
3195
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 5a3 3 0 1 1 5.997.125 4 4 0 0 1 2.526 5.77 4 4 0 0 1-.556 6.588A4 4 0 1 1 12 18Z" })
3196
+ ] });
3197
+ }
3198
+ function GlobeIcon2() {
3199
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
3200
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10" }),
3201
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" }),
3202
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 12h20" })
3203
+ ] });
3204
+ }
3205
+ function CodeIcon2() {
3206
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
3207
+ /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "16 18 22 12 16 6" }),
3208
+ /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "8 6 2 12 8 18" })
3209
+ ] });
3210
+ }
3211
+ function BranchIcon() {
3212
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
3213
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "6", y1: "3", x2: "6", y2: "15" }),
3214
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "18", cy: "6", r: "3" }),
3215
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "6", cy: "18", r: "3" }),
3216
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 9a9 9 0 0 1-9 9" })
3217
+ ] });
3218
+ }
3219
+ function MailIcon2() {
3220
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
3221
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { width: "20", height: "16", x: "2", y: "4", rx: "2" }),
3222
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" })
3223
+ ] });
3224
+ }
3225
+
3226
+ exports.BaseNode = BaseNode;
3227
+ exports.CodeNode = CodeNode;
3228
+ exports.ConditionalNode = ConditionalNode;
3229
+ exports.FetchUrlNode = FetchUrlNode;
3230
+ exports.PromptNode = PromptNode;
3231
+ exports.RuntypeFlowEditor = RuntypeFlowEditor;
3232
+ exports.SUPPORTED_NODE_TYPES = SUPPORTED_NODE_TYPES;
3233
+ exports.SendEmailNode = SendEmailNode;
3234
+ exports.autoLayout = autoLayout;
3235
+ exports.centerNodes = centerNodes;
3236
+ exports.cloneStep = cloneStep;
3237
+ exports.createDefaultStep = createDefaultStep;
3238
+ exports.createEdgesFromNodes = createEdgesFromNodes;
3239
+ exports.flowStepsToNodes = flowStepsToNodes;
3240
+ exports.generateStepId = generateStepId;
3241
+ exports.getDefaultStepName = getDefaultStepName;
3242
+ exports.getNodesBoundingBox = getNodesBoundingBox;
3243
+ exports.isSupportedNodeType = isSupportedNodeType;
3244
+ exports.nodesToFlowSteps = nodesToFlowSteps;
3245
+ exports.snapToGrid = snapToGrid;
3246
+ exports.useFlowValidation = useFlowValidation;
3247
+ exports.useRuntypeFlow = useRuntypeFlow;
3248
+ //# sourceMappingURL=index.js.map
3249
+ //# sourceMappingURL=index.js.map