@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
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ForEach source-path helpers (pure, framework-free).
|
|
3
|
+
*
|
|
4
|
+
* Extracted from ForEachConfigPanel so the iterable-path collection logic can
|
|
5
|
+
* be unit-tested without dragging the Design System into the test runner.
|
|
6
|
+
* These mirror the legacy `loopableInSource` collector and emit dot-paths that
|
|
7
|
+
* the engine's `resolveArrayPath` resolves directly.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* The upstream-node shape a config panel passes in.
|
|
11
|
+
*
|
|
12
|
+
* Declared here rather than imported from the UI's panel registry: this
|
|
13
|
+
* package must not depend on React, and only this one field was ever used.
|
|
14
|
+
* The UI's `CustomConfigComponentProps['upstreamNodes']` is assignable to it.
|
|
15
|
+
*/
|
|
16
|
+
export interface UpstreamNodeRef {
|
|
17
|
+
id: string;
|
|
18
|
+
label?: string;
|
|
19
|
+
type?: string;
|
|
20
|
+
config?: Record<string, unknown>;
|
|
21
|
+
outputSchema?: unknown;
|
|
22
|
+
/** The last run's output, when the editor has one to offer. */
|
|
23
|
+
executionData?: {
|
|
24
|
+
output?: unknown;
|
|
25
|
+
};
|
|
26
|
+
[key: string]: unknown;
|
|
27
|
+
}
|
|
28
|
+
export interface PathOption {
|
|
29
|
+
id: string;
|
|
30
|
+
text: string;
|
|
31
|
+
description?: string;
|
|
32
|
+
}
|
|
33
|
+
/** Recursively infer a DataSchema-like object from a runtime sample record. */
|
|
34
|
+
export declare function inferSchemaFromSample(sample: Record<string, unknown>): {
|
|
35
|
+
type: string;
|
|
36
|
+
properties: Record<string, any>;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Recursively walk a JSONSchema-like shape, emitting one PathOption per
|
|
40
|
+
* array node encountered. Mirrors the legacy `loopableInSource` collector
|
|
41
|
+
* (cloudwf-ui editmap.jsp:241-265) so the dropdown surfaces every level
|
|
42
|
+
* the user could iterate, not just the top.
|
|
43
|
+
*
|
|
44
|
+
* Emitted dot-paths match the engine's `resolveArrayPath` resolver, which
|
|
45
|
+
* already walks dot-notation and falls back to looking inside `data[0]`
|
|
46
|
+
* for nested fields — so `data.departments` resolves correctly without
|
|
47
|
+
* any engine change.
|
|
48
|
+
*/
|
|
49
|
+
export declare function collectArrayPaths(schema: any, prefix: string, add: (id: string, text: string, description?: string) => void, depth?: number): void;
|
|
50
|
+
/** Walk a runtime sample for the same path collection — used when the
|
|
51
|
+
* static schema is missing/shallow but executionData has real shape. */
|
|
52
|
+
export declare function collectArrayPathsFromSample(sample: unknown, prefix: string, add: (id: string, text: string, description?: string) => void, depth?: number): void;
|
|
53
|
+
/**
|
|
54
|
+
* Build iterable field options from upstream nodes.
|
|
55
|
+
*
|
|
56
|
+
* Walks the upstream output schema (and execution data as a fallback) to
|
|
57
|
+
* surface every array path the user can iterate. The legacy mapper
|
|
58
|
+
* collected the same set as `loopableInSource` and exposed it via the
|
|
59
|
+
* "Loop Over" dropdown; we surface it here so ForEach has equivalent
|
|
60
|
+
* reach for nested arrays inside JSONB columns.
|
|
61
|
+
*/
|
|
62
|
+
export declare function buildPathOptions(upstreamNodes?: UpstreamNodeRef[]): PathOption[];
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ForEach source-path helpers (pure, framework-free).
|
|
3
|
+
*
|
|
4
|
+
* Extracted from ForEachConfigPanel so the iterable-path collection logic can
|
|
5
|
+
* be unit-tested without dragging the Design System into the test runner.
|
|
6
|
+
* These mirror the legacy `loopableInSource` collector and emit dot-paths that
|
|
7
|
+
* the engine's `resolveArrayPath` resolves directly.
|
|
8
|
+
*/
|
|
9
|
+
/** Recursively infer a DataSchema-like object from a runtime sample record. */
|
|
10
|
+
export function inferSchemaFromSample(sample) {
|
|
11
|
+
const properties = {};
|
|
12
|
+
for (const [key, value] of Object.entries(sample)) {
|
|
13
|
+
if (value === null || value === undefined) {
|
|
14
|
+
properties[key] = { type: 'string' };
|
|
15
|
+
}
|
|
16
|
+
else if (Array.isArray(value)) {
|
|
17
|
+
if (value.length > 0 && typeof value[0] === 'object' && value[0] !== null) {
|
|
18
|
+
properties[key] = { type: 'array', items: inferSchemaFromSample(value[0]) };
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
properties[key] = { type: 'array' };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
else if (typeof value === 'object') {
|
|
25
|
+
properties[key] = inferSchemaFromSample(value);
|
|
26
|
+
}
|
|
27
|
+
else if (typeof value === 'number') {
|
|
28
|
+
properties[key] = { type: 'number' };
|
|
29
|
+
}
|
|
30
|
+
else if (typeof value === 'boolean') {
|
|
31
|
+
properties[key] = { type: 'boolean' };
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
properties[key] = { type: 'string' };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return { type: 'object', properties };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Recursively walk a JSONSchema-like shape, emitting one PathOption per
|
|
41
|
+
* array node encountered. Mirrors the legacy `loopableInSource` collector
|
|
42
|
+
* (cloudwf-ui editmap.jsp:241-265) so the dropdown surfaces every level
|
|
43
|
+
* the user could iterate, not just the top.
|
|
44
|
+
*
|
|
45
|
+
* Emitted dot-paths match the engine's `resolveArrayPath` resolver, which
|
|
46
|
+
* already walks dot-notation and falls back to looking inside `data[0]`
|
|
47
|
+
* for nested fields — so `data.departments` resolves correctly without
|
|
48
|
+
* any engine change.
|
|
49
|
+
*/
|
|
50
|
+
export function collectArrayPaths(schema, prefix, add, depth = 0) {
|
|
51
|
+
if (!schema || typeof schema !== 'object' || depth > 8)
|
|
52
|
+
return;
|
|
53
|
+
if (schema.type === 'array') {
|
|
54
|
+
if (prefix) {
|
|
55
|
+
const itemsType = schema.items?.type;
|
|
56
|
+
const label = itemsType === 'object' ? 'array of objects' : 'array';
|
|
57
|
+
add(prefix, `${prefix} (${label})`, `Iterate over "${prefix}"`);
|
|
58
|
+
}
|
|
59
|
+
// Descend into items so nested arrays inside this array are emitted too.
|
|
60
|
+
if (schema.items) {
|
|
61
|
+
collectArrayPaths(schema.items, prefix, add, depth + 1);
|
|
62
|
+
}
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (schema.type === 'object' && schema.properties) {
|
|
66
|
+
for (const [key, child] of Object.entries(schema.properties)) {
|
|
67
|
+
const next = prefix ? `${prefix}.${key}` : key;
|
|
68
|
+
collectArrayPaths(child, next, add, depth + 1);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** Walk a runtime sample for the same path collection — used when the
|
|
73
|
+
* static schema is missing/shallow but executionData has real shape. */
|
|
74
|
+
export function collectArrayPathsFromSample(sample, prefix, add, depth = 0) {
|
|
75
|
+
if (!sample || typeof sample !== 'object' || depth > 8)
|
|
76
|
+
return;
|
|
77
|
+
if (Array.isArray(sample)) {
|
|
78
|
+
if (prefix) {
|
|
79
|
+
const itemsObj = sample.length > 0 && typeof sample[0] === 'object' && sample[0] !== null;
|
|
80
|
+
const label = itemsObj ? 'array of objects' : 'array';
|
|
81
|
+
add(prefix, `${prefix} (${label})`, `Iterate over "${prefix}"`);
|
|
82
|
+
}
|
|
83
|
+
if (sample.length > 0) {
|
|
84
|
+
collectArrayPathsFromSample(sample[0], prefix, add, depth + 1);
|
|
85
|
+
}
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
for (const [key, value] of Object.entries(sample)) {
|
|
89
|
+
const next = prefix ? `${prefix}.${key}` : key;
|
|
90
|
+
collectArrayPathsFromSample(value, next, add, depth + 1);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Build iterable field options from upstream nodes.
|
|
95
|
+
*
|
|
96
|
+
* Walks the upstream output schema (and execution data as a fallback) to
|
|
97
|
+
* surface every array path the user can iterate. The legacy mapper
|
|
98
|
+
* collected the same set as `loopableInSource` and exposed it via the
|
|
99
|
+
* "Loop Over" dropdown; we surface it here so ForEach has equivalent
|
|
100
|
+
* reach for nested arrays inside JSONB columns.
|
|
101
|
+
*/
|
|
102
|
+
export function buildPathOptions(upstreamNodes) {
|
|
103
|
+
const paths = [];
|
|
104
|
+
const seen = new Set();
|
|
105
|
+
const add = (id, text, description) => {
|
|
106
|
+
if (seen.has(id))
|
|
107
|
+
return;
|
|
108
|
+
seen.add(id);
|
|
109
|
+
paths.push({ id, text, description });
|
|
110
|
+
};
|
|
111
|
+
if (upstreamNodes) {
|
|
112
|
+
for (const node of upstreamNodes) {
|
|
113
|
+
const label = node.label || node.type || 'Upstream';
|
|
114
|
+
const queryTable = node.config?.visualConfig?.tables?.[0];
|
|
115
|
+
// Always offer "data" — the standard array wrapper from queries. At
|
|
116
|
+
// RUNTIME a Query emits `{ data: rows }` regardless of object name, so
|
|
117
|
+
// the iterable path is `data`; we just LABEL it with the object name
|
|
118
|
+
// (e.g. "contacts") when known. Offering the bare object name AS the
|
|
119
|
+
// path resolved nowhere at runtime ("does not resolve to an array").
|
|
120
|
+
add('data', queryTable ? `${queryTable} (${label})` : `All records (${label})`, queryTable ? `Iterate over every ${queryTable} record` : 'Iterate over every record from upstream');
|
|
121
|
+
// Recursive walk of static schema. The engine's resolveArrayPath
|
|
122
|
+
// handles dot-paths like `data.departments` by walking obj.data[0]
|
|
123
|
+
// for the nested field, so deep paths Just Work without any engine
|
|
124
|
+
// change.
|
|
125
|
+
const schema = node.outputSchema || node.config?._outputSchema;
|
|
126
|
+
if (schema)
|
|
127
|
+
collectArrayPaths(schema, '', add);
|
|
128
|
+
// Fallback: when the static schema is missing or shallow, walk the
|
|
129
|
+
// last execution's actual output. Same path format.
|
|
130
|
+
const output = node.executionData?.output;
|
|
131
|
+
if (output) {
|
|
132
|
+
const records = Array.isArray(output.data)
|
|
133
|
+
? output.data
|
|
134
|
+
: Array.isArray(output)
|
|
135
|
+
? output
|
|
136
|
+
: null;
|
|
137
|
+
if (records && records.length > 0 && typeof records[0] === 'object') {
|
|
138
|
+
collectArrayPathsFromSample(records[0], '', add);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// NOTE: we deliberately do NOT offer the bare object/table name as a
|
|
142
|
+
// path — at runtime the rows live under `data`, not under the object
|
|
143
|
+
// name (the object name only keys the DataStream schema tree). The
|
|
144
|
+
// `data` option above is labelled with the object name instead.
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (paths.length === 0) {
|
|
148
|
+
add('data', 'data (upstream output)');
|
|
149
|
+
}
|
|
150
|
+
return paths;
|
|
151
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Group action
|
|
3
|
+
*
|
|
4
|
+
* A generic container — drop nodes inside and they become children
|
|
5
|
+
* (parentId points at the group). No runtime semantics: the engine
|
|
6
|
+
* just executes the children in their normal order. Used to fold a
|
|
7
|
+
* sub-flow into a single visual block on the canvas. Drag a child
|
|
8
|
+
* out of the group's bbox to detach.
|
|
9
|
+
*
|
|
10
|
+
* Mirrors ForEach structurally (container + top input / bottom output
|
|
11
|
+
* ports) but without the iteration config. The DS renders it via the
|
|
12
|
+
* built-in `group` node kind.
|
|
13
|
+
*/
|
|
14
|
+
import { type ActionDefinition } from '../../types';
|
|
15
|
+
export declare const groupDefinition: ActionDefinition;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Group action
|
|
3
|
+
*
|
|
4
|
+
* A generic container — drop nodes inside and they become children
|
|
5
|
+
* (parentId points at the group). No runtime semantics: the engine
|
|
6
|
+
* just executes the children in their normal order. Used to fold a
|
|
7
|
+
* sub-flow into a single visual block on the canvas. Drag a child
|
|
8
|
+
* out of the group's bbox to detach.
|
|
9
|
+
*
|
|
10
|
+
* Mirrors ForEach structurally (container + top input / bottom output
|
|
11
|
+
* ports) but without the iteration config. The DS renders it via the
|
|
12
|
+
* built-in `group` node kind.
|
|
13
|
+
*/
|
|
14
|
+
import { ActionCategory, ActionStatus, ActionType, } from '../../types';
|
|
15
|
+
export const groupDefinition = {
|
|
16
|
+
id: 'group',
|
|
17
|
+
name: 'Group',
|
|
18
|
+
description: 'Visually group a set of steps — drop nodes inside to nest them.',
|
|
19
|
+
category: ActionCategory.Logic,
|
|
20
|
+
type: ActionType.Group,
|
|
21
|
+
tags: ['logic', 'container', 'subflow', 'built-in'],
|
|
22
|
+
status: ActionStatus.Stable,
|
|
23
|
+
icon: 'GroupObjects',
|
|
24
|
+
color: '#6f6f6f',
|
|
25
|
+
// No fields — the group itself has no config.
|
|
26
|
+
inputSchema: { fields: [] },
|
|
27
|
+
// The engine surfaces whatever the last child step emitted; we
|
|
28
|
+
// declare a generic output bag so downstream nodes can still see
|
|
29
|
+
// "something" came out of the group.
|
|
30
|
+
outputSchema: {
|
|
31
|
+
type: 'object',
|
|
32
|
+
properties: [
|
|
33
|
+
{
|
|
34
|
+
key: 'result',
|
|
35
|
+
type: 'object',
|
|
36
|
+
description: 'Aggregated output of the contained steps.',
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
version: '1.0.0',
|
|
41
|
+
createdAt: '2026-05-19T00:00:00Z',
|
|
42
|
+
updatedAt: '2026-05-19T00:00:00Z',
|
|
43
|
+
createdBy: 'system',
|
|
44
|
+
isOfficial: true,
|
|
45
|
+
testable: false,
|
|
46
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Policies
|
|
3
|
+
* Define rules and constraints for workflow behavior
|
|
4
|
+
*/
|
|
5
|
+
export interface WorkflowPolicies {
|
|
6
|
+
connection: ConnectionPolicies;
|
|
7
|
+
node: NodePolicies;
|
|
8
|
+
execution: ExecutionPolicies;
|
|
9
|
+
validation: ValidationPolicies;
|
|
10
|
+
}
|
|
11
|
+
export interface ConnectionPolicies {
|
|
12
|
+
allowSelfLoop: boolean;
|
|
13
|
+
allowMultipleOutputs: boolean;
|
|
14
|
+
allowMultipleInputs: boolean;
|
|
15
|
+
strictTypeChecking: boolean;
|
|
16
|
+
maxConnectionsPerNode?: number;
|
|
17
|
+
preventCircularDependencies: boolean;
|
|
18
|
+
allowConditionalConnections: boolean;
|
|
19
|
+
requireAllInputsConnected: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface NodePolicies {
|
|
22
|
+
minNodes: number;
|
|
23
|
+
maxNodes?: number;
|
|
24
|
+
allowDuplicateTypes: boolean;
|
|
25
|
+
requiredNodeTypes?: string[];
|
|
26
|
+
forbiddenNodeTypes?: string[];
|
|
27
|
+
allowOrphanNodes: boolean;
|
|
28
|
+
snapToGrid: boolean;
|
|
29
|
+
gridSize: number;
|
|
30
|
+
}
|
|
31
|
+
export interface ExecutionPolicies {
|
|
32
|
+
allowParallelExecution: boolean;
|
|
33
|
+
maxExecutionTime?: number;
|
|
34
|
+
retryFailedNodes: boolean;
|
|
35
|
+
maxRetries: number;
|
|
36
|
+
continueOnError: boolean;
|
|
37
|
+
requireApproval: boolean;
|
|
38
|
+
}
|
|
39
|
+
export interface ValidationPolicies {
|
|
40
|
+
validateOnChange: boolean;
|
|
41
|
+
validateBeforeExecution: boolean;
|
|
42
|
+
blockExecutionOnValidationError: boolean;
|
|
43
|
+
showValidationWarnings: boolean;
|
|
44
|
+
strictMode: boolean;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Policy violation types
|
|
48
|
+
*/
|
|
49
|
+
export declare enum PolicyViolationType {
|
|
50
|
+
SelfLoop = "self_loop",
|
|
51
|
+
MultipleOutputs = "multiple_outputs",
|
|
52
|
+
MultipleInputs = "multiple_inputs",
|
|
53
|
+
TypeMismatch = "type_mismatch",
|
|
54
|
+
MaxConnectionsExceeded = "max_connections_exceeded",
|
|
55
|
+
CircularDependency = "circular_dependency",
|
|
56
|
+
OrphanNode = "orphan_node",
|
|
57
|
+
MissingRequiredNode = "missing_required_node",
|
|
58
|
+
ForbiddenNodeType = "forbidden_node_type",
|
|
59
|
+
MaxNodesExceeded = "max_nodes_exceeded",
|
|
60
|
+
MinNodesNotMet = "min_nodes_not_met",
|
|
61
|
+
RequiredInputNotConnected = "required_input_not_connected"
|
|
62
|
+
}
|
|
63
|
+
export interface PolicyViolation {
|
|
64
|
+
type: PolicyViolationType;
|
|
65
|
+
severity: 'error' | 'warning' | 'info';
|
|
66
|
+
message: string;
|
|
67
|
+
nodeId?: string;
|
|
68
|
+
edgeId?: string;
|
|
69
|
+
portId?: string;
|
|
70
|
+
suggestion?: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Default workflow policies
|
|
74
|
+
*/
|
|
75
|
+
export declare const DEFAULT_WORKFLOW_POLICIES: WorkflowPolicies;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Policies
|
|
3
|
+
* Define rules and constraints for workflow behavior
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Policy violation types
|
|
7
|
+
*/
|
|
8
|
+
export var PolicyViolationType;
|
|
9
|
+
(function (PolicyViolationType) {
|
|
10
|
+
PolicyViolationType["SelfLoop"] = "self_loop";
|
|
11
|
+
PolicyViolationType["MultipleOutputs"] = "multiple_outputs";
|
|
12
|
+
PolicyViolationType["MultipleInputs"] = "multiple_inputs";
|
|
13
|
+
PolicyViolationType["TypeMismatch"] = "type_mismatch";
|
|
14
|
+
PolicyViolationType["MaxConnectionsExceeded"] = "max_connections_exceeded";
|
|
15
|
+
PolicyViolationType["CircularDependency"] = "circular_dependency";
|
|
16
|
+
PolicyViolationType["OrphanNode"] = "orphan_node";
|
|
17
|
+
PolicyViolationType["MissingRequiredNode"] = "missing_required_node";
|
|
18
|
+
PolicyViolationType["ForbiddenNodeType"] = "forbidden_node_type";
|
|
19
|
+
PolicyViolationType["MaxNodesExceeded"] = "max_nodes_exceeded";
|
|
20
|
+
PolicyViolationType["MinNodesNotMet"] = "min_nodes_not_met";
|
|
21
|
+
PolicyViolationType["RequiredInputNotConnected"] = "required_input_not_connected";
|
|
22
|
+
})(PolicyViolationType || (PolicyViolationType = {}));
|
|
23
|
+
/**
|
|
24
|
+
* Default workflow policies
|
|
25
|
+
*/
|
|
26
|
+
export const DEFAULT_WORKFLOW_POLICIES = {
|
|
27
|
+
connection: {
|
|
28
|
+
allowSelfLoop: false,
|
|
29
|
+
allowMultipleOutputs: true,
|
|
30
|
+
allowMultipleInputs: false,
|
|
31
|
+
strictTypeChecking: true,
|
|
32
|
+
maxConnectionsPerNode: undefined,
|
|
33
|
+
preventCircularDependencies: true,
|
|
34
|
+
allowConditionalConnections: true,
|
|
35
|
+
requireAllInputsConnected: false,
|
|
36
|
+
},
|
|
37
|
+
node: {
|
|
38
|
+
minNodes: 1,
|
|
39
|
+
maxNodes: undefined,
|
|
40
|
+
allowDuplicateTypes: true,
|
|
41
|
+
requiredNodeTypes: undefined,
|
|
42
|
+
forbiddenNodeTypes: undefined,
|
|
43
|
+
allowOrphanNodes: true,
|
|
44
|
+
snapToGrid: true,
|
|
45
|
+
gridSize: 20,
|
|
46
|
+
},
|
|
47
|
+
execution: {
|
|
48
|
+
allowParallelExecution: true,
|
|
49
|
+
maxExecutionTime: undefined,
|
|
50
|
+
retryFailedNodes: true,
|
|
51
|
+
maxRetries: 3,
|
|
52
|
+
continueOnError: false,
|
|
53
|
+
requireApproval: false,
|
|
54
|
+
},
|
|
55
|
+
validation: {
|
|
56
|
+
validateOnChange: true,
|
|
57
|
+
validateBeforeExecution: true,
|
|
58
|
+
blockExecutionOnValidationError: true,
|
|
59
|
+
showValidationWarnings: true,
|
|
60
|
+
strictMode: false,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ActionCategory, ActionType, ActionStatus, FieldType } from '../../types';
|
|
2
|
+
export const csvActionDefinition = {
|
|
3
|
+
id: 'csv_action',
|
|
4
|
+
name: 'CSV',
|
|
5
|
+
description: 'Parse CSV files into structured records or generate CSV files from workflow data',
|
|
6
|
+
category: ActionCategory.Storage,
|
|
7
|
+
type: ActionType.CsvAction,
|
|
8
|
+
tags: ['csv', 'parse', 'generate', 'file', 'format', 'built-in'],
|
|
9
|
+
status: ActionStatus.Stable,
|
|
10
|
+
icon: 'Document',
|
|
11
|
+
color: '#198038',
|
|
12
|
+
inputSchema: {
|
|
13
|
+
fields: [
|
|
14
|
+
{ key: 'operation', label: 'Operation', type: FieldType.Select, options: [{ label: 'Parse (CSV → Records)', value: 'parse' }, { label: 'Generate (Records → CSV)', value: 'generate' }], defaultValue: 'parse', validation: { required: true } },
|
|
15
|
+
{ key: 'content', label: 'CSV Content', type: FieldType.String, description: 'Paste CSV content or use FX token from upstream step' },
|
|
16
|
+
{ key: 'delimiter', label: 'Delimiter', type: FieldType.Select, options: [{ label: 'Comma (,)', value: ',' }, { label: 'Semicolon (;)', value: ';' }, { label: 'Tab', value: '\t' }, { label: 'Pipe (|)', value: '|' }], defaultValue: ',' },
|
|
17
|
+
{ key: 'headerRow', label: 'Header Row', type: FieldType.Number, description: 'Row number containing column headers (default: 1)', defaultValue: 1 },
|
|
18
|
+
{ key: 'encoding', label: 'Encoding', type: FieldType.Select, options: [{ label: 'UTF-8', value: 'utf-8' }, { label: 'Latin-1', value: 'latin1' }, { label: 'ASCII', value: 'ascii' }], defaultValue: 'utf-8' },
|
|
19
|
+
{ key: 'includeHeader', label: 'Include Header Row', type: FieldType.Boolean, description: 'Include column headers in generated CSV', defaultValue: true },
|
|
20
|
+
{ key: 'fileName', label: 'Output File Name', type: FieldType.String, description: 'Name for generated file (e.g. export.csv)', defaultValue: 'export.csv' },
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
outputSchema: {
|
|
24
|
+
type: 'object',
|
|
25
|
+
properties: [
|
|
26
|
+
{ key: 'data', type: FieldType.Array, description: 'Parsed records (parse mode) — loop these with a ForEach. Generated CSV string in generate mode.' },
|
|
27
|
+
{ key: 'columns', type: FieldType.JSON, description: 'Column names' },
|
|
28
|
+
{ key: 'rowCount', type: FieldType.Number, description: 'Number of records' },
|
|
29
|
+
],
|
|
30
|
+
sampleOutput: { data: [{ id: 1, name: 'Widget', price: 9.99 }], columns: ['id', 'name', 'price'], rowCount: 1 },
|
|
31
|
+
},
|
|
32
|
+
version: '1.0.0',
|
|
33
|
+
createdAt: '2026-03-28T00:00:00Z',
|
|
34
|
+
updatedAt: '2026-03-28T00:00:00Z',
|
|
35
|
+
createdBy: 'system',
|
|
36
|
+
isOfficial: true,
|
|
37
|
+
testable: false,
|
|
38
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ActionCategory, ActionType, ActionStatus, FieldType } from '../../types';
|
|
2
|
+
export const dropboxActionDefinition = {
|
|
3
|
+
id: 'dropbox_action',
|
|
4
|
+
name: 'Dropbox',
|
|
5
|
+
description: 'Upload, download, list, delete, move, or copy files in Dropbox',
|
|
6
|
+
category: ActionCategory.Storage,
|
|
7
|
+
type: ActionType.DropboxAction,
|
|
8
|
+
tags: ['dropbox', 'cloud', 'storage', 'upload', 'download', 'built-in'],
|
|
9
|
+
status: ActionStatus.Beta,
|
|
10
|
+
icon: 'CloudUpload',
|
|
11
|
+
color: '#0061FF',
|
|
12
|
+
inputSchema: {
|
|
13
|
+
fields: [
|
|
14
|
+
{ key: 'connector', label: 'Dropbox Account', type: FieldType.Connection, description: 'Select a connected Dropbox account', validation: { required: true } },
|
|
15
|
+
{ key: 'operation', label: 'Operation', type: FieldType.Select, options: [{ label: 'Download File', value: 'download' }, { label: 'Upload File', value: 'upload' }, { label: 'List Files', value: 'list' }, { label: 'Delete', value: 'delete' }, { label: 'Move', value: 'move' }, { label: 'Copy', value: 'copy' }, { label: 'Create Folder', value: 'create_folder' }, { label: 'Get Shared Link', value: 'shared_link' }], defaultValue: 'download', validation: { required: true } },
|
|
16
|
+
{ key: 'path', label: 'File / Folder Path', type: FieldType.String, description: 'Path on Dropbox (use file explorer to browse)' },
|
|
17
|
+
{ key: 'content', label: 'File Content (Upload)', type: FieldType.String, description: 'Content to upload — use FX token from upstream' },
|
|
18
|
+
{ key: 'fileName', label: 'File Name (Upload)', type: FieldType.String },
|
|
19
|
+
{ key: 'destPath', label: 'Destination Path (Move/Copy)', type: FieldType.String },
|
|
20
|
+
{ key: 'mode', label: 'Upload Mode', type: FieldType.Select, options: [{ label: 'Add (fail if exists)', value: 'add' }, { label: 'Overwrite', value: 'overwrite' }], defaultValue: 'overwrite' },
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
outputSchema: {
|
|
24
|
+
type: 'object',
|
|
25
|
+
properties: [
|
|
26
|
+
{ key: 'data', type: FieldType.JSON, description: 'File content, list, or metadata' },
|
|
27
|
+
{ key: 'path', type: FieldType.String, description: 'Dropbox file path' },
|
|
28
|
+
{ key: 'sharedLink', type: FieldType.String, description: 'Shared link URL' },
|
|
29
|
+
],
|
|
30
|
+
sampleOutput: { path: '/reports/monthly.csv', data: 'content...' },
|
|
31
|
+
},
|
|
32
|
+
version: '1.0.0', createdAt: '2026-03-28T00:00:00Z', updatedAt: '2026-03-28T00:00:00Z', createdBy: 'system', isOfficial: true, testable: false,
|
|
33
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ActionCategory, ActionType, ActionStatus, FieldType } from '../../types';
|
|
2
|
+
export const excelActionDefinition = {
|
|
3
|
+
id: 'excel_action',
|
|
4
|
+
name: 'Excel',
|
|
5
|
+
description: 'Parse Excel (.xlsx) files into structured records or generate Excel files from workflow data',
|
|
6
|
+
category: ActionCategory.Storage,
|
|
7
|
+
type: ActionType.ExcelAction,
|
|
8
|
+
tags: ['excel', 'xlsx', 'xls', 'spreadsheet', 'parse', 'generate', 'built-in'],
|
|
9
|
+
status: ActionStatus.Stable,
|
|
10
|
+
icon: 'Spreadsheet',
|
|
11
|
+
color: '#217346',
|
|
12
|
+
inputSchema: {
|
|
13
|
+
fields: [
|
|
14
|
+
{ key: 'operation', label: 'Operation', type: FieldType.Select, options: [{ label: 'Parse (Excel → Records)', value: 'parse' }, { label: 'Generate (Records → Excel)', value: 'generate' }], defaultValue: 'parse', validation: { required: true } },
|
|
15
|
+
{ key: 'content', label: 'Excel File', type: FieldType.String, description: 'S3 key of uploaded Excel file or FX token from upstream' },
|
|
16
|
+
{ key: 'sheetName', label: 'Sheet Name', type: FieldType.String, description: 'Name of sheet to read (default: first sheet)' },
|
|
17
|
+
{ key: 'headerRow', label: 'Header Row', type: FieldType.Number, description: 'Row number containing headers', defaultValue: 1 },
|
|
18
|
+
{ key: 'fileName', label: 'Output File Name', type: FieldType.String, defaultValue: 'export.xlsx' },
|
|
19
|
+
],
|
|
20
|
+
},
|
|
21
|
+
outputSchema: {
|
|
22
|
+
type: 'object',
|
|
23
|
+
properties: [
|
|
24
|
+
{ key: 'data', type: FieldType.Array, description: 'Parsed records (parse mode) — loop these with a ForEach. File metadata in generate mode.' },
|
|
25
|
+
{ key: 'columns', type: FieldType.JSON, description: 'Column names' },
|
|
26
|
+
{ key: 'rowCount', type: FieldType.Number, description: 'Number of records' },
|
|
27
|
+
{ key: 's3Key', type: FieldType.String, description: 'S3 key of generated file' },
|
|
28
|
+
],
|
|
29
|
+
sampleOutput: { data: [{ id: 1, name: 'Widget' }], columns: ['id', 'name'], rowCount: 1 },
|
|
30
|
+
},
|
|
31
|
+
version: '1.0.0', createdAt: '2026-03-28T00:00:00Z', updatedAt: '2026-03-28T00:00:00Z', createdBy: 'system', isOfficial: true, testable: false,
|
|
32
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { ActionCategory, ActionType, ActionStatus, FieldType } from '../../types';
|
|
2
|
+
export const fileActionDefinition = {
|
|
3
|
+
id: 'file_action',
|
|
4
|
+
name: 'Files',
|
|
5
|
+
description: 'Parse, generate, or convert files (CSV, JSON, XML, Excel). Read from S3, SFTP, FTP, Google Drive, URL, or upload. Write generated files to any storage destination.',
|
|
6
|
+
category: ActionCategory.Storage,
|
|
7
|
+
type: ActionType.FileAction,
|
|
8
|
+
tags: ['file', 'csv', 'json', 'xml', 'excel', 'parse', 'generate', 'convert', 's3', 'sftp', 'ftp', 'built-in'],
|
|
9
|
+
status: ActionStatus.Beta,
|
|
10
|
+
icon: 'DocumentImport',
|
|
11
|
+
color: '#6929c4',
|
|
12
|
+
inputSchema: {
|
|
13
|
+
fields: [
|
|
14
|
+
{
|
|
15
|
+
key: 'mode',
|
|
16
|
+
label: 'Mode',
|
|
17
|
+
type: FieldType.Select,
|
|
18
|
+
options: [
|
|
19
|
+
{ label: 'Parse File (Read)', value: 'parse' },
|
|
20
|
+
{ label: 'Generate File (Write)', value: 'generate' },
|
|
21
|
+
{ label: 'Convert Format', value: 'convert' },
|
|
22
|
+
],
|
|
23
|
+
defaultValue: 'parse',
|
|
24
|
+
validation: { required: true },
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
key: 'source',
|
|
28
|
+
label: 'Source',
|
|
29
|
+
type: FieldType.Select,
|
|
30
|
+
options: [
|
|
31
|
+
// 'upload' removed: there is no runtime upload source — the Engine
|
|
32
|
+
// always failed it with "No content to parse" (DEV-249).
|
|
33
|
+
{ label: 'AWS S3', value: 's3' },
|
|
34
|
+
{ label: 'URL', value: 'url' },
|
|
35
|
+
{ label: 'Inline Paste', value: 'inline' },
|
|
36
|
+
{ label: 'Previous Step Output', value: 'previous_step' },
|
|
37
|
+
],
|
|
38
|
+
defaultValue: 'inline',
|
|
39
|
+
validation: { required: false },
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
key: 'format',
|
|
43
|
+
label: 'File Format',
|
|
44
|
+
type: FieldType.Select,
|
|
45
|
+
options: [
|
|
46
|
+
{ label: 'Auto-detect', value: 'auto' },
|
|
47
|
+
{ label: 'CSV', value: 'csv' },
|
|
48
|
+
{ label: 'TSV', value: 'tsv' },
|
|
49
|
+
{ label: 'JSON', value: 'json' },
|
|
50
|
+
{ label: 'JSONL', value: 'jsonl' },
|
|
51
|
+
{ label: 'XML', value: 'xml' },
|
|
52
|
+
{ label: 'Excel (.xlsx)', value: 'excel' },
|
|
53
|
+
],
|
|
54
|
+
defaultValue: 'auto',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
key: 'inlineContent',
|
|
58
|
+
label: 'File Content',
|
|
59
|
+
type: FieldType.String,
|
|
60
|
+
description: 'Paste CSV, JSON, or other file content here',
|
|
61
|
+
validation: { required: false },
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
key: 's3Key',
|
|
65
|
+
label: 'S3 Key',
|
|
66
|
+
type: FieldType.String,
|
|
67
|
+
description: 'S3 object key (path) to read from',
|
|
68
|
+
validation: { required: false },
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
key: 'url',
|
|
72
|
+
label: 'File URL',
|
|
73
|
+
type: FieldType.String,
|
|
74
|
+
description: 'Public URL to download file from',
|
|
75
|
+
validation: { required: false },
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
key: 'outputFormat',
|
|
79
|
+
label: 'Output Format (Generate/Convert)',
|
|
80
|
+
type: FieldType.Select,
|
|
81
|
+
options: [
|
|
82
|
+
{ label: 'CSV', value: 'csv' },
|
|
83
|
+
{ label: 'JSON', value: 'json' },
|
|
84
|
+
{ label: 'Excel (.xlsx)', value: 'excel' },
|
|
85
|
+
{ label: 'XML', value: 'xml' },
|
|
86
|
+
{ label: 'TSV', value: 'tsv' },
|
|
87
|
+
],
|
|
88
|
+
defaultValue: 'csv',
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
key: 'outputFileName',
|
|
92
|
+
label: 'Output File Name',
|
|
93
|
+
type: FieldType.String,
|
|
94
|
+
description: 'Name for generated file (e.g. report.csv)',
|
|
95
|
+
validation: { required: false },
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
outputSchema: {
|
|
100
|
+
type: 'object',
|
|
101
|
+
properties: [
|
|
102
|
+
{ key: 'data', type: FieldType.JSON, description: 'Parsed records (parse mode) or file metadata (generate mode)' },
|
|
103
|
+
{ key: 'columns', type: FieldType.JSON, description: 'Column names from parsed file' },
|
|
104
|
+
{ key: 'rowCount', type: FieldType.Number, description: 'Number of records' },
|
|
105
|
+
{ key: 's3Key', type: FieldType.String, description: 'S3 key of generated file' },
|
|
106
|
+
],
|
|
107
|
+
sampleOutput: {
|
|
108
|
+
data: [{ id: 1, name: 'Widget', price: 9.99 }],
|
|
109
|
+
columns: ['id', 'name', 'price'],
|
|
110
|
+
rowCount: 1,
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
version: '1.0.0',
|
|
114
|
+
createdAt: '2026-03-27T00:00:00Z',
|
|
115
|
+
updatedAt: '2026-03-27T00:00:00Z',
|
|
116
|
+
createdBy: 'system',
|
|
117
|
+
isOfficial: true,
|
|
118
|
+
testable: false,
|
|
119
|
+
};
|