@octaviaflow/flow-rules 0.1.0 → 0.2.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 (74) hide show
  1. package/dist/index.d.ts +6 -0
  2. package/dist/index.js +3010 -28
  3. package/package.json +14 -5
  4. package/dist/catalog/actions/console-log/config.js +0 -70
  5. package/dist/catalog/actions/console-log/index.js +0 -89
  6. package/dist/catalog/actions/delay/config.js +0 -79
  7. package/dist/catalog/actions/delay/index.js +0 -71
  8. package/dist/catalog/actions/delay/migrate.js +0 -38
  9. package/dist/catalog/actions/delay/types.js +0 -17
  10. package/dist/catalog/actions/http-request/config.js +0 -111
  11. package/dist/catalog/actions/http-request/index.js +0 -223
  12. package/dist/catalog/ai/ai-agent/index.js +0 -72
  13. package/dist/catalog/ai/idp-extract/index.js +0 -90
  14. package/dist/catalog/api/graphql-query/config.js +0 -31
  15. package/dist/catalog/api/graphql-query/index.js +0 -75
  16. package/dist/catalog/communication/email-send/config.js +0 -80
  17. package/dist/catalog/communication/email-send/index.js +0 -152
  18. package/dist/catalog/communication/google-chat/config.js +0 -28
  19. package/dist/catalog/communication/google-chat/index.js +0 -36
  20. package/dist/catalog/communication/slack-message/config.js +0 -36
  21. package/dist/catalog/communication/slack-message/index.js +0 -37
  22. package/dist/catalog/communication/teams-message/config.js +0 -29
  23. package/dist/catalog/communication/teams-message/index.js +0 -39
  24. package/dist/catalog/communication/webhook-call/config.js +0 -31
  25. package/dist/catalog/communication/webhook-call/index.js +0 -43
  26. package/dist/catalog/communication/whatsapp-send/config.js +0 -36
  27. package/dist/catalog/communication/whatsapp-send/index.js +0 -57
  28. package/dist/catalog/general/query/config.js +0 -257
  29. package/dist/catalog/general/query/index.js +0 -271
  30. package/dist/catalog/general/query/types.js +0 -82
  31. package/dist/catalog/general/transform/config.js +0 -95
  32. package/dist/catalog/general/transform/index.js +0 -63
  33. package/dist/catalog/index.js +0 -168
  34. package/dist/catalog/logic/condition/config.js +0 -93
  35. package/dist/catalog/logic/condition/index.js +0 -64
  36. package/dist/catalog/logic/for-each/config.js +0 -75
  37. package/dist/catalog/logic/for-each/index.js +0 -92
  38. package/dist/catalog/logic/for-each/pathOptions.js +0 -151
  39. package/dist/catalog/logic/group/index.js +0 -46
  40. package/dist/catalog/policies.js +0 -62
  41. package/dist/catalog/storage/csv-action/index.js +0 -38
  42. package/dist/catalog/storage/dropbox-action/index.js +0 -33
  43. package/dist/catalog/storage/excel-action/index.js +0 -32
  44. package/dist/catalog/storage/file-action/index.js +0 -119
  45. package/dist/catalog/storage/file-operation/config.js +0 -45
  46. package/dist/catalog/storage/file-operation/index.js +0 -111
  47. package/dist/catalog/storage/ftp-action/index.js +0 -33
  48. package/dist/catalog/storage/google-drive-action/index.js +0 -38
  49. package/dist/catalog/storage/json-action/index.js +0 -31
  50. package/dist/catalog/storage/onedrive-action/index.js +0 -33
  51. package/dist/catalog/storage/s3-action/index.js +0 -36
  52. package/dist/catalog/storage/storage-action/index.js +0 -72
  53. package/dist/catalog/storage/storageCapabilities.js +0 -207
  54. package/dist/catalog/storage/xml-action/index.js +0 -31
  55. package/dist/catalog/transforms/format/config.js +0 -19
  56. package/dist/catalog/transforms/format/index.js +0 -39
  57. package/dist/catalog/triggers/connector-trigger/index.js +0 -72
  58. package/dist/catalog/triggers/manual-trigger/config.js +0 -60
  59. package/dist/catalog/triggers/manual-trigger/index.js +0 -74
  60. package/dist/catalog/triggers/schedule-trigger/config.js +0 -42
  61. package/dist/catalog/triggers/schedule-trigger/index.js +0 -102
  62. package/dist/catalog/triggers/webhook-trigger/config.js +0 -27
  63. package/dist/catalog/triggers/webhook-trigger/index.js +0 -89
  64. package/dist/catalog/types.js +0 -135
  65. package/dist/catalog/utility/debug/config.js +0 -90
  66. package/dist/catalog/utility/debug/index.js +0 -38
  67. package/dist/catalog/utility/error/config.js +0 -25
  68. package/dist/catalog/utility/error/index.js +0 -46
  69. package/dist/catalog/utility/variables/config.js +0 -70
  70. package/dist/catalog/utility/variables/index.js +0 -40
  71. package/dist/catalog/workflow.js +0 -25
  72. package/dist/ids.js +0 -53
  73. package/dist/rules/nodeConfigStatus.js +0 -217
  74. package/dist/rules/workflowValidator.js +0 -358
