@runtypelabs/react-flow 0.1.0 → 0.1.2

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