@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
package/README.md ADDED
@@ -0,0 +1,96 @@
1
+ # @octaviaflow/flow-rules
2
+
3
+ The flow **action catalog** and the **rules engine behind Flow Doctor** — the
4
+ two things that decide what a step accepts and whether a flow works.
5
+
6
+ ## Why this exists
7
+
8
+ Both lived in `octaviaflow-ui`, so both were reachable only from a browser.
9
+ That was fine while the editor was the only thing building flows. It stopped
10
+ being fine when an AI agent became a second author (DEV-391):
11
+
12
+ - an agent that cannot read an action's `inputSchema` **guesses** at the
13
+ config, and a guessed config is a flow that fails at run time on the
14
+ customer's live systems;
15
+ - an agent that cannot run the rules cannot tell whether what it built works,
16
+ so it reports success and hands over a broken flow.
17
+
18
+ Copying either into Backend would have produced two rule sets that agree on
19
+ the day they are written — the same failure mode as a duplicated permission
20
+ predicate, and the copy that drifts would be the one the agent trusts.
21
+
22
+ So they live here, and both the editor and the server import them. The editor
23
+ keeps validating in-process on every structural canvas change; Backend gets
24
+ the identical verdict for `check_flow`.
25
+
26
+ ## What is and is not here
27
+
28
+ **Here:** the `ActionDefinition` catalog (ids, descriptions, `inputSchema`,
29
+ `outputSchema`), the workflow validator, node config status, and the id
30
+ generators, so a caller building a flow makes ids the editor recognises.
31
+
32
+ **Not here:** React. The config **panels** stay in `octaviaflow-ui` — a
33
+ component in this package would make it unusable from Backend, which is the
34
+ whole point. `ActionDefinition.icon` is a string key the consumer's catalog
35
+ adapter resolves; this package never names a component.
36
+
37
+ ## Usage
38
+
39
+ ```ts
40
+ import {
41
+ getAllActions,
42
+ getActionById,
43
+ validateWorkflow,
44
+ getNodeConfigStatus,
45
+ } from "@octaviaflow/flow-rules";
46
+
47
+ // What may this step be configured with?
48
+ const action = getActionById("http_request");
49
+ const required = action?.inputSchema.fields.filter((f) => f.validation?.required);
50
+
51
+ // Does this flow work?
52
+ const { isValid, errors, warnings } = validateWorkflow(nodes, edges);
53
+ ```
54
+
55
+ ### The severity contract
56
+
57
+ Unchanged from rules-v2 (DEV-220, ADR-flow-pause-and-rules-v2):
58
+
59
+ | | |
60
+ |---|---|
61
+ | `error` | the flow cannot work as built. **Blocks activation.** |
62
+ | `warning` | it will run, but probably not the way the author thinks. Blocks nothing. |
63
+
64
+ **Saving is never blocked.** A caller that treats a warning as a failure will
65
+ refuse flows the editor accepts.
66
+
67
+ ### One field name worth knowing
68
+
69
+ A node names its action with **`actionDefinitionId`**, not `actionId`. The
70
+ latter looks right and silently matches nothing — which is exactly the kind of
71
+ mistake this package exists to stop an agent making.
72
+
73
+ ## Commands
74
+
75
+ ```bash
76
+ bun install
77
+ bun test
78
+ bun run typecheck
79
+ bun run build # tsc → dist (ESM + .d.ts), which is what consumers get
80
+ ```
81
+
82
+ It ships **built** ESM plus declarations rather than raw TypeScript
83
+ (`@octaviaflow/connector-crypto` ships source, but that package is only
84
+ consumed by Bun services — `octaviaflow-ui` is Next.js and would need
85
+ `transpilePackages` for source).
86
+
87
+ ## Consumers
88
+
89
+ | Repo | Uses |
90
+ |---|---|
91
+ | `octaviaflow-ui` | the editor: catalog, live validation, node status badges |
92
+ | `Octaviaflow-Backend` | `check_flow` and the agent authoring routes it serves |
93
+ | `Octaviaflow-MCP` | indirectly, through Backend |
94
+
95
+ A change to a rule or an action schema changes what the agent may build. Run
96
+ both consumers' suites before publishing.
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Console Log Configuration
3
+ *
4
+ * Defines the configuration structure and default values for the Console Log action
5
+ */
6
+ export interface ConsoleLogConfigType {
7
+ message: string;
8
+ level?: 'info' | 'warning' | 'error' | 'debug';
9
+ data?: unknown;
10
+ /**
11
+ * When false, the previous step's output is NOT dumped after the
12
+ * custom message — only the message prints. Useful for summary
13
+ * "Done" logs following a ForEach that would otherwise spew the
14
+ * entire iteration result. Defaults to true (legacy behavior).
15
+ */
16
+ includeInputData?: boolean;
17
+ }
18
+ export declare const ConsoleLogConfig: {
19
+ /**
20
+ * Default configuration for Console Log
21
+ */
22
+ defaults: ConsoleLogConfigType;
23
+ /**
24
+ * Configuration schema for validation
25
+ */
26
+ schema: {
27
+ message: {
28
+ type: string;
29
+ required: boolean;
30
+ description: string;
31
+ };
32
+ level: {
33
+ type: string;
34
+ required: boolean;
35
+ description: string;
36
+ };
37
+ data: {
38
+ type: string;
39
+ required: boolean;
40
+ description: string;
41
+ };
42
+ };
43
+ /**
44
+ * Validate configuration
45
+ */
46
+ validate: (config: Partial<ConsoleLogConfigType>) => {
47
+ valid: boolean;
48
+ errors: string[];
49
+ };
50
+ /**
51
+ * Merge user config with defaults
52
+ */
53
+ merge: (userConfig: Partial<ConsoleLogConfigType>) => ConsoleLogConfigType;
54
+ /**
55
+ * Get display label for configuration
56
+ */
57
+ getLabel: (config: ConsoleLogConfigType) => string;
58
+ };
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Console Log Configuration
3
+ *
4
+ * Defines the configuration structure and default values for the Console Log action
5
+ */
6
+ export const ConsoleLogConfig = {
7
+ /**
8
+ * Default configuration for Console Log
9
+ */
10
+ defaults: {
11
+ message: '',
12
+ level: 'info',
13
+ data: undefined,
14
+ includeInputData: true,
15
+ },
16
+ /**
17
+ * Configuration schema for validation
18
+ */
19
+ schema: {
20
+ message: {
21
+ type: 'string',
22
+ required: true,
23
+ description: 'Message to log',
24
+ },
25
+ level: {
26
+ type: 'select',
27
+ required: false,
28
+ description: 'Log level for the message',
29
+ },
30
+ data: {
31
+ type: 'json',
32
+ required: false,
33
+ description: 'Additional data to log',
34
+ },
35
+ },
36
+ /**
37
+ * Validate configuration
38
+ */
39
+ validate: (config) => {
40
+ const errors = [];
41
+ if (!config.message) {
42
+ errors.push('Message is required');
43
+ }
44
+ else if (typeof config.message !== 'string') {
45
+ errors.push('Message must be a string');
46
+ }
47
+ if (config.level && !['info', 'warning', 'error', 'debug'].includes(config.level)) {
48
+ errors.push('Invalid log level');
49
+ }
50
+ return {
51
+ valid: errors.length === 0,
52
+ errors,
53
+ };
54
+ },
55
+ /**
56
+ * Merge user config with defaults
57
+ */
58
+ merge: (userConfig) => {
59
+ return {
60
+ ...ConsoleLogConfig.defaults,
61
+ ...userConfig,
62
+ };
63
+ },
64
+ /**
65
+ * Get display label for configuration
66
+ */
67
+ getLabel: (config) => {
68
+ return `Log [${config.level}]: ${config.message}`;
69
+ },
70
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Console Log Action
3
+ *
4
+ * Log messages to the workflow console for debugging and monitoring
5
+ */
6
+ import { ActionDefinition } from '../../types';
7
+ export declare const consoleLogDefinition: ActionDefinition;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Console Log Action
3
+ *
4
+ * Log messages to the workflow console for debugging and monitoring
5
+ */
6
+ import { ActionCategory, ActionType, ActionStatus, FieldType } from '../../types';
7
+ export const consoleLogDefinition = {
8
+ id: 'console_log',
9
+ name: 'Console Log',
10
+ description: 'Log messages to the workflow console for debugging',
11
+ category: ActionCategory.Utility,
12
+ type: ActionType.Console,
13
+ tags: ['utility', 'logging', 'debug', 'built-in'],
14
+ status: ActionStatus.Stable,
15
+ icon: 'Terminal',
16
+ color: '#525252',
17
+ inputSchema: {
18
+ fields: [
19
+ {
20
+ key: 'message',
21
+ label: 'Message',
22
+ type: FieldType.String,
23
+ description: 'Message to log',
24
+ placeholder: 'e.g., Processing user data...',
25
+ validation: { required: true },
26
+ },
27
+ {
28
+ key: 'level',
29
+ label: 'Log Level',
30
+ type: FieldType.Select,
31
+ description: 'Log level for the message',
32
+ defaultValue: 'info',
33
+ options: [
34
+ { label: 'Info', value: 'info' },
35
+ { label: 'Warning', value: 'warning' },
36
+ { label: 'Error', value: 'error' },
37
+ { label: 'Debug', value: 'debug' },
38
+ ],
39
+ validation: { required: true },
40
+ },
41
+ {
42
+ key: 'data',
43
+ label: 'Data',
44
+ type: FieldType.JSON,
45
+ description: 'Additional data to log',
46
+ validation: { required: false },
47
+ },
48
+ {
49
+ key: 'includeInputData',
50
+ label: 'Include previous step output',
51
+ type: FieldType.Boolean,
52
+ description: 'When off, only the custom message prints — useful for summary "Done" logs that follow a ForEach.',
53
+ defaultValue: true,
54
+ validation: { required: false },
55
+ },
56
+ ],
57
+ },
58
+ outputSchema: {
59
+ type: 'object',
60
+ properties: [
61
+ {
62
+ key: 'logged',
63
+ type: FieldType.Boolean,
64
+ description: 'Whether the message was successfully logged',
65
+ },
66
+ {
67
+ key: 'timestamp',
68
+ type: FieldType.DateTime,
69
+ description: 'Timestamp of the log entry',
70
+ },
71
+ {
72
+ key: 'level',
73
+ type: FieldType.String,
74
+ description: 'Log level used',
75
+ },
76
+ ],
77
+ sampleOutput: {
78
+ logged: true,
79
+ timestamp: new Date().toISOString(),
80
+ level: 'info',
81
+ },
82
+ },
83
+ version: '1.0.0',
84
+ createdAt: '2025-01-01T00:00:00Z',
85
+ updatedAt: '2025-12-15T00:00:00Z',
86
+ createdBy: 'system',
87
+ isOfficial: true,
88
+ testable: true,
89
+ };
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Delay Configuration
3
+ *
4
+ * Defines the configuration structure and default values for the Delay action
5
+ */
6
+ export interface DelayConfigType {
7
+ duration: number;
8
+ unit?: 'milliseconds' | 'seconds' | 'minutes' | 'hours';
9
+ }
10
+ export declare const DelayConfig: {
11
+ /**
12
+ * Default configuration for Delay
13
+ */
14
+ defaults: DelayConfigType;
15
+ /**
16
+ * Configuration schema for validation
17
+ */
18
+ schema: {
19
+ duration: {
20
+ type: string;
21
+ required: boolean;
22
+ description: string;
23
+ min: number;
24
+ };
25
+ unit: {
26
+ type: string;
27
+ required: boolean;
28
+ description: string;
29
+ };
30
+ };
31
+ /**
32
+ * Validate configuration
33
+ */
34
+ validate: (config: Partial<DelayConfigType>) => {
35
+ valid: boolean;
36
+ errors: string[];
37
+ };
38
+ /**
39
+ * Convert duration to milliseconds
40
+ */
41
+ toMilliseconds: (duration: number, unit?: string) => number;
42
+ /**
43
+ * Merge user config with defaults
44
+ */
45
+ merge: (userConfig: Partial<DelayConfigType>) => DelayConfigType;
46
+ /**
47
+ * Get display label for configuration
48
+ */
49
+ getLabel: (config: DelayConfigType) => string;
50
+ };
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Delay Configuration
3
+ *
4
+ * Defines the configuration structure and default values for the Delay action
5
+ */
6
+ export const DelayConfig = {
7
+ /**
8
+ * Default configuration for Delay
9
+ */
10
+ defaults: {
11
+ duration: 1000,
12
+ unit: 'milliseconds',
13
+ },
14
+ /**
15
+ * Configuration schema for validation
16
+ */
17
+ schema: {
18
+ duration: {
19
+ type: 'number',
20
+ required: true,
21
+ description: 'Duration to delay',
22
+ min: 0,
23
+ },
24
+ unit: {
25
+ type: 'select',
26
+ required: false,
27
+ description: 'Time unit for the duration',
28
+ },
29
+ },
30
+ /**
31
+ * Validate configuration
32
+ */
33
+ validate: (config) => {
34
+ const errors = [];
35
+ if (config.duration === undefined || config.duration === null) {
36
+ errors.push('Duration is required');
37
+ }
38
+ else if (typeof config.duration !== 'number') {
39
+ errors.push('Duration must be a number');
40
+ }
41
+ else if (config.duration < 0) {
42
+ errors.push('Duration must be non-negative');
43
+ }
44
+ if (config.unit && !['milliseconds', 'seconds', 'minutes', 'hours'].includes(config.unit)) {
45
+ errors.push('Invalid time unit');
46
+ }
47
+ return {
48
+ valid: errors.length === 0,
49
+ errors,
50
+ };
51
+ },
52
+ /**
53
+ * Convert duration to milliseconds
54
+ */
55
+ toMilliseconds: (duration, unit = 'milliseconds') => {
56
+ const multipliers = {
57
+ milliseconds: 1,
58
+ seconds: 1000,
59
+ minutes: 60000,
60
+ hours: 3600000,
61
+ };
62
+ return duration * (multipliers[unit] || 1);
63
+ },
64
+ /**
65
+ * Merge user config with defaults
66
+ */
67
+ merge: (userConfig) => {
68
+ return {
69
+ ...DelayConfig.defaults,
70
+ ...userConfig,
71
+ };
72
+ },
73
+ /**
74
+ * Get display label for configuration
75
+ */
76
+ getLabel: (config) => {
77
+ return `Delay ${config.duration}${config.unit ? ' ' + config.unit : 'ms'}`;
78
+ },
79
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Delay Action
3
+ *
4
+ * Pause workflow execution for a specified duration
5
+ */
6
+ import { ActionDefinition } from '../../types';
7
+ export declare const delayDefinition: ActionDefinition;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Delay Action
3
+ *
4
+ * Pause workflow execution for a specified duration
5
+ */
6
+ import { ActionCategory, ActionType, ActionStatus, FieldType } from '../../types';
7
+ export const delayDefinition = {
8
+ id: 'delay',
9
+ name: 'Delay',
10
+ description: 'Pause workflow execution for a specified duration',
11
+ category: ActionCategory.Utility,
12
+ type: ActionType.Delay,
13
+ tags: ['utility', 'delay', 'wait', 'built-in'],
14
+ status: ActionStatus.Stable,
15
+ icon: 'Timer',
16
+ color: '#8f8f8f',
17
+ inputSchema: {
18
+ fields: [
19
+ {
20
+ key: 'duration',
21
+ label: 'Duration (ms)',
22
+ type: FieldType.Number,
23
+ description: 'Duration to delay in milliseconds',
24
+ defaultValue: 1000,
25
+ validation: { required: true, min: 0 },
26
+ },
27
+ {
28
+ key: 'unit',
29
+ label: 'Unit',
30
+ type: FieldType.Select,
31
+ description: 'Time unit for the duration',
32
+ defaultValue: 'milliseconds',
33
+ options: [
34
+ { label: 'Milliseconds', value: 'milliseconds' },
35
+ { label: 'Seconds', value: 'seconds' },
36
+ { label: 'Minutes', value: 'minutes' },
37
+ { label: 'Hours', value: 'hours' },
38
+ ],
39
+ validation: { required: true },
40
+ },
41
+ ],
42
+ },
43
+ outputSchema: {
44
+ type: 'object',
45
+ properties: [
46
+ {
47
+ key: 'delayedFor',
48
+ type: FieldType.Number,
49
+ description: 'Actual delay duration in milliseconds',
50
+ },
51
+ {
52
+ key: 'completedAt',
53
+ type: FieldType.DateTime,
54
+ description: 'Timestamp when delay completed',
55
+ },
56
+ ],
57
+ sampleOutput: {
58
+ delayedFor: 1000,
59
+ completedAt: new Date().toISOString(),
60
+ },
61
+ },
62
+ execution: {
63
+ timeout: 3600000,
64
+ },
65
+ version: '1.0.0',
66
+ createdAt: '2025-01-01T00:00:00Z',
67
+ updatedAt: '2025-12-15T00:00:00Z',
68
+ createdBy: 'system',
69
+ isOfficial: true,
70
+ testable: true,
71
+ };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Migration shim — legacy `{ duration, unit }` Delay config → v2 multi-mode shape.
3
+ *
4
+ * Runs at read time in both UI (panel renders v2 shape) and Engine (executor
5
+ * dispatches v2 modes). One-way and pure: persisted v1 configs stay v1 on
6
+ * disk until a user explicitly saves the step in the v2 UI panel.
7
+ *
8
+ * Detection rule: a config is v2 when it has a `mode` property; otherwise
9
+ * treat as v1 and rewrite to fixed-mode with the legacy duration/unit.
10
+ *
11
+ * See implementation doc §5.7 for design rationale.
12
+ */
13
+ import type { DelayConfig } from './types';
14
+ /**
15
+ * Convert any persisted Delay config (v1 legacy or v2 multi-mode) into the v2
16
+ * `DelayConfig` shape. Always safe to call — passes v2 inputs through unchanged.
17
+ */
18
+ export declare function migrateDelayConfig(raw: unknown): DelayConfig;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Migration shim — legacy `{ duration, unit }` Delay config → v2 multi-mode shape.
3
+ *
4
+ * Runs at read time in both UI (panel renders v2 shape) and Engine (executor
5
+ * dispatches v2 modes). One-way and pure: persisted v1 configs stay v1 on
6
+ * disk until a user explicitly saves the step in the v2 UI panel.
7
+ *
8
+ * Detection rule: a config is v2 when it has a `mode` property; otherwise
9
+ * treat as v1 and rewrite to fixed-mode with the legacy duration/unit.
10
+ *
11
+ * See implementation doc §5.7 for design rationale.
12
+ */
13
+ const LEGACY_UNITS = new Set([
14
+ 'milliseconds',
15
+ 'seconds',
16
+ 'minutes',
17
+ 'hours',
18
+ ]);
19
+ /**
20
+ * Convert any persisted Delay config (v1 legacy or v2 multi-mode) into the v2
21
+ * `DelayConfig` shape. Always safe to call — passes v2 inputs through unchanged.
22
+ */
23
+ export function migrateDelayConfig(raw) {
24
+ if (raw && typeof raw === 'object' && 'mode' in raw) {
25
+ return raw;
26
+ }
27
+ const legacy = (raw ?? {});
28
+ const duration = typeof legacy.duration === 'number' && Number.isFinite(legacy.duration)
29
+ ? legacy.duration
30
+ : 1;
31
+ const unit = typeof legacy.unit === 'string' && LEGACY_UNITS.has(legacy.unit)
32
+ ? legacy.unit
33
+ : 'milliseconds';
34
+ return {
35
+ mode: 'fixed',
36
+ fixed: { duration, unit },
37
+ };
38
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Delay Action — v2 type definitions.
3
+ *
4
+ * v2 turns Delay into a multi-mode primitive (fixed / until / random-jitter /
5
+ * expression) with per-mode configs. See architecture doc for design rationale:
6
+ * (design notes live in the platform's own documentation)
7
+ *
8
+ * PR 1 ships these types alongside the legacy `config.ts`. PR 3 collapses the
9
+ * legacy file and rewrites the action definition (`index.ts`) against this
10
+ * schema.
11
+ */
12
+ export type DelayMode = 'fixed' | 'until' | 'random-jitter' | 'expression';
13
+ /**
14
+ * FxValue<T>: a literal T value OR an `ods://...` expression string that
15
+ * resolves to T at runtime.
16
+ *
17
+ * v1 status: FX is not yet a platform-wide feature. Delay ships FxValue typing
18
+ * as a testbed so the contract (typing + runtime resolution + tests) lands in
19
+ * production code before the platform-wide FX rollout. Other actions remain
20
+ * literal-only for now. See implementation doc §5.3 + §8.5.
21
+ */
22
+ export type FxValue<T> = T | string;
23
+ export type FixedUnit = 'milliseconds' | 'seconds' | 'minutes' | 'hours';
24
+ export interface FixedModeConfig {
25
+ duration: FxValue<number>;
26
+ unit: FixedUnit;
27
+ }
28
+ export interface UntilModeConfig {
29
+ /** ISO 8601 datetime literal OR an `ods://` expression resolving to one. */
30
+ datetime: FxValue<string>;
31
+ /** Optional clock-skew tolerance in ms. Literal or FX. Default 0. */
32
+ toleranceMs?: FxValue<number>;
33
+ }
34
+ export interface RandomJitterModeConfig {
35
+ baseMs: FxValue<number>;
36
+ jitterMs: FxValue<number>;
37
+ }
38
+ export interface ExpressionModeConfig {
39
+ /** Resolves to either a number (ms) or a duration string ("30s", "5m"). */
40
+ raw: string;
41
+ /** Fallback when the expression evaluates to undefined / NaN. Default 0. */
42
+ fallbackMs?: FxValue<number>;
43
+ }
44
+ export interface DelayConfig {
45
+ mode: DelayMode;
46
+ /** Optional gate. When set and falsy at runtime, the step short-circuits. */
47
+ condition?: string;
48
+ fixed?: FixedModeConfig;
49
+ until?: UntilModeConfig;
50
+ randomJitter?: RandomJitterModeConfig;
51
+ expression?: ExpressionModeConfig;
52
+ }
53
+ /**
54
+ * Schema version. Bumped from the legacy 1.0.0 to mark the multi-mode
55
+ * shape. The migration shim (`migrate.ts`) detects v1 configs by the
56
+ * absence of `mode` and rewrites them to v2 fixed-mode equivalents.
57
+ */
58
+ export declare const DELAY_CONFIG_VERSION = "2.0.0";
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Delay Action — v2 type definitions.
3
+ *
4
+ * v2 turns Delay into a multi-mode primitive (fixed / until / random-jitter /
5
+ * expression) with per-mode configs. See architecture doc for design rationale:
6
+ * (design notes live in the platform's own documentation)
7
+ *
8
+ * PR 1 ships these types alongside the legacy `config.ts`. PR 3 collapses the
9
+ * legacy file and rewrites the action definition (`index.ts`) against this
10
+ * schema.
11
+ */
12
+ /**
13
+ * Schema version. Bumped from the legacy 1.0.0 to mark the multi-mode
14
+ * shape. The migration shim (`migrate.ts`) detects v1 configs by the
15
+ * absence of `mode` and rewrites them to v2 fixed-mode equivalents.
16
+ */
17
+ export const DELAY_CONFIG_VERSION = '2.0.0';