@@ -1,95 +0,0 @@
1
- /**
2
- * Transform Configuration
3
- *
4
- * Configuration for data transformation and field mapping between workflow steps.
5
- * Supports visual field mapping (drag-and-drop) and expression-based transforms.
6
- */
7
- import { randomSuffix } from '../../../ids';
8
- export const TRANSFORM_OPERATIONS = [
9
- { id: 'upsert', label: 'Upsert' },
10
- { id: 'insert', label: 'Insert' },
11
- { id: 'update', label: 'Update' },
12
- { id: 'delete', label: 'Delete' },
13
- ];
14
- /** Database connector IDs that support the database dropdown */
15
- export const DATABASE_CONNECTOR_IDS = new Set(['mongodb', 'postgresql', 'mysql', 'sqlite', 'google_sheets']);
16
- export const TransformConfig = {
17
- defaults: {
18
- name: 'Transform',
19
- operation: 'upsert',
20
- connectorId: '',
21
- database: '',
22
- objectName: '',
23
- mode: 'visual',
24
- mappings: [],
25
- expression: '',
26
- fieldDefaults: {},
27
- upsertMatchKey: '',
28
- sheetHeaders: [],
29
- createTabIfMissing: true,
30
- writeHeaderRow: true,
31
- clearBeforeWrite: false,
32
- sheetCustomLayout: false,
33
- sheetHeaderRow: 1,
34
- sheetColumns: '',
35
- },
36
- schema: {
37
- operation: { type: 'select', required: true },
38
- connectorId: { type: 'connection', required: true },
39
- database: { type: 'text', required: false },
40
- objectName: { type: 'select', required: true },
41
- mode: { type: 'select', required: true },
42
- mappings: { type: 'array', required: false },
43
- expression: { type: 'code', required: false },
44
- },
45
- /** Auto-generate a descriptive name from the 3 dropdown selections */
46
- generateName: (operation, connectorLabel, objectName) => {
47
- const opLabel = TRANSFORM_OPERATIONS.find(o => o.id === operation)?.label || 'Transform';
48
- const target = connectorLabel || 'Target';
49
- const obj = objectName || 'Object';
50
- return `${opLabel} → ${target} · ${obj}`;
51
- },
52
- validate: (config) => {
53
- const errors = [];
54
- if (!config.operation) {
55
- errors.push('Operation is required');
56
- }
57
- if (!config.connectorId) {
58
- errors.push('Target connector is required');
59
- }
60
- if (!config.objectName) {
61
- errors.push('Object (table) is required');
62
- }
63
- // The Visual Field Mapper is the only authoring mode. Legacy steps saved
64
- // in the retired JavaScript-expression mode still execute (the engine keeps
65
- // that path for back-compat), so don't flag them invalid for lacking mappings.
66
- const isLegacyExpression = config.mode === 'expression' && !!config.expression?.trim();
67
- if (!isLegacyExpression) {
68
- if (!config.mappings || config.mappings.length === 0) {
69
- errors.push('At least one field mapping is required');
70
- }
71
- else {
72
- config.mappings.forEach((mapping, index) => {
73
- if (!mapping.sourceField) {
74
- errors.push(`Mapping ${index + 1}: Source field is required`);
75
- }
76
- if (!mapping.targetField) {
77
- errors.push(`Mapping ${index + 1}: Target field is required`);
78
- }
79
- });
80
- }
81
- }
82
- return { valid: errors.length === 0, errors };
83
- },
84
- merge: (userConfig) => {
85
- return { ...TransformConfig.defaults, ...userConfig };
86
- },
87
- getLabel: (config) => {
88
- const count = config.mappings?.length ?? 0;
89
- return `${config.name || 'Transform'} (${count} field${count !== 1 ? 's' : ''})`;
90
- },
91
- /** Generate a unique ID for a new mapping row */
92
- createMappingId: () => {
93
- return `map_${Date.now()}_${randomSuffix(5)}`;
94
- },
95
- };
@@ -1,63 +0,0 @@
1
- /**
2
- * Transform Action
3
- *
4
- * Data transformation action that maps and reshapes data between workflow steps
5
- * using the visual field mapper (drag-and-drop from the upstream schema).
6
- */
7
- import { ActionCategory, ActionType, ActionStatus, FieldType } from '../../types';
8
- export const transformDefinition = {
9
- id: 'transform',
10
- name: 'Transform',
11
- description: 'Map and transform data between workflow steps using the visual field mapper',
12
- category: ActionCategory.Transform,
13
- type: ActionType.Transform,
14
- tags: ['transform', 'mapping', 'data', 'reshape', 'convert', 'built-in'],
15
- status: ActionStatus.Stable,
16
- icon: 'Transform',
17
- color: '#0043ce',
18
- inputSchema: {
19
- fields: [
20
- {
21
- key: 'name',
22
- label: 'Transform Name',
23
- type: FieldType.String,
24
- description: 'A descriptive name for this transform step',
25
- defaultValue: 'Transform',
26
- validation: { required: false },
27
- },
28
- {
29
- key: 'mappings',
30
- label: 'Field Mappings',
31
- type: FieldType.Array,
32
- description: 'Map source fields from upstream nodes to target output fields',
33
- validation: { required: false },
34
- },
35
- ],
36
- },
37
- outputSchema: {
38
- type: 'object',
39
- properties: [
40
- {
41
- key: 'result',
42
- type: FieldType.JSON,
43
- description: 'Transformed data output',
44
- },
45
- {
46
- key: 'mappedFieldCount',
47
- type: FieldType.Number,
48
- description: 'Number of fields that were mapped/transformed',
49
- },
50
- ],
51
- sampleOutput: {
52
- result: { name: 'John Doe', email: 'john@example.com', age: 30 },
53
- mappedFieldCount: 3,
54
- },
55
- dynamic: true,
56
- },
57
- version: '2.0.0',
58
- createdAt: '2025-01-01T00:00:00Z',
59
- updatedAt: '2026-02-13T00:00:00Z',
60
- createdBy: 'system',
61
- isOfficial: true,
62
- testable: true,
63
- };
@@ -1,168 +0,0 @@
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, };
@@ -1,93 +0,0 @@
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
- };
@@ -1,64 +0,0 @@
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
- };
@@ -1,75 +0,0 @@
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
- };
@@ -1,92 +0,0 @@
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
- };