@octaviaflow/flow-rules 0.1.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.
Files changed (146) hide show
  1. package/README.md +96 -0
  2. package/dist/catalog/actions/console-log/config.d.ts +58 -0
  3. package/dist/catalog/actions/console-log/config.js +70 -0
  4. package/dist/catalog/actions/console-log/index.d.ts +7 -0
  5. package/dist/catalog/actions/console-log/index.js +89 -0
  6. package/dist/catalog/actions/delay/config.d.ts +50 -0
  7. package/dist/catalog/actions/delay/config.js +79 -0
  8. package/dist/catalog/actions/delay/index.d.ts +7 -0
  9. package/dist/catalog/actions/delay/index.js +71 -0
  10. package/dist/catalog/actions/delay/migrate.d.ts +18 -0
  11. package/dist/catalog/actions/delay/migrate.js +38 -0
  12. package/dist/catalog/actions/delay/types.d.ts +58 -0
  13. package/dist/catalog/actions/delay/types.js +17 -0
  14. package/dist/catalog/actions/http-request/config.d.ts +114 -0
  15. package/dist/catalog/actions/http-request/config.js +111 -0
  16. package/dist/catalog/actions/http-request/index.d.ts +7 -0
  17. package/dist/catalog/actions/http-request/index.js +223 -0
  18. package/dist/catalog/ai/ai-agent/index.d.ts +12 -0
  19. package/dist/catalog/ai/ai-agent/index.js +72 -0
  20. package/dist/catalog/ai/idp-extract/index.d.ts +18 -0
  21. package/dist/catalog/ai/idp-extract/index.js +90 -0
  22. package/dist/catalog/api/graphql-query/config.d.ts +36 -0
  23. package/dist/catalog/api/graphql-query/config.js +31 -0
  24. package/dist/catalog/api/graphql-query/index.d.ts +7 -0
  25. package/dist/catalog/api/graphql-query/index.js +75 -0
  26. package/dist/catalog/communication/email-send/config.d.ts +80 -0
  27. package/dist/catalog/communication/email-send/config.js +80 -0
  28. package/dist/catalog/communication/email-send/index.d.ts +11 -0
  29. package/dist/catalog/communication/email-send/index.js +152 -0
  30. package/dist/catalog/communication/google-chat/config.d.ts +45 -0
  31. package/dist/catalog/communication/google-chat/config.js +28 -0
  32. package/dist/catalog/communication/google-chat/index.d.ts +5 -0
  33. package/dist/catalog/communication/google-chat/index.js +36 -0
  34. package/dist/catalog/communication/slack-message/config.d.ts +47 -0
  35. package/dist/catalog/communication/slack-message/config.js +36 -0
  36. package/dist/catalog/communication/slack-message/index.d.ts +5 -0
  37. package/dist/catalog/communication/slack-message/index.js +37 -0
  38. package/dist/catalog/communication/teams-message/config.d.ts +48 -0
  39. package/dist/catalog/communication/teams-message/config.js +29 -0
  40. package/dist/catalog/communication/teams-message/index.d.ts +5 -0
  41. package/dist/catalog/communication/teams-message/index.js +39 -0
  42. package/dist/catalog/communication/webhook-call/config.d.ts +36 -0
  43. package/dist/catalog/communication/webhook-call/config.js +31 -0
  44. package/dist/catalog/communication/webhook-call/index.d.ts +5 -0
  45. package/dist/catalog/communication/webhook-call/index.js +43 -0
  46. package/dist/catalog/communication/whatsapp-send/config.d.ts +23 -0
  47. package/dist/catalog/communication/whatsapp-send/config.js +36 -0
  48. package/dist/catalog/communication/whatsapp-send/index.d.ts +15 -0
  49. package/dist/catalog/communication/whatsapp-send/index.js +57 -0
  50. package/dist/catalog/general/query/config.d.ts +36 -0
  51. package/dist/catalog/general/query/config.js +257 -0
  52. package/dist/catalog/general/query/index.d.ts +11 -0
  53. package/dist/catalog/general/query/index.js +271 -0
  54. package/dist/catalog/general/query/types.d.ts +205 -0
  55. package/dist/catalog/general/query/types.js +82 -0
  56. package/dist/catalog/general/transform/config.d.ts +117 -0
  57. package/dist/catalog/general/transform/config.js +95 -0
  58. package/dist/catalog/general/transform/index.d.ts +8 -0
  59. package/dist/catalog/general/transform/index.js +63 -0
  60. package/dist/catalog/index.d.ts +57 -0
  61. package/dist/catalog/index.js +168 -0
  62. package/dist/catalog/logic/condition/config.d.ts +54 -0
  63. package/dist/catalog/logic/condition/config.js +93 -0
  64. package/dist/catalog/logic/condition/index.d.ts +7 -0
  65. package/dist/catalog/logic/condition/index.js +64 -0
  66. package/dist/catalog/logic/for-each/config.d.ts +100 -0
  67. package/dist/catalog/logic/for-each/config.js +75 -0
  68. package/dist/catalog/logic/for-each/index.d.ts +7 -0
  69. package/dist/catalog/logic/for-each/index.js +92 -0
  70. package/dist/catalog/logic/for-each/pathOptions.d.ts +62 -0
  71. package/dist/catalog/logic/for-each/pathOptions.js +151 -0
  72. package/dist/catalog/logic/group/index.d.ts +15 -0
  73. package/dist/catalog/logic/group/index.js +46 -0
  74. package/dist/catalog/policies.d.ts +75 -0
  75. package/dist/catalog/policies.js +62 -0
  76. package/dist/catalog/storage/csv-action/index.d.ts +2 -0
  77. package/dist/catalog/storage/csv-action/index.js +38 -0
  78. package/dist/catalog/storage/dropbox-action/index.d.ts +2 -0
  79. package/dist/catalog/storage/dropbox-action/index.js +33 -0
  80. package/dist/catalog/storage/excel-action/index.d.ts +2 -0
  81. package/dist/catalog/storage/excel-action/index.js +32 -0
  82. package/dist/catalog/storage/file-action/index.d.ts +2 -0
  83. package/dist/catalog/storage/file-action/index.js +119 -0
  84. package/dist/catalog/storage/file-operation/config.d.ts +48 -0
  85. package/dist/catalog/storage/file-operation/config.js +45 -0
  86. package/dist/catalog/storage/file-operation/index.d.ts +8 -0
  87. package/dist/catalog/storage/file-operation/index.js +111 -0
  88. package/dist/catalog/storage/ftp-action/index.d.ts +2 -0
  89. package/dist/catalog/storage/ftp-action/index.js +33 -0
  90. package/dist/catalog/storage/google-drive-action/index.d.ts +2 -0
  91. package/dist/catalog/storage/google-drive-action/index.js +38 -0
  92. package/dist/catalog/storage/json-action/index.d.ts +2 -0
  93. package/dist/catalog/storage/json-action/index.js +31 -0
  94. package/dist/catalog/storage/onedrive-action/index.d.ts +2 -0
  95. package/dist/catalog/storage/onedrive-action/index.js +33 -0
  96. package/dist/catalog/storage/s3-action/index.d.ts +2 -0
  97. package/dist/catalog/storage/s3-action/index.js +36 -0
  98. package/dist/catalog/storage/storage-action/index.d.ts +13 -0
  99. package/dist/catalog/storage/storage-action/index.js +72 -0
  100. package/dist/catalog/storage/storageCapabilities.d.ts +57 -0
  101. package/dist/catalog/storage/storageCapabilities.js +207 -0
  102. package/dist/catalog/storage/xml-action/index.d.ts +2 -0
  103. package/dist/catalog/storage/xml-action/index.js +31 -0
  104. package/dist/catalog/transforms/format/config.d.ts +23 -0
  105. package/dist/catalog/transforms/format/config.js +19 -0
  106. package/dist/catalog/transforms/format/index.d.ts +5 -0
  107. package/dist/catalog/transforms/format/index.js +39 -0
  108. package/dist/catalog/triggers/connector-trigger/index.d.ts +7 -0
  109. package/dist/catalog/triggers/connector-trigger/index.js +72 -0
  110. package/dist/catalog/triggers/manual-trigger/config.d.ts +40 -0
  111. package/dist/catalog/triggers/manual-trigger/config.js +60 -0
  112. package/dist/catalog/triggers/manual-trigger/index.d.ts +10 -0
  113. package/dist/catalog/triggers/manual-trigger/index.js +74 -0
  114. package/dist/catalog/triggers/schedule-trigger/config.d.ts +42 -0
  115. package/dist/catalog/triggers/schedule-trigger/config.js +42 -0
  116. package/dist/catalog/triggers/schedule-trigger/index.d.ts +7 -0
  117. package/dist/catalog/triggers/schedule-trigger/index.js +102 -0
  118. package/dist/catalog/triggers/webhook-trigger/config.d.ts +31 -0
  119. package/dist/catalog/triggers/webhook-trigger/config.js +27 -0
  120. package/dist/catalog/triggers/webhook-trigger/index.d.ts +7 -0
  121. package/dist/catalog/triggers/webhook-trigger/index.js +89 -0
  122. package/dist/catalog/types.d.ts +360 -0
  123. package/dist/catalog/types.js +135 -0
  124. package/dist/catalog/utility/debug/config.d.ts +72 -0
  125. package/dist/catalog/utility/debug/config.js +90 -0
  126. package/dist/catalog/utility/debug/index.d.ts +11 -0
  127. package/dist/catalog/utility/debug/index.js +38 -0
  128. package/dist/catalog/utility/error/config.d.ts +26 -0
  129. package/dist/catalog/utility/error/config.js +25 -0
  130. package/dist/catalog/utility/error/index.d.ts +7 -0
  131. package/dist/catalog/utility/error/index.js +46 -0
  132. package/dist/catalog/utility/variables/config.d.ts +76 -0
  133. package/dist/catalog/utility/variables/config.js +70 -0
  134. package/dist/catalog/utility/variables/index.d.ts +13 -0
  135. package/dist/catalog/utility/variables/index.js +40 -0
  136. package/dist/catalog/workflow.d.ts +308 -0
  137. package/dist/catalog/workflow.js +25 -0
  138. package/dist/ids.d.ts +31 -0
  139. package/dist/ids.js +53 -0
  140. package/dist/index.d.ts +25 -0
  141. package/dist/index.js +28 -0
  142. package/dist/rules/nodeConfigStatus.d.ts +33 -0
  143. package/dist/rules/nodeConfigStatus.js +217 -0
  144. package/dist/rules/workflowValidator.d.ts +53 -0
  145. package/dist/rules/workflowValidator.js +358 -0
  146. package/package.json +41 -0
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Actions Registry
3
+ *
4
+ * Central registry for all built-in actions
5
+ * Each action is self-contained with its own configuration, UI, and metadata
6
+ */
7
+ import { ActionCategory } from './types';
8
+ // Trigger actions
9
+ import { manualTriggerDefinition } from './triggers/manual-trigger';
10
+ import { scheduleTriggerDefinition } from './triggers/schedule-trigger';
11
+ import { webhookTriggerDefinition } from './triggers/webhook-trigger';
12
+ import { connectorTriggerDefinition } from './triggers/connector-trigger';
13
+ // Action actions
14
+ import { httpRequestDefinition } from './actions/http-request';
15
+ import { consoleLogDefinition } from './actions/console-log';
16
+ import { delayDefinition } from './actions/delay';
17
+ // Logic actions
18
+ import { conditionDefinition } from './logic/condition';
19
+ import { forEachDefinition } from './logic/for-each';
20
+ import { groupDefinition } from './logic/group';
21
+ // Transform actions
22
+ // General actions (work across all platforms)
23
+ import { queryDefinition } from './general/query';
24
+ import { transformDefinition } from './general/transform';
25
+ // `data_replication` was removed — it now lives as its own platform
26
+ //. Workflows
27
+ // that referenced it will fail with `unknown_action_type`; there is
28
+ // no in-place migration by design.
29
+ // Storage / File actions
30
+ import { csvActionDefinition } from './storage/csv-action';
31
+ import { jsonActionDefinition } from './storage/json-action';
32
+ import { xmlActionDefinition } from './storage/xml-action';
33
+ import { excelActionDefinition } from './storage/excel-action';
34
+ import { s3ActionDefinition } from './storage/s3-action';
35
+ import { ftpActionDefinition } from './storage/ftp-action';
36
+ import { googleDriveActionDefinition } from './storage/google-drive-action';
37
+ import { dropboxActionDefinition } from './storage/dropbox-action';
38
+ import { onedriveActionDefinition } from './storage/onedrive-action';
39
+ import { storageActionDefinition } from './storage/storage-action';
40
+ // Communication actions
41
+ import { emailDefinition } from './communication/email-send';
42
+ import { slackMessageDefinition } from './communication/slack-message';
43
+ import { whatsappSendDefinition } from './communication/whatsapp-send';
44
+ import { teamsMessageDefinition } from './communication/teams-message';
45
+ import { googleChatDefinition } from './communication/google-chat';
46
+ import { webhookCallDefinition } from './communication/webhook-call';
47
+ // Utility actions
48
+ import { debugDefinition } from './utility/debug';
49
+ import { errorDefinition } from './utility/error';
50
+ import { variablesDefinition } from './utility/variables';
51
+ // API actions
52
+ import { graphqlQueryDefinition } from './api/graphql-query';
53
+ // AI actions
54
+ //
55
+ // The only generic AI workflow action is `ai_agent` — a first-class Agent
56
+ // reference (DEV-85, see the platform documentation).
57
+ // The legacy `llm_chat` action was removed in DEV-93; any workflows that
58
+ // referenced it fail with `unknown_action_type` (no migration, per user direction).
59
+ //
60
+ // Other removals (DEV-14 reshape):
61
+ // - llm_completion, classification, sentiment, summarization, translation,
62
+ // extraction, ml_inference — prompt-template wrappers with no engine impl.
63
+ // - embedding, vector_search — replaced by the Knowledge Bases app (DEV-16).
64
+ // - image_analysis, image_generation, speech_to_text, text_to_speech —
65
+ // niche; users hit the provider through HTTP Request.
66
+ //
67
+ // Document parsing belongs to the IDP app,
68
+ // not a workflow action — except for `idp_extract` which orchestrates the IDP
69
+ // service from inside a workflow.
70
+ import { aiAgentDefinition } from './ai/ai-agent';
71
+ import { idpExtractDefinition } from './ai/idp-extract';
72
+ /**
73
+ * Registry of all available actions
74
+ * Organized by category for easy lookup and management
75
+ */
76
+ export const actionsRegistry = {
77
+ [ActionCategory.Trigger]: {
78
+ manual_trigger: manualTriggerDefinition,
79
+ schedule_trigger: scheduleTriggerDefinition,
80
+ webhook_trigger: webhookTriggerDefinition,
81
+ connector_trigger: connectorTriggerDefinition,
82
+ },
83
+ [ActionCategory.Action]: {
84
+ http_request: httpRequestDefinition,
85
+ console_log: consoleLogDefinition,
86
+ delay: delayDefinition,
87
+ query: queryDefinition,
88
+ transform: transformDefinition,
89
+ },
90
+ [ActionCategory.Logic]: {
91
+ condition: conditionDefinition,
92
+ for_each: forEachDefinition,
93
+ group: groupDefinition,
94
+ },
95
+ [ActionCategory.Transform]: {
96
+ // Format action will be added when implemented
97
+ },
98
+ [ActionCategory.Database]: {},
99
+ [ActionCategory.Storage]: {
100
+ csv_action: csvActionDefinition,
101
+ json_action: jsonActionDefinition,
102
+ excel_action: excelActionDefinition,
103
+ xml_action: xmlActionDefinition,
104
+ // Unified Cloud Storage action — the one users add. The five per-provider
105
+ // actions below are kept registered (so existing nodes still resolve +
106
+ // edit + execute) but marked deprecated → hidden from the add-palette.
107
+ storage_action: storageActionDefinition,
108
+ s3_action: { ...s3ActionDefinition, deprecated: true, replacedBy: 'storage_action' },
109
+ ftp_action: { ...ftpActionDefinition, deprecated: true, replacedBy: 'storage_action' },
110
+ google_drive_action: { ...googleDriveActionDefinition, deprecated: true, replacedBy: 'storage_action' },
111
+ dropbox_action: { ...dropboxActionDefinition, deprecated: true, replacedBy: 'storage_action' },
112
+ onedrive_action: { ...onedriveActionDefinition, deprecated: true, replacedBy: 'storage_action' },
113
+ },
114
+ [ActionCategory.Communication]: {
115
+ email: emailDefinition,
116
+ slack_message: slackMessageDefinition,
117
+ whatsapp_send: whatsappSendDefinition,
118
+ teams_message: teamsMessageDefinition,
119
+ google_chat: googleChatDefinition,
120
+ webhook_call: webhookCallDefinition,
121
+ },
122
+ [ActionCategory.Utility]: {
123
+ variables: variablesDefinition,
124
+ debug: debugDefinition,
125
+ },
126
+ [ActionCategory.Ecommerce]: {},
127
+ [ActionCategory.API]: {
128
+ // GraphQL action will be added when implemented
129
+ },
130
+ [ActionCategory.AI]: {
131
+ ai_agent: aiAgentDefinition,
132
+ idp_extract: idpExtractDefinition,
133
+ },
134
+ };
135
+ /**
136
+ * Get all actions as a flat array
137
+ */
138
+ export const getAllActions = () => {
139
+ const allActions = [];
140
+ for (const category of Object.values(actionsRegistry)) {
141
+ allActions.push(...Object.values(category).filter((action) => action !== undefined));
142
+ }
143
+ return allActions;
144
+ };
145
+ /**
146
+ * Get action by ID
147
+ */
148
+ export const getActionById = (id) => {
149
+ for (const category of Object.values(actionsRegistry)) {
150
+ for (const action of Object.values(category)) {
151
+ if (action.id === id) {
152
+ return action;
153
+ }
154
+ }
155
+ }
156
+ return undefined;
157
+ };
158
+ /**
159
+ * Get actions by category
160
+ */
161
+ export const getActionsByCategory = (category) => {
162
+ const categoryActions = actionsRegistry[category];
163
+ if (!categoryActions)
164
+ return [];
165
+ return Object.values(categoryActions);
166
+ };
167
+ // Export individual action definitions for direct imports
168
+ export { csvActionDefinition, jsonActionDefinition, xmlActionDefinition, excelActionDefinition, s3ActionDefinition, ftpActionDefinition, googleDriveActionDefinition, dropboxActionDefinition, onedriveActionDefinition, manualTriggerDefinition, scheduleTriggerDefinition, webhookTriggerDefinition, httpRequestDefinition, consoleLogDefinition, delayDefinition, conditionDefinition, forEachDefinition, groupDefinition, queryDefinition, transformDefinition, debugDefinition, errorDefinition, variablesDefinition, graphqlQueryDefinition, emailDefinition, slackMessageDefinition, whatsappSendDefinition, teamsMessageDefinition, googleChatDefinition, webhookCallDefinition, aiAgentDefinition, idpExtractDefinition, };
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Condition Configuration
3
+ *
4
+ * Defines the configuration structure and default values for the Condition action.
5
+ * Supports two modes:
6
+ * - visual: a list of field/operator/value filter rows joined by AND/OR
7
+ * - expression: a raw JavaScript expression
8
+ */
9
+ export type ConditionOperator = 'equals' | 'not_equals' | 'greater_than' | 'greater_than_equals' | 'less_than' | 'less_than_equals' | 'like' | 'is_null' | 'is_not_null' | 'is_empty' | 'contains' | 'starts_with' | 'ends_with';
10
+ export declare const CONDITION_OPERATORS: {
11
+ id: ConditionOperator;
12
+ label: string;
13
+ needsValue: boolean;
14
+ }[];
15
+ export interface ConditionFilter {
16
+ id: string;
17
+ field: string;
18
+ operator: ConditionOperator;
19
+ value: string;
20
+ logicalOperator?: 'and' | 'or';
21
+ }
22
+ export interface ConditionConfigType {
23
+ mode: 'visual' | 'expression';
24
+ filters: ConditionFilter[];
25
+ condition: string;
26
+ /** Auto-generated display name for the node */
27
+ name?: string;
28
+ }
29
+ export declare const ConditionConfig: {
30
+ defaults: ConditionConfigType;
31
+ schema: {
32
+ mode: {
33
+ type: string;
34
+ required: boolean;
35
+ };
36
+ filters: {
37
+ type: string;
38
+ required: boolean;
39
+ };
40
+ condition: {
41
+ type: string;
42
+ required: boolean;
43
+ };
44
+ };
45
+ validate: (config: Partial<ConditionConfigType>) => {
46
+ valid: boolean;
47
+ errors: string[];
48
+ };
49
+ merge: (userConfig: Partial<ConditionConfigType>) => ConditionConfigType;
50
+ /** Build a human-readable summary from visual filters */
51
+ generateName: (filters: ConditionFilter[]) => string;
52
+ getLabel: (config: ConditionConfigType) => string;
53
+ createFilterId: () => string;
54
+ };
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Condition Configuration
3
+ *
4
+ * Defines the configuration structure and default values for the Condition action.
5
+ * Supports two modes:
6
+ * - visual: a list of field/operator/value filter rows joined by AND/OR
7
+ * - expression: a raw JavaScript expression
8
+ */
9
+ import { randomSuffix } from '../../../ids';
10
+ export const CONDITION_OPERATORS = [
11
+ { id: 'equals', label: 'Equals', needsValue: true },
12
+ { id: 'not_equals', label: 'Not Equals', needsValue: true },
13
+ { id: 'greater_than', label: 'Greater Than', needsValue: true },
14
+ { id: 'greater_than_equals', label: 'Greater Than or Equals', needsValue: true },
15
+ { id: 'less_than', label: 'Less Than', needsValue: true },
16
+ { id: 'less_than_equals', label: 'Less Than or Equals', needsValue: true },
17
+ { id: 'like', label: 'Like', needsValue: true },
18
+ { id: 'contains', label: 'Contains', needsValue: true },
19
+ { id: 'starts_with', label: 'Starts With', needsValue: true },
20
+ { id: 'ends_with', label: 'Ends With', needsValue: true },
21
+ { id: 'is_null', label: 'Is Null', needsValue: false },
22
+ { id: 'is_not_null', label: 'Is Not Null', needsValue: false },
23
+ { id: 'is_empty', label: 'Is Empty', needsValue: false },
24
+ ];
25
+ export const ConditionConfig = {
26
+ defaults: {
27
+ mode: 'visual',
28
+ filters: [],
29
+ condition: '',
30
+ },
31
+ schema: {
32
+ mode: { type: 'select', required: true },
33
+ filters: { type: 'array', required: false },
34
+ condition: { type: 'expression', required: false },
35
+ },
36
+ validate: (config) => {
37
+ const errors = [];
38
+ if (config.mode === 'expression') {
39
+ if (!config.condition) {
40
+ errors.push('Condition expression is required');
41
+ }
42
+ else {
43
+ try {
44
+ new Function(`return ${config.condition}`);
45
+ }
46
+ catch (e) {
47
+ errors.push(`Invalid expression: ${e instanceof Error ? e.message : 'Unknown error'}`);
48
+ }
49
+ }
50
+ }
51
+ else {
52
+ // Visual mode
53
+ if (!config.filters || config.filters.length === 0) {
54
+ errors.push('At least one condition filter is required');
55
+ }
56
+ else {
57
+ config.filters.forEach((f, i) => {
58
+ if (!f.field)
59
+ errors.push(`Filter ${i + 1}: Field is required`);
60
+ if (!f.operator)
61
+ errors.push(`Filter ${i + 1}: Operator is required`);
62
+ const opDef = CONDITION_OPERATORS.find(o => o.id === f.operator);
63
+ if (opDef?.needsValue && !f.value) {
64
+ errors.push(`Filter ${i + 1}: Value is required`);
65
+ }
66
+ });
67
+ }
68
+ }
69
+ return { valid: errors.length === 0, errors };
70
+ },
71
+ merge: (userConfig) => {
72
+ return { ...ConditionConfig.defaults, ...userConfig };
73
+ },
74
+ /** Build a human-readable summary from visual filters */
75
+ generateName: (filters) => {
76
+ if (filters.length === 0)
77
+ return 'If …';
78
+ const parts = filters.map((f, i) => {
79
+ const opLabel = CONDITION_OPERATORS.find(o => o.id === f.operator)?.label || f.operator;
80
+ const base = `${f.field || '?'} ${opLabel}${f.value ? ` ${f.value}` : ''}`;
81
+ if (i === 0)
82
+ return base;
83
+ return `${(f.logicalOperator || 'and').toUpperCase()} ${base}`;
84
+ });
85
+ return `If ${parts.join(' ')}`;
86
+ },
87
+ getLabel: (config) => {
88
+ if (config.mode === 'expression')
89
+ return `If ${config.condition || '…'}`;
90
+ return ConditionConfig.generateName(config.filters);
91
+ },
92
+ createFilterId: () => `cond_${Date.now()}_${randomSuffix(5)}`,
93
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Condition Action
3
+ *
4
+ * Branch workflow execution based on conditions
5
+ */
6
+ import { ActionDefinition } from '../../types';
7
+ export declare const conditionDefinition: ActionDefinition;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Condition Action
3
+ *
4
+ * Branch workflow execution based on conditions
5
+ */
6
+ import { ActionCategory, ActionType, ActionStatus, FieldType } from '../../types';
7
+ export const conditionDefinition = {
8
+ id: 'condition',
9
+ name: 'Condition',
10
+ description: 'Branch workflow execution based on conditions',
11
+ category: ActionCategory.Logic,
12
+ type: ActionType.Condition,
13
+ tags: ['logic', 'condition', 'branching', 'built-in'],
14
+ status: ActionStatus.Stable,
15
+ icon: 'DecisionTree',
16
+ color: '#f1c21b',
17
+ // NOTE: the Condition node renders via its custom ConditionConfigPanel
18
+ // (visual builder only), so these fallback fields aren't shown in the
19
+ // editor. Kept minimal + consistent with the visual-only authoring model.
20
+ inputSchema: {
21
+ fields: [
22
+ {
23
+ key: 'mode',
24
+ label: 'Mode',
25
+ type: FieldType.String,
26
+ description: 'Authoring mode (visual builder).',
27
+ defaultValue: 'visual',
28
+ validation: { required: true },
29
+ },
30
+ {
31
+ key: 'filters',
32
+ label: 'Condition Filters',
33
+ type: FieldType.Array,
34
+ description: 'Visual condition filters (field / operator / value rows)',
35
+ validation: { required: false },
36
+ },
37
+ ],
38
+ },
39
+ outputSchema: {
40
+ type: 'object',
41
+ properties: [
42
+ {
43
+ key: 'result',
44
+ type: FieldType.Boolean,
45
+ description: 'Result of the condition evaluation',
46
+ },
47
+ {
48
+ key: 'branch',
49
+ type: FieldType.String,
50
+ description: 'Which branch was taken (true or false)',
51
+ },
52
+ ],
53
+ sampleOutput: {
54
+ result: true,
55
+ branch: 'true',
56
+ },
57
+ },
58
+ version: '1.0.0',
59
+ createdAt: '2025-01-01T00:00:00Z',
60
+ updatedAt: '2025-12-15T00:00:00Z',
61
+ createdBy: 'system',
62
+ isOfficial: true,
63
+ testable: true,
64
+ };
@@ -0,0 +1,100 @@
1
+ /**
2
+ * ForEach Configuration
3
+ *
4
+ * A general, mode-based iteration primitive for ETL + agentic-ETL flows.
5
+ * The iteration mode is the core config axis; execution, resilience and
6
+ * output controls layer on top of any mode.
7
+ */
8
+ export type ForEachMode = 'records' | 'fields' | 'range' | 'nested' | 'batch' | 'cursor' | 'while' | 'array';
9
+ export interface ForEachConfigType {
10
+ /** Variable name exposed for each item (default: "item"). */
11
+ itemVariable: string;
12
+ /** Variable name exposed for the index (default: "index"). */
13
+ indexVariable: string;
14
+ /** Dot-path to the array in upstream data (e.g. "Account", "data.items"). */
15
+ arrayPath: string;
16
+ /** What to iterate over. Defaults to 'records'. */
17
+ iterationMode?: ForEachMode;
18
+ /** range mode — number of iterations (0..count-1). */
19
+ count?: number;
20
+ /** nested mode — dot-path to the sub-array inside each record. */
21
+ nestedPath?: string;
22
+ /** fields mode — allow-list of field names. Empty/absent → every field. */
23
+ fields?: string[];
24
+ /** sequential (default) or parallel. */
25
+ concurrency?: 'sequential' | 'parallel';
26
+ /** parallel cap (default 5). Never unbounded. */
27
+ maxConcurrency?: number;
28
+ /** batch mode — chunk size. */
29
+ batchSize: number;
30
+ /** throttle: max iteration launches per minute. */
31
+ rateLimitPerMinute?: number;
32
+ /** agentic throttle: max estimated tokens per minute. */
33
+ tokensPerMinute?: number;
34
+ /** continue past per-item failures (maps to onItemError: 'continue'). */
35
+ continueOnError: boolean;
36
+ /** explicit per-item failure policy (overrides continueOnError when set). */
37
+ onItemError?: 'fail-fast' | 'continue';
38
+ /** per-item retries (default 0). */
39
+ retryCount?: number;
40
+ /** base backoff between retries, doubled each attempt (default 250ms). */
41
+ retryBackoffMs?: number;
42
+ /** per-item timeout in ms (0/absent = none). */
43
+ itemTimeoutMs?: number;
44
+ /** abort once failed/processed exceeds this % (0-100). */
45
+ toleratedFailurePercentage?: number;
46
+ /** abort once this many items have failed. */
47
+ toleratedFailureCount?: number;
48
+ /** hard runaway cap for cursor/while (default 10000). */
49
+ maxIterations?: number;
50
+ /** dot-path on each item; items whose key was already seen are skipped. */
51
+ idempotencyKeyPath?: string;
52
+ /** how per-item results are collected (default 'array'). */
53
+ collect?: 'array' | 'none' | 'groupBy' | 'reduce';
54
+ /** groupBy — dot-path on each result used as the group key. */
55
+ groupByPath?: string;
56
+ /** reduce — built-in reduction over successful results. */
57
+ reduceOp?: 'sum' | 'count' | 'concat' | 'merge';
58
+ /** reduce — dot-path on each result to feed the reduction. */
59
+ reducePath?: string;
60
+ /** Per-item source schema captured for the FieldMapper (records/fields modes). */
61
+ _outputSchema?: unknown;
62
+ /** Auto-generated display name for the node. */
63
+ name?: string;
64
+ }
65
+ export declare const ForEachConfig: {
66
+ defaults: ForEachConfigType;
67
+ schema: {
68
+ arrayPath: {
69
+ type: string;
70
+ required: boolean;
71
+ };
72
+ iterationMode: {
73
+ type: string;
74
+ required: boolean;
75
+ };
76
+ itemVariable: {
77
+ type: string;
78
+ required: boolean;
79
+ };
80
+ indexVariable: {
81
+ type: string;
82
+ required: boolean;
83
+ };
84
+ batchSize: {
85
+ type: string;
86
+ required: boolean;
87
+ };
88
+ continueOnError: {
89
+ type: string;
90
+ required: boolean;
91
+ };
92
+ };
93
+ validate: (config: Partial<ForEachConfigType>) => {
94
+ valid: boolean;
95
+ errors: string[];
96
+ };
97
+ merge: (userConfig: Partial<ForEachConfigType>) => ForEachConfigType;
98
+ getLabel: (config: ForEachConfigType) => string;
99
+ generateName: (arrayPath: string) => string;
100
+ };
@@ -0,0 +1,75 @@
1
+ /**
2
+ * ForEach Configuration
3
+ *
4
+ * A general, mode-based iteration primitive for ETL + agentic-ETL flows.
5
+ * The iteration mode is the core config axis; execution, resilience and
6
+ * output controls layer on top of any mode.
7
+ */
8
+ /** Modes that don't iterate an upstream array (no arrayPath required). */
9
+ const SOURCELESS_MODES = new Set(['range', 'cursor', 'while']);
10
+ export const ForEachConfig = {
11
+ defaults: {
12
+ arrayPath: '',
13
+ iterationMode: 'records',
14
+ itemVariable: 'item',
15
+ indexVariable: 'index',
16
+ batchSize: 0,
17
+ continueOnError: false,
18
+ concurrency: 'sequential',
19
+ collect: 'array',
20
+ },
21
+ schema: {
22
+ arrayPath: { type: 'select', required: false },
23
+ iterationMode: { type: 'select', required: false },
24
+ itemVariable: { type: 'string', required: true },
25
+ indexVariable: { type: 'string', required: false },
26
+ batchSize: { type: 'number', required: false },
27
+ continueOnError: { type: 'boolean', required: false },
28
+ },
29
+ validate: (config) => {
30
+ const errors = [];
31
+ const mode = (config.iterationMode || 'records');
32
+ if (mode === 'range') {
33
+ if (!config.count || config.count <= 0) {
34
+ errors.push('Range mode needs a positive iteration count');
35
+ }
36
+ }
37
+ else if (mode === 'nested') {
38
+ if (!config.arrayPath)
39
+ errors.push('Select the records to drill into');
40
+ if (!config.nestedPath)
41
+ errors.push('Nested mode needs the sub-array path to iterate (e.g. "lineItems")');
42
+ }
43
+ else if (!SOURCELESS_MODES.has(mode)) {
44
+ if (!config.arrayPath) {
45
+ errors.push('Array path is required — select which records to iterate over');
46
+ }
47
+ }
48
+ if (config.concurrency === 'parallel' && config.maxConcurrency !== undefined && config.maxConcurrency < 1) {
49
+ errors.push('Max concurrency must be at least 1');
50
+ }
51
+ if (config.batchSize !== undefined && config.batchSize < 0) {
52
+ errors.push('Batch size must be 0 (all) or a positive number');
53
+ }
54
+ if (config.collect === 'groupBy' && !config.groupByPath) {
55
+ errors.push('Group-by collection needs a field path to group on');
56
+ }
57
+ return { valid: errors.length === 0, errors };
58
+ },
59
+ merge: (userConfig) => {
60
+ return { ...ForEachConfig.defaults, ...userConfig };
61
+ },
62
+ getLabel: (config) => {
63
+ const mode = (config.iterationMode || 'records');
64
+ if (mode === 'range')
65
+ return `ForEach ×${config.count ?? '…'}`;
66
+ if (mode === 'cursor')
67
+ return 'ForEach (paginate)';
68
+ if (mode === 'while')
69
+ return 'ForEach (while)';
70
+ return `ForEach in ${config.arrayPath || '…'}`;
71
+ },
72
+ generateName: (arrayPath) => {
73
+ return `ForEach in ${arrayPath || '…'}`;
74
+ },
75
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * ForEach Action
3
+ *
4
+ * Iterate over array items and execute actions for each
5
+ */
6
+ import { ActionDefinition } from '../../types';
7
+ export declare const forEachDefinition: ActionDefinition;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * ForEach Action
3
+ *
4
+ * Iterate over array items and execute actions for each
5
+ */
6
+ import { ActionCategory, ActionType, ActionStatus, FieldType } from '../../types';
7
+ export const forEachDefinition = {
8
+ id: 'for_each',
9
+ name: 'ForEach',
10
+ description: 'Iterate over array items and execute actions for each',
11
+ category: ActionCategory.Logic,
12
+ type: ActionType.ForEach,
13
+ tags: ['logic', 'loop', 'iteration', 'array', 'built-in'],
14
+ status: ActionStatus.Stable,
15
+ icon: 'Repeat',
16
+ color: '#f1c21b',
17
+ inputSchema: {
18
+ fields: [
19
+ {
20
+ key: 'arrayPath',
21
+ label: 'Records in',
22
+ type: FieldType.Expression,
23
+ description: 'Path to the array to iterate over',
24
+ placeholder: 'e.g., Account, data.items',
25
+ // NOT required (DEV-220 rules-engine parity with config.ts): in
26
+ // records mode ForEach auto-iterates the upstream step's rows when
27
+ // no explicit path is set, and several modes (range/while/…) never
28
+ // use it. The per-mode validate() in config.ts enforces it for the
29
+ // modes that genuinely need it — an unconditional `required` here
30
+ // made the rules engine flag correctly-configured loops.
31
+ validation: { required: false },
32
+ },
33
+ {
34
+ key: 'itemVariable',
35
+ label: 'Item Variable Name',
36
+ type: FieldType.String,
37
+ description: 'Name of the variable for each item',
38
+ defaultValue: 'item',
39
+ validation: { required: true },
40
+ },
41
+ {
42
+ key: 'indexVariable',
43
+ label: 'Index Variable Name',
44
+ type: FieldType.String,
45
+ description: 'Name of the variable for the index',
46
+ defaultValue: 'index',
47
+ validation: { required: false },
48
+ },
49
+ {
50
+ key: 'batchSize',
51
+ label: 'Batch Size',
52
+ type: FieldType.Number,
53
+ description: 'Number of items to process per batch (0 = all at once)',
54
+ defaultValue: 0,
55
+ validation: { required: false },
56
+ },
57
+ {
58
+ key: 'continueOnError',
59
+ label: 'Continue on Error',
60
+ type: FieldType.Boolean,
61
+ description: 'Whether to continue processing remaining items if one fails',
62
+ defaultValue: false,
63
+ validation: { required: false },
64
+ },
65
+ ],
66
+ },
67
+ outputSchema: {
68
+ type: 'object',
69
+ properties: [
70
+ {
71
+ key: 'itemsProcessed',
72
+ type: FieldType.Number,
73
+ description: 'Number of items processed',
74
+ },
75
+ {
76
+ key: 'results',
77
+ type: FieldType.Array,
78
+ description: 'Results from each iteration',
79
+ },
80
+ ],
81
+ sampleOutput: {
82
+ itemsProcessed: 5,
83
+ results: [{ item: 1 }, { item: 2 }],
84
+ },
85
+ },
86
+ version: '1.0.0',
87
+ createdAt: '2025-01-01T00:00:00Z',
88
+ updatedAt: '2025-12-15T00:00:00Z',
89
+ createdBy: 'system',
90
+ isOfficial: true,
91
+ testable: true,
92
+ };