@fsai-flow/workflow 0.0.1
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/.eslintrc.json +33 -0
- package/README.md +11 -0
- package/dist/README.md +11 -0
- package/dist/package.json +42 -0
- package/dist/src/index.d.ts +21 -0
- package/dist/src/index.js +33 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/lib/Constants.d.ts +68 -0
- package/dist/src/lib/Constants.js +106 -0
- package/dist/src/lib/Constants.js.map +1 -0
- package/dist/src/lib/DeferredPromise.d.ts +6 -0
- package/dist/src/lib/DeferredPromise.js +11 -0
- package/dist/src/lib/DeferredPromise.js.map +1 -0
- package/dist/src/lib/Expression.d.ts +65 -0
- package/dist/src/lib/Expression.js +215 -0
- package/dist/src/lib/Expression.js.map +1 -0
- package/dist/src/lib/Interfaces.d.ts +1569 -0
- package/dist/src/lib/Interfaces.js +44 -0
- package/dist/src/lib/Interfaces.js.map +1 -0
- package/dist/src/lib/LoggerProxy.d.ts +9 -0
- package/dist/src/lib/LoggerProxy.js +40 -0
- package/dist/src/lib/LoggerProxy.js.map +1 -0
- package/dist/src/lib/MetadataUtils.d.ts +4 -0
- package/dist/src/lib/MetadataUtils.js +27 -0
- package/dist/src/lib/MetadataUtils.js.map +1 -0
- package/dist/src/lib/NodeErrors.d.ts +82 -0
- package/dist/src/lib/NodeErrors.js +289 -0
- package/dist/src/lib/NodeErrors.js.map +1 -0
- package/dist/src/lib/NodeHelpers.d.ts +198 -0
- package/dist/src/lib/NodeHelpers.js +1348 -0
- package/dist/src/lib/NodeHelpers.js.map +1 -0
- package/dist/src/lib/ObservableObject.d.ts +5 -0
- package/dist/src/lib/ObservableObject.js +61 -0
- package/dist/src/lib/ObservableObject.js.map +1 -0
- package/dist/src/lib/RoutingNode.d.ts +18 -0
- package/dist/src/lib/RoutingNode.js +508 -0
- package/dist/src/lib/RoutingNode.js.map +1 -0
- package/dist/src/lib/TelemetryHelpers.d.ts +3 -0
- package/dist/src/lib/TelemetryHelpers.js +69 -0
- package/dist/src/lib/TelemetryHelpers.js.map +1 -0
- package/dist/src/lib/TypeValidation.d.ts +21 -0
- package/dist/src/lib/TypeValidation.js +385 -0
- package/dist/src/lib/TypeValidation.js.map +1 -0
- package/dist/src/lib/VersionedNodeType.d.ts +9 -0
- package/dist/src/lib/VersionedNodeType.js +26 -0
- package/dist/src/lib/VersionedNodeType.js.map +1 -0
- package/dist/src/lib/Workflow.d.ts +248 -0
- package/dist/src/lib/Workflow.js +901 -0
- package/dist/src/lib/Workflow.js.map +1 -0
- package/dist/src/lib/WorkflowDataProxy.d.ts +87 -0
- package/dist/src/lib/WorkflowDataProxy.js +556 -0
- package/dist/src/lib/WorkflowDataProxy.js.map +1 -0
- package/dist/src/lib/WorkflowErrors.d.ts +9 -0
- package/dist/src/lib/WorkflowErrors.js +18 -0
- package/dist/src/lib/WorkflowErrors.js.map +1 -0
- package/dist/src/lib/WorkflowHooks.d.ts +11 -0
- package/dist/src/lib/WorkflowHooks.js +34 -0
- package/dist/src/lib/WorkflowHooks.js.map +1 -0
- package/dist/src/lib/errors/base/base.error.d.ts +30 -0
- package/dist/src/lib/errors/base/base.error.js +45 -0
- package/dist/src/lib/errors/base/base.error.js.map +1 -0
- package/dist/src/lib/errors/base/operational.error.d.ts +15 -0
- package/dist/src/lib/errors/base/operational.error.js +19 -0
- package/dist/src/lib/errors/base/operational.error.js.map +1 -0
- package/dist/src/lib/errors/error.types.d.ts +11 -0
- package/dist/src/lib/errors/error.types.js +3 -0
- package/dist/src/lib/errors/error.types.js.map +1 -0
- package/dist/src/lib/errors/index.d.ts +1 -0
- package/dist/src/lib/errors/index.js +6 -0
- package/dist/src/lib/errors/index.js.map +1 -0
- package/dist/src/lib/result.d.ts +19 -0
- package/dist/src/lib/result.js +36 -0
- package/dist/src/lib/result.js.map +1 -0
- package/dist/src/lib/utils.d.ts +50 -0
- package/dist/src/lib/utils.js +110 -0
- package/dist/src/lib/utils.js.map +1 -0
- package/eslint.config.js +19 -0
- package/jest.config.ts +10 -0
- package/package.json +40 -0
- package/project.json +19 -0
- package/src/index.ts +33 -0
- package/src/lib/Constants.ts +124 -0
- package/src/lib/DeferredPromise.ts +14 -0
- package/src/lib/Expression.ts +375 -0
- package/src/lib/Interfaces.ts +2229 -0
- package/src/lib/LoggerProxy.ts +43 -0
- package/src/lib/MetadataUtils.ts +34 -0
- package/src/lib/NodeErrors.ts +332 -0
- package/src/lib/NodeHelpers.ts +1666 -0
- package/src/lib/ObservableObject.ts +77 -0
- package/src/lib/RoutingNode.ts +862 -0
- package/src/lib/TelemetryHelpers.ts +86 -0
- package/src/lib/TypeValidation.ts +431 -0
- package/src/lib/VersionedNodeType.ts +30 -0
- package/src/lib/Workflow.ts +1266 -0
- package/src/lib/WorkflowDataProxy.ts +708 -0
- package/src/lib/WorkflowErrors.ts +18 -0
- package/src/lib/WorkflowHooks.ts +51 -0
- package/src/lib/errors/base/base.error.ts +68 -0
- package/src/lib/errors/base/operational.error.ts +21 -0
- package/src/lib/errors/error.types.ts +14 -0
- package/src/lib/errors/index.ts +1 -0
- package/src/lib/result.ts +34 -0
- package/src/lib/utils.ts +132 -0
- package/tests/Helpers.ts +667 -0
- package/tests/NodeHelpers.test.ts +3053 -0
- package/tests/ObservableObject.test.ts +171 -0
- package/tests/RoutingNode.test.ts +1680 -0
- package/tests/Workflow.test.ts +1284 -0
- package/tests/WorkflowDataProxy.test.ts +199 -0
- package/tsconfig.json +27 -0
- package/tsconfig.lib.json +11 -0
- package/tsconfig.spec.json +14 -0
|
@@ -0,0 +1,708 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
3
|
+
/* eslint-disable no-restricted-syntax */
|
|
4
|
+
/* eslint-disable no-param-reassign */
|
|
5
|
+
/* eslint-disable @typescript-eslint/no-this-alias */
|
|
6
|
+
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
7
|
+
/* eslint-disable no-prototype-builtins */
|
|
8
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
9
|
+
|
|
10
|
+
import { DateTime, Duration, Interval } from 'luxon';
|
|
11
|
+
import * as jmespath from 'jmespath';
|
|
12
|
+
|
|
13
|
+
// eslint-disable-next-line import/no-cycle
|
|
14
|
+
import {
|
|
15
|
+
IDataObject,
|
|
16
|
+
INodeExecutionData,
|
|
17
|
+
INodeParameters,
|
|
18
|
+
IRunExecutionData,
|
|
19
|
+
IWorkflowDataProxyAdditionalKeys,
|
|
20
|
+
IWorkflowDataProxyData,
|
|
21
|
+
NodeHelpers,
|
|
22
|
+
NodeParameterValue,
|
|
23
|
+
Workflow,
|
|
24
|
+
WorkflowExecuteMode,
|
|
25
|
+
} from '..';
|
|
26
|
+
|
|
27
|
+
export class WorkflowDataProxy {
|
|
28
|
+
private workflow: Workflow;
|
|
29
|
+
|
|
30
|
+
private runExecutionData: IRunExecutionData | null;
|
|
31
|
+
|
|
32
|
+
private defaultReturnRunIndex: number;
|
|
33
|
+
|
|
34
|
+
private runIndex: number;
|
|
35
|
+
|
|
36
|
+
private itemIndex: number;
|
|
37
|
+
|
|
38
|
+
private activeNodeName: string;
|
|
39
|
+
|
|
40
|
+
private connectionInputData: INodeExecutionData[];
|
|
41
|
+
|
|
42
|
+
private siblingParameters: INodeParameters;
|
|
43
|
+
|
|
44
|
+
private mode: WorkflowExecuteMode;
|
|
45
|
+
|
|
46
|
+
private selfData: IDataObject;
|
|
47
|
+
|
|
48
|
+
private additionalKeys: IWorkflowDataProxyAdditionalKeys;
|
|
49
|
+
|
|
50
|
+
constructor(
|
|
51
|
+
workflow: Workflow,
|
|
52
|
+
runExecutionData: IRunExecutionData | null,
|
|
53
|
+
runIndex: number,
|
|
54
|
+
itemIndex: number,
|
|
55
|
+
activeNodeName: string,
|
|
56
|
+
connectionInputData: INodeExecutionData[],
|
|
57
|
+
siblingParameters: INodeParameters,
|
|
58
|
+
mode: WorkflowExecuteMode,
|
|
59
|
+
additionalKeys: IWorkflowDataProxyAdditionalKeys,
|
|
60
|
+
defaultReturnRunIndex = -1,
|
|
61
|
+
selfData = {},
|
|
62
|
+
) {
|
|
63
|
+
this.workflow = workflow;
|
|
64
|
+
this.runExecutionData = runExecutionData;
|
|
65
|
+
this.defaultReturnRunIndex = defaultReturnRunIndex;
|
|
66
|
+
this.runIndex = runIndex;
|
|
67
|
+
this.itemIndex = itemIndex;
|
|
68
|
+
this.activeNodeName = activeNodeName;
|
|
69
|
+
this.connectionInputData = connectionInputData;
|
|
70
|
+
this.siblingParameters = siblingParameters;
|
|
71
|
+
this.mode = mode;
|
|
72
|
+
this.selfData = selfData;
|
|
73
|
+
this.additionalKeys = additionalKeys;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Returns a proxy which allows to query context data of a given node
|
|
78
|
+
*
|
|
79
|
+
* @private
|
|
80
|
+
* @param {string} nodeName The name of the node to get the context from
|
|
81
|
+
* @returns
|
|
82
|
+
* @memberof WorkflowDataProxy
|
|
83
|
+
*/
|
|
84
|
+
private nodeContextGetter(nodeName: string) {
|
|
85
|
+
const that = this;
|
|
86
|
+
const node = this.workflow.nodes[nodeName];
|
|
87
|
+
|
|
88
|
+
return new Proxy(
|
|
89
|
+
{},
|
|
90
|
+
{
|
|
91
|
+
ownKeys(target) {
|
|
92
|
+
if (Reflect.ownKeys(target).length === 0) {
|
|
93
|
+
// Target object did not get set yet
|
|
94
|
+
Object.assign(target, NodeHelpers.getContext(that.runExecutionData!, 'node', node));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return Reflect.ownKeys(target);
|
|
98
|
+
},
|
|
99
|
+
getOwnPropertyDescriptor(k) {
|
|
100
|
+
return {
|
|
101
|
+
enumerable: true,
|
|
102
|
+
configurable: true,
|
|
103
|
+
};
|
|
104
|
+
},
|
|
105
|
+
get(target, name, receiver) {
|
|
106
|
+
// eslint-disable-next-line no-param-reassign
|
|
107
|
+
name = name.toString();
|
|
108
|
+
const contextData = NodeHelpers.getContext(that.runExecutionData!, 'node', node);
|
|
109
|
+
|
|
110
|
+
if (!contextData.hasOwnProperty(name)) {
|
|
111
|
+
// Parameter does not exist on node
|
|
112
|
+
throw new Error(`Could not find parameter "${name}" on context of node "${nodeName}"`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return contextData[name];
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private selfGetter() {
|
|
122
|
+
const that = this;
|
|
123
|
+
|
|
124
|
+
return new Proxy(
|
|
125
|
+
{},
|
|
126
|
+
{
|
|
127
|
+
ownKeys(target) {
|
|
128
|
+
return Reflect.ownKeys(target);
|
|
129
|
+
},
|
|
130
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
131
|
+
get(target, name, receiver) {
|
|
132
|
+
name = name.toString();
|
|
133
|
+
return that.selfData[name];
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Returns a proxy which allows to query parameter data of a given node
|
|
141
|
+
*
|
|
142
|
+
* @private
|
|
143
|
+
* @param {string} nodeName The name of the node to query data from
|
|
144
|
+
* @returns
|
|
145
|
+
* @memberof WorkflowDataGetter
|
|
146
|
+
*/
|
|
147
|
+
private nodeParameterGetter(nodeName: string) {
|
|
148
|
+
const that = this;
|
|
149
|
+
const node = this.workflow.nodes[nodeName];
|
|
150
|
+
|
|
151
|
+
return new Proxy(node.parameters, {
|
|
152
|
+
ownKeys(target) {
|
|
153
|
+
return Reflect.ownKeys(target);
|
|
154
|
+
},
|
|
155
|
+
getOwnPropertyDescriptor(k) {
|
|
156
|
+
return {
|
|
157
|
+
enumerable: true,
|
|
158
|
+
configurable: true,
|
|
159
|
+
};
|
|
160
|
+
},
|
|
161
|
+
get(target, name, receiver) {
|
|
162
|
+
name = name.toString();
|
|
163
|
+
|
|
164
|
+
let returnValue:
|
|
165
|
+
| INodeParameters
|
|
166
|
+
| NodeParameterValue
|
|
167
|
+
| NodeParameterValue[]
|
|
168
|
+
| INodeParameters[];
|
|
169
|
+
if (name[0] === '&') {
|
|
170
|
+
const key = name.slice(1);
|
|
171
|
+
if (!that.siblingParameters.hasOwnProperty(key)) {
|
|
172
|
+
throw new Error(`Could not find sibling parameter "${key}" on node "${nodeName}"`);
|
|
173
|
+
}
|
|
174
|
+
returnValue = that.siblingParameters[key];
|
|
175
|
+
} else {
|
|
176
|
+
if (!node.parameters.hasOwnProperty(name)) {
|
|
177
|
+
// Parameter does not exist on node
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
returnValue = node.parameters[name];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (typeof returnValue === 'string' && returnValue.charAt(0) === '=') {
|
|
185
|
+
// The found value is an expression so resolve it
|
|
186
|
+
return that.workflow.expression.getParameterValue(
|
|
187
|
+
returnValue,
|
|
188
|
+
that.runExecutionData,
|
|
189
|
+
that.runIndex,
|
|
190
|
+
that.itemIndex,
|
|
191
|
+
that.activeNodeName,
|
|
192
|
+
that.connectionInputData,
|
|
193
|
+
that.mode,
|
|
194
|
+
that.additionalKeys,
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return returnValue;
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Returns the node ExecutionData
|
|
205
|
+
*
|
|
206
|
+
* @private
|
|
207
|
+
* @param {string} nodeName The name of the node query data from
|
|
208
|
+
* @param {boolean} [shortSyntax=false] If short syntax got used
|
|
209
|
+
* @param {number} [outputIndex] The index of the output, if not given the first one gets used
|
|
210
|
+
* @param {number} [runIndex] The index of the run, if not given the current one does get used
|
|
211
|
+
* @returns {INodeExecutionData[]}
|
|
212
|
+
* @memberof WorkflowDataProxy
|
|
213
|
+
*/
|
|
214
|
+
private getNodeExecutionData(
|
|
215
|
+
nodeName: string,
|
|
216
|
+
shortSyntax = false,
|
|
217
|
+
outputIndex?: number,
|
|
218
|
+
runIndex?: number,
|
|
219
|
+
): INodeExecutionData[] {
|
|
220
|
+
const that = this;
|
|
221
|
+
|
|
222
|
+
let executionData: INodeExecutionData[];
|
|
223
|
+
if (!shortSyntax) {
|
|
224
|
+
// Long syntax got used to return data from node in path
|
|
225
|
+
|
|
226
|
+
if (that.runExecutionData === null) {
|
|
227
|
+
throw new Error(`Workflow did not run so do not have any execution-data.`);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (!that.runExecutionData.resultData.runData.hasOwnProperty(nodeName)) {
|
|
231
|
+
if (that.workflow.getNode(nodeName)) {
|
|
232
|
+
throw new Error(
|
|
233
|
+
`The node "${nodeName}" hasn't been executed yet, so you can't reference its output data`,
|
|
234
|
+
);
|
|
235
|
+
} else {
|
|
236
|
+
throw new Error(`No node called "${nodeName}" in this workflow`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
runIndex = runIndex === undefined ? that.defaultReturnRunIndex : runIndex;
|
|
241
|
+
runIndex =
|
|
242
|
+
runIndex === -1 ? that.runExecutionData.resultData.runData[nodeName].length - 1 : runIndex;
|
|
243
|
+
|
|
244
|
+
if (that.runExecutionData.resultData.runData[nodeName].length <= runIndex) {
|
|
245
|
+
throw new Error(`Run ${runIndex} of node "${nodeName}" not found`);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const taskData = that.runExecutionData.resultData.runData[nodeName][runIndex].data!;
|
|
249
|
+
|
|
250
|
+
if (taskData['main'] === null || !taskData['main'].length || taskData['main'][0] === null) {
|
|
251
|
+
// throw new Error(`No data found for item-index: "${itemIndex}"`);
|
|
252
|
+
throw new Error(`No data found from "main" input.`);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Check from which output to read the data.
|
|
256
|
+
// Depends on how the nodes are connected.
|
|
257
|
+
// (example "IF" node. If node is connected to "true" or to "false" output)
|
|
258
|
+
if (outputIndex === undefined) {
|
|
259
|
+
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
260
|
+
const outputIndex = that.workflow.getNodeConnectionOutputIndex(
|
|
261
|
+
that.activeNodeName,
|
|
262
|
+
nodeName,
|
|
263
|
+
'main',
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
if (outputIndex === undefined) {
|
|
267
|
+
throw new Error(
|
|
268
|
+
`The node "${that.activeNodeName}" is not connected with node "${nodeName}" so no data can get returned from it.`,
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (outputIndex === undefined) {
|
|
274
|
+
outputIndex = 0;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (taskData['main'].length <= outputIndex) {
|
|
278
|
+
throw new Error(`Node "${nodeName}" has no branch with index ${outputIndex}.`);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
executionData = taskData['main'][outputIndex] as INodeExecutionData[];
|
|
282
|
+
} else {
|
|
283
|
+
// Short syntax got used to return data from active node
|
|
284
|
+
|
|
285
|
+
// TODO: Here have to generate connection Input data for the current node by itself
|
|
286
|
+
// Data needed:
|
|
287
|
+
// #- the run-index
|
|
288
|
+
// - node which did send data (has to be the one from last recent execution)
|
|
289
|
+
// - later also the name of the input and its index (currently not needed as it is always "main" and index "0")
|
|
290
|
+
executionData = that.connectionInputData;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return executionData;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Returns a proxy which allows to query data of a given node
|
|
298
|
+
*
|
|
299
|
+
* @private
|
|
300
|
+
* @param {string} nodeName The name of the node query data from
|
|
301
|
+
* @param {boolean} [shortSyntax=false] If short syntax got used
|
|
302
|
+
* @returns
|
|
303
|
+
* @memberof WorkflowDataGetter
|
|
304
|
+
*/
|
|
305
|
+
private nodeDataGetter(nodeName: string, shortSyntax = false) {
|
|
306
|
+
const that = this;
|
|
307
|
+
const node = this.workflow.nodes[nodeName];
|
|
308
|
+
|
|
309
|
+
if (!node) {
|
|
310
|
+
return undefined;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return new Proxy(
|
|
314
|
+
{},
|
|
315
|
+
{
|
|
316
|
+
get(target, name, receiver) {
|
|
317
|
+
name = name.toString();
|
|
318
|
+
|
|
319
|
+
if (['binary', 'data', 'json'].includes(name)) {
|
|
320
|
+
const executionData = that.getNodeExecutionData(nodeName, shortSyntax, undefined);
|
|
321
|
+
|
|
322
|
+
if (executionData.length <= that.itemIndex) {
|
|
323
|
+
throw new Error(`No data found for item-index: "${that.itemIndex}"`);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (['data', 'json'].includes(name)) {
|
|
327
|
+
// JSON-Data
|
|
328
|
+
return executionData[that.itemIndex].json;
|
|
329
|
+
}
|
|
330
|
+
if (name === 'binary') {
|
|
331
|
+
// Binary-Data
|
|
332
|
+
const returnData: IDataObject = {};
|
|
333
|
+
|
|
334
|
+
if (!executionData[that.itemIndex].binary) {
|
|
335
|
+
return returnData;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const binaryKeyData = executionData[that.itemIndex].binary!;
|
|
339
|
+
for (const keyName of Object.keys(binaryKeyData)) {
|
|
340
|
+
returnData[keyName] = {};
|
|
341
|
+
|
|
342
|
+
const binaryData = binaryKeyData[keyName];
|
|
343
|
+
for (const propertyName in binaryData) {
|
|
344
|
+
if (propertyName === 'data') {
|
|
345
|
+
// Skip the data property
|
|
346
|
+
// eslint-disable-next-line no-continue
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
(returnData[keyName] as IDataObject)[propertyName] = binaryData[propertyName];
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return returnData;
|
|
354
|
+
}
|
|
355
|
+
} else if (name === 'context') {
|
|
356
|
+
return that.nodeContextGetter(nodeName);
|
|
357
|
+
} else if (name === 'parameter') {
|
|
358
|
+
// Get node parameter data
|
|
359
|
+
return that.nodeParameterGetter(nodeName);
|
|
360
|
+
} else if (name === 'runIndex') {
|
|
361
|
+
if (
|
|
362
|
+
that.runExecutionData === null ||
|
|
363
|
+
!that.runExecutionData.resultData.runData[nodeName]
|
|
364
|
+
) {
|
|
365
|
+
return -1;
|
|
366
|
+
}
|
|
367
|
+
return that.runExecutionData.resultData.runData[nodeName].length - 1;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return Reflect.get(target, name, receiver);
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Returns a proxy to query data from the environment
|
|
378
|
+
*
|
|
379
|
+
* @private
|
|
380
|
+
* @returns
|
|
381
|
+
* @memberof WorkflowDataGetter
|
|
382
|
+
*/
|
|
383
|
+
private envGetter() {
|
|
384
|
+
return new Proxy(
|
|
385
|
+
{},
|
|
386
|
+
{
|
|
387
|
+
get(target, name, receiver) {
|
|
388
|
+
return process.env[name.toString()];
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Returns a proxt to query data from the workflow
|
|
396
|
+
*
|
|
397
|
+
* @private
|
|
398
|
+
* @returns
|
|
399
|
+
* @memberof WorkflowDataProxy
|
|
400
|
+
*/
|
|
401
|
+
private workflowGetter() {
|
|
402
|
+
const allowedValues = ['active', 'id', 'name'];
|
|
403
|
+
const that = this;
|
|
404
|
+
|
|
405
|
+
return new Proxy(
|
|
406
|
+
{},
|
|
407
|
+
{
|
|
408
|
+
ownKeys(target) {
|
|
409
|
+
return allowedValues;
|
|
410
|
+
},
|
|
411
|
+
getOwnPropertyDescriptor(k) {
|
|
412
|
+
return {
|
|
413
|
+
enumerable: true,
|
|
414
|
+
configurable: true,
|
|
415
|
+
};
|
|
416
|
+
},
|
|
417
|
+
get(target, name, receiver) {
|
|
418
|
+
if (!allowedValues.includes(name.toString())) {
|
|
419
|
+
throw new Error(`The key "${name.toString()}" is not supported!`);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// @ts-ignore
|
|
423
|
+
return that.workflow[name.toString()];
|
|
424
|
+
},
|
|
425
|
+
},
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Returns a proxy to query data of all nodes
|
|
431
|
+
*
|
|
432
|
+
* @private
|
|
433
|
+
* @returns
|
|
434
|
+
* @memberof WorkflowDataGetter
|
|
435
|
+
*/
|
|
436
|
+
private nodeGetter() {
|
|
437
|
+
const that = this;
|
|
438
|
+
return new Proxy(
|
|
439
|
+
{},
|
|
440
|
+
{
|
|
441
|
+
get(target, name, receiver) {
|
|
442
|
+
return that.nodeDataGetter(name.toString());
|
|
443
|
+
},
|
|
444
|
+
},
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Returns the data proxy object which allows to query data from current run
|
|
450
|
+
*
|
|
451
|
+
* @returns
|
|
452
|
+
* @memberof WorkflowDataGetter
|
|
453
|
+
*/
|
|
454
|
+
getDataProxy(): IWorkflowDataProxyData {
|
|
455
|
+
const that = this;
|
|
456
|
+
|
|
457
|
+
const getNodeOutput = (nodeName?: string, branchIndex?: number, runIndex?: number) => {
|
|
458
|
+
let executionData: INodeExecutionData[];
|
|
459
|
+
|
|
460
|
+
if (nodeName === undefined) {
|
|
461
|
+
executionData = that.connectionInputData;
|
|
462
|
+
} else {
|
|
463
|
+
branchIndex = branchIndex || 0;
|
|
464
|
+
runIndex = runIndex === undefined ? -1 : runIndex;
|
|
465
|
+
executionData = that.getNodeExecutionData(nodeName, false, branchIndex, runIndex);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
return executionData;
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
// replacing proxies with the actual data.
|
|
472
|
+
const jmespathWrapper = (data: IDataObject | IDataObject[], query: string) => {
|
|
473
|
+
if (!Array.isArray(data) && typeof data === 'object') {
|
|
474
|
+
return jmespath.search({ ...data }, query);
|
|
475
|
+
}
|
|
476
|
+
return jmespath.search(data, query);
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
const base = {
|
|
480
|
+
$: (nodeName: string) => {
|
|
481
|
+
if (!nodeName) {
|
|
482
|
+
throw new Error(`When calling $(), please specify a node`);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
return new Proxy(
|
|
486
|
+
{},
|
|
487
|
+
{
|
|
488
|
+
get(target, property, receiver) {
|
|
489
|
+
if (property === 'pairedItem') {
|
|
490
|
+
return () => {
|
|
491
|
+
const executionData = getNodeOutput(nodeName, 0, that.runIndex);
|
|
492
|
+
if (executionData[that.itemIndex]) {
|
|
493
|
+
return executionData[that.itemIndex];
|
|
494
|
+
}
|
|
495
|
+
return undefined;
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
if (property === 'item') {
|
|
499
|
+
return (itemIndex?: number, branchIndex?: number, runIndex?: number) => {
|
|
500
|
+
if (itemIndex === undefined) {
|
|
501
|
+
itemIndex = that.itemIndex;
|
|
502
|
+
branchIndex = 0;
|
|
503
|
+
runIndex = that.runIndex;
|
|
504
|
+
}
|
|
505
|
+
const executionData = getNodeOutput(nodeName, branchIndex, runIndex);
|
|
506
|
+
if (executionData[itemIndex]) {
|
|
507
|
+
return executionData[itemIndex];
|
|
508
|
+
}
|
|
509
|
+
let errorMessage = '';
|
|
510
|
+
|
|
511
|
+
if (branchIndex === undefined && runIndex === undefined) {
|
|
512
|
+
errorMessage = `
|
|
513
|
+
No item found at index ${itemIndex}
|
|
514
|
+
(for node "${nodeName}")`;
|
|
515
|
+
throw new Error(errorMessage);
|
|
516
|
+
}
|
|
517
|
+
if (branchIndex === undefined) {
|
|
518
|
+
errorMessage = `
|
|
519
|
+
No item found at index ${itemIndex}
|
|
520
|
+
in run ${runIndex || that.runIndex}
|
|
521
|
+
(for node "${nodeName}")`;
|
|
522
|
+
throw new Error(errorMessage);
|
|
523
|
+
}
|
|
524
|
+
if (runIndex === undefined) {
|
|
525
|
+
errorMessage = `
|
|
526
|
+
No item found at index ${itemIndex}
|
|
527
|
+
of branch ${branchIndex || 0}
|
|
528
|
+
(for node "${nodeName}")`;
|
|
529
|
+
throw new Error(errorMessage);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
errorMessage = `
|
|
533
|
+
No item found at index ${itemIndex}
|
|
534
|
+
of branch ${branchIndex || 0}
|
|
535
|
+
in run ${runIndex || that.runIndex}
|
|
536
|
+
(for node "${nodeName}")`;
|
|
537
|
+
throw new Error(errorMessage);
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
if (property === 'first') {
|
|
541
|
+
return (branchIndex?: number, runIndex?: number) => {
|
|
542
|
+
const executionData = getNodeOutput(nodeName, branchIndex, runIndex);
|
|
543
|
+
if (executionData[0]) return executionData[0];
|
|
544
|
+
return undefined;
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
if (property === 'last') {
|
|
548
|
+
return (branchIndex?: number, runIndex?: number) => {
|
|
549
|
+
const executionData = getNodeOutput(nodeName, branchIndex, runIndex);
|
|
550
|
+
if (!executionData.length) return undefined;
|
|
551
|
+
if (executionData[executionData.length - 1]) {
|
|
552
|
+
return executionData[executionData.length - 1];
|
|
553
|
+
}
|
|
554
|
+
return undefined;
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
if (property === 'all') {
|
|
558
|
+
return (branchIndex?: number, runIndex?: number) =>
|
|
559
|
+
getNodeOutput(nodeName, branchIndex, runIndex);
|
|
560
|
+
}
|
|
561
|
+
if (property === 'context') {
|
|
562
|
+
return that.nodeContextGetter(nodeName);
|
|
563
|
+
}
|
|
564
|
+
if (property === 'params') {
|
|
565
|
+
return that.workflow.getNode(nodeName)?.parameters;
|
|
566
|
+
}
|
|
567
|
+
return Reflect.get(target, property, receiver);
|
|
568
|
+
},
|
|
569
|
+
},
|
|
570
|
+
);
|
|
571
|
+
},
|
|
572
|
+
|
|
573
|
+
$input: new Proxy(
|
|
574
|
+
{},
|
|
575
|
+
{
|
|
576
|
+
get(target, property, receiver) {
|
|
577
|
+
if (property === 'thisItem') {
|
|
578
|
+
return that.connectionInputData[that.itemIndex];
|
|
579
|
+
}
|
|
580
|
+
if (property === 'item') {
|
|
581
|
+
return (itemIndex?: number) => {
|
|
582
|
+
if (itemIndex === undefined) itemIndex = that.itemIndex;
|
|
583
|
+
const result = that.connectionInputData;
|
|
584
|
+
if (result[itemIndex]) {
|
|
585
|
+
return result[itemIndex];
|
|
586
|
+
}
|
|
587
|
+
return undefined;
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
if (property === 'first') {
|
|
591
|
+
return () => {
|
|
592
|
+
const result = that.connectionInputData;
|
|
593
|
+
if (result[0]) {
|
|
594
|
+
return result[0];
|
|
595
|
+
}
|
|
596
|
+
return undefined;
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
if (property === 'last') {
|
|
600
|
+
return () => {
|
|
601
|
+
const result = that.connectionInputData;
|
|
602
|
+
if (result.length && result[result.length - 1]) {
|
|
603
|
+
return result[result.length - 1];
|
|
604
|
+
}
|
|
605
|
+
return undefined;
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
if (property === 'all') {
|
|
609
|
+
return () => {
|
|
610
|
+
const result = that.connectionInputData;
|
|
611
|
+
if (result.length) {
|
|
612
|
+
return result;
|
|
613
|
+
}
|
|
614
|
+
return [];
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
return Reflect.get(target, property, receiver);
|
|
618
|
+
},
|
|
619
|
+
},
|
|
620
|
+
),
|
|
621
|
+
|
|
622
|
+
$thisItem: that.connectionInputData[that.itemIndex],
|
|
623
|
+
$binary: {}, // Placeholder
|
|
624
|
+
$data: {}, // Placeholder
|
|
625
|
+
$env: this.envGetter(),
|
|
626
|
+
$evaluateExpression: (expression: string, itemIndex?: number) => {
|
|
627
|
+
itemIndex = itemIndex || that.itemIndex;
|
|
628
|
+
return that.workflow.expression.getParameterValue(
|
|
629
|
+
`=${expression}`,
|
|
630
|
+
that.runExecutionData,
|
|
631
|
+
that.runIndex,
|
|
632
|
+
itemIndex,
|
|
633
|
+
that.activeNodeName,
|
|
634
|
+
that.connectionInputData,
|
|
635
|
+
that.mode,
|
|
636
|
+
that.additionalKeys,
|
|
637
|
+
);
|
|
638
|
+
},
|
|
639
|
+
$item: (itemIndex: number, runIndex?: number) => {
|
|
640
|
+
const defaultReturnRunIndex = runIndex === undefined ? -1 : runIndex;
|
|
641
|
+
const dataProxy = new WorkflowDataProxy(
|
|
642
|
+
this.workflow,
|
|
643
|
+
this.runExecutionData,
|
|
644
|
+
this.runIndex,
|
|
645
|
+
itemIndex,
|
|
646
|
+
this.activeNodeName,
|
|
647
|
+
this.connectionInputData,
|
|
648
|
+
that.siblingParameters,
|
|
649
|
+
that.mode,
|
|
650
|
+
that.additionalKeys,
|
|
651
|
+
defaultReturnRunIndex,
|
|
652
|
+
);
|
|
653
|
+
return dataProxy.getDataProxy();
|
|
654
|
+
},
|
|
655
|
+
$items: (nodeName?: string, outputIndex?: number, runIndex?: number) => {
|
|
656
|
+
let executionData: INodeExecutionData[];
|
|
657
|
+
|
|
658
|
+
if (nodeName === undefined) {
|
|
659
|
+
executionData = that.connectionInputData;
|
|
660
|
+
} else {
|
|
661
|
+
outputIndex = outputIndex || 0;
|
|
662
|
+
runIndex = runIndex === undefined ? -1 : runIndex;
|
|
663
|
+
executionData = that.getNodeExecutionData(nodeName, false, outputIndex, runIndex);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
return executionData;
|
|
667
|
+
},
|
|
668
|
+
$json: {}, // Placeholder
|
|
669
|
+
$node: this.nodeGetter(),
|
|
670
|
+
$self: this.selfGetter(),
|
|
671
|
+
$parameter: this.nodeParameterGetter(this.activeNodeName),
|
|
672
|
+
$position: this.itemIndex,
|
|
673
|
+
$runIndex: this.runIndex,
|
|
674
|
+
$mode: this.mode,
|
|
675
|
+
$workflow: this.workflowGetter(),
|
|
676
|
+
$thisRunIndex: this.runIndex,
|
|
677
|
+
$thisItemIndex: this.itemIndex,
|
|
678
|
+
$now: DateTime.now(),
|
|
679
|
+
$today: DateTime.now().set({ hour: 0, minute: 0, second: 0, millisecond: 0 }),
|
|
680
|
+
$jmespath: jmespathWrapper,
|
|
681
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
682
|
+
DateTime,
|
|
683
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
684
|
+
Interval,
|
|
685
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
686
|
+
Duration,
|
|
687
|
+
...that.additionalKeys,
|
|
688
|
+
$nodeId: that.workflow.getNode(that.activeNodeName)?.id,
|
|
689
|
+
$nodeVersion: that.workflow.getNode(that.activeNodeName)?.typeVersion,
|
|
690
|
+
$webhookId: that.workflow.getNode(that.activeNodeName)?.webhookId,
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
return new Proxy(base, {
|
|
694
|
+
get(target, name, receiver) {
|
|
695
|
+
if (['$data', '$json'].includes(name as string)) {
|
|
696
|
+
// @ts-ignore
|
|
697
|
+
return that.nodeDataGetter(that.activeNodeName, true).json;
|
|
698
|
+
}
|
|
699
|
+
if (name === '$binary') {
|
|
700
|
+
// @ts-ignore
|
|
701
|
+
return that.nodeDataGetter(that.activeNodeName, true).binary;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
return Reflect.get(target, name, receiver);
|
|
705
|
+
},
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// eslint-disable-next-line import/no-cycle
|
|
2
|
+
import { INode } from '..';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Class for instantiating an operational error, e.g. a timeout error.
|
|
6
|
+
*/
|
|
7
|
+
export class WorkflowOperationError extends Error {
|
|
8
|
+
node: INode | undefined;
|
|
9
|
+
|
|
10
|
+
timestamp: number;
|
|
11
|
+
|
|
12
|
+
constructor(message: string, node?: INode) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = this.constructor.name;
|
|
15
|
+
this.node = node;
|
|
16
|
+
this.timestamp = Date.now();
|
|
17
|
+
}
|
|
18
|
+
}
|