@octaviaflow/flow-rules 0.3.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,4095 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ function __accessProp(key) {
6
+ return this[key];
7
+ }
8
+ var __toCommonJS = (from) => {
9
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
10
+ if (entry)
11
+ return entry;
12
+ entry = __defProp({}, "__esModule", { value: true });
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (var key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(entry, key))
16
+ __defProp(entry, key, {
17
+ get: __accessProp.bind(from, key),
18
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
19
+ });
20
+ }
21
+ __moduleCache.set(from, entry);
22
+ return entry;
23
+ };
24
+ var __moduleCache;
25
+ var __returnValue = (v) => v;
26
+ function __exportSetter(name, newValue) {
27
+ this[name] = __returnValue.bind(null, newValue);
28
+ }
29
+ var __export = (target, all) => {
30
+ for (var name in all)
31
+ __defProp(target, name, {
32
+ get: all[name],
33
+ enumerable: true,
34
+ configurable: true,
35
+ set: __exportSetter.bind(all, name)
36
+ });
37
+ };
38
+
39
+ // src/index.ts
40
+ var exports_src = {};
41
+ __export(exports_src, {
42
+ ActionCategory: () => ActionCategory,
43
+ ActionStatus: () => ActionStatus,
44
+ ActionType: () => ActionType,
45
+ AggregateFunction: () => AggregateFunction,
46
+ CONDITION_OPERATORS: () => CONDITION_OPERATORS,
47
+ ConditionConfig: () => ConditionConfig,
48
+ DATABASE_CONNECTOR_IDS: () => DATABASE_CONNECTOR_IDS,
49
+ DebugConfig: () => DebugConfig,
50
+ EdgeType: () => EdgeType,
51
+ EmailConfig: () => EmailConfig,
52
+ FieldType: () => FieldType,
53
+ ForEachConfig: () => ForEachConfig,
54
+ JoinType: () => JoinType,
55
+ LogicalOperator: () => LogicalOperator,
56
+ ManualTriggerConfig: () => ManualTriggerConfig,
57
+ NodeStatus: () => NodeStatus,
58
+ QueryMode: () => QueryMode,
59
+ QueryType: () => QueryType,
60
+ STORAGE_CONNECTOR_IDS: () => STORAGE_CONNECTOR_IDS,
61
+ SortDirection: () => SortDirection,
62
+ TRANSFORM_OPERATIONS: () => TRANSFORM_OPERATIONS,
63
+ TransformConfig: () => TransformConfig,
64
+ VariablesConfig: () => VariablesConfig,
65
+ actionsRegistry: () => actionsRegistry,
66
+ buildPathOptions: () => buildPathOptions,
67
+ collectArrayPaths: () => collectArrayPaths,
68
+ collectArrayPathsFromSample: () => collectArrayPathsFromSample,
69
+ emailDefinition: () => emailDefinition,
70
+ flattenNestedWorkflow: () => flattenNestedWorkflow,
71
+ generateConnectionsFromSteps: () => generateConnectionsFromSteps,
72
+ generateEdgeId: () => generateEdgeId,
73
+ generateStepId: () => generateStepId,
74
+ generateUUIDv4: () => generateUUIDv4,
75
+ generateWorkflowId: () => generateWorkflowId,
76
+ getActionById: () => getActionById,
77
+ getActionsByCategory: () => getActionsByCategory,
78
+ getAllActions: () => getAllActions,
79
+ getEdgeValidationStatus: () => getEdgeValidationStatus,
80
+ getNodeConfigStatus: () => getNodeConfigStatus,
81
+ getNodeValidationStatus: () => getNodeValidationStatus,
82
+ getStorageProvider: () => getStorageProvider,
83
+ inferSchemaFromSample: () => inferSchemaFromSample,
84
+ isQueryableConnector: () => isQueryableConnector,
85
+ migrateDelayConfig: () => migrateDelayConfig,
86
+ queryDefinition: () => queryDefinition,
87
+ storageConfigKeys: () => storageConfigKeys,
88
+ transformConnectionToEdge: () => transformConnectionToEdge,
89
+ transformFlowToWorkflow: () => transformFlowToWorkflow,
90
+ transformStepToNode: () => transformStepToNode,
91
+ validateEdge: () => validateEdge,
92
+ validateFlowData: () => validateFlowData,
93
+ validateNode: () => validateNode,
94
+ validateWorkflow: () => validateWorkflow
95
+ });
96
+ module.exports = __toCommonJS(exports_src);
97
+
98
+ // src/catalog/types.ts
99
+ var ActionCategory;
100
+ ((ActionCategory) => {
101
+ ActionCategory["Trigger"] = "trigger";
102
+ ActionCategory["Action"] = "action";
103
+ ActionCategory["Logic"] = "logic";
104
+ ActionCategory["Transform"] = "transform";
105
+ ActionCategory["AI"] = "ai";
106
+ ActionCategory["Database"] = "database";
107
+ ActionCategory["API"] = "api";
108
+ ActionCategory["Storage"] = "storage";
109
+ ActionCategory["FileStorage"] = "file_storage";
110
+ ActionCategory["Communication"] = "communication";
111
+ ActionCategory["CRM"] = "crm";
112
+ ActionCategory["Ecommerce"] = "ecommerce";
113
+ ActionCategory["Marketing"] = "marketing";
114
+ ActionCategory["Analytics"] = "analytics";
115
+ ActionCategory["Productivity"] = "productivity";
116
+ ActionCategory["Custom"] = "custom";
117
+ ActionCategory["Utility"] = "utility";
118
+ })(ActionCategory ||= {});
119
+ var ActionType;
120
+ ((ActionType) => {
121
+ ActionType["Schedule"] = "schedule";
122
+ ActionType["Webhook"] = "webhook";
123
+ ActionType["Manual"] = "manual";
124
+ ActionType["DataChange"] = "data_change";
125
+ ActionType["Event"] = "event";
126
+ ActionType["Read"] = "read";
127
+ ActionType["Write"] = "write";
128
+ ActionType["Update"] = "update";
129
+ ActionType["Delete"] = "delete";
130
+ ActionType["Query"] = "query";
131
+ ActionType["HTTPRequest"] = "http_request";
132
+ ActionType["GraphQLQuery"] = "graphql_query";
133
+ ActionType["Condition"] = "condition";
134
+ ActionType["ForEach"] = "for_each";
135
+ ActionType["Group"] = "group";
136
+ ActionType["Format"] = "format";
137
+ ActionType["AIAgent"] = "ai_agent";
138
+ ActionType["Embedding"] = "embedding";
139
+ ActionType["VectorSearch"] = "vector_search";
140
+ ActionType["ImageGeneration"] = "image_generation";
141
+ ActionType["ImageAnalysis"] = "image_analysis";
142
+ ActionType["SpeechToText"] = "speech_to_text";
143
+ ActionType["TextToSpeech"] = "text_to_speech";
144
+ ActionType["Transform"] = "transform";
145
+ ActionType["FileOperation"] = "file_operation";
146
+ ActionType["FileAction"] = "file_action";
147
+ ActionType["CsvAction"] = "csv_action";
148
+ ActionType["JsonAction"] = "json_action";
149
+ ActionType["XmlAction"] = "xml_action";
150
+ ActionType["ExcelAction"] = "excel_action";
151
+ ActionType["S3Action"] = "s3_action";
152
+ ActionType["FtpAction"] = "ftp_action";
153
+ ActionType["GoogleDriveAction"] = "google_drive_action";
154
+ ActionType["DropboxAction"] = "dropbox_action";
155
+ ActionType["OneDriveAction"] = "onedrive_action";
156
+ ActionType["StorageAction"] = "storage_action";
157
+ ActionType["EmailSend"] = "email_send";
158
+ ActionType["SlackMessage"] = "slack_message";
159
+ ActionType["WhatsappSend"] = "whatsapp_send";
160
+ ActionType["TeamsMessage"] = "teams_message";
161
+ ActionType["GoogleChat"] = "google_chat";
162
+ ActionType["WebhookCall"] = "webhook_call";
163
+ ActionType["Delay"] = "delay";
164
+ ActionType["Wait"] = "wait";
165
+ ActionType["Console"] = "console";
166
+ ActionType["Debug"] = "debug";
167
+ ActionType["Error"] = "error";
168
+ ActionType["CustomCode"] = "custom_code";
169
+ ActionType["CustomAction"] = "custom_action";
170
+ ActionType["IdpExtract"] = "idp_extract";
171
+ })(ActionType ||= {});
172
+ var ActionStatus;
173
+ ((ActionStatus) => {
174
+ ActionStatus["Stable"] = "stable";
175
+ ActionStatus["Beta"] = "beta";
176
+ ActionStatus["Alpha"] = "alpha";
177
+ ActionStatus["Experimental"] = "experimental";
178
+ ActionStatus["Deprecated"] = "deprecated";
179
+ })(ActionStatus ||= {});
180
+ var FieldType;
181
+ ((FieldType) => {
182
+ FieldType["String"] = "string";
183
+ FieldType["Number"] = "number";
184
+ FieldType["Boolean"] = "boolean";
185
+ FieldType["Date"] = "date";
186
+ FieldType["DateTime"] = "datetime";
187
+ FieldType["Array"] = "array";
188
+ FieldType["Object"] = "object";
189
+ FieldType["JSON"] = "json";
190
+ FieldType["File"] = "file";
191
+ FieldType["Image"] = "image";
192
+ FieldType["Select"] = "select";
193
+ FieldType["MultiSelect"] = "multi_select";
194
+ FieldType["Code"] = "code";
195
+ FieldType["Expression"] = "expression";
196
+ FieldType["Mapping"] = "mapping";
197
+ FieldType["Connection"] = "connection";
198
+ FieldType["Secret"] = "secret";
199
+ FieldType["Color"] = "color";
200
+ FieldType["URL"] = "url";
201
+ FieldType["Email"] = "email";
202
+ FieldType["Phone"] = "phone";
203
+ FieldType["RichText"] = "rich_text";
204
+ FieldType["Markdown"] = "markdown";
205
+ })(FieldType ||= {});
206
+ // src/ids.ts
207
+ function randomSuffix(length = 7) {
208
+ const bytes = new Uint8Array(length);
209
+ crypto.getRandomValues(bytes);
210
+ let out = "";
211
+ for (let i = 0;i < length; i++) {
212
+ out += (bytes[i] % 36).toString(36);
213
+ }
214
+ return out;
215
+ }
216
+ function generateUUIDv4() {
217
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
218
+ const r = crypto.getRandomValues(new Uint8Array(1))[0] % 16;
219
+ const v = c === "x" ? r : r & 3 | 8;
220
+ return v.toString(16);
221
+ });
222
+ }
223
+ function generateWorkflowId() {
224
+ return generateUUIDv4();
225
+ }
226
+ function generateStepId() {
227
+ return `node_${Date.now()}_${randomSuffix(7)}`;
228
+ }
229
+ function generateEdgeId(sourceId, targetId) {
230
+ return `edge_${sourceId}_${targetId}_${Date.now()}_${randomSuffix(7)}`;
231
+ }
232
+
233
+ // src/catalog/triggers/manual-trigger/config.ts
234
+ var ManualTriggerConfig = {
235
+ defaults: {
236
+ description: ""
237
+ },
238
+ schema: {
239
+ description: {
240
+ type: "string",
241
+ maxLength: 500,
242
+ required: false,
243
+ description: "Optional description for this trigger (shown on node)"
244
+ }
245
+ },
246
+ validate: (config) => {
247
+ const errors = [];
248
+ if (config.description !== undefined) {
249
+ if (typeof config.description !== "string") {
250
+ errors.push("Description must be a string");
251
+ }
252
+ if (config.description.length > 500) {
253
+ errors.push("Description must not exceed 500 characters");
254
+ }
255
+ }
256
+ return {
257
+ valid: errors.length === 0,
258
+ errors
259
+ };
260
+ },
261
+ merge: (userConfig) => {
262
+ return {
263
+ ...ManualTriggerConfig.defaults,
264
+ ...userConfig
265
+ };
266
+ },
267
+ getLabel: (config) => {
268
+ if (config.description) {
269
+ return `Manual Trigger: ${config.description}`;
270
+ }
271
+ return "Manual Trigger";
272
+ }
273
+ };
274
+
275
+ // src/catalog/triggers/manual-trigger/index.ts
276
+ var manualTriggerDefinition = {
277
+ id: "manual_trigger",
278
+ name: "Manual Trigger",
279
+ description: "Manually trigger workflow with optional description",
280
+ category: "trigger" /* Trigger */,
281
+ type: "manual" /* Manual */,
282
+ tags: ["trigger", "manual", "built-in"],
283
+ status: "stable" /* Stable */,
284
+ icon: "PlayOutline",
285
+ color: "#0f62fe",
286
+ inputSchema: {
287
+ fields: [
288
+ {
289
+ key: "description",
290
+ label: "Description",
291
+ type: "string" /* String */,
292
+ description: "Optional description for this trigger (shown on node)",
293
+ placeholder: "e.g., Manual data sync, Testing workflow, etc.",
294
+ validation: {
295
+ required: false,
296
+ maxLength: 500
297
+ }
298
+ }
299
+ ]
300
+ },
301
+ outputSchema: {
302
+ type: "object",
303
+ properties: [
304
+ {
305
+ key: "triggeredAt",
306
+ type: "datetime" /* DateTime */,
307
+ description: "Timestamp when workflow was triggered"
308
+ },
309
+ {
310
+ key: "executionId",
311
+ type: "string" /* String */,
312
+ description: "Unique execution ID for this workflow run"
313
+ },
314
+ {
315
+ key: "description",
316
+ type: "string" /* String */,
317
+ description: "The description provided by the user (if any)"
318
+ }
319
+ ],
320
+ sampleOutput: {
321
+ triggeredAt: new Date().toISOString(),
322
+ executionId: `exec_${Date.now()}_${randomSuffix(9)}`,
323
+ description: "Manual data sync"
324
+ }
325
+ },
326
+ version: "1.0.0",
327
+ createdAt: "2025-01-01T00:00:00Z",
328
+ updatedAt: "2025-12-15T00:00:00Z",
329
+ createdBy: "system",
330
+ isOfficial: true,
331
+ testable: true
332
+ };
333
+
334
+ // src/catalog/triggers/schedule-trigger/index.ts
335
+ var scheduleTriggerDefinition = {
336
+ id: "schedule_trigger",
337
+ name: "Schedule Trigger",
338
+ description: "Trigger workflow on a schedule using cron or intervals",
339
+ category: "trigger" /* Trigger */,
340
+ type: "schedule" /* Schedule */,
341
+ tags: ["trigger", "schedule", "cron", "built-in"],
342
+ status: "stable" /* Stable */,
343
+ icon: "Time",
344
+ color: "#0f62fe",
345
+ inputSchema: {
346
+ fields: [
347
+ {
348
+ key: "scheduleType",
349
+ label: "Schedule Type",
350
+ type: "select" /* Select */,
351
+ description: "Type of schedule",
352
+ defaultValue: "interval",
353
+ options: [
354
+ { label: "Interval", value: "interval" },
355
+ { label: "Cron Expression", value: "cron" },
356
+ { label: "Specific Time", value: "specific" }
357
+ ],
358
+ validation: { required: true }
359
+ },
360
+ {
361
+ key: "interval",
362
+ label: "Interval",
363
+ type: "number" /* Number */,
364
+ description: "Interval value (used with interval type)",
365
+ validation: { required: false, min: 1 }
366
+ },
367
+ {
368
+ key: "intervalUnit",
369
+ label: "Interval Unit",
370
+ type: "select" /* Select */,
371
+ description: "Unit for interval (minutes, hours, days)",
372
+ defaultValue: "minutes",
373
+ options: [
374
+ { label: "Minutes", value: "minutes" },
375
+ { label: "Hours", value: "hours" },
376
+ { label: "Days", value: "days" },
377
+ { label: "Weeks", value: "weeks" }
378
+ ],
379
+ validation: { required: false }
380
+ },
381
+ {
382
+ key: "cronExpression",
383
+ label: "Cron Expression",
384
+ type: "string" /* String */,
385
+ description: "Cron expression (e.g., 0 0 * * * for daily at midnight)",
386
+ placeholder: "0 0 * * *",
387
+ validation: { required: false }
388
+ },
389
+ {
390
+ key: "timezone",
391
+ label: "Timezone",
392
+ type: "string" /* String */,
393
+ description: "Timezone for schedule (e.g., UTC, America/New_York)",
394
+ defaultValue: "UTC",
395
+ validation: { required: false }
396
+ }
397
+ ]
398
+ },
399
+ outputSchema: {
400
+ type: "object",
401
+ properties: [
402
+ {
403
+ key: "scheduledAt",
404
+ type: "datetime" /* DateTime */,
405
+ description: "When the schedule was triggered"
406
+ },
407
+ {
408
+ key: "nextRun",
409
+ type: "datetime" /* DateTime */,
410
+ description: "When the next run is scheduled"
411
+ },
412
+ {
413
+ key: "scheduleType",
414
+ type: "string" /* String */,
415
+ description: "Type of schedule that triggered"
416
+ }
417
+ ],
418
+ sampleOutput: {
419
+ scheduledAt: new Date().toISOString(),
420
+ nextRun: new Date(Date.now() + 3600000).toISOString(),
421
+ scheduleType: "interval"
422
+ }
423
+ },
424
+ version: "1.0.0",
425
+ createdAt: "2025-01-01T00:00:00Z",
426
+ updatedAt: "2025-12-15T00:00:00Z",
427
+ createdBy: "system",
428
+ isOfficial: true,
429
+ testable: true
430
+ };
431
+
432
+ // src/catalog/triggers/webhook-trigger/index.ts
433
+ var webhookTriggerDefinition = {
434
+ id: "webhook_trigger",
435
+ name: "Webhook Trigger",
436
+ description: "Trigger workflow via HTTP webhook",
437
+ category: "trigger" /* Trigger */,
438
+ type: "webhook" /* Webhook */,
439
+ tags: ["trigger", "webhook", "http", "built-in"],
440
+ status: "stable" /* Stable */,
441
+ icon: "WebhookAlt",
442
+ color: "#0f62fe",
443
+ inputSchema: {
444
+ fields: [
445
+ {
446
+ key: "webhookPath",
447
+ label: "Webhook Path",
448
+ type: "string" /* String */,
449
+ description: "Custom path for the webhook URL",
450
+ placeholder: "/my-webhook",
451
+ validation: { required: false }
452
+ },
453
+ {
454
+ key: "method",
455
+ label: "HTTP Method",
456
+ type: "select" /* Select */,
457
+ description: "Allowed HTTP methods",
458
+ defaultValue: "POST",
459
+ options: [
460
+ { label: "GET", value: "GET" },
461
+ { label: "POST", value: "POST" },
462
+ { label: "PUT", value: "PUT" },
463
+ { label: "PATCH", value: "PATCH" },
464
+ { label: "DELETE", value: "DELETE" }
465
+ ],
466
+ validation: { required: true }
467
+ },
468
+ {
469
+ key: "requireAuth",
470
+ label: "Require Authentication",
471
+ type: "boolean" /* Boolean */,
472
+ description: "Require API key or token for webhook",
473
+ defaultValue: true,
474
+ validation: { required: false }
475
+ }
476
+ ]
477
+ },
478
+ outputSchema: {
479
+ type: "object",
480
+ properties: [
481
+ {
482
+ key: "webhookUrl",
483
+ type: "url" /* URL */,
484
+ description: "The generated webhook URL"
485
+ },
486
+ {
487
+ key: "method",
488
+ type: "string" /* String */,
489
+ description: "HTTP method used"
490
+ },
491
+ {
492
+ key: "payload",
493
+ type: "json" /* JSON */,
494
+ description: "Request payload received"
495
+ },
496
+ {
497
+ key: "headers",
498
+ type: "object" /* Object */,
499
+ description: "Request headers"
500
+ }
501
+ ],
502
+ sampleOutput: {
503
+ webhookUrl: "https://api.example.com/webhooks/trigger-123",
504
+ method: "POST",
505
+ payload: { data: "example" },
506
+ headers: { "content-type": "application/json" }
507
+ }
508
+ },
509
+ version: "1.0.0",
510
+ createdAt: "2025-01-01T00:00:00Z",
511
+ updatedAt: "2025-12-15T00:00:00Z",
512
+ createdBy: "system",
513
+ isOfficial: true,
514
+ testable: true
515
+ };
516
+
517
+ // src/catalog/triggers/connector-trigger/index.ts
518
+ var connectorTriggerDefinition = {
519
+ id: "connector_trigger",
520
+ name: "Connector Trigger",
521
+ description: "Trigger workflow when a connector platform event occurs",
522
+ category: "trigger" /* Trigger */,
523
+ type: "event" /* Event */,
524
+ tags: ["trigger", "connector", "event", "built-in"],
525
+ status: "stable" /* Stable */,
526
+ icon: "Connect",
527
+ color: "#6929c4",
528
+ inputSchema: {
529
+ fields: [
530
+ {
531
+ key: "connectorInstanceId",
532
+ label: "Connector Instance",
533
+ type: "string" /* String */,
534
+ description: "The connected app instance to listen to",
535
+ validation: { required: true }
536
+ },
537
+ {
538
+ key: "events",
539
+ label: "Events",
540
+ type: "json" /* JSON */,
541
+ description: "Entity/operation pairs to subscribe to",
542
+ validation: { required: true }
543
+ }
544
+ ]
545
+ },
546
+ outputSchema: {
547
+ type: "object",
548
+ properties: [
549
+ {
550
+ key: "eventType",
551
+ type: "string" /* String */,
552
+ description: "The type of event that occurred"
553
+ },
554
+ {
555
+ key: "entity",
556
+ type: "string" /* String */,
557
+ description: "The entity that changed (e.g. Invoice)"
558
+ },
559
+ {
560
+ key: "operation",
561
+ type: "string" /* String */,
562
+ description: "The operation performed (e.g. Create)"
563
+ },
564
+ {
565
+ key: "payload",
566
+ type: "json" /* JSON */,
567
+ description: "The event payload from the connector"
568
+ }
569
+ ],
570
+ sampleOutput: {
571
+ eventType: "connector.event",
572
+ entity: "Invoice",
573
+ operation: "Create",
574
+ payload: { id: "123", amount: 500 }
575
+ }
576
+ },
577
+ version: "1.0.0",
578
+ createdAt: "2025-01-01T00:00:00Z",
579
+ updatedAt: "2025-12-15T00:00:00Z",
580
+ createdBy: "system",
581
+ isOfficial: true,
582
+ testable: false
583
+ };
584
+
585
+ // src/catalog/actions/http-request/index.ts
586
+ var httpRequestDefinition = {
587
+ id: "http_request",
588
+ name: "HTTP Request",
589
+ description: "Make HTTP requests to external APIs and services",
590
+ category: "api" /* API */,
591
+ type: "http_request" /* HTTPRequest */,
592
+ tags: ["api", "http", "request", "built-in"],
593
+ status: "stable" /* Stable */,
594
+ icon: "CloudUpload",
595
+ color: "#0043ce",
596
+ inputSchema: {
597
+ fields: [
598
+ {
599
+ key: "apiType",
600
+ label: "API Type",
601
+ type: "select" /* Select */,
602
+ description: "Type of API request to make",
603
+ defaultValue: "rest",
604
+ options: [
605
+ { label: "REST", value: "rest" },
606
+ { label: "GraphQL", value: "graphql" }
607
+ ],
608
+ validation: { required: true }
609
+ },
610
+ {
611
+ key: "method",
612
+ label: "Method",
613
+ type: "select" /* Select */,
614
+ description: "HTTP method to use (REST only)",
615
+ defaultValue: "GET",
616
+ options: [
617
+ { label: "GET", value: "GET" },
618
+ { label: "POST", value: "POST" },
619
+ { label: "PUT", value: "PUT" },
620
+ { label: "PATCH", value: "PATCH" },
621
+ { label: "DELETE", value: "DELETE" },
622
+ { label: "HEAD", value: "HEAD" },
623
+ { label: "OPTIONS", value: "OPTIONS" }
624
+ ],
625
+ validation: { required: false }
626
+ },
627
+ {
628
+ key: "url",
629
+ label: "URL",
630
+ type: "url" /* URL */,
631
+ description: "The URL to send the request to. Supports {{variable}} interpolation.",
632
+ placeholder: "https://api.example.com/endpoint",
633
+ validation: { required: true }
634
+ },
635
+ {
636
+ key: "headers",
637
+ label: "Headers",
638
+ type: "json" /* JSON */,
639
+ description: "HTTP headers (JSON object or key-value array). Supports {{variable}} interpolation.",
640
+ defaultValue: {},
641
+ validation: { required: false }
642
+ },
643
+ {
644
+ key: "body",
645
+ label: "Request Body",
646
+ type: "json" /* JSON */,
647
+ description: "Request body for POST/PUT/PATCH. Supports {{variable}} interpolation.",
648
+ validation: { required: false }
649
+ },
650
+ {
651
+ key: "graphqlQuery",
652
+ label: "GraphQL Query",
653
+ type: "string" /* String */,
654
+ description: "GraphQL query or mutation string (GraphQL only)",
655
+ validation: { required: false }
656
+ },
657
+ {
658
+ key: "graphqlVariables",
659
+ label: "GraphQL Variables",
660
+ type: "json" /* JSON */,
661
+ description: "GraphQL variables object. Supports {{variable}} interpolation.",
662
+ defaultValue: {},
663
+ validation: { required: false }
664
+ },
665
+ {
666
+ key: "auth",
667
+ label: "Authentication",
668
+ type: "json" /* JSON */,
669
+ description: 'Authentication config: { type: "none"|"basic"|"bearer"|"apikey", token?, username?, password?, apiKeyName?, apiKeyValue?, apiKeyLocation? }',
670
+ defaultValue: { type: "none" },
671
+ validation: { required: false }
672
+ },
673
+ {
674
+ key: "timeout",
675
+ label: "Timeout (ms)",
676
+ type: "number" /* Number */,
677
+ description: "Request timeout in milliseconds",
678
+ defaultValue: 30000,
679
+ validation: { required: false, min: 1000 }
680
+ },
681
+ {
682
+ key: "failOnError",
683
+ label: "Fail on non-2xx",
684
+ type: "boolean" /* Boolean */,
685
+ description: "If true, step fails when response status is not 2xx. Default: true.",
686
+ defaultValue: true,
687
+ validation: { required: false }
688
+ },
689
+ {
690
+ key: "responseType",
691
+ label: "Response Type",
692
+ type: "select" /* Select */,
693
+ description: "How to parse the response body. JSON tries to parse as JSON; Text returns raw text; Binary returns Uint8Array bytes plus fileName/contentType/size.",
694
+ defaultValue: "json",
695
+ options: [
696
+ { label: "JSON", value: "json" },
697
+ { label: "Text", value: "text" },
698
+ { label: "Binary", value: "binary" }
699
+ ],
700
+ validation: { required: false }
701
+ },
702
+ {
703
+ key: "expectedContentTypes",
704
+ label: "Expected Content-Types",
705
+ type: "json" /* JSON */,
706
+ description: 'Optional array of content-type prefixes (e.g. ["application/pdf"]). Logs a warning if the response content-type does not start with any of these.',
707
+ defaultValue: [],
708
+ validation: { required: false }
709
+ }
710
+ ]
711
+ },
712
+ outputSchema: {
713
+ type: "object",
714
+ properties: [
715
+ {
716
+ key: "status",
717
+ type: "number" /* Number */,
718
+ description: "HTTP status code"
719
+ },
720
+ {
721
+ key: "statusText",
722
+ type: "string" /* String */,
723
+ description: "HTTP status text"
724
+ },
725
+ {
726
+ key: "ok",
727
+ type: "boolean" /* Boolean */,
728
+ description: "True if status is 2xx"
729
+ },
730
+ {
731
+ key: "headers",
732
+ type: "object" /* Object */,
733
+ description: "Response headers"
734
+ },
735
+ {
736
+ key: "body",
737
+ type: "json" /* JSON */,
738
+ description: "Response body (parsed JSON or raw string)"
739
+ },
740
+ {
741
+ key: "duration",
742
+ type: "number" /* Number */,
743
+ description: "Request duration in milliseconds"
744
+ },
745
+ {
746
+ key: "graphqlErrors",
747
+ type: "json" /* JSON */,
748
+ description: "GraphQL errors array (GraphQL only, present when errors returned)"
749
+ },
750
+ {
751
+ key: "pages",
752
+ type: "number" /* Number */,
753
+ description: "Number of pages fetched (pagination only)"
754
+ },
755
+ {
756
+ key: "attempts",
757
+ type: "number" /* Number */,
758
+ description: "Total fetch attempts made (includes retries)"
759
+ },
760
+ {
761
+ key: "extracted",
762
+ type: "object" /* Object */,
763
+ description: "Named fields extracted from response body via dot-notation paths"
764
+ },
765
+ {
766
+ key: "fileName",
767
+ type: "string" /* String */,
768
+ description: "Derived file name (only present when Response Type is Binary). Sourced from Content-Disposition header or URL pathname."
769
+ },
770
+ {
771
+ key: "contentType",
772
+ type: "string" /* String */,
773
+ description: "Response content-type (only present when Response Type is Binary). Defaults to application/octet-stream when missing."
774
+ },
775
+ {
776
+ key: "size",
777
+ type: "number" /* Number */,
778
+ description: "Response body size in bytes (only present when Response Type is Binary)."
779
+ }
780
+ ],
781
+ sampleOutput: {
782
+ status: 200,
783
+ statusText: "OK",
784
+ ok: true,
785
+ headers: { "content-type": "application/json" },
786
+ body: { success: true, data: {} },
787
+ duration: 245,
788
+ attempts: 1,
789
+ extracted: {}
790
+ }
791
+ },
792
+ execution: {
793
+ timeout: 30000,
794
+ retryable: true
795
+ },
796
+ version: "1.0.0",
797
+ createdAt: "2025-01-01T00:00:00Z",
798
+ updatedAt: "2025-12-15T00:00:00Z",
799
+ createdBy: "system",
800
+ isOfficial: true,
801
+ testable: true
802
+ };
803
+
804
+ // src/catalog/actions/console-log/index.ts
805
+ var consoleLogDefinition = {
806
+ id: "console_log",
807
+ name: "Console Log",
808
+ description: "Log messages to the workflow console for debugging",
809
+ category: "utility" /* Utility */,
810
+ type: "console" /* Console */,
811
+ tags: ["utility", "logging", "debug", "built-in"],
812
+ status: "stable" /* Stable */,
813
+ icon: "Terminal",
814
+ color: "#525252",
815
+ inputSchema: {
816
+ fields: [
817
+ {
818
+ key: "message",
819
+ label: "Message",
820
+ type: "string" /* String */,
821
+ description: "Message to log",
822
+ placeholder: "e.g., Processing user data...",
823
+ validation: { required: true }
824
+ },
825
+ {
826
+ key: "level",
827
+ label: "Log Level",
828
+ type: "select" /* Select */,
829
+ description: "Log level for the message",
830
+ defaultValue: "info",
831
+ options: [
832
+ { label: "Info", value: "info" },
833
+ { label: "Warning", value: "warning" },
834
+ { label: "Error", value: "error" },
835
+ { label: "Debug", value: "debug" }
836
+ ],
837
+ validation: { required: true }
838
+ },
839
+ {
840
+ key: "data",
841
+ label: "Data",
842
+ type: "json" /* JSON */,
843
+ description: "Additional data to log",
844
+ validation: { required: false }
845
+ },
846
+ {
847
+ key: "includeInputData",
848
+ label: "Include previous step output",
849
+ type: "boolean" /* Boolean */,
850
+ description: 'When off, only the custom message prints — useful for summary "Done" logs that follow a ForEach.',
851
+ defaultValue: true,
852
+ validation: { required: false }
853
+ }
854
+ ]
855
+ },
856
+ outputSchema: {
857
+ type: "object",
858
+ properties: [
859
+ {
860
+ key: "logged",
861
+ type: "boolean" /* Boolean */,
862
+ description: "Whether the message was successfully logged"
863
+ },
864
+ {
865
+ key: "timestamp",
866
+ type: "datetime" /* DateTime */,
867
+ description: "Timestamp of the log entry"
868
+ },
869
+ {
870
+ key: "level",
871
+ type: "string" /* String */,
872
+ description: "Log level used"
873
+ }
874
+ ],
875
+ sampleOutput: {
876
+ logged: true,
877
+ timestamp: new Date().toISOString(),
878
+ level: "info"
879
+ }
880
+ },
881
+ version: "1.0.0",
882
+ createdAt: "2025-01-01T00:00:00Z",
883
+ updatedAt: "2025-12-15T00:00:00Z",
884
+ createdBy: "system",
885
+ isOfficial: true,
886
+ testable: true
887
+ };
888
+
889
+ // src/catalog/actions/delay/index.ts
890
+ var delayDefinition = {
891
+ id: "delay",
892
+ name: "Delay",
893
+ description: "Pause workflow execution for a specified duration",
894
+ category: "utility" /* Utility */,
895
+ type: "delay" /* Delay */,
896
+ tags: ["utility", "delay", "wait", "built-in"],
897
+ status: "stable" /* Stable */,
898
+ icon: "Timer",
899
+ color: "#8f8f8f",
900
+ inputSchema: {
901
+ fields: [
902
+ {
903
+ key: "duration",
904
+ label: "Duration (ms)",
905
+ type: "number" /* Number */,
906
+ description: "Duration to delay in milliseconds",
907
+ defaultValue: 1000,
908
+ validation: { required: true, min: 0 }
909
+ },
910
+ {
911
+ key: "unit",
912
+ label: "Unit",
913
+ type: "select" /* Select */,
914
+ description: "Time unit for the duration",
915
+ defaultValue: "milliseconds",
916
+ options: [
917
+ { label: "Milliseconds", value: "milliseconds" },
918
+ { label: "Seconds", value: "seconds" },
919
+ { label: "Minutes", value: "minutes" },
920
+ { label: "Hours", value: "hours" }
921
+ ],
922
+ validation: { required: true }
923
+ }
924
+ ]
925
+ },
926
+ outputSchema: {
927
+ type: "object",
928
+ properties: [
929
+ {
930
+ key: "delayedFor",
931
+ type: "number" /* Number */,
932
+ description: "Actual delay duration in milliseconds"
933
+ },
934
+ {
935
+ key: "completedAt",
936
+ type: "datetime" /* DateTime */,
937
+ description: "Timestamp when delay completed"
938
+ }
939
+ ],
940
+ sampleOutput: {
941
+ delayedFor: 1000,
942
+ completedAt: new Date().toISOString()
943
+ }
944
+ },
945
+ execution: {
946
+ timeout: 3600000
947
+ },
948
+ version: "1.0.0",
949
+ createdAt: "2025-01-01T00:00:00Z",
950
+ updatedAt: "2025-12-15T00:00:00Z",
951
+ createdBy: "system",
952
+ isOfficial: true,
953
+ testable: true
954
+ };
955
+
956
+ // src/catalog/logic/condition/index.ts
957
+ var conditionDefinition = {
958
+ id: "condition",
959
+ name: "Condition",
960
+ description: "Branch workflow execution based on conditions",
961
+ category: "logic" /* Logic */,
962
+ type: "condition" /* Condition */,
963
+ tags: ["logic", "condition", "branching", "built-in"],
964
+ status: "stable" /* Stable */,
965
+ icon: "DecisionTree",
966
+ color: "#f1c21b",
967
+ inputSchema: {
968
+ fields: [
969
+ {
970
+ key: "mode",
971
+ label: "Mode",
972
+ type: "string" /* String */,
973
+ description: "Authoring mode (visual builder).",
974
+ defaultValue: "visual",
975
+ validation: { required: true }
976
+ },
977
+ {
978
+ key: "filters",
979
+ label: "Condition Filters",
980
+ type: "array" /* Array */,
981
+ description: "Visual condition filters (field / operator / value rows)",
982
+ validation: { required: false }
983
+ }
984
+ ]
985
+ },
986
+ outputSchema: {
987
+ type: "object",
988
+ properties: [
989
+ {
990
+ key: "result",
991
+ type: "boolean" /* Boolean */,
992
+ description: "Result of the condition evaluation"
993
+ },
994
+ {
995
+ key: "branch",
996
+ type: "string" /* String */,
997
+ description: "Which branch was taken (true or false)"
998
+ }
999
+ ],
1000
+ sampleOutput: {
1001
+ result: true,
1002
+ branch: "true"
1003
+ }
1004
+ },
1005
+ version: "1.0.0",
1006
+ createdAt: "2025-01-01T00:00:00Z",
1007
+ updatedAt: "2025-12-15T00:00:00Z",
1008
+ createdBy: "system",
1009
+ isOfficial: true,
1010
+ testable: true
1011
+ };
1012
+
1013
+ // src/catalog/logic/for-each/index.ts
1014
+ var forEachDefinition = {
1015
+ id: "for_each",
1016
+ name: "ForEach",
1017
+ description: "Iterate over array items and execute actions for each",
1018
+ category: "logic" /* Logic */,
1019
+ type: "for_each" /* ForEach */,
1020
+ tags: ["logic", "loop", "iteration", "array", "built-in"],
1021
+ status: "stable" /* Stable */,
1022
+ icon: "Repeat",
1023
+ color: "#f1c21b",
1024
+ inputSchema: {
1025
+ fields: [
1026
+ {
1027
+ key: "arrayPath",
1028
+ label: "Records in",
1029
+ type: "expression" /* Expression */,
1030
+ description: "Path to the array to iterate over",
1031
+ placeholder: "e.g., Account, data.items",
1032
+ validation: { required: false }
1033
+ },
1034
+ {
1035
+ key: "itemVariable",
1036
+ label: "Item Variable Name",
1037
+ type: "string" /* String */,
1038
+ description: "Name of the variable for each item",
1039
+ defaultValue: "item",
1040
+ validation: { required: true }
1041
+ },
1042
+ {
1043
+ key: "indexVariable",
1044
+ label: "Index Variable Name",
1045
+ type: "string" /* String */,
1046
+ description: "Name of the variable for the index",
1047
+ defaultValue: "index",
1048
+ validation: { required: false }
1049
+ },
1050
+ {
1051
+ key: "batchSize",
1052
+ label: "Batch Size",
1053
+ type: "number" /* Number */,
1054
+ description: "Number of items to process per batch (0 = all at once)",
1055
+ defaultValue: 0,
1056
+ validation: { required: false }
1057
+ },
1058
+ {
1059
+ key: "continueOnError",
1060
+ label: "Continue on Error",
1061
+ type: "boolean" /* Boolean */,
1062
+ description: "Whether to continue processing remaining items if one fails",
1063
+ defaultValue: false,
1064
+ validation: { required: false }
1065
+ }
1066
+ ]
1067
+ },
1068
+ outputSchema: {
1069
+ type: "object",
1070
+ properties: [
1071
+ {
1072
+ key: "itemsProcessed",
1073
+ type: "number" /* Number */,
1074
+ description: "Number of items processed"
1075
+ },
1076
+ {
1077
+ key: "results",
1078
+ type: "array" /* Array */,
1079
+ description: "Results from each iteration"
1080
+ }
1081
+ ],
1082
+ sampleOutput: {
1083
+ itemsProcessed: 5,
1084
+ results: [{ item: 1 }, { item: 2 }]
1085
+ }
1086
+ },
1087
+ version: "1.0.0",
1088
+ createdAt: "2025-01-01T00:00:00Z",
1089
+ updatedAt: "2025-12-15T00:00:00Z",
1090
+ createdBy: "system",
1091
+ isOfficial: true,
1092
+ testable: true
1093
+ };
1094
+
1095
+ // src/catalog/logic/group/index.ts
1096
+ var groupDefinition = {
1097
+ id: "group",
1098
+ name: "Group",
1099
+ description: "Visually group a set of steps — drop nodes inside to nest them.",
1100
+ category: "logic" /* Logic */,
1101
+ type: "group" /* Group */,
1102
+ tags: ["logic", "container", "subflow", "built-in"],
1103
+ status: "stable" /* Stable */,
1104
+ icon: "GroupObjects",
1105
+ color: "#6f6f6f",
1106
+ inputSchema: { fields: [] },
1107
+ outputSchema: {
1108
+ type: "object",
1109
+ properties: [
1110
+ {
1111
+ key: "result",
1112
+ type: "object",
1113
+ description: "Aggregated output of the contained steps."
1114
+ }
1115
+ ]
1116
+ },
1117
+ version: "1.0.0",
1118
+ createdAt: "2026-05-19T00:00:00Z",
1119
+ updatedAt: "2026-05-19T00:00:00Z",
1120
+ createdBy: "system",
1121
+ isOfficial: true,
1122
+ testable: false
1123
+ };
1124
+
1125
+ // src/catalog/general/query/types.ts
1126
+ var QueryMode;
1127
+ ((QueryMode) => {
1128
+ QueryMode["Visual"] = "visual";
1129
+ QueryMode["SQL"] = "sql";
1130
+ })(QueryMode ||= {});
1131
+ var QueryType;
1132
+ ((QueryType) => {
1133
+ QueryType["Select"] = "select";
1134
+ QueryType["Insert"] = "insert";
1135
+ QueryType["Update"] = "update";
1136
+ QueryType["Delete"] = "delete";
1137
+ QueryType["Custom"] = "custom";
1138
+ })(QueryType ||= {});
1139
+ var LogicalOperator;
1140
+ ((LogicalOperator) => {
1141
+ LogicalOperator["And"] = "and";
1142
+ LogicalOperator["Or"] = "or";
1143
+ })(LogicalOperator ||= {});
1144
+ var SortDirection;
1145
+ ((SortDirection) => {
1146
+ SortDirection["Ascending"] = "asc";
1147
+ SortDirection["Descending"] = "desc";
1148
+ })(SortDirection ||= {});
1149
+ var JoinType;
1150
+ ((JoinType) => {
1151
+ JoinType["Inner"] = "inner";
1152
+ JoinType["Left"] = "left";
1153
+ JoinType["Right"] = "right";
1154
+ JoinType["Full"] = "full";
1155
+ })(JoinType ||= {});
1156
+ var AggregateFunction;
1157
+ ((AggregateFunction) => {
1158
+ AggregateFunction["Count"] = "count";
1159
+ AggregateFunction["Sum"] = "sum";
1160
+ AggregateFunction["Average"] = "avg";
1161
+ AggregateFunction["Min"] = "min";
1162
+ AggregateFunction["Max"] = "max";
1163
+ AggregateFunction["CountDistinct"] = "count_distinct";
1164
+ })(AggregateFunction ||= {});
1165
+ // src/catalog/general/query/config.ts
1166
+ var BuildQueryConfigDefaults = {
1167
+ mode: "visual" /* Visual */,
1168
+ queryType: "select" /* Select */,
1169
+ timeout: 30000,
1170
+ maxRows: 1000,
1171
+ visualConfig: {
1172
+ tables: [],
1173
+ fields: [],
1174
+ filters: undefined,
1175
+ joins: [],
1176
+ groupBy: [],
1177
+ sort: [],
1178
+ limit: 10,
1179
+ offset: 0
1180
+ },
1181
+ sqlConfig: {
1182
+ sql: "",
1183
+ parameters: {}
1184
+ }
1185
+ };
1186
+ function isQueryableConnector(connector) {
1187
+ if (connector.isQueryable !== undefined) {
1188
+ return connector.isQueryable;
1189
+ }
1190
+ if (connector.category === "storage") {
1191
+ return false;
1192
+ }
1193
+ if (!connector.type) {
1194
+ return false;
1195
+ }
1196
+ const storageTypes = [
1197
+ "dropbox",
1198
+ "google_drive",
1199
+ "google-drive",
1200
+ "onedrive",
1201
+ "box",
1202
+ "ftp",
1203
+ "sftp",
1204
+ "s3",
1205
+ "azure_blob",
1206
+ "azure-blob",
1207
+ "storage"
1208
+ ];
1209
+ return !storageTypes.includes(connector.type.toLowerCase());
1210
+ }
1211
+
1212
+ // src/catalog/general/query/index.ts
1213
+ var queryDefinition = {
1214
+ id: "query",
1215
+ name: "Query",
1216
+ description: "Execute queries against connected databases, APIs, and CRMs",
1217
+ longDescription: "Create powerful queries using either a visual no-code builder or advanced SQL editor. Supports databases (PostgreSQL, MySQL, MongoDB, etc.), APIs (REST, GraphQL), and CRMs (Salesforce, HubSpot). Query results can be used as input for downstream actions.",
1218
+ category: "database" /* Database */,
1219
+ type: "query" /* Query */,
1220
+ tags: ["query", "database", "sql", "visual-builder", "no-code", "api", "crm", "built-in"],
1221
+ status: "stable" /* Stable */,
1222
+ icon: "QueryQueue",
1223
+ color: "#0043ce",
1224
+ inputSchema: {
1225
+ fields: [
1226
+ {
1227
+ key: "connectorId",
1228
+ label: "Select Connector",
1229
+ type: "connection" /* Connection */,
1230
+ description: "Choose a connected database, API, or CRM (storage connectors like Dropbox/Google Drive are not supported)",
1231
+ validation: { required: true },
1232
+ helpText: "Only queryable connectors are shown. File storage connectors have separate actions."
1233
+ },
1234
+ {
1235
+ key: "mode",
1236
+ label: "Query Mode",
1237
+ type: "select" /* Select */,
1238
+ description: "Choose between visual query builder or SQL editor",
1239
+ options: [
1240
+ {
1241
+ label: "Visual Builder (No-Code)",
1242
+ value: "visual" /* Visual */,
1243
+ description: "Build queries visually without writing code"
1244
+ },
1245
+ {
1246
+ label: "SQL Editor (Advanced)",
1247
+ value: "sql" /* SQL */,
1248
+ description: "Write raw SQL queries with syntax highlighting"
1249
+ }
1250
+ ],
1251
+ defaultValue: "visual" /* Visual */,
1252
+ validation: { required: true }
1253
+ },
1254
+ {
1255
+ key: "queryType",
1256
+ label: "Query Type",
1257
+ type: "select" /* Select */,
1258
+ description: "Type of query operation — the Query action reads data; use Transform to write",
1259
+ options: [
1260
+ { label: "SELECT (Read Data)", value: "select" /* Select */ }
1261
+ ],
1262
+ defaultValue: "select" /* Select */,
1263
+ validation: { required: true },
1264
+ conditional: [
1265
+ {
1266
+ field: "mode",
1267
+ operator: "==",
1268
+ value: "visual" /* Visual */,
1269
+ action: "show"
1270
+ }
1271
+ ]
1272
+ },
1273
+ {
1274
+ key: "visualConfig.tables",
1275
+ label: "Select Tables",
1276
+ type: "multi_select" /* MultiSelect */,
1277
+ description: "Choose one or more tables to query",
1278
+ validation: { required: true },
1279
+ conditional: [
1280
+ {
1281
+ field: "mode",
1282
+ operator: "==",
1283
+ value: "visual" /* Visual */,
1284
+ action: "show"
1285
+ }
1286
+ ],
1287
+ optionsSource: {
1288
+ type: "dynamic",
1289
+ dependsOn: ["connectorId"]
1290
+ }
1291
+ },
1292
+ {
1293
+ key: "visualConfig.fields",
1294
+ label: "Select Fields",
1295
+ type: "array" /* Array */,
1296
+ description: "Choose fields to include in the query result",
1297
+ validation: { required: true },
1298
+ conditional: [
1299
+ {
1300
+ field: "mode",
1301
+ operator: "==",
1302
+ value: "visual" /* Visual */,
1303
+ action: "show"
1304
+ }
1305
+ ]
1306
+ },
1307
+ {
1308
+ key: "visualConfig.limit",
1309
+ label: "Limit",
1310
+ type: "number" /* Number */,
1311
+ description: "Maximum number of rows to return",
1312
+ defaultValue: 10,
1313
+ validation: { required: false, min: 1, max: 1e4 },
1314
+ conditional: [
1315
+ {
1316
+ field: "mode",
1317
+ operator: "==",
1318
+ value: "visual" /* Visual */,
1319
+ action: "show"
1320
+ }
1321
+ ]
1322
+ },
1323
+ {
1324
+ key: "sqlConfig.sql",
1325
+ label: "SQL Query",
1326
+ type: "code" /* Code */,
1327
+ language: "sql",
1328
+ description: "Write your SQL query here",
1329
+ placeholder: "SELECT * FROM users WHERE status = 'active' LIMIT 100",
1330
+ validation: { required: true },
1331
+ conditional: [
1332
+ {
1333
+ field: "mode",
1334
+ operator: "==",
1335
+ value: "sql" /* SQL */,
1336
+ action: "show"
1337
+ }
1338
+ ]
1339
+ },
1340
+ {
1341
+ key: "sqlConfig.parameters",
1342
+ label: "Query Parameters",
1343
+ type: "json" /* JSON */,
1344
+ description: 'Parameters for parameterized queries (e.g., {"userId": 123})',
1345
+ validation: { required: false },
1346
+ advanced: true,
1347
+ conditional: [
1348
+ {
1349
+ field: "mode",
1350
+ operator: "==",
1351
+ value: "sql" /* SQL */,
1352
+ action: "show"
1353
+ }
1354
+ ]
1355
+ },
1356
+ {
1357
+ key: "timeout",
1358
+ label: "Query Timeout (ms)",
1359
+ type: "number" /* Number */,
1360
+ description: "Maximum time to wait for query execution",
1361
+ defaultValue: 30000,
1362
+ validation: { required: false, min: 1000, max: 300000 },
1363
+ advanced: true
1364
+ },
1365
+ {
1366
+ key: "maxRows",
1367
+ label: "Max Rows",
1368
+ type: "number" /* Number */,
1369
+ description: "Maximum number of rows to return",
1370
+ defaultValue: 1000,
1371
+ validation: { required: false, min: 1, max: 1e4 },
1372
+ advanced: true
1373
+ }
1374
+ ],
1375
+ groups: [
1376
+ {
1377
+ id: "connection",
1378
+ label: "Connection",
1379
+ description: "Select the data source to query",
1380
+ fields: ["connectorId"]
1381
+ },
1382
+ {
1383
+ id: "query_mode",
1384
+ label: "Query Configuration",
1385
+ description: "Configure how you want to build your query",
1386
+ fields: ["mode", "queryType"]
1387
+ },
1388
+ {
1389
+ id: "visual_builder",
1390
+ label: "Visual Query Builder",
1391
+ description: "Build your query visually without writing code",
1392
+ fields: ["visualConfig.tables", "visualConfig.fields", "visualConfig.limit"]
1393
+ },
1394
+ {
1395
+ id: "sql_editor",
1396
+ label: "SQL Editor",
1397
+ description: "Write raw SQL queries",
1398
+ fields: ["sqlConfig.sql", "sqlConfig.parameters"]
1399
+ },
1400
+ {
1401
+ id: "settings",
1402
+ label: "Advanced Settings",
1403
+ description: "Configure query execution settings",
1404
+ collapsed: true,
1405
+ fields: ["timeout", "maxRows"]
1406
+ }
1407
+ ]
1408
+ },
1409
+ outputSchema: {
1410
+ type: "object",
1411
+ properties: [
1412
+ {
1413
+ key: "data",
1414
+ type: "array" /* Array */,
1415
+ description: "Query result data as an array of objects",
1416
+ example: [{ id: 1, name: "John Doe", email: "john@example.com" }]
1417
+ },
1418
+ {
1419
+ key: "rowCount",
1420
+ type: "number" /* Number */,
1421
+ description: "Number of rows returned",
1422
+ example: 1
1423
+ },
1424
+ {
1425
+ key: "columns",
1426
+ type: "array" /* Array */,
1427
+ description: "Column names in the result set",
1428
+ example: ["id", "name", "email"]
1429
+ },
1430
+ {
1431
+ key: "executionTime",
1432
+ type: "number" /* Number */,
1433
+ description: "Query execution time in milliseconds",
1434
+ example: 45
1435
+ },
1436
+ {
1437
+ key: "generatedSQL",
1438
+ type: "string" /* String */,
1439
+ description: "The SQL query that was executed (for visual builder mode)",
1440
+ example: "SELECT id, name, email FROM users WHERE status = 'active' LIMIT 100"
1441
+ }
1442
+ ],
1443
+ sampleOutput: {
1444
+ data: [
1445
+ { id: 1, name: "John Doe", email: "john@example.com", status: "active" },
1446
+ { id: 2, name: "Jane Smith", email: "jane@example.com", status: "active" }
1447
+ ],
1448
+ rowCount: 2,
1449
+ columns: ["id", "name", "email", "status"],
1450
+ executionTime: 45,
1451
+ generatedSQL: "SELECT id, name, email, status FROM users WHERE status = 'active' LIMIT 100"
1452
+ }
1453
+ },
1454
+ execution: {
1455
+ timeout: 30000,
1456
+ retryable: true,
1457
+ requiresAuth: true
1458
+ },
1459
+ testable: true,
1460
+ version: "1.0.0",
1461
+ createdAt: "2025-01-19T00:00:00Z",
1462
+ updatedAt: "2025-01-19T00:00:00Z",
1463
+ createdBy: "system",
1464
+ isOfficial: true
1465
+ };
1466
+
1467
+ // src/catalog/general/transform/index.ts
1468
+ var transformDefinition = {
1469
+ id: "transform",
1470
+ name: "Transform",
1471
+ description: "Map and transform data between workflow steps using the visual field mapper",
1472
+ category: "transform" /* Transform */,
1473
+ type: "transform" /* Transform */,
1474
+ tags: ["transform", "mapping", "data", "reshape", "convert", "built-in"],
1475
+ status: "stable" /* Stable */,
1476
+ icon: "Transform",
1477
+ color: "#0043ce",
1478
+ inputSchema: {
1479
+ fields: [
1480
+ {
1481
+ key: "name",
1482
+ label: "Transform Name",
1483
+ type: "string" /* String */,
1484
+ description: "A descriptive name for this transform step",
1485
+ defaultValue: "Transform",
1486
+ validation: { required: false }
1487
+ },
1488
+ {
1489
+ key: "mappings",
1490
+ label: "Field Mappings",
1491
+ type: "array" /* Array */,
1492
+ description: "Map source fields from upstream nodes to target output fields",
1493
+ validation: { required: false }
1494
+ }
1495
+ ]
1496
+ },
1497
+ outputSchema: {
1498
+ type: "object",
1499
+ properties: [
1500
+ {
1501
+ key: "result",
1502
+ type: "json" /* JSON */,
1503
+ description: "Transformed data output"
1504
+ },
1505
+ {
1506
+ key: "mappedFieldCount",
1507
+ type: "number" /* Number */,
1508
+ description: "Number of fields that were mapped/transformed"
1509
+ }
1510
+ ],
1511
+ sampleOutput: {
1512
+ result: { name: "John Doe", email: "john@example.com", age: 30 },
1513
+ mappedFieldCount: 3
1514
+ },
1515
+ dynamic: true
1516
+ },
1517
+ version: "2.0.0",
1518
+ createdAt: "2025-01-01T00:00:00Z",
1519
+ updatedAt: "2026-02-13T00:00:00Z",
1520
+ createdBy: "system",
1521
+ isOfficial: true,
1522
+ testable: true
1523
+ };
1524
+
1525
+ // src/catalog/storage/csv-action/index.ts
1526
+ var csvActionDefinition = {
1527
+ id: "csv_action",
1528
+ name: "CSV",
1529
+ description: "Parse CSV files into structured records or generate CSV files from workflow data",
1530
+ category: "storage" /* Storage */,
1531
+ type: "csv_action" /* CsvAction */,
1532
+ tags: ["csv", "parse", "generate", "file", "format", "built-in"],
1533
+ status: "stable" /* Stable */,
1534
+ icon: "Document",
1535
+ color: "#198038",
1536
+ inputSchema: {
1537
+ fields: [
1538
+ { key: "operation", label: "Operation", type: "select" /* Select */, options: [{ label: "Parse (CSV → Records)", value: "parse" }, { label: "Generate (Records → CSV)", value: "generate" }], defaultValue: "parse", validation: { required: true } },
1539
+ { key: "content", label: "CSV Content", type: "string" /* String */, description: "Paste CSV content or use FX token from upstream step" },
1540
+ { key: "delimiter", label: "Delimiter", type: "select" /* Select */, options: [{ label: "Comma (,)", value: "," }, { label: "Semicolon (;)", value: ";" }, { label: "Tab", value: "\t" }, { label: "Pipe (|)", value: "|" }], defaultValue: "," },
1541
+ { key: "headerRow", label: "Header Row", type: "number" /* Number */, description: "Row number containing column headers (default: 1)", defaultValue: 1 },
1542
+ { key: "encoding", label: "Encoding", type: "select" /* Select */, options: [{ label: "UTF-8", value: "utf-8" }, { label: "Latin-1", value: "latin1" }, { label: "ASCII", value: "ascii" }], defaultValue: "utf-8" },
1543
+ { key: "includeHeader", label: "Include Header Row", type: "boolean" /* Boolean */, description: "Include column headers in generated CSV", defaultValue: true },
1544
+ { key: "fileName", label: "Output File Name", type: "string" /* String */, description: "Name for generated file (e.g. export.csv)", defaultValue: "export.csv" }
1545
+ ]
1546
+ },
1547
+ outputSchema: {
1548
+ type: "object",
1549
+ properties: [
1550
+ { key: "data", type: "array" /* Array */, description: "Parsed records (parse mode) — loop these with a ForEach. Generated CSV string in generate mode." },
1551
+ { key: "columns", type: "json" /* JSON */, description: "Column names" },
1552
+ { key: "rowCount", type: "number" /* Number */, description: "Number of records" }
1553
+ ],
1554
+ sampleOutput: { data: [{ id: 1, name: "Widget", price: 9.99 }], columns: ["id", "name", "price"], rowCount: 1 }
1555
+ },
1556
+ version: "1.0.0",
1557
+ createdAt: "2026-03-28T00:00:00Z",
1558
+ updatedAt: "2026-03-28T00:00:00Z",
1559
+ createdBy: "system",
1560
+ isOfficial: true,
1561
+ testable: false
1562
+ };
1563
+
1564
+ // src/catalog/storage/json-action/index.ts
1565
+ var jsonActionDefinition = {
1566
+ id: "json_action",
1567
+ name: "JSON",
1568
+ description: "Parse JSON/JSONL files into structured records or generate JSON from workflow data",
1569
+ category: "storage" /* Storage */,
1570
+ type: "json_action" /* JsonAction */,
1571
+ tags: ["json", "jsonl", "parse", "generate", "file", "format", "built-in"],
1572
+ status: "stable" /* Stable */,
1573
+ icon: "DataStructured",
1574
+ color: "#f1c21b",
1575
+ inputSchema: {
1576
+ fields: [
1577
+ { key: "operation", label: "Operation", type: "select" /* Select */, options: [{ label: "Parse (JSON → Records)", value: "parse" }, { label: "Generate (Records → JSON)", value: "generate" }], defaultValue: "parse", validation: { required: true } },
1578
+ { key: "format", label: "Format", type: "select" /* Select */, options: [{ label: "JSON (array)", value: "json" }, { label: "JSONL (one object per line)", value: "jsonl" }], defaultValue: "json" },
1579
+ { key: "content", label: "JSON Content", type: "string" /* String */, description: "Paste JSON content or use FX token from upstream step" },
1580
+ { key: "prettyPrint", label: "Pretty Print", type: "boolean" /* Boolean */, description: "Format output with indentation", defaultValue: true },
1581
+ { key: "fileName", label: "Output File Name", type: "string" /* String */, defaultValue: "export.json" }
1582
+ ]
1583
+ },
1584
+ outputSchema: {
1585
+ type: "object",
1586
+ properties: [
1587
+ { key: "data", type: "array" /* Array */, description: "Parsed records (parse mode) — loop these with a ForEach. Generated JSON string in generate mode." },
1588
+ { key: "columns", type: "json" /* JSON */, description: "Field names" },
1589
+ { key: "rowCount", type: "number" /* Number */, description: "Number of records" }
1590
+ ],
1591
+ sampleOutput: { data: [{ id: 1, name: "Widget" }], columns: ["id", "name"], rowCount: 1 }
1592
+ },
1593
+ version: "1.0.0",
1594
+ createdAt: "2026-03-28T00:00:00Z",
1595
+ updatedAt: "2026-03-28T00:00:00Z",
1596
+ createdBy: "system",
1597
+ isOfficial: true,
1598
+ testable: false
1599
+ };
1600
+
1601
+ // src/catalog/storage/xml-action/index.ts
1602
+ var xmlActionDefinition = {
1603
+ id: "xml_action",
1604
+ name: "XML",
1605
+ description: "Parse XML files into structured records or generate XML from workflow data",
1606
+ category: "storage" /* Storage */,
1607
+ type: "xml_action" /* XmlAction */,
1608
+ tags: ["xml", "parse", "generate", "file", "format", "built-in"],
1609
+ status: "beta" /* Beta */,
1610
+ icon: "Code",
1611
+ color: "#e65100",
1612
+ inputSchema: {
1613
+ fields: [
1614
+ { key: "operation", label: "Operation", type: "select" /* Select */, options: [{ label: "Parse (XML → Records)", value: "parse" }, { label: "Generate (Records → XML)", value: "generate" }], defaultValue: "parse", validation: { required: true } },
1615
+ { key: "content", label: "XML Content", type: "string" /* String */, description: "Paste XML or use FX token" },
1616
+ { key: "rootElement", label: "Root Element", type: "string" /* String */, description: "Root XML element name (for generate)", defaultValue: "data" },
1617
+ { key: "rowElement", label: "Row Element", type: "string" /* String */, description: "Element name per record (for generate)", defaultValue: "row" },
1618
+ { key: "fileName", label: "Output File Name", type: "string" /* String */, defaultValue: "export.xml" }
1619
+ ]
1620
+ },
1621
+ outputSchema: {
1622
+ type: "object",
1623
+ properties: [
1624
+ { key: "data", type: "array" /* Array */, description: "Parsed records (parse mode) — loop these with a ForEach. Generated XML string in generate mode." },
1625
+ { key: "columns", type: "json" /* JSON */, description: "Field names" },
1626
+ { key: "rowCount", type: "number" /* Number */, description: "Number of records" }
1627
+ ],
1628
+ sampleOutput: { data: [{ id: 1, name: "Widget" }], columns: ["id", "name"], rowCount: 1 }
1629
+ },
1630
+ version: "1.0.0",
1631
+ createdAt: "2026-03-28T00:00:00Z",
1632
+ updatedAt: "2026-03-28T00:00:00Z",
1633
+ createdBy: "system",
1634
+ isOfficial: true,
1635
+ testable: false
1636
+ };
1637
+
1638
+ // src/catalog/storage/excel-action/index.ts
1639
+ var excelActionDefinition = {
1640
+ id: "excel_action",
1641
+ name: "Excel",
1642
+ description: "Parse Excel (.xlsx) files into structured records or generate Excel files from workflow data",
1643
+ category: "storage" /* Storage */,
1644
+ type: "excel_action" /* ExcelAction */,
1645
+ tags: ["excel", "xlsx", "xls", "spreadsheet", "parse", "generate", "built-in"],
1646
+ status: "stable" /* Stable */,
1647
+ icon: "Spreadsheet",
1648
+ color: "#217346",
1649
+ inputSchema: {
1650
+ fields: [
1651
+ { key: "operation", label: "Operation", type: "select" /* Select */, options: [{ label: "Parse (Excel → Records)", value: "parse" }, { label: "Generate (Records → Excel)", value: "generate" }], defaultValue: "parse", validation: { required: true } },
1652
+ { key: "content", label: "Excel File", type: "string" /* String */, description: "S3 key of uploaded Excel file or FX token from upstream" },
1653
+ { key: "sheetName", label: "Sheet Name", type: "string" /* String */, description: "Name of sheet to read (default: first sheet)" },
1654
+ { key: "headerRow", label: "Header Row", type: "number" /* Number */, description: "Row number containing headers", defaultValue: 1 },
1655
+ { key: "fileName", label: "Output File Name", type: "string" /* String */, defaultValue: "export.xlsx" }
1656
+ ]
1657
+ },
1658
+ outputSchema: {
1659
+ type: "object",
1660
+ properties: [
1661
+ { key: "data", type: "array" /* Array */, description: "Parsed records (parse mode) — loop these with a ForEach. File metadata in generate mode." },
1662
+ { key: "columns", type: "json" /* JSON */, description: "Column names" },
1663
+ { key: "rowCount", type: "number" /* Number */, description: "Number of records" },
1664
+ { key: "s3Key", type: "string" /* String */, description: "S3 key of generated file" }
1665
+ ],
1666
+ sampleOutput: { data: [{ id: 1, name: "Widget" }], columns: ["id", "name"], rowCount: 1 }
1667
+ },
1668
+ version: "1.0.0",
1669
+ createdAt: "2026-03-28T00:00:00Z",
1670
+ updatedAt: "2026-03-28T00:00:00Z",
1671
+ createdBy: "system",
1672
+ isOfficial: true,
1673
+ testable: false
1674
+ };
1675
+
1676
+ // src/catalog/storage/s3-action/index.ts
1677
+ var s3ActionDefinition = {
1678
+ id: "s3_action",
1679
+ name: "AWS S3",
1680
+ description: "Upload, download, list, delete, or copy files in Amazon S3 buckets",
1681
+ category: "storage" /* Storage */,
1682
+ type: "s3_action" /* S3Action */,
1683
+ tags: ["s3", "aws", "storage", "cloud", "bucket", "upload", "download", "built-in"],
1684
+ status: "stable" /* Stable */,
1685
+ icon: "CloudUpload",
1686
+ color: "#569A31",
1687
+ inputSchema: {
1688
+ fields: [
1689
+ { key: "operation", label: "Operation", type: "select" /* Select */, options: [{ label: "List Files", value: "list" }, { label: "Upload File", value: "upload" }, { label: "Download File", value: "download" }, { label: "Delete File", value: "delete" }, { label: "Copy File", value: "copy" }, { label: "Move / Rename", value: "move" }, { label: "Get Signed URL", value: "presign" }], defaultValue: "download", validation: { required: true } },
1690
+ { key: "bucket", label: "Bucket Name", type: "string" /* String */, description: "S3 bucket name (defaults to the connector’s bucket)" },
1691
+ { key: "key", label: "Object Key (Path)", type: "string" /* String */, description: "S3 object key, e.g. data/reports/monthly.csv" },
1692
+ { key: "prefix", label: "Prefix (for List)", type: "string" /* String */, description: "Filter objects by prefix (folder path)" },
1693
+ { key: "content", label: "File Content (for Upload)", type: "string" /* String */, description: "Content to upload — use FX token from upstream step" },
1694
+ { key: "contentType", label: "Content Type", type: "string" /* String */, description: "MIME type (e.g. text/csv, application/json)", defaultValue: "application/octet-stream" },
1695
+ { key: "destBucket", label: "Destination Bucket (for Copy)", type: "string" /* String */ },
1696
+ { key: "destKey", label: "Destination Key (for Copy)", type: "string" /* String */ },
1697
+ { key: "expiresIn", label: "URL Expiry (seconds)", type: "number" /* Number */, description: "Presigned URL expiry time", defaultValue: 3600 },
1698
+ { key: "maxKeys", label: "Max Results (for List)", type: "number" /* Number */, defaultValue: 100 }
1699
+ ]
1700
+ },
1701
+ outputSchema: {
1702
+ type: "object",
1703
+ properties: [
1704
+ { key: "data", type: "json" /* JSON */, description: "Downloaded content, file list, or operation result" },
1705
+ { key: "key", type: "string" /* String */, description: "S3 object key" },
1706
+ { key: "url", type: "string" /* String */, description: "Presigned URL (for presign operation)" }
1707
+ ],
1708
+ sampleOutput: { data: "file content here", key: "data/reports/monthly.csv" }
1709
+ },
1710
+ version: "1.0.0",
1711
+ createdAt: "2026-03-28T00:00:00Z",
1712
+ updatedAt: "2026-03-28T00:00:00Z",
1713
+ createdBy: "system",
1714
+ isOfficial: true,
1715
+ testable: false
1716
+ };
1717
+
1718
+ // src/catalog/storage/ftp-action/index.ts
1719
+ var ftpActionDefinition = {
1720
+ id: "ftp_action",
1721
+ name: "FTP / SFTP",
1722
+ description: "Upload, download, list, delete, or move files on FTP/SFTP servers. Select a configured FTP connector, then pick files from the remote file explorer.",
1723
+ category: "storage" /* Storage */,
1724
+ type: "ftp_action" /* FtpAction */,
1725
+ tags: ["ftp", "sftp", "ftps", "file", "transfer", "server", "built-in"],
1726
+ status: "beta" /* Beta */,
1727
+ icon: "DataBackup",
1728
+ color: "#005d5d",
1729
+ inputSchema: {
1730
+ fields: [
1731
+ { key: "connector", label: "FTP / SFTP Connection", type: "connection" /* Connection */, description: "Select a configured FTP/SFTP connector from Integrations", validation: { required: true } },
1732
+ { key: "operation", label: "Operation", type: "select" /* Select */, options: [{ label: "Download File", value: "download" }, { label: "Upload File", value: "upload" }, { label: "List Files", value: "list" }, { label: "Delete File", value: "delete" }, { label: "Move / Rename", value: "move" }], defaultValue: "download", validation: { required: true } },
1733
+ { key: "remotePath", label: "Remote Path", type: "string" /* String */, description: "File or folder path on the server (use file explorer to browse)" },
1734
+ { key: "content", label: "File Content (Upload)", type: "string" /* String */, description: "Content to upload — use FX token from upstream step" },
1735
+ { key: "fileName", label: "File Name (Upload)", type: "string" /* String */, description: "Name for the uploaded file" },
1736
+ { key: "destPath", label: "Destination Path (Move)", type: "string" /* String */, description: "New path for moved/renamed file" },
1737
+ { key: "ifExists", label: "If File Exists", type: "select" /* Select */, options: [{ label: "Overwrite", value: "overwrite" }, { label: "Skip", value: "skip" }], defaultValue: "overwrite" }
1738
+ ]
1739
+ },
1740
+ outputSchema: {
1741
+ type: "object",
1742
+ properties: [
1743
+ { key: "data", type: "json" /* JSON */, description: "Downloaded content, file list, or result" },
1744
+ { key: "files", type: "json" /* JSON */, description: "List of files (for list op)" },
1745
+ { key: "success", type: "boolean" /* Boolean */, description: "Whether operation succeeded" }
1746
+ ],
1747
+ sampleOutput: { success: true, data: "file content here" }
1748
+ },
1749
+ version: "1.0.0",
1750
+ createdAt: "2026-03-29T00:00:00Z",
1751
+ updatedAt: "2026-03-29T00:00:00Z",
1752
+ createdBy: "system",
1753
+ isOfficial: true,
1754
+ testable: false
1755
+ };
1756
+
1757
+ // src/catalog/storage/google-drive-action/index.ts
1758
+ var googleDriveActionDefinition = {
1759
+ id: "google_drive_action",
1760
+ name: "Google Drive",
1761
+ description: "Upload, download, list, delete, move, copy, or share files in Google Drive",
1762
+ category: "storage" /* Storage */,
1763
+ type: "google_drive_action" /* GoogleDriveAction */,
1764
+ tags: ["google", "drive", "cloud", "storage", "upload", "download", "built-in"],
1765
+ status: "beta" /* Beta */,
1766
+ icon: "CloudUpload",
1767
+ color: "#4285F4",
1768
+ inputSchema: {
1769
+ fields: [
1770
+ { key: "connector", label: "Google Account", type: "connection" /* Connection */, description: "Select a connected Google Sheets connector (shares Drive access)", validation: { required: true } },
1771
+ { key: "operation", label: "Operation", type: "select" /* Select */, options: [{ label: "Upload File", value: "upload" }, { label: "Download File", value: "download" }, { label: "List Files", value: "list" }, { label: "Delete File", value: "delete" }, { label: "Move File", value: "move" }, { label: "Copy File", value: "copy" }, { label: "Share File", value: "share" }, { label: "Create Folder", value: "create_folder" }], defaultValue: "upload", validation: { required: true } },
1772
+ { key: "fileId", label: "File ID / Path", type: "string" /* String */, description: "Google Drive file ID (use file explorer to browse)" },
1773
+ { key: "folderId", label: "Folder ID", type: "string" /* String */, description: "Target folder (root if empty)" },
1774
+ { key: "fileName", label: "File Name", type: "string" /* String */ },
1775
+ { key: "content", label: "File Content (Upload)", type: "string" /* String */, description: "Content to upload — use FX token from upstream" },
1776
+ { key: "mimeType", label: "MIME Type", type: "string" /* String */, defaultValue: "application/octet-stream" },
1777
+ { key: "destFolderId", label: "Destination Folder (Move/Copy)", type: "string" /* String */ },
1778
+ { key: "shareEmail", label: "Share With Email", type: "string" /* String */ },
1779
+ { key: "shareRole", label: "Permission", type: "select" /* Select */, options: [{ label: "Viewer", value: "reader" }, { label: "Editor", value: "writer" }], defaultValue: "reader" },
1780
+ { key: "query", label: "Search Query (List)", type: "string" /* String */, description: "e.g. name contains 'report'" },
1781
+ { key: "pageSize", label: "Max Results", type: "number" /* Number */, defaultValue: 50 }
1782
+ ]
1783
+ },
1784
+ outputSchema: {
1785
+ type: "object",
1786
+ properties: [
1787
+ { key: "data", type: "json" /* JSON */, description: "File content, file list, or operation result" },
1788
+ { key: "fileId", type: "string" /* String */, description: "Google Drive file ID" },
1789
+ { key: "webViewLink", type: "string" /* String */, description: "Link to view file in browser" }
1790
+ ],
1791
+ sampleOutput: { fileId: "1abc...", webViewLink: "https://drive.google.com/file/d/1abc.../view" }
1792
+ },
1793
+ version: "1.0.0",
1794
+ createdAt: "2026-03-28T00:00:00Z",
1795
+ updatedAt: "2026-03-28T00:00:00Z",
1796
+ createdBy: "system",
1797
+ isOfficial: true,
1798
+ testable: false
1799
+ };
1800
+
1801
+ // src/catalog/storage/dropbox-action/index.ts
1802
+ var dropboxActionDefinition = {
1803
+ id: "dropbox_action",
1804
+ name: "Dropbox",
1805
+ description: "Upload, download, list, delete, move, or copy files in Dropbox",
1806
+ category: "storage" /* Storage */,
1807
+ type: "dropbox_action" /* DropboxAction */,
1808
+ tags: ["dropbox", "cloud", "storage", "upload", "download", "built-in"],
1809
+ status: "beta" /* Beta */,
1810
+ icon: "CloudUpload",
1811
+ color: "#0061FF",
1812
+ inputSchema: {
1813
+ fields: [
1814
+ { key: "connector", label: "Dropbox Account", type: "connection" /* Connection */, description: "Select a connected Dropbox account", validation: { required: true } },
1815
+ { key: "operation", label: "Operation", type: "select" /* Select */, options: [{ label: "Download File", value: "download" }, { label: "Upload File", value: "upload" }, { label: "List Files", value: "list" }, { label: "Delete", value: "delete" }, { label: "Move", value: "move" }, { label: "Copy", value: "copy" }, { label: "Create Folder", value: "create_folder" }, { label: "Get Shared Link", value: "shared_link" }], defaultValue: "download", validation: { required: true } },
1816
+ { key: "path", label: "File / Folder Path", type: "string" /* String */, description: "Path on Dropbox (use file explorer to browse)" },
1817
+ { key: "content", label: "File Content (Upload)", type: "string" /* String */, description: "Content to upload — use FX token from upstream" },
1818
+ { key: "fileName", label: "File Name (Upload)", type: "string" /* String */ },
1819
+ { key: "destPath", label: "Destination Path (Move/Copy)", type: "string" /* String */ },
1820
+ { key: "mode", label: "Upload Mode", type: "select" /* Select */, options: [{ label: "Add (fail if exists)", value: "add" }, { label: "Overwrite", value: "overwrite" }], defaultValue: "overwrite" }
1821
+ ]
1822
+ },
1823
+ outputSchema: {
1824
+ type: "object",
1825
+ properties: [
1826
+ { key: "data", type: "json" /* JSON */, description: "File content, list, or metadata" },
1827
+ { key: "path", type: "string" /* String */, description: "Dropbox file path" },
1828
+ { key: "sharedLink", type: "string" /* String */, description: "Shared link URL" }
1829
+ ],
1830
+ sampleOutput: { path: "/reports/monthly.csv", data: "content..." }
1831
+ },
1832
+ version: "1.0.0",
1833
+ createdAt: "2026-03-28T00:00:00Z",
1834
+ updatedAt: "2026-03-28T00:00:00Z",
1835
+ createdBy: "system",
1836
+ isOfficial: true,
1837
+ testable: false
1838
+ };
1839
+
1840
+ // src/catalog/storage/onedrive-action/index.ts
1841
+ var onedriveActionDefinition = {
1842
+ id: "onedrive_action",
1843
+ name: "OneDrive",
1844
+ description: "Upload, download, list, delete, move, or copy files in Microsoft OneDrive",
1845
+ category: "storage" /* Storage */,
1846
+ type: "onedrive_action" /* OneDriveAction */,
1847
+ tags: ["onedrive", "microsoft", "cloud", "storage", "built-in"],
1848
+ status: "beta" /* Beta */,
1849
+ icon: "CloudUpload",
1850
+ color: "#0078D4",
1851
+ inputSchema: {
1852
+ fields: [
1853
+ { key: "connector", label: "Microsoft Account", type: "connection" /* Connection */, description: "Select a connected Microsoft/OneDrive account", validation: { required: true } },
1854
+ { key: "operation", label: "Operation", type: "select" /* Select */, options: [{ label: "Download File", value: "download" }, { label: "Upload File", value: "upload" }, { label: "List Files", value: "list" }, { label: "Delete", value: "delete" }, { label: "Move", value: "move" }, { label: "Copy", value: "copy" }], defaultValue: "download", validation: { required: true } },
1855
+ { key: "path", label: "File / Folder Path", type: "string" /* String */, description: "Path on OneDrive (use file explorer to browse)" },
1856
+ { key: "itemId", label: "Item ID", type: "string" /* String */, description: "OneDrive item ID (alternative to path)" },
1857
+ { key: "content", label: "File Content (Upload)", type: "string" /* String */, description: "Content to upload — use FX token from upstream" },
1858
+ { key: "fileName", label: "File Name (Upload)", type: "string" /* String */ },
1859
+ { key: "destPath", label: "Destination Path (Move/Copy)", type: "string" /* String */ }
1860
+ ]
1861
+ },
1862
+ outputSchema: {
1863
+ type: "object",
1864
+ properties: [
1865
+ { key: "data", type: "json" /* JSON */, description: "File content, list, or metadata" },
1866
+ { key: "itemId", type: "string" /* String */, description: "OneDrive item ID" },
1867
+ { key: "webUrl", type: "string" /* String */, description: "Browser URL" }
1868
+ ],
1869
+ sampleOutput: { itemId: "abc123", webUrl: "https://onedrive.live.com/..." }
1870
+ },
1871
+ version: "1.0.0",
1872
+ createdAt: "2026-03-28T00:00:00Z",
1873
+ updatedAt: "2026-03-28T00:00:00Z",
1874
+ createdBy: "system",
1875
+ isOfficial: true,
1876
+ testable: false
1877
+ };
1878
+
1879
+ // src/catalog/storage/storage-action/index.ts
1880
+ var storageActionDefinition = {
1881
+ id: "storage_action",
1882
+ name: "Storage",
1883
+ description: "Browse, transfer, and manage files on any connected storage — cloud (Amazon S3, Google Drive, OneDrive, Dropbox, GCS, Azure Blob) or FTP/SFTP.",
1884
+ category: "storage" /* Storage */,
1885
+ type: "storage_action" /* StorageAction */,
1886
+ tags: ["storage", "files", "s3", "dropbox", "onedrive", "google drive", "ftp", "sftp", "upload", "download", "cloud", "built-in"],
1887
+ status: "stable" /* Stable */,
1888
+ icon: "CloudUpload",
1889
+ color: "#4F46E5",
1890
+ inputSchema: {
1891
+ fields: [
1892
+ { key: "connector", label: "Storage connector", type: "connection" /* Connection */, description: "Pick a connected storage connector — its provider drives the available operations.", validation: { required: true } },
1893
+ {
1894
+ key: "operation",
1895
+ label: "Operation",
1896
+ type: "select" /* Select */,
1897
+ options: [
1898
+ { label: "List files", value: "list" },
1899
+ { label: "Download file", value: "download" },
1900
+ { label: "Upload file", value: "upload" },
1901
+ { label: "Delete file", value: "delete" },
1902
+ { label: "Copy file", value: "copy" },
1903
+ { label: "Move / rename", value: "move" },
1904
+ { label: "Get signed URL", value: "presign" },
1905
+ { label: "Share", value: "share" },
1906
+ { label: "Create folder", value: "create_folder" },
1907
+ { label: "Transfer to another connector", value: "transfer" }
1908
+ ],
1909
+ defaultValue: "download",
1910
+ validation: { required: true }
1911
+ },
1912
+ { key: "path", label: "Path", type: "string" /* String */, description: "File or folder path — use the file browser in the panel." },
1913
+ { key: "destPath", label: "Destination path", type: "string" /* String */, description: "Target for copy / move." },
1914
+ { key: "content", label: "File content (for Upload)", type: "string" /* String */, description: "Content to upload — bind an FX token from an upstream step." }
1915
+ ]
1916
+ },
1917
+ outputSchema: {
1918
+ type: "object",
1919
+ properties: [
1920
+ { key: "operation", type: "string" /* String */, description: "The operation that ran" },
1921
+ { key: "data", type: "json" /* JSON */, description: "Operation result or downloaded content" },
1922
+ { key: "files", type: "json" /* JSON */, description: "Listing (for the List operation)" },
1923
+ { key: "path", type: "string" /* String */, description: "Affected file/folder path" },
1924
+ { key: "url", type: "string" /* String */, description: "Signed URL (for the Get signed URL operation)" }
1925
+ ],
1926
+ sampleOutput: {
1927
+ operation: "list",
1928
+ files: [
1929
+ { name: "report.csv", path: "/reports/report.csv", ext: "csv", mimeType: "text/csv", type: "file", size: 2048, modifiedAt: "2026-06-18T10:00:00Z" }
1930
+ ]
1931
+ }
1932
+ },
1933
+ version: "1.0.0",
1934
+ createdAt: "2026-06-05T00:00:00Z",
1935
+ updatedAt: "2026-06-05T00:00:00Z",
1936
+ createdBy: "system",
1937
+ isOfficial: true,
1938
+ testable: false
1939
+ };
1940
+
1941
+ // src/catalog/communication/email-send/index.ts
1942
+ var emailDefinition = {
1943
+ id: "email",
1944
+ name: "Email",
1945
+ description: "Send an email through any connected email service provider",
1946
+ category: "communication" /* Communication */,
1947
+ type: "email_send" /* EmailSend */,
1948
+ tags: ["communication", "email", "smtp", "sendgrid", "ses", "imap", "pop3", "built-in"],
1949
+ status: "stable" /* Stable */,
1950
+ icon: "Email",
1951
+ color: "#0043ce",
1952
+ inputSchema: {
1953
+ fields: [
1954
+ {
1955
+ key: "connection",
1956
+ label: "Email Service",
1957
+ type: "connection" /* Connection */,
1958
+ description: "Email service connection (SMTP, IMAP, SendGrid, AWS SES, etc.)",
1959
+ validation: { required: true }
1960
+ },
1961
+ {
1962
+ key: "operation",
1963
+ label: "Operation",
1964
+ type: "select" /* Select */,
1965
+ description: "Email operation — Send is the only operation available today",
1966
+ options: [
1967
+ { label: "Send", value: "send" }
1968
+ ],
1969
+ defaultValue: "send",
1970
+ validation: { required: true }
1971
+ },
1972
+ {
1973
+ key: "to",
1974
+ label: "To",
1975
+ type: "string" /* String */,
1976
+ description: "Recipient email address(es), comma-separated (for send operation)",
1977
+ validation: { required: false }
1978
+ },
1979
+ {
1980
+ key: "cc",
1981
+ label: "CC",
1982
+ type: "string" /* String */,
1983
+ description: "CC email address(es), comma-separated (for send operation)",
1984
+ validation: { required: false }
1985
+ },
1986
+ {
1987
+ key: "bcc",
1988
+ label: "BCC",
1989
+ type: "string" /* String */,
1990
+ description: "BCC email address(es), comma-separated (for send operation)",
1991
+ validation: { required: false }
1992
+ },
1993
+ {
1994
+ key: "subject",
1995
+ label: "Subject",
1996
+ type: "string" /* String */,
1997
+ description: "Email subject (for send operation)",
1998
+ validation: { required: false }
1999
+ },
2000
+ {
2001
+ key: "body",
2002
+ label: "Body",
2003
+ type: "string" /* String */,
2004
+ description: "Email body content (for send operation)",
2005
+ validation: { required: false }
2006
+ },
2007
+ {
2008
+ key: "isHtml",
2009
+ label: "Is HTML",
2010
+ type: "boolean" /* Boolean */,
2011
+ description: "Whether body is HTML content",
2012
+ defaultValue: false,
2013
+ validation: { required: false }
2014
+ },
2015
+ {
2016
+ key: "attachments",
2017
+ label: "Attachments",
2018
+ type: "array" /* Array */,
2019
+ description: "File attachments (URLs or file paths)",
2020
+ validation: { required: false }
2021
+ },
2022
+ {
2023
+ key: "folder",
2024
+ label: "Folder",
2025
+ type: "string" /* String */,
2026
+ description: "Email folder (Inbox, Sent, Drafts, etc.)",
2027
+ validation: { required: false }
2028
+ },
2029
+ {
2030
+ key: "query",
2031
+ label: "Search Query",
2032
+ type: "string" /* String */,
2033
+ description: "Search criteria (for search/read operations)",
2034
+ validation: { required: false }
2035
+ },
2036
+ {
2037
+ key: "limit",
2038
+ label: "Limit",
2039
+ type: "number" /* Number */,
2040
+ description: "Maximum number of emails to retrieve",
2041
+ defaultValue: 10,
2042
+ validation: { required: false }
2043
+ }
2044
+ ]
2045
+ },
2046
+ outputSchema: {
2047
+ type: "object",
2048
+ properties: [
2049
+ {
2050
+ key: "success",
2051
+ type: "boolean" /* Boolean */,
2052
+ description: "Whether operation was successful"
2053
+ },
2054
+ {
2055
+ key: "data",
2056
+ type: "json" /* JSON */,
2057
+ description: "Operation result data (emails, message ID, etc.)"
2058
+ },
2059
+ {
2060
+ key: "count",
2061
+ type: "number" /* Number */,
2062
+ description: "Number of emails affected/returned"
2063
+ },
2064
+ {
2065
+ key: "messageId",
2066
+ type: "string" /* String */,
2067
+ description: "Email message ID (for send operation)"
2068
+ }
2069
+ ],
2070
+ sampleOutput: {
2071
+ success: true,
2072
+ data: [{ id: "email_123", from: "sender@example.com", subject: "Test" }],
2073
+ count: 1,
2074
+ messageId: "msg_123456"
2075
+ }
2076
+ },
2077
+ version: "1.0.0",
2078
+ createdAt: "2025-01-01T00:00:00Z",
2079
+ updatedAt: "2025-12-15T00:00:00Z",
2080
+ createdBy: "system",
2081
+ isOfficial: true,
2082
+ testable: true
2083
+ };
2084
+
2085
+ // src/catalog/communication/slack-message/index.ts
2086
+ var slackMessageDefinition = {
2087
+ id: "slack_message",
2088
+ name: "Slack",
2089
+ description: "Send messages to Slack channels or users",
2090
+ category: "communication" /* Communication */,
2091
+ type: "slack_message" /* SlackMessage */,
2092
+ tags: ["communication", "slack", "chat", "built-in"],
2093
+ status: "stable" /* Stable */,
2094
+ icon: "brand:slack",
2095
+ color: "#4A154B",
2096
+ inputSchema: {
2097
+ fields: [
2098
+ { key: "connection", label: "Slack Workspace", type: "connection" /* Connection */, validation: { required: true } },
2099
+ { key: "channel", label: "Channel/User", type: "string" /* String */, validation: { required: true } },
2100
+ { key: "message", label: "Message", type: "string" /* String */, validation: { required: true } },
2101
+ { key: "blocks", label: "Blocks (JSON)", type: "json" /* JSON */, validation: { required: false } }
2102
+ ]
2103
+ },
2104
+ outputSchema: {
2105
+ type: "object",
2106
+ properties: [
2107
+ { key: "success", type: "boolean" /* Boolean */, description: "Whether message was sent" },
2108
+ { key: "timestamp", type: "string" /* String */, description: "Message timestamp" }
2109
+ ],
2110
+ sampleOutput: { success: true, timestamp: "1234567890.123456" }
2111
+ },
2112
+ version: "1.0.0",
2113
+ createdAt: "2025-01-01T00:00:00Z",
2114
+ updatedAt: "2025-12-15T00:00:00Z",
2115
+ createdBy: "system",
2116
+ isOfficial: true,
2117
+ testable: true
2118
+ };
2119
+
2120
+ // src/catalog/communication/whatsapp-send/index.ts
2121
+ var whatsappSendDefinition = {
2122
+ id: "whatsapp_send",
2123
+ name: "WhatsApp",
2124
+ description: "Send a WhatsApp message — an approved template, or freeform text inside the 24-hour reply window",
2125
+ category: "communication" /* Communication */,
2126
+ type: "whatsapp_send" /* WhatsappSend */,
2127
+ tags: ["communication", "whatsapp", "messaging", "template", "built-in"],
2128
+ status: "beta" /* Beta */,
2129
+ icon: "brand:whatsapp",
2130
+ color: "#25D366",
2131
+ inputSchema: {
2132
+ fields: [
2133
+ { key: "connection", label: "WhatsApp Connection", type: "connection" /* Connection */, validation: { required: true } },
2134
+ { key: "to", label: "To (phone number)", type: "string" /* String */, validation: { required: true } },
2135
+ { key: "mode", label: "Message Type", type: "select" /* Select */, validation: { required: true } },
2136
+ { key: "templateName", label: "Template", type: "string" /* String */, validation: { required: false } },
2137
+ { key: "templateLanguage", label: "Template Language", type: "string" /* String */, validation: { required: false } },
2138
+ { key: "templateVariables", label: "Template Variables", type: "json" /* JSON */, validation: { required: false } },
2139
+ { key: "text", label: "Message", type: "string" /* String */, validation: { required: false } }
2140
+ ]
2141
+ },
2142
+ outputSchema: {
2143
+ type: "object",
2144
+ properties: [
2145
+ { key: "ok", type: "boolean" /* Boolean */, description: "Whether WhatsApp accepted the message" },
2146
+ { key: "messageId", type: "string" /* String */, description: "WhatsApp message ID (wamid…)" },
2147
+ { key: "waId", type: "string" /* String */, description: "Recipient's resolved WhatsApp ID" },
2148
+ { key: "mode", type: "string" /* String */, description: "template | text" }
2149
+ ],
2150
+ sampleOutput: {
2151
+ ok: true,
2152
+ messageId: "wamid.HBgMOTE4ODAyODg1MTQ1FQIAERgSN0YxN0E5RkQ5MEQ4RkE5QzFEAA==",
2153
+ waId: "919876543210",
2154
+ mode: "template"
2155
+ }
2156
+ },
2157
+ version: "1.0.0",
2158
+ createdAt: "2026-07-30T00:00:00Z",
2159
+ updatedAt: "2026-07-30T00:00:00Z",
2160
+ createdBy: "system",
2161
+ isOfficial: true,
2162
+ testable: true
2163
+ };
2164
+
2165
+ // src/catalog/communication/teams-message/index.ts
2166
+ var teamsMessageDefinition = {
2167
+ id: "teams_message",
2168
+ name: "Teams",
2169
+ description: "Post messages to Microsoft Teams channels via OAuth 2.0",
2170
+ category: "communication" /* Communication */,
2171
+ type: "teams_message" /* TeamsMessage */,
2172
+ tags: ["communication", "teams", "microsoft", "chat", "built-in"],
2173
+ status: "stable" /* Stable */,
2174
+ icon: "brand:teams",
2175
+ color: "#4B53BC",
2176
+ inputSchema: {
2177
+ fields: [
2178
+ { key: "connection", label: "Teams Account", type: "connection" /* Connection */, validation: { required: true } },
2179
+ { key: "teamId", label: "Team", type: "string" /* String */, validation: { required: true } },
2180
+ { key: "channelId", label: "Channel", type: "string" /* String */, validation: { required: true } },
2181
+ { key: "title", label: "Subject", type: "string" /* String */, validation: { required: false } },
2182
+ { key: "message", label: "Message", type: "string" /* String */, validation: { required: true } }
2183
+ ]
2184
+ },
2185
+ outputSchema: {
2186
+ type: "object",
2187
+ properties: [
2188
+ { key: "ok", type: "boolean" /* Boolean */, description: "Whether the message was sent" },
2189
+ { key: "id", type: "string" /* String */, description: "Sent message id" },
2190
+ { key: "webUrl", type: "string" /* String */, description: "Deep link to the message" }
2191
+ ],
2192
+ sampleOutput: { ok: true, id: "1700000000000", webUrl: "https://teams.microsoft.com/l/message/..." }
2193
+ },
2194
+ version: "1.0.0",
2195
+ createdAt: "2025-01-01T00:00:00Z",
2196
+ updatedAt: "2025-12-15T00:00:00Z",
2197
+ createdBy: "system",
2198
+ isOfficial: true,
2199
+ testable: true
2200
+ };
2201
+
2202
+ // src/catalog/communication/google-chat/index.ts
2203
+ var googleChatDefinition = {
2204
+ id: "google_chat",
2205
+ name: "Google Chat",
2206
+ description: "Post a message to a Google Chat space (OAuth 2.0 — pick any space you belong to)",
2207
+ category: "communication" /* Communication */,
2208
+ type: "google_chat" /* GoogleChat */,
2209
+ tags: ["communication", "google", "chat", "webhook", "built-in"],
2210
+ status: "stable" /* Stable */,
2211
+ icon: "brand:google_chat",
2212
+ color: "#00AC47",
2213
+ inputSchema: {
2214
+ fields: [
2215
+ { key: "connection", label: "Google Chat Space", type: "connection" /* Connection */, validation: { required: true } },
2216
+ { key: "text", label: "Message", type: "string" /* String */, validation: { required: true } },
2217
+ { key: "threadKey", label: "Thread Key", type: "string" /* String */, validation: { required: false } }
2218
+ ]
2219
+ },
2220
+ outputSchema: {
2221
+ type: "object",
2222
+ properties: [
2223
+ { key: "ok", type: "boolean" /* Boolean */, description: "Whether the message was sent" },
2224
+ { key: "name", type: "string" /* String */, description: "Created message resource name" }
2225
+ ],
2226
+ sampleOutput: { ok: true, name: "spaces/AAAA/messages/BBBB" }
2227
+ },
2228
+ version: "1.0.0",
2229
+ createdAt: "2026-06-18T00:00:00Z",
2230
+ updatedAt: "2026-06-18T00:00:00Z",
2231
+ createdBy: "system",
2232
+ isOfficial: true,
2233
+ testable: true
2234
+ };
2235
+
2236
+ // src/catalog/communication/webhook-call/index.ts
2237
+ var webhookCallDefinition = {
2238
+ id: "webhook_call",
2239
+ name: "Webhook Call",
2240
+ description: "Call external webhooks with custom payloads",
2241
+ category: "communication" /* Communication */,
2242
+ type: "webhook_call" /* WebhookCall */,
2243
+ tags: ["communication", "webhook", "http", "built-in"],
2244
+ status: "stable" /* Stable */,
2245
+ icon: "Webhook",
2246
+ color: "#0043ce",
2247
+ inputSchema: {
2248
+ fields: [
2249
+ { key: "url", label: "Webhook URL", type: "url" /* URL */, validation: { required: true } },
2250
+ { key: "method", label: "Method", type: "select" /* Select */, options: [
2251
+ { label: "POST", value: "POST" },
2252
+ { label: "PUT", value: "PUT" },
2253
+ { label: "PATCH", value: "PATCH" },
2254
+ { label: "GET", value: "GET" }
2255
+ ], defaultValue: "POST", validation: { required: true } },
2256
+ { key: "payload", label: "Payload", type: "json" /* JSON */, validation: { required: false } },
2257
+ { key: "headers", label: "Headers", type: "json" /* JSON */, validation: { required: false } }
2258
+ ]
2259
+ },
2260
+ outputSchema: {
2261
+ type: "object",
2262
+ properties: [
2263
+ { key: "statusCode", type: "number" /* Number */, description: "HTTP status code" },
2264
+ { key: "response", type: "json" /* JSON */, description: "Response body" },
2265
+ { key: "success", type: "boolean" /* Boolean */, description: "Whether call succeeded" }
2266
+ ],
2267
+ sampleOutput: { statusCode: 200, response: {}, success: true }
2268
+ },
2269
+ version: "1.0.0",
2270
+ createdAt: "2025-01-01T00:00:00Z",
2271
+ updatedAt: "2025-12-15T00:00:00Z",
2272
+ createdBy: "system",
2273
+ isOfficial: true,
2274
+ testable: true
2275
+ };
2276
+
2277
+ // src/catalog/utility/debug/index.ts
2278
+ var debugDefinition = {
2279
+ id: "debug",
2280
+ name: "Debug",
2281
+ description: "Inspect, assert, watch, profile, or log workflow data at any point. Supports condition gating, sampling, and schema-drift detection.",
2282
+ category: "utility" /* Utility */,
2283
+ type: "debug" /* Debug */,
2284
+ tags: ["utility", "debug", "observability", "assert", "snapshot", "profile", "built-in"],
2285
+ status: "stable" /* Stable */,
2286
+ icon: "Debug",
2287
+ color: "#6929C4",
2288
+ inputSchema: { fields: [] },
2289
+ outputSchema: {
2290
+ type: "object",
2291
+ properties: [],
2292
+ sampleOutput: { debugged: true, mode: "log" }
2293
+ },
2294
+ version: "2.0.0",
2295
+ createdAt: "2025-01-01T00:00:00Z",
2296
+ updatedAt: "2026-05-02T00:00:00Z",
2297
+ createdBy: "system",
2298
+ isOfficial: true,
2299
+ testable: false
2300
+ };
2301
+
2302
+ // src/catalog/utility/error/index.ts
2303
+ var errorDefinition = {
2304
+ id: "error",
2305
+ name: "Error",
2306
+ description: "Throw an error to stop workflow execution",
2307
+ category: "utility" /* Utility */,
2308
+ type: "error" /* Error */,
2309
+ tags: ["utility", "error", "control", "built-in"],
2310
+ status: "stable" /* Stable */,
2311
+ icon: "ErrorFilled",
2312
+ color: "#da3742",
2313
+ inputSchema: {
2314
+ fields: [
2315
+ {
2316
+ key: "message",
2317
+ label: "Error Message",
2318
+ type: "string" /* String */,
2319
+ description: "Error message to throw",
2320
+ validation: { required: true }
2321
+ },
2322
+ {
2323
+ key: "code",
2324
+ label: "Error Code",
2325
+ type: "string" /* String */,
2326
+ description: "Error code",
2327
+ validation: { required: false }
2328
+ }
2329
+ ]
2330
+ },
2331
+ outputSchema: {
2332
+ type: "void",
2333
+ properties: [],
2334
+ sampleOutput: null
2335
+ },
2336
+ version: "1.0.0",
2337
+ createdAt: "2025-01-01T00:00:00Z",
2338
+ updatedAt: "2025-12-15T00:00:00Z",
2339
+ createdBy: "system",
2340
+ isOfficial: true,
2341
+ testable: true
2342
+ };
2343
+
2344
+ // src/catalog/utility/variables/index.ts
2345
+ var variablesDefinition = {
2346
+ id: "variables",
2347
+ name: "Variables",
2348
+ description: "Emit one or more typed user-defined values as a step output. Sources: literal, expression, prompt, secret, env.",
2349
+ category: "utility" /* Utility */,
2350
+ type: "write" /* Write */,
2351
+ tags: ["utility", "variables", "value", "expression", "built-in"],
2352
+ status: "stable" /* Stable */,
2353
+ icon: "Parameter",
2354
+ color: "#0F62FE",
2355
+ inputSchema: { fields: [] },
2356
+ outputSchema: {
2357
+ type: "object",
2358
+ properties: [],
2359
+ sampleOutput: {}
2360
+ },
2361
+ version: "1.0.0",
2362
+ createdAt: "2026-05-02T00:00:00Z",
2363
+ updatedAt: "2026-05-02T00:00:00Z",
2364
+ createdBy: "system",
2365
+ isOfficial: true,
2366
+ testable: false
2367
+ };
2368
+
2369
+ // src/catalog/api/graphql-query/index.ts
2370
+ var graphqlQueryDefinition = {
2371
+ id: "graphql_query",
2372
+ name: "GraphQL Query",
2373
+ description: "Execute GraphQL queries against GraphQL endpoints",
2374
+ category: "api" /* API */,
2375
+ type: "graphql_query" /* GraphQLQuery */,
2376
+ tags: ["api", "graphql", "query", "built-in"],
2377
+ status: "stable" /* Stable */,
2378
+ icon: "GraphQL",
2379
+ color: "#0043ce",
2380
+ inputSchema: {
2381
+ fields: [
2382
+ {
2383
+ key: "endpoint",
2384
+ label: "GraphQL Endpoint",
2385
+ type: "url" /* URL */,
2386
+ description: "GraphQL endpoint URL",
2387
+ validation: { required: true }
2388
+ },
2389
+ {
2390
+ key: "query",
2391
+ label: "Query",
2392
+ type: "code" /* Code */,
2393
+ description: "GraphQL query",
2394
+ language: "json",
2395
+ validation: { required: true }
2396
+ },
2397
+ {
2398
+ key: "variables",
2399
+ label: "Variables",
2400
+ type: "json" /* JSON */,
2401
+ description: "Query variables",
2402
+ validation: { required: false }
2403
+ },
2404
+ {
2405
+ key: "headers",
2406
+ label: "Headers",
2407
+ type: "json" /* JSON */,
2408
+ description: "HTTP headers",
2409
+ validation: { required: false }
2410
+ }
2411
+ ]
2412
+ },
2413
+ outputSchema: {
2414
+ type: "object",
2415
+ properties: [
2416
+ {
2417
+ key: "data",
2418
+ type: "json" /* JSON */,
2419
+ description: "Query result data"
2420
+ },
2421
+ {
2422
+ key: "errors",
2423
+ type: "array" /* Array */,
2424
+ description: "GraphQL errors"
2425
+ }
2426
+ ],
2427
+ sampleOutput: {
2428
+ data: { user: { id: "1", name: "John" } },
2429
+ errors: []
2430
+ }
2431
+ },
2432
+ version: "1.0.0",
2433
+ createdAt: "2025-01-01T00:00:00Z",
2434
+ updatedAt: "2025-12-15T00:00:00Z",
2435
+ createdBy: "system",
2436
+ isOfficial: true,
2437
+ testable: true
2438
+ };
2439
+
2440
+ // src/catalog/ai/ai-agent/index.ts
2441
+ var aiAgentDefinition = {
2442
+ id: "ai_agent",
2443
+ name: "AI Agent",
2444
+ description: "Run a reusable AI agent. Pick a saved agent from /ai/agents; optionally override model, temperature, or instructions per step.",
2445
+ category: "ai" /* AI */,
2446
+ type: "ai_agent" /* AIAgent */,
2447
+ tags: ["ai", "agent", "chat", "built-in"],
2448
+ status: "stable" /* Stable */,
2449
+ icon: "Bot",
2450
+ color: "#7c3aed",
2451
+ inputSchema: {
2452
+ fields: [
2453
+ {
2454
+ key: "agentId",
2455
+ label: "Agent",
2456
+ type: "string" /* String */,
2457
+ description: "Saved Agent public id (e.g. agt_xxx).",
2458
+ validation: { required: true }
2459
+ },
2460
+ {
2461
+ key: "input",
2462
+ label: "Input",
2463
+ type: "string" /* String */,
2464
+ description: "Chat agents: a string (template-supported via {{step.field}}). ETL agents: rows array. When blank, falls back to upstream step output."
2465
+ },
2466
+ {
2467
+ key: "overrides",
2468
+ label: "Overrides",
2469
+ type: "json" /* JSON */,
2470
+ description: "Optional per-step overrides of the agent’s own settings: model, temperature, maxTokens, topP, instructions and instructionsMode."
2471
+ }
2472
+ ]
2473
+ },
2474
+ outputSchema: {
2475
+ type: "object",
2476
+ properties: [
2477
+ { key: "text", type: "string" /* String */, description: "Agent response text (chat agents)" },
2478
+ { key: "rows", type: "json" /* JSON */, description: "Output rows (etl agents)" },
2479
+ { key: "usage", type: "json" /* JSON */, description: "Token usage + cost: tokensIn, tokensOut, latencyMs, costUsd" },
2480
+ { key: "model", type: "string" /* String */, description: "Model that produced the response" },
2481
+ { key: "agentVersion", type: "number" /* Number */, description: "Version of the agent definition that ran" }
2482
+ ],
2483
+ sampleOutput: {
2484
+ text: "Sure — happy to help. What would you like to know?",
2485
+ usage: { tokensIn: 42, tokensOut: 18, latencyMs: 612, costUsd: 0.000041 },
2486
+ model: "gpt-4o-mini",
2487
+ agentVersion: 3
2488
+ }
2489
+ },
2490
+ version: "1.0.0",
2491
+ createdAt: "2026-05-27T00:00:00Z",
2492
+ updatedAt: "2026-05-27T00:00:00Z",
2493
+ createdBy: "system",
2494
+ isOfficial: true,
2495
+ testable: true
2496
+ };
2497
+
2498
+ // src/catalog/ai/idp-extract/index.ts
2499
+ var idpExtractDefinition = {
2500
+ id: "idp_extract",
2501
+ name: "IDP",
2502
+ description: "Extract structured data from documents received from an upstream step. Configure the model provider, model, and the JSON Schema to extract.",
2503
+ category: "ai" /* AI */,
2504
+ type: "idp_extract" /* IdpExtract */,
2505
+ tags: ["ai", "idp", "document", "extract", "built-in"],
2506
+ status: "stable" /* Stable */,
2507
+ icon: "DocumentImport",
2508
+ color: "#0F62FE",
2509
+ inputSchema: {
2510
+ fields: [
2511
+ {
2512
+ key: "llmConnectorId",
2513
+ label: "Model provider (connector)",
2514
+ type: "select" /* Select */,
2515
+ description: "Connected AI provider (OpenAI, Anthropic, Gemini, …). Resolved at execution time.",
2516
+ validation: { required: true }
2517
+ },
2518
+ {
2519
+ key: "model",
2520
+ label: "Model",
2521
+ type: "select" /* Select */,
2522
+ description: "LLM available on the selected provider (e.g. gpt-4o, claude-3.5-sonnet, gemini-2.0-flash). Vision-capable models recommended.",
2523
+ validation: { required: true }
2524
+ },
2525
+ {
2526
+ key: "expectedSchema",
2527
+ label: "Output schema",
2528
+ type: "json" /* JSON */,
2529
+ description: "JSON Schema describing the fields to extract. The LLM is forced to emit JSON matching this shape.",
2530
+ validation: { required: false }
2531
+ },
2532
+ {
2533
+ key: "systemPromptOverride",
2534
+ label: "System prompt override",
2535
+ type: "string" /* String */,
2536
+ description: "Optional extra instructions appended to the extraction prompt."
2537
+ },
2538
+ {
2539
+ key: "strategy",
2540
+ label: "Strategy",
2541
+ type: "select" /* Select */,
2542
+ description: "vision-direct sends the file as an image to a vision LLM. auto picks based on PDF text content.",
2543
+ defaultValue: "vision-direct"
2544
+ }
2545
+ ]
2546
+ },
2547
+ outputSchema: {
2548
+ type: "object",
2549
+ properties: [
2550
+ { key: "state", type: "string" /* String */, description: "Aggregate state — completed | partial-success | failed." },
2551
+ {
2552
+ key: "pages",
2553
+ type: "array" /* Array */,
2554
+ description: "One row per file received from upstream: { fileName, data, confidence, audit, error? }"
2555
+ },
2556
+ {
2557
+ key: "totals",
2558
+ type: "object" /* Object */,
2559
+ description: "Summary { pages, completed, failed }"
2560
+ }
2561
+ ]
2562
+ },
2563
+ version: "2.0.0",
2564
+ createdAt: "2026-05-06T00:00:00Z",
2565
+ updatedAt: "2026-05-10T00:00:00Z",
2566
+ createdBy: "system"
2567
+ };
2568
+
2569
+ // src/catalog/index.ts
2570
+ var actionsRegistry = {
2571
+ ["trigger" /* Trigger */]: {
2572
+ manual_trigger: manualTriggerDefinition,
2573
+ schedule_trigger: scheduleTriggerDefinition,
2574
+ webhook_trigger: webhookTriggerDefinition,
2575
+ connector_trigger: connectorTriggerDefinition
2576
+ },
2577
+ ["action" /* Action */]: {
2578
+ http_request: httpRequestDefinition,
2579
+ console_log: consoleLogDefinition,
2580
+ delay: delayDefinition,
2581
+ query: queryDefinition,
2582
+ transform: transformDefinition
2583
+ },
2584
+ ["logic" /* Logic */]: {
2585
+ condition: conditionDefinition,
2586
+ for_each: forEachDefinition,
2587
+ group: groupDefinition
2588
+ },
2589
+ ["transform" /* Transform */]: {},
2590
+ ["database" /* Database */]: {},
2591
+ ["storage" /* Storage */]: {
2592
+ csv_action: csvActionDefinition,
2593
+ json_action: jsonActionDefinition,
2594
+ excel_action: excelActionDefinition,
2595
+ xml_action: xmlActionDefinition,
2596
+ storage_action: storageActionDefinition,
2597
+ s3_action: { ...s3ActionDefinition, deprecated: true, replacedBy: "storage_action" },
2598
+ ftp_action: { ...ftpActionDefinition, deprecated: true, replacedBy: "storage_action" },
2599
+ google_drive_action: { ...googleDriveActionDefinition, deprecated: true, replacedBy: "storage_action" },
2600
+ dropbox_action: { ...dropboxActionDefinition, deprecated: true, replacedBy: "storage_action" },
2601
+ onedrive_action: { ...onedriveActionDefinition, deprecated: true, replacedBy: "storage_action" }
2602
+ },
2603
+ ["communication" /* Communication */]: {
2604
+ email: emailDefinition,
2605
+ slack_message: slackMessageDefinition,
2606
+ whatsapp_send: whatsappSendDefinition,
2607
+ teams_message: teamsMessageDefinition,
2608
+ google_chat: googleChatDefinition,
2609
+ webhook_call: webhookCallDefinition
2610
+ },
2611
+ ["utility" /* Utility */]: {
2612
+ variables: variablesDefinition,
2613
+ debug: debugDefinition
2614
+ },
2615
+ ["ecommerce" /* Ecommerce */]: {},
2616
+ ["api" /* API */]: {},
2617
+ ["ai" /* AI */]: {
2618
+ ai_agent: aiAgentDefinition,
2619
+ idp_extract: idpExtractDefinition
2620
+ }
2621
+ };
2622
+ var getAllActions = () => {
2623
+ const allActions = [];
2624
+ for (const category of Object.values(actionsRegistry)) {
2625
+ allActions.push(...Object.values(category).filter((action) => action !== undefined));
2626
+ }
2627
+ return allActions;
2628
+ };
2629
+ var getActionById = (id) => {
2630
+ for (const category of Object.values(actionsRegistry)) {
2631
+ for (const action of Object.values(category)) {
2632
+ if (action.id === id) {
2633
+ return action;
2634
+ }
2635
+ }
2636
+ }
2637
+ return;
2638
+ };
2639
+ var getActionsByCategory = (category) => {
2640
+ const categoryActions = actionsRegistry[category];
2641
+ if (!categoryActions)
2642
+ return [];
2643
+ return Object.values(categoryActions);
2644
+ };
2645
+ // src/rules/nodeConfigStatus.ts
2646
+ var HIDDEN_STATUS_ACTIONS = new Set(["console_log"]);
2647
+ function isFieldFilled(value) {
2648
+ if (value === undefined || value === null)
2649
+ return false;
2650
+ if (typeof value === "string")
2651
+ return value.trim().length > 0;
2652
+ if (typeof value === "number")
2653
+ return true;
2654
+ if (typeof value === "boolean")
2655
+ return true;
2656
+ if (Array.isArray(value))
2657
+ return value.length > 0;
2658
+ if (typeof value === "object")
2659
+ return Object.keys(value).length > 0;
2660
+ return false;
2661
+ }
2662
+ function isSatisfiedOutOfBand(actionId, fieldKey, config) {
2663
+ if (actionId === "connector_trigger" && fieldKey === "events") {
2664
+ return Number(config.eventCount ?? 0) > 0;
2665
+ }
2666
+ if (MESSAGE_BODY_ACTIONS.has(actionId) && (fieldKey === "message" || fieldKey === "text")) {
2667
+ const text = config.text ?? config.message;
2668
+ if (typeof text === "string" && text.trim().length > 0)
2669
+ return true;
2670
+ return Array.isArray(config.blocks) && config.blocks.length > 0;
2671
+ }
2672
+ return false;
2673
+ }
2674
+ var MESSAGE_BODY_ACTIONS = new Set([
2675
+ "slack_message",
2676
+ "teams_message",
2677
+ "google_chat"
2678
+ ]);
2679
+ function getNestedValue(config, keyPath) {
2680
+ const parts = keyPath.split(".");
2681
+ let current = config;
2682
+ for (const part of parts) {
2683
+ if (current === null || current === undefined || typeof current !== "object") {
2684
+ return;
2685
+ }
2686
+ current = current[part];
2687
+ }
2688
+ return current;
2689
+ }
2690
+ function isFieldActive(field, config) {
2691
+ if (!field.conditional || field.conditional.length === 0) {
2692
+ return true;
2693
+ }
2694
+ return field.conditional.some((cond) => {
2695
+ if (cond.action !== "show" && cond.action !== "require") {
2696
+ return false;
2697
+ }
2698
+ const fieldValue = getNestedValue(config, cond.field);
2699
+ switch (cond.operator) {
2700
+ case "==":
2701
+ return fieldValue === cond.value;
2702
+ case "!=":
2703
+ return fieldValue !== cond.value;
2704
+ case ">":
2705
+ return fieldValue > cond.value;
2706
+ case "<":
2707
+ return fieldValue < cond.value;
2708
+ case ">=":
2709
+ return fieldValue >= cond.value;
2710
+ case "<=":
2711
+ return fieldValue <= cond.value;
2712
+ case "in":
2713
+ return Array.isArray(cond.value) && cond.value.includes(fieldValue);
2714
+ case "not_in":
2715
+ return Array.isArray(cond.value) && !cond.value.includes(fieldValue);
2716
+ case "contains":
2717
+ return typeof fieldValue === "string" && fieldValue.includes(cond.value);
2718
+ default:
2719
+ return false;
2720
+ }
2721
+ });
2722
+ }
2723
+ function getNodeConfigStatus(node) {
2724
+ if (HIDDEN_STATUS_ACTIONS.has(node.actionDefinitionId)) {
2725
+ return {
2726
+ status: "hidden",
2727
+ requiredTotal: 0,
2728
+ requiredFilled: 0,
2729
+ optionalTotal: 0,
2730
+ optionalFilled: 0,
2731
+ missingRequired: [],
2732
+ filledOptional: []
2733
+ };
2734
+ }
2735
+ const definition = getActionById(node.actionDefinitionId);
2736
+ if (!definition) {
2737
+ return {
2738
+ status: "unconfigured",
2739
+ requiredTotal: 0,
2740
+ requiredFilled: 0,
2741
+ optionalTotal: 0,
2742
+ optionalFilled: 0,
2743
+ missingRequired: [],
2744
+ filledOptional: []
2745
+ };
2746
+ }
2747
+ const fields = definition.inputSchema?.fields ?? [];
2748
+ const config = node.config ?? {};
2749
+ const activeFields = fields.filter((f) => !f.hidden && isFieldActive(f, config));
2750
+ const requiredFields = activeFields.filter((f) => f.validation?.required);
2751
+ const optionalFields = activeFields.filter((f) => !f.validation?.required);
2752
+ const missingRequired = [];
2753
+ let requiredFilled = 0;
2754
+ for (const field of requiredFields) {
2755
+ const value = getNestedValue(config, field.key);
2756
+ if (isFieldFilled(value)) {
2757
+ requiredFilled++;
2758
+ } else if (isFieldFilled(field.defaultValue)) {
2759
+ requiredFilled++;
2760
+ } else if (isSatisfiedOutOfBand(node.actionDefinitionId, field.key, config)) {
2761
+ requiredFilled++;
2762
+ } else {
2763
+ missingRequired.push(field.key);
2764
+ }
2765
+ }
2766
+ const filledOptional = [];
2767
+ let optionalFilled = 0;
2768
+ for (const field of optionalFields) {
2769
+ const value = getNestedValue(config, field.key);
2770
+ if (isFieldFilled(value)) {
2771
+ optionalFilled++;
2772
+ filledOptional.push(field.key);
2773
+ }
2774
+ }
2775
+ const requiredTotal = requiredFields.length;
2776
+ const optionalTotal = optionalFields.length;
2777
+ let status;
2778
+ if (requiredTotal === 0) {
2779
+ status = "valid";
2780
+ } else if (missingRequired.length === 0) {
2781
+ status = "valid";
2782
+ } else if (requiredFilled > 0 || optionalFilled > 0) {
2783
+ status = "warning";
2784
+ } else {
2785
+ status = "error";
2786
+ }
2787
+ return {
2788
+ status,
2789
+ requiredTotal,
2790
+ requiredFilled,
2791
+ optionalTotal,
2792
+ optionalFilled,
2793
+ missingRequired,
2794
+ filledOptional
2795
+ };
2796
+ }
2797
+
2798
+ // src/rules/workflowValidator.ts
2799
+ var nodeName = (n) => n.label || n.id;
2800
+ function validateNode(node, allNodes, allEdges) {
2801
+ const errors = [];
2802
+ if (!node.id || node.id.trim().length === 0) {
2803
+ errors.push({
2804
+ id: `node-${node.id}-id`,
2805
+ type: "node",
2806
+ severity: "error",
2807
+ message: "Node ID is required",
2808
+ nodeId: node.id
2809
+ });
2810
+ }
2811
+ if (!node.label || node.label.trim().length === 0) {
2812
+ errors.push({
2813
+ id: `node-${node.id}-label`,
2814
+ type: "node",
2815
+ severity: "error",
2816
+ message: "Node label is required",
2817
+ nodeId: node.id
2818
+ });
2819
+ }
2820
+ const cfg = getNodeConfigStatus(node);
2821
+ if (cfg.missingRequired.length > 0) {
2822
+ const fields = cfg.missingRequired.slice(0, 4).join(", ");
2823
+ const more = cfg.missingRequired.length > 4 ? ` +${cfg.missingRequired.length - 4} more` : "";
2824
+ errors.push({
2825
+ id: `node-${node.id}-config`,
2826
+ type: "node",
2827
+ severity: "error",
2828
+ message: `Missing required settings: ${fields}${more}. Open the step and fill them in.`,
2829
+ nodeId: node.id
2830
+ });
2831
+ }
2832
+ const hasOutput = allEdges.some((edge) => edge.source === node.id);
2833
+ if (!hasOutput && node.type === "trigger") {
2834
+ errors.push({
2835
+ id: `node-${node.id}-output`,
2836
+ type: "node",
2837
+ severity: "warning",
2838
+ message: `Trigger "${nodeName(node)}" has no outgoing connections`,
2839
+ nodeId: node.id
2840
+ });
2841
+ }
2842
+ return errors;
2843
+ }
2844
+ function validateEdge(edge, allNodes, allEdges = []) {
2845
+ const errors = [];
2846
+ const sourceNode = allNodes.find((n) => n.id === edge.source);
2847
+ if (!sourceNode) {
2848
+ errors.push({
2849
+ id: `edge-${edge.id}-source`,
2850
+ type: "edge",
2851
+ severity: "error",
2852
+ message: `Source node "${edge.source}" does not exist`,
2853
+ edgeId: edge.id
2854
+ });
2855
+ }
2856
+ const targetNode = allNodes.find((n) => n.id === edge.target);
2857
+ if (!targetNode) {
2858
+ errors.push({
2859
+ id: `edge-${edge.id}-target`,
2860
+ type: "edge",
2861
+ severity: "error",
2862
+ message: `Target node "${edge.target}" does not exist`,
2863
+ edgeId: edge.id
2864
+ });
2865
+ }
2866
+ if (edge.source === edge.target) {
2867
+ errors.push({
2868
+ id: `edge-${edge.id}-loop`,
2869
+ type: "edge",
2870
+ severity: "error",
2871
+ message: "Nodes cannot connect to themselves",
2872
+ edgeId: edge.id
2873
+ });
2874
+ }
2875
+ const key = (e) => `${e.source}|${e.sourceHandle ?? ""}→${e.target}|${e.targetHandle ?? ""}`;
2876
+ const myKey = key(edge);
2877
+ const firstIndex = allEdges.findIndex((e) => key(e) === myKey);
2878
+ const myIndex = allEdges.findIndex((e) => e.id === edge.id);
2879
+ if (firstIndex !== -1 && myIndex > firstIndex) {
2880
+ errors.push({
2881
+ id: `edge-${edge.id}-duplicate`,
2882
+ type: "edge",
2883
+ severity: "warning",
2884
+ message: `Duplicate connection between "${sourceNode ? nodeName(sourceNode) : edge.source}" and "${targetNode ? nodeName(targetNode) : edge.target}"`,
2885
+ edgeId: edge.id
2886
+ });
2887
+ }
2888
+ return errors;
2889
+ }
2890
+ function validateWorkflow(nodes, edges) {
2891
+ const allErrors = [];
2892
+ const hasTrigger = nodes.some((node) => node.type === "trigger");
2893
+ if (!hasTrigger) {
2894
+ allErrors.push({
2895
+ id: "workflow-trigger",
2896
+ type: "workflow",
2897
+ severity: "error",
2898
+ message: "Workflow must have at least one trigger node"
2899
+ });
2900
+ }
2901
+ const hasAction = nodes.some((node) => node.type === "action");
2902
+ if (!hasAction && nodes.length > 0) {
2903
+ allErrors.push({
2904
+ id: "workflow-action",
2905
+ type: "workflow",
2906
+ severity: "warning",
2907
+ message: "Workflow should have at least one action node"
2908
+ });
2909
+ }
2910
+ nodes.forEach((node) => {
2911
+ const nodeErrors = validateNode(node, nodes, edges);
2912
+ allErrors.push(...nodeErrors);
2913
+ });
2914
+ edges.forEach((edge) => {
2915
+ const edgeErrors = validateEdge(edge, nodes, edges);
2916
+ allErrors.push(...edgeErrors);
2917
+ });
2918
+ if (nodes.length > 0 && edges.length > 0) {
2919
+ const inDegree = new Map(nodes.map((n) => [n.id, 0]));
2920
+ const out = new Map;
2921
+ for (const e of edges) {
2922
+ if (e.source === e.target)
2923
+ continue;
2924
+ if (!inDegree.has(e.source) || !inDegree.has(e.target))
2925
+ continue;
2926
+ inDegree.set(e.target, (inDegree.get(e.target) ?? 0) + 1);
2927
+ const list = out.get(e.source);
2928
+ if (list)
2929
+ list.push(e.target);
2930
+ else
2931
+ out.set(e.source, [e.target]);
2932
+ }
2933
+ const queue = nodes.filter((n) => (inDegree.get(n.id) ?? 0) === 0).map((n) => n.id);
2934
+ let visited = 0;
2935
+ while (queue.length) {
2936
+ const cur = queue.shift();
2937
+ visited++;
2938
+ for (const next of out.get(cur) ?? []) {
2939
+ const d = (inDegree.get(next) ?? 1) - 1;
2940
+ inDegree.set(next, d);
2941
+ if (d === 0)
2942
+ queue.push(next);
2943
+ }
2944
+ }
2945
+ if (visited < nodes.length) {
2946
+ const stuck = nodes.filter((n) => (inDegree.get(n.id) ?? 0) > 0);
2947
+ const names = stuck.slice(0, 3).map(nodeName).join(", ");
2948
+ const more = stuck.length > 3 ? ` +${stuck.length - 3} more` : "";
2949
+ allErrors.push({
2950
+ id: "workflow-cycle",
2951
+ type: "workflow",
2952
+ severity: "error",
2953
+ message: `Circular connection detected involving: ${names}${more}. Break the loop — execution order is undefined inside a cycle.`,
2954
+ nodeId: stuck[0]?.id
2955
+ });
2956
+ }
2957
+ }
2958
+ const isTrigger = (n) => n.type === "trigger" || String(n.actionDefinitionId ?? "").endsWith("_trigger");
2959
+ const triggerIds = nodes.filter(isTrigger).map((n) => n.id);
2960
+ const adjacency = new Map;
2961
+ for (const e of edges) {
2962
+ const list = adjacency.get(e.source);
2963
+ if (list)
2964
+ list.push(e.target);
2965
+ else
2966
+ adjacency.set(e.source, [e.target]);
2967
+ }
2968
+ const reachable = new Set(triggerIds);
2969
+ const queue = [...triggerIds];
2970
+ while (queue.length) {
2971
+ const cur = queue.shift();
2972
+ for (const next of adjacency.get(cur) ?? []) {
2973
+ if (!reachable.has(next)) {
2974
+ reachable.add(next);
2975
+ queue.push(next);
2976
+ }
2977
+ }
2978
+ }
2979
+ let changed = true;
2980
+ while (changed) {
2981
+ changed = false;
2982
+ for (const n of nodes) {
2983
+ if (reachable.has(n.id)) {
2984
+ if (n.parentId && !reachable.has(n.parentId)) {
2985
+ reachable.add(n.parentId);
2986
+ changed = true;
2987
+ }
2988
+ } else if (n.parentId && reachable.has(n.parentId)) {
2989
+ reachable.add(n.id);
2990
+ changed = true;
2991
+ }
2992
+ }
2993
+ }
2994
+ nodes.forEach((node) => {
2995
+ if (isTrigger(node))
2996
+ return;
2997
+ const isConnected = edges.some((e) => e.source === node.id || e.target === node.id);
2998
+ const wontRun = triggerIds.length > 0 ? !reachable.has(node.id) : !isConnected;
2999
+ if (wontRun) {
3000
+ allErrors.push({
3001
+ id: `node-${node.id}-orphan`,
3002
+ type: "node",
3003
+ severity: "warning",
3004
+ message: isConnected ? `"${nodeName(node)}" isn't reachable from a trigger and won't run.` : `"${nodeName(node)}" isn't connected to a flow and won't run.`,
3005
+ nodeId: node.id
3006
+ });
3007
+ }
3008
+ });
3009
+ if (triggerIds.length > 1) {
3010
+ const parentOf = new Map(nodes.filter((n) => n.parentId).map((n) => [n.id, n.parentId]));
3011
+ const undirected = new Map;
3012
+ const link = (a, b) => {
3013
+ const la = undirected.get(a);
3014
+ if (la)
3015
+ la.push(b);
3016
+ else
3017
+ undirected.set(a, [b]);
3018
+ };
3019
+ for (const e of edges) {
3020
+ link(e.source, e.target);
3021
+ link(e.target, e.source);
3022
+ }
3023
+ for (const [child, parent] of parentOf) {
3024
+ link(child, parent);
3025
+ link(parent, child);
3026
+ }
3027
+ const seen = new Set;
3028
+ let flowsWithTrigger = 0;
3029
+ for (const t of triggerIds) {
3030
+ if (seen.has(t))
3031
+ continue;
3032
+ flowsWithTrigger++;
3033
+ const stack = [t];
3034
+ seen.add(t);
3035
+ while (stack.length) {
3036
+ const cur = stack.pop();
3037
+ for (const next of undirected.get(cur) ?? []) {
3038
+ if (!seen.has(next)) {
3039
+ seen.add(next);
3040
+ stack.push(next);
3041
+ }
3042
+ }
3043
+ }
3044
+ }
3045
+ if (flowsWithTrigger > 1) {
3046
+ allErrors.push({
3047
+ id: "workflow-multi-flow",
3048
+ type: "workflow",
3049
+ severity: "warning",
3050
+ message: `This canvas holds ${flowsWithTrigger} separate flows. Each trigger runs only its own flow — consider splitting them into separate flows for clarity.`
3051
+ });
3052
+ }
3053
+ }
3054
+ const errors = allErrors.filter((e) => e.severity === "error");
3055
+ const warnings = allErrors.filter((e) => e.severity === "warning");
3056
+ return {
3057
+ isValid: errors.length === 0,
3058
+ errors,
3059
+ warnings
3060
+ };
3061
+ }
3062
+ function getNodeValidationStatus(nodeId, validationResult) {
3063
+ const hasError = validationResult.errors.some((e) => e.nodeId === nodeId);
3064
+ if (hasError)
3065
+ return "error";
3066
+ const hasWarning = validationResult.warnings.some((e) => e.nodeId === nodeId);
3067
+ if (hasWarning)
3068
+ return "warning";
3069
+ return "valid";
3070
+ }
3071
+ function getEdgeValidationStatus(edgeId, validationResult) {
3072
+ const hasError = validationResult.errors.some((e) => e.edgeId === edgeId);
3073
+ if (hasError)
3074
+ return "error";
3075
+ const hasWarning = validationResult.warnings.some((e) => e.edgeId === edgeId);
3076
+ if (hasWarning)
3077
+ return "warning";
3078
+ return "valid";
3079
+ }
3080
+ // src/catalog/logic/condition/config.ts
3081
+ var CONDITION_OPERATORS = [
3082
+ { id: "equals", label: "Equals", needsValue: true },
3083
+ { id: "not_equals", label: "Not Equals", needsValue: true },
3084
+ { id: "greater_than", label: "Greater Than", needsValue: true },
3085
+ { id: "greater_than_equals", label: "Greater Than or Equals", needsValue: true },
3086
+ { id: "less_than", label: "Less Than", needsValue: true },
3087
+ { id: "less_than_equals", label: "Less Than or Equals", needsValue: true },
3088
+ { id: "like", label: "Like", needsValue: true },
3089
+ { id: "contains", label: "Contains", needsValue: true },
3090
+ { id: "starts_with", label: "Starts With", needsValue: true },
3091
+ { id: "ends_with", label: "Ends With", needsValue: true },
3092
+ { id: "is_null", label: "Is Null", needsValue: false },
3093
+ { id: "is_not_null", label: "Is Not Null", needsValue: false },
3094
+ { id: "is_empty", label: "Is Empty", needsValue: false }
3095
+ ];
3096
+ var ConditionConfig = {
3097
+ defaults: {
3098
+ mode: "visual",
3099
+ filters: [],
3100
+ condition: ""
3101
+ },
3102
+ schema: {
3103
+ mode: { type: "select", required: true },
3104
+ filters: { type: "array", required: false },
3105
+ condition: { type: "expression", required: false }
3106
+ },
3107
+ validate: (config) => {
3108
+ const errors = [];
3109
+ if (config.mode === "expression") {
3110
+ if (!config.condition) {
3111
+ errors.push("Condition expression is required");
3112
+ } else {
3113
+ try {
3114
+ new Function(`return ${config.condition}`);
3115
+ } catch (e) {
3116
+ errors.push(`Invalid expression: ${e instanceof Error ? e.message : "Unknown error"}`);
3117
+ }
3118
+ }
3119
+ } else {
3120
+ if (!config.filters || config.filters.length === 0) {
3121
+ errors.push("At least one condition filter is required");
3122
+ } else {
3123
+ config.filters.forEach((f, i) => {
3124
+ if (!f.field)
3125
+ errors.push(`Filter ${i + 1}: Field is required`);
3126
+ if (!f.operator)
3127
+ errors.push(`Filter ${i + 1}: Operator is required`);
3128
+ const opDef = CONDITION_OPERATORS.find((o) => o.id === f.operator);
3129
+ if (opDef?.needsValue && !f.value) {
3130
+ errors.push(`Filter ${i + 1}: Value is required`);
3131
+ }
3132
+ });
3133
+ }
3134
+ }
3135
+ return { valid: errors.length === 0, errors };
3136
+ },
3137
+ merge: (userConfig) => {
3138
+ return { ...ConditionConfig.defaults, ...userConfig };
3139
+ },
3140
+ generateName: (filters) => {
3141
+ if (filters.length === 0)
3142
+ return "If …";
3143
+ const parts = filters.map((f, i) => {
3144
+ const opLabel = CONDITION_OPERATORS.find((o) => o.id === f.operator)?.label || f.operator;
3145
+ const base = `${f.field || "?"} ${opLabel}${f.value ? ` ${f.value}` : ""}`;
3146
+ if (i === 0)
3147
+ return base;
3148
+ return `${(f.logicalOperator || "and").toUpperCase()} ${base}`;
3149
+ });
3150
+ return `If ${parts.join(" ")}`;
3151
+ },
3152
+ getLabel: (config) => {
3153
+ if (config.mode === "expression")
3154
+ return `If ${config.condition || "…"}`;
3155
+ return ConditionConfig.generateName(config.filters);
3156
+ },
3157
+ createFilterId: () => `cond_${Date.now()}_${randomSuffix(5)}`
3158
+ };
3159
+ // src/catalog/logic/for-each/config.ts
3160
+ var SOURCELESS_MODES = new Set(["range", "cursor", "while"]);
3161
+ var ForEachConfig = {
3162
+ defaults: {
3163
+ arrayPath: "",
3164
+ iterationMode: "records",
3165
+ itemVariable: "item",
3166
+ indexVariable: "index",
3167
+ batchSize: 0,
3168
+ continueOnError: false,
3169
+ concurrency: "sequential",
3170
+ collect: "array"
3171
+ },
3172
+ schema: {
3173
+ arrayPath: { type: "select", required: false },
3174
+ iterationMode: { type: "select", required: false },
3175
+ itemVariable: { type: "string", required: true },
3176
+ indexVariable: { type: "string", required: false },
3177
+ batchSize: { type: "number", required: false },
3178
+ continueOnError: { type: "boolean", required: false }
3179
+ },
3180
+ validate: (config) => {
3181
+ const errors = [];
3182
+ const mode = config.iterationMode || "records";
3183
+ if (mode === "range") {
3184
+ if (!config.count || config.count <= 0) {
3185
+ errors.push("Range mode needs a positive iteration count");
3186
+ }
3187
+ } else if (mode === "nested") {
3188
+ if (!config.arrayPath)
3189
+ errors.push("Select the records to drill into");
3190
+ if (!config.nestedPath)
3191
+ errors.push('Nested mode needs the sub-array path to iterate (e.g. "lineItems")');
3192
+ } else if (!SOURCELESS_MODES.has(mode)) {
3193
+ if (!config.arrayPath) {
3194
+ errors.push("Array path is required — select which records to iterate over");
3195
+ }
3196
+ }
3197
+ if (config.concurrency === "parallel" && config.maxConcurrency !== undefined && config.maxConcurrency < 1) {
3198
+ errors.push("Max concurrency must be at least 1");
3199
+ }
3200
+ if (config.batchSize !== undefined && config.batchSize < 0) {
3201
+ errors.push("Batch size must be 0 (all) or a positive number");
3202
+ }
3203
+ if (config.collect === "groupBy" && !config.groupByPath) {
3204
+ errors.push("Group-by collection needs a field path to group on");
3205
+ }
3206
+ return { valid: errors.length === 0, errors };
3207
+ },
3208
+ merge: (userConfig) => {
3209
+ return { ...ForEachConfig.defaults, ...userConfig };
3210
+ },
3211
+ getLabel: (config) => {
3212
+ const mode = config.iterationMode || "records";
3213
+ if (mode === "range")
3214
+ return `ForEach ×${config.count ?? "…"}`;
3215
+ if (mode === "cursor")
3216
+ return "ForEach (paginate)";
3217
+ if (mode === "while")
3218
+ return "ForEach (while)";
3219
+ return `ForEach in ${config.arrayPath || "…"}`;
3220
+ },
3221
+ generateName: (arrayPath) => {
3222
+ return `ForEach in ${arrayPath || "…"}`;
3223
+ }
3224
+ };
3225
+ // src/catalog/logic/for-each/pathOptions.ts
3226
+ function inferSchemaFromSample(sample) {
3227
+ const properties = {};
3228
+ for (const [key, value] of Object.entries(sample)) {
3229
+ if (value === null || value === undefined) {
3230
+ properties[key] = { type: "string" };
3231
+ } else if (Array.isArray(value)) {
3232
+ if (value.length > 0 && typeof value[0] === "object" && value[0] !== null) {
3233
+ properties[key] = { type: "array", items: inferSchemaFromSample(value[0]) };
3234
+ } else {
3235
+ properties[key] = { type: "array" };
3236
+ }
3237
+ } else if (typeof value === "object") {
3238
+ properties[key] = inferSchemaFromSample(value);
3239
+ } else if (typeof value === "number") {
3240
+ properties[key] = { type: "number" };
3241
+ } else if (typeof value === "boolean") {
3242
+ properties[key] = { type: "boolean" };
3243
+ } else {
3244
+ properties[key] = { type: "string" };
3245
+ }
3246
+ }
3247
+ return { type: "object", properties };
3248
+ }
3249
+ function collectArrayPaths(schema, prefix, add, depth = 0) {
3250
+ if (!schema || typeof schema !== "object" || depth > 8)
3251
+ return;
3252
+ if (schema.type === "array") {
3253
+ if (prefix) {
3254
+ const itemsType = schema.items?.type;
3255
+ const label = itemsType === "object" ? "array of objects" : "array";
3256
+ add(prefix, `${prefix} (${label})`, `Iterate over "${prefix}"`);
3257
+ }
3258
+ if (schema.items) {
3259
+ collectArrayPaths(schema.items, prefix, add, depth + 1);
3260
+ }
3261
+ return;
3262
+ }
3263
+ if (schema.type === "object" && schema.properties) {
3264
+ for (const [key, child] of Object.entries(schema.properties)) {
3265
+ const next = prefix ? `${prefix}.${key}` : key;
3266
+ collectArrayPaths(child, next, add, depth + 1);
3267
+ }
3268
+ }
3269
+ }
3270
+ function collectArrayPathsFromSample(sample, prefix, add, depth = 0) {
3271
+ if (!sample || typeof sample !== "object" || depth > 8)
3272
+ return;
3273
+ if (Array.isArray(sample)) {
3274
+ if (prefix) {
3275
+ const itemsObj = sample.length > 0 && typeof sample[0] === "object" && sample[0] !== null;
3276
+ const label = itemsObj ? "array of objects" : "array";
3277
+ add(prefix, `${prefix} (${label})`, `Iterate over "${prefix}"`);
3278
+ }
3279
+ if (sample.length > 0) {
3280
+ collectArrayPathsFromSample(sample[0], prefix, add, depth + 1);
3281
+ }
3282
+ return;
3283
+ }
3284
+ for (const [key, value] of Object.entries(sample)) {
3285
+ const next = prefix ? `${prefix}.${key}` : key;
3286
+ collectArrayPathsFromSample(value, next, add, depth + 1);
3287
+ }
3288
+ }
3289
+ function buildPathOptions(upstreamNodes) {
3290
+ const paths = [];
3291
+ const seen = new Set;
3292
+ const add = (id, text, description) => {
3293
+ if (seen.has(id))
3294
+ return;
3295
+ seen.add(id);
3296
+ paths.push({ id, text, description });
3297
+ };
3298
+ if (upstreamNodes) {
3299
+ for (const node of upstreamNodes) {
3300
+ const label = node.label || node.type || "Upstream";
3301
+ const queryTable = node.config?.visualConfig?.tables?.[0];
3302
+ add("data", queryTable ? `${queryTable} (${label})` : `All records (${label})`, queryTable ? `Iterate over every ${queryTable} record` : "Iterate over every record from upstream");
3303
+ const schema = node.outputSchema || node.config?._outputSchema;
3304
+ if (schema)
3305
+ collectArrayPaths(schema, "", add);
3306
+ const output = node.executionData?.output;
3307
+ if (output) {
3308
+ const records = Array.isArray(output.data) ? output.data : Array.isArray(output) ? output : null;
3309
+ if (records && records.length > 0 && typeof records[0] === "object") {
3310
+ collectArrayPathsFromSample(records[0], "", add);
3311
+ }
3312
+ }
3313
+ }
3314
+ }
3315
+ if (paths.length === 0) {
3316
+ add("data", "data (upstream output)");
3317
+ }
3318
+ return paths;
3319
+ }
3320
+ // src/catalog/utility/variables/config.ts
3321
+ var RESERVED_KEYS = new Set(["_lineage", "_meta", "_redacted", "_error"]);
3322
+ var KEY_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
3323
+ var VariablesConfig = {
3324
+ defaults: {
3325
+ fields: []
3326
+ },
3327
+ validate(config) {
3328
+ const errors = [];
3329
+ const fields = config.fields ?? [];
3330
+ const seen = new Set;
3331
+ for (const f of fields) {
3332
+ if (!f.key) {
3333
+ errors.push("Each field needs a key.");
3334
+ continue;
3335
+ }
3336
+ if (RESERVED_KEYS.has(f.key)) {
3337
+ errors.push(`"${f.key}" is reserved — pick another key.`);
3338
+ continue;
3339
+ }
3340
+ if (!KEY_PATTERN.test(f.key)) {
3341
+ errors.push(`"${f.key}" is not a valid identifier (letters, digits, underscore; must not start with a digit).`);
3342
+ continue;
3343
+ }
3344
+ if (seen.has(f.key)) {
3345
+ errors.push(`Duplicate key "${f.key}".`);
3346
+ continue;
3347
+ }
3348
+ seen.add(f.key);
3349
+ if (!f.type)
3350
+ errors.push(`"${f.key}" is missing a type.`);
3351
+ if (!f.source)
3352
+ errors.push(`"${f.key}" is missing a source.`);
3353
+ }
3354
+ return { valid: errors.length === 0, errors };
3355
+ },
3356
+ computeOutputSchema(fields) {
3357
+ const properties = {};
3358
+ for (const f of fields) {
3359
+ properties[f.key] = fieldToJsonSchema(f);
3360
+ }
3361
+ return { type: "object", properties };
3362
+ }
3363
+ };
3364
+ function fieldToJsonSchema(f) {
3365
+ const node = { type: f.type };
3366
+ if (f.description)
3367
+ node.description = f.description;
3368
+ if (f.validation?.enum)
3369
+ node.enum = f.validation.enum;
3370
+ return node;
3371
+ }
3372
+ // src/catalog/utility/debug/config.ts
3373
+ var DebugConfig = {
3374
+ defaults: {
3375
+ mode: "log",
3376
+ label: "",
3377
+ log: { level: "info", message: "" }
3378
+ },
3379
+ validate(config) {
3380
+ const errors = [];
3381
+ if (!config.mode)
3382
+ errors.push("Mode is required.");
3383
+ if (!config.label?.trim())
3384
+ errors.push("Label is required.");
3385
+ switch (config.mode) {
3386
+ case "log":
3387
+ if (!config.log?.message?.trim())
3388
+ errors.push("Log mode: message is required.");
3389
+ if (!config.log?.level)
3390
+ errors.push("Log mode: level is required.");
3391
+ break;
3392
+ case "snapshot":
3393
+ break;
3394
+ case "watch":
3395
+ if (!config.watch?.expressions?.length) {
3396
+ errors.push("Watch mode: add at least one expression.");
3397
+ } else {
3398
+ for (const e of config.watch.expressions) {
3399
+ if (!e.label?.trim())
3400
+ errors.push("Watch mode: each expression needs a label.");
3401
+ if (!e.expression?.trim())
3402
+ errors.push("Watch mode: each expression needs an expression string.");
3403
+ }
3404
+ }
3405
+ break;
3406
+ case "assert":
3407
+ if (!config.assert?.predicate?.trim())
3408
+ errors.push("Assert mode: predicate is required.");
3409
+ if (!config.assert?.failureMessage?.trim())
3410
+ errors.push("Assert mode: failure message is required.");
3411
+ break;
3412
+ case "profile":
3413
+ if (!config.profile?.scope)
3414
+ errors.push("Profile mode: scope is required.");
3415
+ break;
3416
+ }
3417
+ return { valid: errors.length === 0, errors };
3418
+ },
3419
+ migrateLegacyStub(config) {
3420
+ if (config.mode) {
3421
+ const { value: _stub, ...rest } = config;
3422
+ return { ...DebugConfig.defaults, ...rest };
3423
+ }
3424
+ return {
3425
+ mode: "log",
3426
+ label: config.label ?? "Debug",
3427
+ log: {
3428
+ level: "info",
3429
+ message: config.label ?? "Debug",
3430
+ includeInputData: true
3431
+ }
3432
+ };
3433
+ },
3434
+ merge(userConfig) {
3435
+ return { ...DebugConfig.defaults, ...userConfig };
3436
+ },
3437
+ getLabel(config) {
3438
+ return `Debug [${config.mode}]: ${config.label}`;
3439
+ }
3440
+ };
3441
+ // src/catalog/actions/delay/migrate.ts
3442
+ var LEGACY_UNITS = new Set([
3443
+ "milliseconds",
3444
+ "seconds",
3445
+ "minutes",
3446
+ "hours"
3447
+ ]);
3448
+ function migrateDelayConfig(raw) {
3449
+ if (raw && typeof raw === "object" && "mode" in raw) {
3450
+ return raw;
3451
+ }
3452
+ const legacy = raw ?? {};
3453
+ const duration = typeof legacy.duration === "number" && Number.isFinite(legacy.duration) ? legacy.duration : 1;
3454
+ const unit = typeof legacy.unit === "string" && LEGACY_UNITS.has(legacy.unit) ? legacy.unit : "milliseconds";
3455
+ return {
3456
+ mode: "fixed",
3457
+ fixed: { duration, unit }
3458
+ };
3459
+ }
3460
+ // src/catalog/communication/email-send/config.ts
3461
+ var EmailConfig = {
3462
+ defaults: {
3463
+ connection: "",
3464
+ operation: "send",
3465
+ to: "",
3466
+ cc: "",
3467
+ bcc: "",
3468
+ subject: "",
3469
+ body: "",
3470
+ isHtml: false,
3471
+ attachments: [],
3472
+ folder: "Inbox",
3473
+ query: "",
3474
+ limit: 10
3475
+ },
3476
+ schema: {
3477
+ connection: { type: "connection", required: true },
3478
+ operation: { type: "select", required: true },
3479
+ to: { type: "string", required: false },
3480
+ cc: { type: "string", required: false },
3481
+ bcc: { type: "string", required: false },
3482
+ subject: { type: "string", required: false },
3483
+ body: { type: "string", required: false },
3484
+ isHtml: { type: "boolean", required: false },
3485
+ attachments: { type: "array", required: false },
3486
+ folder: { type: "string", required: false },
3487
+ query: { type: "string", required: false },
3488
+ limit: { type: "number", required: false }
3489
+ },
3490
+ validate: (config) => {
3491
+ const errors = [];
3492
+ if (!config.connection)
3493
+ errors.push("Email service connection is required");
3494
+ if (!config.operation)
3495
+ errors.push("Operation is required");
3496
+ if (config.operation === "send") {
3497
+ if (!config.to)
3498
+ errors.push("Recipient email is required for send operation");
3499
+ if (!config.subject)
3500
+ errors.push("Subject is required for send operation");
3501
+ if (!config.body)
3502
+ errors.push("Body is required for send operation");
3503
+ } else if (config.operation) {
3504
+ errors.push("Only Send is available for the Email action right now");
3505
+ }
3506
+ return { valid: errors.length === 0, errors };
3507
+ },
3508
+ merge: (userConfig) => {
3509
+ return { ...EmailConfig.defaults, ...userConfig };
3510
+ },
3511
+ getLabel: (config) => {
3512
+ switch (config.operation) {
3513
+ case "send":
3514
+ return `Email: Send to ${config.to}`;
3515
+ case "read":
3516
+ return `Email: Read from ${config.folder}`;
3517
+ case "search":
3518
+ return `Email: Search "${config.query}"`;
3519
+ case "delete":
3520
+ return `Email: Delete from ${config.folder}`;
3521
+ case "move":
3522
+ return `Email: Move to ${config.folder}`;
3523
+ case "mark_read":
3524
+ return `Email: Mark as read`;
3525
+ default:
3526
+ return `Email: ${config.operation}`;
3527
+ }
3528
+ }
3529
+ };
3530
+ // src/catalog/general/transform/config.ts
3531
+ var TRANSFORM_OPERATIONS = [
3532
+ { id: "upsert", label: "Upsert" },
3533
+ { id: "insert", label: "Insert" },
3534
+ { id: "update", label: "Update" },
3535
+ { id: "delete", label: "Delete" }
3536
+ ];
3537
+ var DATABASE_CONNECTOR_IDS = new Set(["mongodb", "postgresql", "mysql", "sqlite", "google_sheets"]);
3538
+ var TransformConfig = {
3539
+ defaults: {
3540
+ name: "Transform",
3541
+ operation: "upsert",
3542
+ connectorId: "",
3543
+ database: "",
3544
+ objectName: "",
3545
+ mode: "visual",
3546
+ mappings: [],
3547
+ expression: "",
3548
+ fieldDefaults: {},
3549
+ upsertMatchKey: "",
3550
+ sheetHeaders: [],
3551
+ createTabIfMissing: true,
3552
+ writeHeaderRow: true,
3553
+ clearBeforeWrite: false,
3554
+ sheetCustomLayout: false,
3555
+ sheetHeaderRow: 1,
3556
+ sheetColumns: ""
3557
+ },
3558
+ schema: {
3559
+ operation: { type: "select", required: true },
3560
+ connectorId: { type: "connection", required: true },
3561
+ database: { type: "text", required: false },
3562
+ objectName: { type: "select", required: true },
3563
+ mode: { type: "select", required: true },
3564
+ mappings: { type: "array", required: false },
3565
+ expression: { type: "code", required: false }
3566
+ },
3567
+ generateName: (operation, connectorLabel, objectName) => {
3568
+ const opLabel = TRANSFORM_OPERATIONS.find((o) => o.id === operation)?.label || "Transform";
3569
+ const target = connectorLabel || "Target";
3570
+ const obj = objectName || "Object";
3571
+ return `${opLabel} → ${target} · ${obj}`;
3572
+ },
3573
+ validate: (config) => {
3574
+ const errors = [];
3575
+ if (!config.operation) {
3576
+ errors.push("Operation is required");
3577
+ }
3578
+ if (!config.connectorId) {
3579
+ errors.push("Target connector is required");
3580
+ }
3581
+ if (!config.objectName) {
3582
+ errors.push("Object (table) is required");
3583
+ }
3584
+ const isLegacyExpression = config.mode === "expression" && !!config.expression?.trim();
3585
+ if (!isLegacyExpression) {
3586
+ if (!config.mappings || config.mappings.length === 0) {
3587
+ errors.push("At least one field mapping is required");
3588
+ } else {
3589
+ config.mappings.forEach((mapping, index) => {
3590
+ if (!mapping.sourceField) {
3591
+ errors.push(`Mapping ${index + 1}: Source field is required`);
3592
+ }
3593
+ if (!mapping.targetField) {
3594
+ errors.push(`Mapping ${index + 1}: Target field is required`);
3595
+ }
3596
+ });
3597
+ }
3598
+ }
3599
+ return { valid: errors.length === 0, errors };
3600
+ },
3601
+ merge: (userConfig) => {
3602
+ return { ...TransformConfig.defaults, ...userConfig };
3603
+ },
3604
+ getLabel: (config) => {
3605
+ const count = config.mappings?.length ?? 0;
3606
+ return `${config.name || "Transform"} (${count} field${count !== 1 ? "s" : ""})`;
3607
+ },
3608
+ createMappingId: () => {
3609
+ return `map_${Date.now()}_${randomSuffix(5)}`;
3610
+ }
3611
+ };
3612
+ // src/catalog/storage/storageCapabilities.ts
3613
+ var contentTypeField = {
3614
+ key: "contentType",
3615
+ label: "Content type",
3616
+ type: "string",
3617
+ placeholder: "application/octet-stream",
3618
+ advanced: true,
3619
+ hint: "MIME type for the uploaded file."
3620
+ };
3621
+ var STORAGE_PROVIDERS = {
3622
+ aws_s3: {
3623
+ connectorId: "aws_s3",
3624
+ label: "Amazon S3",
3625
+ browse: true,
3626
+ operations: [
3627
+ { value: "list", label: "List files", path: { key: "prefix", label: "Folder", selectMode: "folder" }, fields: [{ key: "maxKeys", label: "Max results", type: "number", defaultValue: 100, advanced: true }] },
3628
+ { value: "download", label: "Download file", path: { key: "key", label: "File", selectMode: "both", required: true } },
3629
+ { value: "upload", label: "Upload file", path: { key: "key", label: "Destination key", selectMode: "both", required: true }, content: true, fields: [contentTypeField] },
3630
+ { value: "delete", label: "Delete file", path: { key: "key", label: "File", selectMode: "both", required: true } },
3631
+ { value: "copy", label: "Copy file", path: { key: "key", label: "Source file", selectMode: "both", required: true }, dest: { key: "destKey", label: "Destination key", selectMode: "both", required: true } },
3632
+ { value: "move", label: "Move / rename", path: { key: "key", label: "Source file", selectMode: "both", required: true }, dest: { key: "destKey", label: "Destination key", selectMode: "both", required: true } },
3633
+ { value: "presign", label: "Get signed URL", path: { key: "key", label: "File", selectMode: "both", required: true }, fields: [{ key: "expiresIn", label: "Expiry (seconds)", type: "number", defaultValue: 3600, advanced: true }] }
3634
+ ]
3635
+ },
3636
+ ftp_sftp: {
3637
+ connectorId: "ftp_sftp",
3638
+ label: "FTP / SFTP",
3639
+ browse: true,
3640
+ operations: [
3641
+ { value: "list", label: "List files", path: { key: "remotePath", label: "Folder", selectMode: "folder" } },
3642
+ { value: "download", label: "Download file", path: { key: "remotePath", label: "File", selectMode: "both", required: true } },
3643
+ { value: "upload", label: "Upload file", path: { key: "remotePath", label: "Destination path", selectMode: "both", required: true }, content: true },
3644
+ { value: "delete", label: "Delete file", path: { key: "remotePath", label: "File", selectMode: "both", required: true } },
3645
+ { value: "move", label: "Move / rename", path: { key: "remotePath", label: "Source file", selectMode: "both", required: true }, dest: { key: "destPath", label: "Destination path", selectMode: "both", required: true } }
3646
+ ]
3647
+ },
3648
+ dropbox: {
3649
+ connectorId: "dropbox",
3650
+ label: "Dropbox",
3651
+ browse: true,
3652
+ operations: [
3653
+ { value: "list", label: "List files", path: { key: "path", label: "Folder", selectMode: "folder" } },
3654
+ { value: "download", label: "Download file", path: { key: "path", label: "File", selectMode: "both", required: true } },
3655
+ { value: "upload", label: "Upload file", path: { key: "path", label: "Destination path", selectMode: "both", required: true }, content: true, fields: [{ key: "mode", label: "Write mode", type: "select", options: [{ label: "Overwrite", value: "overwrite" }, { label: "Add (keep both)", value: "add" }], defaultValue: "overwrite", advanced: true }] },
3656
+ { value: "delete", label: "Delete file", path: { key: "path", label: "File", selectMode: "both", required: true } },
3657
+ { value: "copy", label: "Copy file", path: { key: "path", label: "Source file", selectMode: "both", required: true }, dest: { key: "destPath", label: "Destination path", selectMode: "both", required: true } },
3658
+ { value: "move", label: "Move / rename", path: { key: "path", label: "Source file", selectMode: "both", required: true }, dest: { key: "destPath", label: "Destination path", selectMode: "both", required: true } }
3659
+ ]
3660
+ },
3661
+ onedrive: {
3662
+ connectorId: "onedrive",
3663
+ label: "OneDrive",
3664
+ browse: true,
3665
+ operations: [
3666
+ { value: "list", label: "List files", path: { key: "path", label: "Folder", selectMode: "folder" } },
3667
+ { value: "download", label: "Download file", path: { key: "path", label: "File", selectMode: "both", required: true } },
3668
+ { value: "upload", label: "Upload file", path: { key: "path", label: "Destination path", selectMode: "both", required: true }, content: true, fields: [contentTypeField] },
3669
+ { value: "delete", label: "Delete file", path: { key: "path", label: "File", selectMode: "both", required: true } },
3670
+ { value: "copy", label: "Copy file", path: { key: "path", label: "Source file", selectMode: "both", required: true }, dest: { key: "destPath", label: "Destination path", selectMode: "both", required: true } },
3671
+ { value: "move", label: "Move / rename", path: { key: "path", label: "Source file", selectMode: "both", required: true }, dest: { key: "destPath", label: "Destination path", selectMode: "both", required: true } }
3672
+ ]
3673
+ },
3674
+ google_drive: {
3675
+ connectorId: "google_drive",
3676
+ label: "Google Drive",
3677
+ browse: true,
3678
+ operations: [
3679
+ { value: "list", label: "List files", path: { key: "folderId", label: "Folder", selectMode: "folder" }, fields: [{ key: "query", label: "Search query", type: "string", advanced: true }, { key: "pageSize", label: "Max results", type: "number", defaultValue: 50, advanced: true }] },
3680
+ { value: "download", label: "Download file", path: { key: "fileId", label: "File", selectMode: "both", required: true } },
3681
+ { value: "upload", label: "Upload file", path: { key: "folderId", label: "Destination folder", selectMode: "both" }, content: true, fields: [{ key: "fileName", label: "File name", type: "string", required: true }, { key: "mimeType", label: "Content type", type: "string", advanced: true }] },
3682
+ { value: "delete", label: "Delete file", path: { key: "fileId", label: "File", selectMode: "both", required: true } },
3683
+ { value: "move", label: "Move", path: { key: "fileId", label: "File", selectMode: "both", required: true }, dest: { key: "destFolderId", label: "Destination folder", selectMode: "both", required: true } },
3684
+ { value: "copy", label: "Copy", path: { key: "fileId", label: "File", selectMode: "both", required: true }, dest: { key: "destFolderId", label: "Destination folder", selectMode: "both" }, fields: [{ key: "fileName", label: "New name", type: "string" }] },
3685
+ { value: "share", label: "Share", path: { key: "fileId", label: "File", selectMode: "both", required: true }, fields: [{ key: "shareEmail", label: "Share with (email)", type: "string", required: true }, { key: "shareRole", label: "Role", type: "select", options: [{ label: "Viewer", value: "reader" }, { label: "Editor", value: "writer" }], defaultValue: "reader" }] },
3686
+ { value: "create_folder", label: "Create folder", path: { key: "folderId", label: "Parent folder", selectMode: "both" }, fields: [{ key: "fileName", label: "Folder name", type: "string", required: true }] }
3687
+ ]
3688
+ },
3689
+ gcs: {
3690
+ connectorId: "gcs",
3691
+ label: "Google Cloud Storage",
3692
+ browse: true,
3693
+ operations: [
3694
+ { value: "list", label: "List files", path: { key: "prefix", label: "Folder", selectMode: "folder" }, fields: [{ key: "maxKeys", label: "Max results", type: "number", defaultValue: 100, advanced: true }] },
3695
+ { value: "download", label: "Download file", path: { key: "key", label: "File", selectMode: "both", required: true } },
3696
+ { value: "upload", label: "Upload file", path: { key: "key", label: "Destination key", selectMode: "both", required: true }, content: true, fields: [contentTypeField] },
3697
+ { value: "delete", label: "Delete file", path: { key: "key", label: "File", selectMode: "both", required: true } },
3698
+ { value: "copy", label: "Copy file", path: { key: "key", label: "Source file", selectMode: "both", required: true }, dest: { key: "destKey", label: "Destination key", selectMode: "both", required: true } },
3699
+ { value: "move", label: "Move / rename", path: { key: "key", label: "Source file", selectMode: "both", required: true }, dest: { key: "destKey", label: "Destination key", selectMode: "both", required: true } },
3700
+ { value: "presign", label: "Get signed URL", path: { key: "key", label: "File", selectMode: "both", required: true }, fields: [{ key: "expiresIn", label: "Expiry (seconds)", type: "number", defaultValue: 3600, advanced: true }] }
3701
+ ]
3702
+ },
3703
+ azure_blob: {
3704
+ connectorId: "azure_blob",
3705
+ label: "Azure Blob Storage",
3706
+ browse: true,
3707
+ operations: [
3708
+ { value: "list", label: "List files", path: { key: "prefix", label: "Folder", selectMode: "folder" }, fields: [{ key: "maxKeys", label: "Max results", type: "number", defaultValue: 100, advanced: true }] },
3709
+ { value: "download", label: "Download file", path: { key: "blob", label: "File", selectMode: "both", required: true } },
3710
+ { value: "upload", label: "Upload file", path: { key: "blob", label: "Destination blob", selectMode: "both", required: true }, content: true, fields: [contentTypeField] },
3711
+ { value: "delete", label: "Delete file", path: { key: "blob", label: "File", selectMode: "both", required: true } },
3712
+ { value: "copy", label: "Copy file", path: { key: "blob", label: "Source blob", selectMode: "both", required: true }, dest: { key: "destBlob", label: "Destination blob", selectMode: "both", required: true } },
3713
+ { value: "move", label: "Move / rename", path: { key: "blob", label: "Source blob", selectMode: "both", required: true }, dest: { key: "destBlob", label: "Destination blob", selectMode: "both", required: true } },
3714
+ { value: "presign", label: "Get signed URL", path: { key: "blob", label: "File", selectMode: "both", required: true }, fields: [{ key: "expiresIn", label: "Expiry (seconds)", type: "number", defaultValue: 3600, advanced: true }] }
3715
+ ]
3716
+ }
3717
+ };
3718
+ STORAGE_PROVIDERS.google_sheets = { ...STORAGE_PROVIDERS.google_drive, connectorId: "google_sheets" };
3719
+ var transferOp = {
3720
+ value: "transfer",
3721
+ label: "Transfer to another connector",
3722
+ path: { key: "path", label: "Source file or folder", selectMode: "both", required: true }
3723
+ };
3724
+ for (const id of ["aws_s3", "ftp_sftp", "dropbox", "onedrive", "google_drive", "gcs", "azure_blob"]) {
3725
+ STORAGE_PROVIDERS[id].operations.push(transferOp);
3726
+ }
3727
+ var syncOp = {
3728
+ value: "sync",
3729
+ label: "Sync folder to another connector",
3730
+ path: { key: "path", label: "Source folder", selectMode: "both", required: true },
3731
+ fields: [
3732
+ {
3733
+ key: "ifExists",
3734
+ label: "If a file already exists",
3735
+ type: "select",
3736
+ options: [
3737
+ { label: "Overwrite", value: "overwrite" },
3738
+ { label: "Skip it", value: "skip" },
3739
+ { label: "Keep both (rename)", value: "rename" }
3740
+ ],
3741
+ defaultValue: "overwrite",
3742
+ hint: "What to do when the destination already has the file."
3743
+ },
3744
+ {
3745
+ key: "onError",
3746
+ label: "On file error",
3747
+ type: "select",
3748
+ options: [
3749
+ { label: "Stop the sync", value: "abort" },
3750
+ { label: "Skip the file & continue", value: "skip" }
3751
+ ],
3752
+ defaultValue: "abort",
3753
+ hint: "A bad file (timeout, lock, permission) stops the whole sync, or is skipped."
3754
+ }
3755
+ ]
3756
+ };
3757
+ for (const id of ["aws_s3", "ftp_sftp", "dropbox", "onedrive", "google_drive", "gcs", "azure_blob"]) {
3758
+ STORAGE_PROVIDERS[id].operations.push(syncOp);
3759
+ }
3760
+ var STORAGE_CONNECTOR_IDS = Object.keys(STORAGE_PROVIDERS).filter((id) => id !== "google_sheets");
3761
+ function getStorageProvider(connectorId) {
3762
+ if (!connectorId)
3763
+ return;
3764
+ return STORAGE_PROVIDERS[connectorId] ?? STORAGE_PROVIDERS[connectorId.replace(/-/g, "_")];
3765
+ }
3766
+ function storageConfigKeys() {
3767
+ const keys = new Set([
3768
+ "operation",
3769
+ "connector",
3770
+ "content",
3771
+ "outputAs",
3772
+ "path",
3773
+ "destPath",
3774
+ "destConnector",
3775
+ "sourceIsDirectory",
3776
+ "cursor",
3777
+ "fileBudget",
3778
+ "timeBudgetMs"
3779
+ ]);
3780
+ for (const provider of Object.values(STORAGE_PROVIDERS)) {
3781
+ for (const op of provider.operations) {
3782
+ if (op.path)
3783
+ keys.add(op.path.key);
3784
+ if (op.dest)
3785
+ keys.add(op.dest.key);
3786
+ for (const f of op.fields ?? [])
3787
+ keys.add(f.key);
3788
+ }
3789
+ }
3790
+ return [...keys];
3791
+ }
3792
+ // src/catalog/workflow.ts
3793
+ var NodeStatus;
3794
+ ((NodeStatus) => {
3795
+ NodeStatus["Idle"] = "idle";
3796
+ NodeStatus["Running"] = "running";
3797
+ NodeStatus["Success"] = "success";
3798
+ NodeStatus["Error"] = "error";
3799
+ NodeStatus["Warning"] = "warning";
3800
+ NodeStatus["Disabled"] = "disabled";
3801
+ })(NodeStatus ||= {});
3802
+ var EdgeType;
3803
+ ((EdgeType) => {
3804
+ EdgeType["Default"] = "default";
3805
+ EdgeType["Conditional"] = "conditional";
3806
+ EdgeType["Loop"] = "loop";
3807
+ EdgeType["Error"] = "error";
3808
+ })(EdgeType ||= {});
3809
+ // src/rules/flattenNestedWorkflow.ts
3810
+ function workflowIsNested(workflow) {
3811
+ const stack = [...workflow.steps];
3812
+ while (stack.length > 0) {
3813
+ const s = stack.pop();
3814
+ if (s.branches && Object.keys(s.branches).length > 0)
3815
+ return true;
3816
+ }
3817
+ return false;
3818
+ }
3819
+ function flattenNestedWorkflow(workflow) {
3820
+ if (!workflowIsNested(workflow))
3821
+ return workflow;
3822
+ const flatSteps = [];
3823
+ const flatConns = [...workflow.connections];
3824
+ const groups = [];
3825
+ const walk = (steps, parentIdForSubflow) => {
3826
+ for (const step of steps) {
3827
+ const { branches, ...rest } = step;
3828
+ const flatStep = {
3829
+ ...rest,
3830
+ ...parentIdForSubflow ? { parentId: parentIdForSubflow } : {}
3831
+ };
3832
+ flatSteps.push(flatStep);
3833
+ if (!branches)
3834
+ continue;
3835
+ if (branches.body && step.type === "group") {
3836
+ const body = branches.body;
3837
+ groups.push({
3838
+ group: flatStep,
3839
+ bodyStepIds: body.steps.map((s) => s.id),
3840
+ bodyConnections: body.connections
3841
+ });
3842
+ for (const c of body.connections)
3843
+ flatConns.push(c);
3844
+ walk(body.steps, step.id);
3845
+ }
3846
+ for (const branchKey of Object.keys(branches)) {
3847
+ if (branchKey === "body" && step.type === "group")
3848
+ continue;
3849
+ const sub = branches[branchKey];
3850
+ if (!sub)
3851
+ continue;
3852
+ for (const c of sub.connections)
3853
+ flatConns.push(c);
3854
+ walk(sub.steps, parentIdForSubflow);
3855
+ }
3856
+ }
3857
+ };
3858
+ walk(workflow.steps, undefined);
3859
+ for (const g of groups) {
3860
+ if (g.bodyStepIds.length === 0)
3861
+ continue;
3862
+ const bodyIdSet = new Set(g.bodyStepIds);
3863
+ const inDeg = new Map;
3864
+ const outDeg = new Map;
3865
+ for (const id of g.bodyStepIds) {
3866
+ inDeg.set(id, 0);
3867
+ outDeg.set(id, 0);
3868
+ }
3869
+ for (const c of g.bodyConnections) {
3870
+ if (bodyIdSet.has(c.sourceStepId)) {
3871
+ outDeg.set(c.sourceStepId, (outDeg.get(c.sourceStepId) ?? 0) + 1);
3872
+ }
3873
+ if (bodyIdSet.has(c.targetStepId)) {
3874
+ inDeg.set(c.targetStepId, (inDeg.get(c.targetStepId) ?? 0) + 1);
3875
+ }
3876
+ }
3877
+ const roots = g.bodyStepIds.filter((id) => (inDeg.get(id) ?? 0) === 0);
3878
+ const leaves = g.bodyStepIds.filter((id) => (outDeg.get(id) ?? 0) === 0);
3879
+ for (const rootId of roots) {
3880
+ flatConns.push({
3881
+ id: `synth-inner-in-${g.group.id}-${rootId}`,
3882
+ sourceStepId: g.group.id,
3883
+ targetStepId: rootId,
3884
+ sourcePort: "_inner_in"
3885
+ });
3886
+ }
3887
+ for (const leafId of leaves) {
3888
+ flatConns.push({
3889
+ id: `synth-inner-out-${leafId}-${g.group.id}`,
3890
+ sourceStepId: leafId,
3891
+ targetStepId: g.group.id,
3892
+ targetPort: "_inner_out"
3893
+ });
3894
+ }
3895
+ }
3896
+ return { ...workflow, steps: flatSteps, connections: flatConns };
3897
+ }
3898
+
3899
+ // src/rules/flowShape.ts
3900
+ function transformStepToNode(step) {
3901
+ const stepType = step.type;
3902
+ const stepActionDefId = step.actionDefinitionId ?? "";
3903
+ const nodeType = stepType === "trigger" ? "trigger" : stepType === "group" || stepActionDefId === "group" ? "group" : "action";
3904
+ let nodeStatus = "idle" /* Idle */;
3905
+ switch (step.status?.toLowerCase()) {
3906
+ case "running":
3907
+ case "executing":
3908
+ nodeStatus = "running" /* Running */;
3909
+ break;
3910
+ case "completed":
3911
+ case "success":
3912
+ nodeStatus = "success" /* Success */;
3913
+ break;
3914
+ case "failed":
3915
+ case "error":
3916
+ nodeStatus = "error" /* Error */;
3917
+ break;
3918
+ case "pending":
3919
+ case "waiting":
3920
+ nodeStatus = "idle" /* Idle */;
3921
+ break;
3922
+ default:
3923
+ nodeStatus = "idle" /* Idle */;
3924
+ }
3925
+ const position = step.position || { x: step.position_x || 0, y: step.position_y || 0 };
3926
+ const posX = typeof position === "object" && position !== null && "x" in position ? position.x : step.position_x || 0;
3927
+ const posY = typeof position === "object" && position !== null && "y" in position ? position.y : step.position_y || 0;
3928
+ const config = step.config || {};
3929
+ const configData = config.data || config || {};
3930
+ const derivedFromName = step.name ? step.name.toLowerCase().replace(/\s+/g, "_") : undefined;
3931
+ const resolvedActionDefinitionId = step.actionDefinitionId || config.connector_id || step.connector_id || derivedFromName || step.type;
3932
+ const actionDef = getActionById(resolvedActionDefinitionId);
3933
+ const node = {
3934
+ id: step.id,
3935
+ type: nodeType,
3936
+ actionDefinitionId: resolvedActionDefinitionId,
3937
+ actionDefinition: actionDef,
3938
+ label: step.label || step.name,
3939
+ description: step.description || config.description || actionDef?.description || "",
3940
+ icon: actionDef?.icon ?? getIconForStepType(step.type),
3941
+ position: {
3942
+ x: posX,
3943
+ y: posY
3944
+ },
3945
+ ...step.parentId ? { parentId: step.parentId } : {},
3946
+ ...step.extent ? { extent: step.extent } : {},
3947
+ ...step.disabled ? { disabled: true } : {},
3948
+ ...step.dimensions && nodeType === "group" ? { dimensions: step.dimensions } : nodeType === "group" ? { dimensions: { width: 480, height: 240 } } : {},
3949
+ config: {
3950
+ ...configData,
3951
+ timeout: step.timeout_seconds,
3952
+ retryPolicy: step.retry_policy,
3953
+ notes: step.notes,
3954
+ tags: step.tags,
3955
+ stepCount: step.step_count
3956
+ },
3957
+ ports: {
3958
+ input: nodeType === "action" || nodeType === "group" ? [
3959
+ {
3960
+ id: `${step.id}-input`,
3961
+ type: "input",
3962
+ position: "top",
3963
+ connected: false
3964
+ }
3965
+ ] : [],
3966
+ output: (() => {
3967
+ if (resolvedActionDefinitionId === "condition") {
3968
+ return [
3969
+ { id: `${step.id}_output_true`, type: "output", position: "bottom", label: "True", connected: false },
3970
+ { id: `${step.id}_output_false`, type: "output", position: "bottom", label: "False", connected: false }
3971
+ ];
3972
+ }
3973
+ if (resolvedActionDefinitionId === "for_each" || resolvedActionDefinitionId === "for-each") {
3974
+ return [
3975
+ { id: `${step.id}_output_each`, type: "output", position: "bottom", label: "Each", connected: false },
3976
+ { id: `${step.id}_output_done`, type: "output", position: "bottom", label: "Done", connected: false }
3977
+ ];
3978
+ }
3979
+ if (resolvedActionDefinitionId === "group") {
3980
+ return [
3981
+ { id: `${step.id}_output_0`, type: "output", position: "bottom", connected: false }
3982
+ ];
3983
+ }
3984
+ return [
3985
+ { id: `${step.id}-output`, type: "output", position: "bottom", connected: false }
3986
+ ];
3987
+ })()
3988
+ },
3989
+ configStatus: step.configStatus || undefined,
3990
+ ...step.outputSchema ? { outputSchema: step.outputSchema } : {},
3991
+ status: nodeStatus,
3992
+ selected: false,
3993
+ dragging: false,
3994
+ isValid: step.configStatus ? step.configStatus === "valid" : true,
3995
+ expanded: step.expanded,
3996
+ minimized: false,
3997
+ locked: false,
3998
+ createdAt: step.created_at || new Date().toISOString(),
3999
+ updatedAt: step.updated_at || new Date().toISOString()
4000
+ };
4001
+ return node;
4002
+ }
4003
+ function transformConnectionToEdge(connection) {
4004
+ const sourceStepId = connection.sourceStepId || connection.source_step_id;
4005
+ const targetStepId = connection.targetStepId || connection.target_step_id;
4006
+ const sourcePort = connection.sourcePort || connection.source_port || `${sourceStepId}-output`;
4007
+ const targetPort = connection.targetPort || connection.target_port || `${targetStepId}-input`;
4008
+ let edgeType = "default" /* Default */;
4009
+ if (connection.type === "success" || connection.type === "failure") {
4010
+ edgeType = "conditional" /* Conditional */;
4011
+ }
4012
+ return {
4013
+ id: connection.id,
4014
+ source: sourceStepId,
4015
+ target: targetStepId,
4016
+ sourcePort,
4017
+ targetPort,
4018
+ type: edgeType,
4019
+ label: connection.label,
4020
+ selected: false,
4021
+ animated: false,
4022
+ createdAt: new Date().toISOString()
4023
+ };
4024
+ }
4025
+ function generateConnectionsFromSteps(steps) {
4026
+ const connections = [];
4027
+ const sortedSteps = [...steps].sort((a, b) => a.step_count - b.step_count);
4028
+ for (let i = 0;i < sortedSteps.length - 1; i++) {
4029
+ const sourceStep = sortedSteps[i];
4030
+ const targetStep = sortedSteps[i + 1];
4031
+ connections.push({
4032
+ id: `${sourceStep.id}-${targetStep.id}`,
4033
+ source_step_id: sourceStep.id,
4034
+ target_step_id: targetStep.id,
4035
+ source_port: `${sourceStep.id}-output`,
4036
+ target_port: `${targetStep.id}-input`,
4037
+ type: "default"
4038
+ });
4039
+ }
4040
+ return connections;
4041
+ }
4042
+ function getIconForStepType(type) {
4043
+ const iconMap = {
4044
+ trigger: "PlayOutline",
4045
+ transform: "Transform",
4046
+ action: "Application",
4047
+ condition: "DecisionTree",
4048
+ loop: "Repeat"
4049
+ };
4050
+ return iconMap[type] || "Application";
4051
+ }
4052
+ function transformFlowToWorkflow(flow) {
4053
+ const flatWorkflow = flattenNestedWorkflow(flow.workflow);
4054
+ const nodes = flatWorkflow.steps.map((step) => transformStepToNode(step));
4055
+ let connections = flatWorkflow.connections;
4056
+ if (connections === undefined || connections === null) {
4057
+ connections = generateConnectionsFromSteps(flatWorkflow.steps);
4058
+ } else {
4059
+ connections = connections || [];
4060
+ }
4061
+ const edges = connections.map((conn, index) => {
4062
+ if (!conn.id) {
4063
+ conn.id = `edge-${conn.source_step_id}-${conn.target_step_id}-${index}`;
4064
+ }
4065
+ return transformConnectionToEdge(conn);
4066
+ });
4067
+ edges.forEach((edge) => {
4068
+ const sourceNode = nodes.find((n) => n.id === edge.source);
4069
+ const targetNode = nodes.find((n) => n.id === edge.target);
4070
+ if (sourceNode) {
4071
+ const port = sourceNode.ports.output.find((p) => p.id === edge.sourcePort);
4072
+ if (port)
4073
+ port.connected = true;
4074
+ }
4075
+ if (targetNode) {
4076
+ const port = targetNode.ports.input.find((p) => p.id === edge.targetPort);
4077
+ if (port)
4078
+ port.connected = true;
4079
+ }
4080
+ });
4081
+ return {
4082
+ id: flow.workflow.id,
4083
+ name: flow.workflow.name,
4084
+ description: flow.workflow.description,
4085
+ nodes,
4086
+ edges,
4087
+ workflowHistory: flow.workflowHistory || []
4088
+ };
4089
+ }
4090
+ function validateFlowData(flow) {
4091
+ if (!flow || typeof flow !== "object")
4092
+ return false;
4093
+ const f = flow;
4094
+ return typeof f.id === "string" && typeof f.name === "string" && f.workflow !== undefined && typeof f.workflow === "object" && f.workflow !== null && Array.isArray(f.workflow.steps);
4095
+ }