@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.
- package/README.md +96 -0
- package/dist/catalog/actions/console-log/config.d.ts +58 -0
- package/dist/catalog/actions/console-log/config.js +70 -0
- package/dist/catalog/actions/console-log/index.d.ts +7 -0
- package/dist/catalog/actions/console-log/index.js +89 -0
- package/dist/catalog/actions/delay/config.d.ts +50 -0
- package/dist/catalog/actions/delay/config.js +79 -0
- package/dist/catalog/actions/delay/index.d.ts +7 -0
- package/dist/catalog/actions/delay/index.js +71 -0
- package/dist/catalog/actions/delay/migrate.d.ts +18 -0
- package/dist/catalog/actions/delay/migrate.js +38 -0
- package/dist/catalog/actions/delay/types.d.ts +58 -0
- package/dist/catalog/actions/delay/types.js +17 -0
- package/dist/catalog/actions/http-request/config.d.ts +114 -0
- package/dist/catalog/actions/http-request/config.js +111 -0
- package/dist/catalog/actions/http-request/index.d.ts +7 -0
- package/dist/catalog/actions/http-request/index.js +223 -0
- package/dist/catalog/ai/ai-agent/index.d.ts +12 -0
- package/dist/catalog/ai/ai-agent/index.js +72 -0
- package/dist/catalog/ai/idp-extract/index.d.ts +18 -0
- package/dist/catalog/ai/idp-extract/index.js +90 -0
- package/dist/catalog/api/graphql-query/config.d.ts +36 -0
- package/dist/catalog/api/graphql-query/config.js +31 -0
- package/dist/catalog/api/graphql-query/index.d.ts +7 -0
- package/dist/catalog/api/graphql-query/index.js +75 -0
- package/dist/catalog/communication/email-send/config.d.ts +80 -0
- package/dist/catalog/communication/email-send/config.js +80 -0
- package/dist/catalog/communication/email-send/index.d.ts +11 -0
- package/dist/catalog/communication/email-send/index.js +152 -0
- package/dist/catalog/communication/google-chat/config.d.ts +45 -0
- package/dist/catalog/communication/google-chat/config.js +28 -0
- package/dist/catalog/communication/google-chat/index.d.ts +5 -0
- package/dist/catalog/communication/google-chat/index.js +36 -0
- package/dist/catalog/communication/slack-message/config.d.ts +47 -0
- package/dist/catalog/communication/slack-message/config.js +36 -0
- package/dist/catalog/communication/slack-message/index.d.ts +5 -0
- package/dist/catalog/communication/slack-message/index.js +37 -0
- package/dist/catalog/communication/teams-message/config.d.ts +48 -0
- package/dist/catalog/communication/teams-message/config.js +29 -0
- package/dist/catalog/communication/teams-message/index.d.ts +5 -0
- package/dist/catalog/communication/teams-message/index.js +39 -0
- package/dist/catalog/communication/webhook-call/config.d.ts +36 -0
- package/dist/catalog/communication/webhook-call/config.js +31 -0
- package/dist/catalog/communication/webhook-call/index.d.ts +5 -0
- package/dist/catalog/communication/webhook-call/index.js +43 -0
- package/dist/catalog/communication/whatsapp-send/config.d.ts +23 -0
- package/dist/catalog/communication/whatsapp-send/config.js +36 -0
- package/dist/catalog/communication/whatsapp-send/index.d.ts +15 -0
- package/dist/catalog/communication/whatsapp-send/index.js +57 -0
- package/dist/catalog/general/query/config.d.ts +36 -0
- package/dist/catalog/general/query/config.js +257 -0
- package/dist/catalog/general/query/index.d.ts +11 -0
- package/dist/catalog/general/query/index.js +271 -0
- package/dist/catalog/general/query/types.d.ts +205 -0
- package/dist/catalog/general/query/types.js +82 -0
- package/dist/catalog/general/transform/config.d.ts +117 -0
- package/dist/catalog/general/transform/config.js +95 -0
- package/dist/catalog/general/transform/index.d.ts +8 -0
- package/dist/catalog/general/transform/index.js +63 -0
- package/dist/catalog/index.d.ts +57 -0
- package/dist/catalog/index.js +168 -0
- package/dist/catalog/logic/condition/config.d.ts +54 -0
- package/dist/catalog/logic/condition/config.js +93 -0
- package/dist/catalog/logic/condition/index.d.ts +7 -0
- package/dist/catalog/logic/condition/index.js +64 -0
- package/dist/catalog/logic/for-each/config.d.ts +100 -0
- package/dist/catalog/logic/for-each/config.js +75 -0
- package/dist/catalog/logic/for-each/index.d.ts +7 -0
- package/dist/catalog/logic/for-each/index.js +92 -0
- package/dist/catalog/logic/for-each/pathOptions.d.ts +62 -0
- package/dist/catalog/logic/for-each/pathOptions.js +151 -0
- package/dist/catalog/logic/group/index.d.ts +15 -0
- package/dist/catalog/logic/group/index.js +46 -0
- package/dist/catalog/policies.d.ts +75 -0
- package/dist/catalog/policies.js +62 -0
- package/dist/catalog/storage/csv-action/index.d.ts +2 -0
- package/dist/catalog/storage/csv-action/index.js +38 -0
- package/dist/catalog/storage/dropbox-action/index.d.ts +2 -0
- package/dist/catalog/storage/dropbox-action/index.js +33 -0
- package/dist/catalog/storage/excel-action/index.d.ts +2 -0
- package/dist/catalog/storage/excel-action/index.js +32 -0
- package/dist/catalog/storage/file-action/index.d.ts +2 -0
- package/dist/catalog/storage/file-action/index.js +119 -0
- package/dist/catalog/storage/file-operation/config.d.ts +48 -0
- package/dist/catalog/storage/file-operation/config.js +45 -0
- package/dist/catalog/storage/file-operation/index.d.ts +8 -0
- package/dist/catalog/storage/file-operation/index.js +111 -0
- package/dist/catalog/storage/ftp-action/index.d.ts +2 -0
- package/dist/catalog/storage/ftp-action/index.js +33 -0
- package/dist/catalog/storage/google-drive-action/index.d.ts +2 -0
- package/dist/catalog/storage/google-drive-action/index.js +38 -0
- package/dist/catalog/storage/json-action/index.d.ts +2 -0
- package/dist/catalog/storage/json-action/index.js +31 -0
- package/dist/catalog/storage/onedrive-action/index.d.ts +2 -0
- package/dist/catalog/storage/onedrive-action/index.js +33 -0
- package/dist/catalog/storage/s3-action/index.d.ts +2 -0
- package/dist/catalog/storage/s3-action/index.js +36 -0
- package/dist/catalog/storage/storage-action/index.d.ts +13 -0
- package/dist/catalog/storage/storage-action/index.js +72 -0
- package/dist/catalog/storage/storageCapabilities.d.ts +57 -0
- package/dist/catalog/storage/storageCapabilities.js +207 -0
- package/dist/catalog/storage/xml-action/index.d.ts +2 -0
- package/dist/catalog/storage/xml-action/index.js +31 -0
- package/dist/catalog/transforms/format/config.d.ts +23 -0
- package/dist/catalog/transforms/format/config.js +19 -0
- package/dist/catalog/transforms/format/index.d.ts +5 -0
- package/dist/catalog/transforms/format/index.js +39 -0
- package/dist/catalog/triggers/connector-trigger/index.d.ts +7 -0
- package/dist/catalog/triggers/connector-trigger/index.js +72 -0
- package/dist/catalog/triggers/manual-trigger/config.d.ts +40 -0
- package/dist/catalog/triggers/manual-trigger/config.js +60 -0
- package/dist/catalog/triggers/manual-trigger/index.d.ts +10 -0
- package/dist/catalog/triggers/manual-trigger/index.js +74 -0
- package/dist/catalog/triggers/schedule-trigger/config.d.ts +42 -0
- package/dist/catalog/triggers/schedule-trigger/config.js +42 -0
- package/dist/catalog/triggers/schedule-trigger/index.d.ts +7 -0
- package/dist/catalog/triggers/schedule-trigger/index.js +102 -0
- package/dist/catalog/triggers/webhook-trigger/config.d.ts +31 -0
- package/dist/catalog/triggers/webhook-trigger/config.js +27 -0
- package/dist/catalog/triggers/webhook-trigger/index.d.ts +7 -0
- package/dist/catalog/triggers/webhook-trigger/index.js +89 -0
- package/dist/catalog/types.d.ts +360 -0
- package/dist/catalog/types.js +135 -0
- package/dist/catalog/utility/debug/config.d.ts +72 -0
- package/dist/catalog/utility/debug/config.js +90 -0
- package/dist/catalog/utility/debug/index.d.ts +11 -0
- package/dist/catalog/utility/debug/index.js +38 -0
- package/dist/catalog/utility/error/config.d.ts +26 -0
- package/dist/catalog/utility/error/config.js +25 -0
- package/dist/catalog/utility/error/index.d.ts +7 -0
- package/dist/catalog/utility/error/index.js +46 -0
- package/dist/catalog/utility/variables/config.d.ts +76 -0
- package/dist/catalog/utility/variables/config.js +70 -0
- package/dist/catalog/utility/variables/index.d.ts +13 -0
- package/dist/catalog/utility/variables/index.js +40 -0
- package/dist/catalog/workflow.d.ts +308 -0
- package/dist/catalog/workflow.js +25 -0
- package/dist/ids.d.ts +31 -0
- package/dist/ids.js +53 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +28 -0
- package/dist/rules/nodeConfigStatus.d.ts +33 -0
- package/dist/rules/nodeConfigStatus.js +217 -0
- package/dist/rules/workflowValidator.d.ts +53 -0
- package/dist/rules/workflowValidator.js +358 -0
- 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,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,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';
|