n8n-workflow 0.117.1 → 0.118.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/src/Expression.d.ts +2 -1
  2. package/dist/src/Expression.js +19 -15
  3. package/dist/src/Expression.js.map +1 -1
  4. package/dist/src/ExpressionError.d.ts +5 -2
  5. package/dist/src/ExpressionError.js +18 -18
  6. package/dist/src/ExpressionError.js.map +1 -1
  7. package/dist/src/Interfaces.d.ts +27 -16
  8. package/dist/src/Interfaces.js.map +1 -1
  9. package/dist/src/LoggerProxy.js.map +1 -1
  10. package/dist/src/NodeErrors.d.ts +1 -1
  11. package/dist/src/NodeErrors.js.map +1 -1
  12. package/dist/src/NodeHelpers.d.ts +1 -1
  13. package/dist/src/NodeHelpers.js.map +1 -1
  14. package/dist/src/ObservableObject.d.ts +1 -1
  15. package/dist/src/ObservableObject.js.map +1 -1
  16. package/dist/src/RoutingNode.d.ts +2 -2
  17. package/dist/src/RoutingNode.js +39 -9
  18. package/dist/src/RoutingNode.js.map +1 -1
  19. package/dist/src/TelemetryHelpers.d.ts +1 -1
  20. package/dist/src/TelemetryHelpers.js.map +1 -1
  21. package/dist/src/Workflow.d.ts +2 -2
  22. package/dist/src/Workflow.js +33 -7
  23. package/dist/src/Workflow.js.map +1 -1
  24. package/dist/src/WorkflowActivationError.d.ts +2 -1
  25. package/dist/src/WorkflowActivationError.js +2 -2
  26. package/dist/src/WorkflowActivationError.js.map +1 -1
  27. package/dist/src/WorkflowDataProxy.d.ts +3 -1
  28. package/dist/src/WorkflowDataProxy.js +247 -129
  29. package/dist/src/WorkflowDataProxy.js.map +1 -1
  30. package/dist/src/WorkflowErrors.d.ts +1 -1
  31. package/dist/src/WorkflowErrors.js.map +1 -1
  32. package/dist/src/WorkflowHooks.js.map +1 -1
  33. package/dist/src/index.d.ts +2 -2
  34. package/dist/src/index.js +3 -2
  35. package/dist/src/index.js.map +1 -1
  36. package/dist/tsconfig.tsbuildinfo +1 -1
  37. package/package.json +12 -3
@@ -26,7 +26,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.WorkflowDataProxy = exports.isResourceLocatorValue = void 0;
27
27
  const luxon_1 = require("luxon");
28
28
  const jmespath = __importStar(require("jmespath"));
29
- const _1 = require(".");
29
+ const NodeHelpers = __importStar(require("./NodeHelpers"));
30
+ const ExpressionError_1 = require("./ExpressionError");
30
31
  function isResourceLocatorValue(value) {
31
32
  return Boolean(typeof value === 'object' && value && 'mode' in value && 'value' in value && '__rl' in value);
32
33
  }
@@ -50,12 +51,19 @@ class WorkflowDataProxy {
50
51
  luxon_1.Settings.defaultZone = this.timezone;
51
52
  }
52
53
  nodeContextGetter(nodeName) {
54
+ var _a;
53
55
  const that = this;
54
56
  const node = this.workflow.nodes[nodeName];
57
+ if (!((_a = that.runExecutionData) === null || _a === void 0 ? void 0 : _a.executionData)) {
58
+ throw new ExpressionError_1.ExpressionError(`The workflow hasn't been executed yet, so you can't reference any context data`, {
59
+ runIndex: that.runIndex,
60
+ itemIndex: that.itemIndex,
61
+ });
62
+ }
55
63
  return new Proxy({}, {
56
64
  ownKeys(target) {
57
65
  if (Reflect.ownKeys(target).length === 0) {
58
- Object.assign(target, _1.NodeHelpers.getContext(that.runExecutionData, 'node', node));
66
+ Object.assign(target, NodeHelpers.getContext(that.runExecutionData, 'node', node));
59
67
  }
60
68
  return Reflect.ownKeys(target);
61
69
  },
@@ -67,10 +75,7 @@ class WorkflowDataProxy {
67
75
  },
68
76
  get(target, name, receiver) {
69
77
  name = name.toString();
70
- const contextData = _1.NodeHelpers.getContext(that.runExecutionData, 'node', node);
71
- if (!contextData.hasOwnProperty(name)) {
72
- throw new Error(`Could not find parameter "${name}" on context of node "${nodeName}"`);
73
- }
78
+ const contextData = NodeHelpers.getContext(that.runExecutionData, 'node', node);
74
79
  return contextData[name];
75
80
  },
76
81
  });
@@ -143,19 +148,19 @@ class WorkflowDataProxy {
143
148
  let executionData;
144
149
  if (!shortSyntax) {
145
150
  if (that.runExecutionData === null) {
146
- throw new _1.ExpressionError(`Workflow did not run so do not have any execution-data.`, {
151
+ throw new ExpressionError_1.ExpressionError(`The workflow hasn't been executed yet, so you can't reference any output data`, {
147
152
  runIndex: that.runIndex,
148
153
  itemIndex: that.itemIndex,
149
154
  });
150
155
  }
151
156
  if (!that.runExecutionData.resultData.runData.hasOwnProperty(nodeName)) {
152
157
  if (that.workflow.getNode(nodeName)) {
153
- throw new _1.ExpressionError(`The node "${nodeName}" hasn't been executed yet, so you can't reference its output data`, {
158
+ throw new ExpressionError_1.ExpressionError(`The node "${nodeName}" hasn't been executed yet, so you can't reference its output data`, {
154
159
  runIndex: that.runIndex,
155
160
  itemIndex: that.itemIndex,
156
161
  });
157
162
  }
158
- throw new _1.ExpressionError(`No node called "${nodeName}" in this workflow`, {
163
+ throw new ExpressionError_1.ExpressionError(`No node called "${nodeName}" in this workflow`, {
159
164
  runIndex: that.runIndex,
160
165
  itemIndex: that.itemIndex,
161
166
  });
@@ -164,14 +169,14 @@ class WorkflowDataProxy {
164
169
  runIndex =
165
170
  runIndex === -1 ? that.runExecutionData.resultData.runData[nodeName].length - 1 : runIndex;
166
171
  if (that.runExecutionData.resultData.runData[nodeName].length <= runIndex) {
167
- throw new _1.ExpressionError(`Run ${runIndex} of node "${nodeName}" not found`, {
172
+ throw new ExpressionError_1.ExpressionError(`Run ${runIndex} of node "${nodeName}" not found`, {
168
173
  runIndex: that.runIndex,
169
174
  itemIndex: that.itemIndex,
170
175
  });
171
176
  }
172
177
  const taskData = that.runExecutionData.resultData.runData[nodeName][runIndex].data;
173
178
  if (taskData.main === null || !taskData.main.length || taskData.main[0] === null) {
174
- throw new _1.ExpressionError(`No data found from "main" input.`, {
179
+ throw new ExpressionError_1.ExpressionError(`No data found from "main" input.`, {
175
180
  runIndex: that.runIndex,
176
181
  itemIndex: that.itemIndex,
177
182
  });
@@ -179,7 +184,7 @@ class WorkflowDataProxy {
179
184
  if (outputIndex === undefined) {
180
185
  const nodeConnection = that.workflow.getNodeConnectionIndexes(that.activeNodeName, nodeName, 'main');
181
186
  if (nodeConnection === undefined) {
182
- throw new _1.ExpressionError(`The node "${that.activeNodeName}" is not connected with node "${nodeName}" so no data can get returned from it.`, {
187
+ throw new ExpressionError_1.ExpressionError(`The node "${that.activeNodeName}" is not connected with node "${nodeName}" so no data can get returned from it.`, {
183
188
  runIndex: that.runIndex,
184
189
  itemIndex: that.itemIndex,
185
190
  });
@@ -190,7 +195,7 @@ class WorkflowDataProxy {
190
195
  outputIndex = 0;
191
196
  }
192
197
  if (taskData.main.length <= outputIndex) {
193
- throw new _1.ExpressionError(`Node "${nodeName}" has no branch with index ${outputIndex}.`, {
198
+ throw new ExpressionError_1.ExpressionError(`Node "${nodeName}" has no branch with index ${outputIndex}.`, {
194
199
  runIndex: that.runIndex,
195
200
  itemIndex: that.itemIndex,
196
201
  });
@@ -214,7 +219,7 @@ class WorkflowDataProxy {
214
219
  if (['binary', 'data', 'json'].includes(name)) {
215
220
  const executionData = that.getNodeExecutionData(nodeName, shortSyntax, undefined);
216
221
  if (executionData.length <= that.itemIndex) {
217
- throw new _1.ExpressionError(`No data found for item-index: "${that.itemIndex}"`, {
222
+ throw new ExpressionError_1.ExpressionError(`No data found for item-index: "${that.itemIndex}"`, {
218
223
  runIndex: that.runIndex,
219
224
  itemIndex: that.itemIndex,
220
225
  });
@@ -263,7 +268,7 @@ class WorkflowDataProxy {
263
268
  return new Proxy({}, {
264
269
  get(target, name, receiver) {
265
270
  if (process.env.N8N_BLOCK_ENV_ACCESS_IN_NODE === 'true') {
266
- throw new _1.ExpressionError('Environment variable access got disabled', {
271
+ throw new ExpressionError_1.ExpressionError('Environment variable access got disabled', {
267
272
  causeDetailed: 'If you need access please contact the administrator to remove the environment variable ‘N8N_BLOCK_ENV_ACCESS_IN_NODE‘',
268
273
  runIndex: that.runIndex,
269
274
  itemIndex: that.itemIndex,
@@ -274,6 +279,38 @@ class WorkflowDataProxy {
274
279
  },
275
280
  });
276
281
  }
282
+ prevNodeGetter() {
283
+ const allowedValues = ['name', 'outputIndex', 'runIndex'];
284
+ const that = this;
285
+ return new Proxy({}, {
286
+ ownKeys(target) {
287
+ return allowedValues;
288
+ },
289
+ getOwnPropertyDescriptor(k) {
290
+ return {
291
+ enumerable: true,
292
+ configurable: true,
293
+ };
294
+ },
295
+ get(target, name, receiver) {
296
+ var _a, _b;
297
+ if (!((_a = that.executeData) === null || _a === void 0 ? void 0 : _a.source)) {
298
+ return undefined;
299
+ }
300
+ const sourceData = (_b = that.executeData) === null || _b === void 0 ? void 0 : _b.source.main[0];
301
+ if (name === 'name') {
302
+ return sourceData.previousNode;
303
+ }
304
+ if (name === 'outputIndex') {
305
+ return sourceData.previousNodeOutput || 0;
306
+ }
307
+ if (name === 'runIndex') {
308
+ return sourceData.previousNodeRun || 0;
309
+ }
310
+ return Reflect.get(target, name, receiver);
311
+ },
312
+ });
313
+ }
277
314
  workflowGetter() {
278
315
  const allowedValues = ['active', 'id', 'name'];
279
316
  const that = this;
@@ -288,10 +325,19 @@ class WorkflowDataProxy {
288
325
  };
289
326
  },
290
327
  get(target, name, receiver) {
291
- if (!allowedValues.includes(name.toString())) {
292
- throw new Error(`The key "${name.toString()}" is not supported!`);
328
+ if (allowedValues.includes(name.toString())) {
329
+ const value = that.workflow[name];
330
+ if (value === undefined && name === 'id') {
331
+ throw new ExpressionError_1.ExpressionError('Workflow is not saved', {
332
+ description: `Please save the workflow first to use $workflow`,
333
+ runIndex: that.runIndex,
334
+ itemIndex: that.itemIndex,
335
+ failExecution: true,
336
+ });
337
+ }
338
+ return value;
293
339
  }
294
- return that.workflow[name];
340
+ return Reflect.get(target, name, receiver);
295
341
  },
296
342
  });
297
343
  }
@@ -323,23 +369,39 @@ class WorkflowDataProxy {
323
369
  }
324
370
  return jmespath.search(data, query);
325
371
  };
326
- const createExpressionError = (message, context, nodeName) => {
327
- if (nodeName) {
372
+ const isFunctionNode = (nodeName) => {
373
+ const node = that.workflow.getNode(nodeName);
374
+ return node && ['n8n-nodes-base.function', 'n8n-nodes-base.functionItem'].includes(node.type);
375
+ };
376
+ const createExpressionError = (message, context) => {
377
+ if (isFunctionNode(that.activeNodeName) && (context === null || context === void 0 ? void 0 : context.functionOverrides)) {
378
+ message = context.functionOverrides.message || message;
379
+ context.description = context.functionOverrides.description || context.description;
380
+ context.messageTemplate = undefined;
381
+ }
382
+ if (context === null || context === void 0 ? void 0 : context.nodeCause) {
383
+ const nodeName = context.nodeCause;
328
384
  const pinData = this.workflow.getPinDataOfNode(nodeName);
329
385
  if (pinData) {
330
386
  if (!context) {
331
387
  context = {};
332
388
  }
333
- message = `‘${nodeName}‘ must be unpinned to execute`;
334
- context.description = `To fetch the data the expression needs, The node ‘${nodeName}’ needs to execute without being pinned. <a>Unpin it</a>`;
335
- context.description = `To fetch the data for the expression, you must unpin the node '${nodeName}' and execute the workflow again.`;
336
- context.descriptionTemplate = `To fetch the data for the expression under '%%PARAMETER%%', you must unpin the node '${nodeName}' and execute the workflow again.`;
389
+ message = `‘Node ${nodeName}‘ must be unpinned to execute`;
390
+ context.messageTemplate = undefined;
391
+ context.description = `To fetch the data for the expression, you must unpin the node <strong>'${nodeName}'</strong> and execute the workflow again.`;
392
+ context.descriptionTemplate = `To fetch the data for the expression under '%%PARAMETER%%', you must unpin the node <strong>'${nodeName}'</strong> and execute the workflow again.`;
393
+ }
394
+ if (context.moreInfoLink && (pinData || isFunctionNode(nodeName))) {
395
+ const moreInfoLink = ' <a target="_blank" href="https://docs.n8n.io/data/data-mapping/data-item-linking/item-linking-errors/">More info</a>';
396
+ context.description += moreInfoLink;
397
+ context.descriptionTemplate += moreInfoLink;
337
398
  }
338
399
  }
339
- return new _1.ExpressionError(message, {
400
+ return new ExpressionError_1.ExpressionError(message, {
340
401
  runIndex: that.runIndex,
341
402
  itemIndex: that.itemIndex,
342
403
  failExecution: true,
404
+ functionality: 'pairedItem',
343
405
  ...context,
344
406
  });
345
407
  };
@@ -351,6 +413,7 @@ class WorkflowDataProxy {
351
413
  item: pairedItem,
352
414
  };
353
415
  }
416
+ let currentPairedItem = pairedItem;
354
417
  let nodeBeforeLast;
355
418
  while (sourceData !== null && destinationNodeName !== sourceData.previousNode) {
356
419
  taskData =
@@ -358,25 +421,43 @@ class WorkflowDataProxy {
358
421
  const previousNodeOutput = sourceData.previousNodeOutput || 0;
359
422
  if (previousNodeOutput >= taskData.data.main.length) {
360
423
  throw createExpressionError('Can’t get data for expression', {
361
- messageTemplate: 'Can’t get data for expression under ‘%%PARAMETER%%’',
424
+ messageTemplate: 'Can’t get data for expression under ‘%%PARAMETER%%’ field',
425
+ functionOverrides: {
426
+ message: 'Can’t get data',
427
+ },
428
+ nodeCause: nodeBeforeLast,
362
429
  description: `Apologies, this is an internal error. See details for more information`,
363
430
  causeDetailed: 'Referencing a non-existent output on a node, problem with source data',
364
- }, nodeBeforeLast);
431
+ type: 'internal',
432
+ });
365
433
  }
366
434
  if (pairedItem.item >= taskData.data.main[previousNodeOutput].length) {
367
435
  throw createExpressionError('Can’t get data for expression', {
368
- messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’`,
369
- description: `Item points to an item which does not exist`,
370
- causeDetailed: `The pairedItem data points to an item ‘${pairedItem.item}‘ which does not exist on node ‘${sourceData.previousNode}‘ (output node did probably supply a wrong one)`,
371
- }, nodeBeforeLast);
436
+ messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’ field`,
437
+ functionOverrides: {
438
+ message: 'Can’t get data',
439
+ },
440
+ nodeCause: nodeBeforeLast,
441
+ description: `In node ‘<strong>${nodeBeforeLast}</strong>’, output item ${currentPairedItem.item || 0} ${sourceData.previousNodeRun
442
+ ? `of run ${(sourceData.previousNodeRun || 0).toString()} `
443
+ : ''}points to an input item on node ‘<strong>${sourceData.previousNode}</strong>‘ that doesn’t exist.`,
444
+ type: 'invalid pairing info',
445
+ moreInfoLink: true,
446
+ });
372
447
  }
373
448
  const itemPreviousNode = taskData.data.main[previousNodeOutput][pairedItem.item];
374
449
  if (itemPreviousNode.pairedItem === undefined) {
375
450
  throw createExpressionError('Can’t get data for expression', {
376
- messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’`,
377
- description: `To fetch the data from other nodes that this expression needs, more information is needed from the node ‘${sourceData.previousNode}’`,
378
- causeDetailed: `Missing pairedItem data (node ‘${sourceData.previousNode}’ did probably not supply it)`,
379
- }, sourceData.previousNode);
451
+ messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’ field`,
452
+ functionOverrides: {
453
+ message: 'Can’t get data',
454
+ },
455
+ nodeCause: sourceData.previousNode,
456
+ description: `To fetch the data from other nodes that this expression needs, more information is needed from the node ‘<strong>${sourceData.previousNode}</strong>’`,
457
+ causeDetailed: `Missing pairedItem data (node ‘${sourceData.previousNode}’ probably didn’t supply it)`,
458
+ type: 'no pairing info',
459
+ moreInfoLink: true,
460
+ });
380
461
  }
381
462
  if (Array.isArray(itemPreviousNode.pairedItem)) {
382
463
  const results = itemPreviousNode.pairedItem
@@ -396,11 +477,17 @@ class WorkflowDataProxy {
396
477
  if (results.length !== 1) {
397
478
  throw createExpressionError('Invalid expression', {
398
479
  messageTemplate: 'Invalid expression under ‘%%PARAMETER%%’',
399
- description: `The expression uses data in node ‘${destinationNodeName}’ but there is more than one matching item in that node`,
480
+ functionOverrides: {
481
+ description: `The code uses data in the node ‘<strong>${destinationNodeName}</strong>’ but there is more than one matching item in that node`,
482
+ message: 'Invalid code',
483
+ },
484
+ description: `The expression uses data in the node ‘<strong>${destinationNodeName}</strong>’ but there is more than one matching item in that node`,
485
+ type: 'multiple matches',
400
486
  });
401
487
  }
402
488
  return results[0];
403
489
  }
490
+ currentPairedItem = pairedItem;
404
491
  if (typeof itemPreviousNode.pairedItem === 'number') {
405
492
  pairedItem = {
406
493
  item: itemPreviousNode.pairedItem,
@@ -414,136 +501,139 @@ class WorkflowDataProxy {
414
501
  if (taskData.source.length === 0) {
415
502
  throw createExpressionError('Invalid expression', {
416
503
  messageTemplate: 'Invalid expression under ‘%%PARAMETER%%’',
417
- description: `The expression uses data in node ‘${destinationNodeName}’ but there is no path back to it. Please check this node is connected to node ‘${that.activeNodeName}’ (there can be other nodes in between).`,
504
+ functionOverrides: {
505
+ description: `The code uses data in the node ‘<strong>${destinationNodeName}</strong>’ but there is no path back to it. Please check this node is connected to it (there can be other nodes in between).`,
506
+ message: 'Invalid code',
507
+ },
508
+ description: `The expression uses data in the node ‘<strong>${destinationNodeName}</strong>’ but there is no path back to it. Please check this node is connected to it (there can be other nodes in between).`,
509
+ type: 'no connection',
510
+ moreInfoLink: true,
418
511
  });
419
512
  }
420
513
  throw createExpressionError('Can’t get data for expression', {
421
- messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’`,
422
- description: `Item points to a node input which does not exist`,
423
- causeDetailed: `The pairedItem data points to a node input ‘${itemInput}‘ which does not exist on node ‘${sourceData.previousNode}‘ (node did probably supply a wrong one)`,
424
- }, nodeBeforeLast);
514
+ messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’ field`,
515
+ functionOverrides: {
516
+ message: `Can’t get data`,
517
+ },
518
+ nodeCause: nodeBeforeLast,
519
+ description: `In node ‘<strong>${sourceData.previousNode}</strong>’, output item ${currentPairedItem.item || 0} of ${sourceData.previousNodeRun
520
+ ? `of run ${(sourceData.previousNodeRun || 0).toString()} `
521
+ : ''}points to a branch that doesn’t exist.`,
522
+ type: 'invalid pairing info',
523
+ });
425
524
  }
426
525
  nodeBeforeLast = sourceData.previousNode;
427
526
  sourceData = taskData.source[pairedItem.input || 0] || null;
428
527
  }
429
528
  if (sourceData === null) {
430
529
  throw createExpressionError('Can’t get data for expression', {
431
- messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’`,
432
- description: `Could not resolve, probably no pairedItem exists`,
433
- }, nodeBeforeLast);
530
+ messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’ field`,
531
+ functionOverrides: {
532
+ message: `Can’t get data`,
533
+ },
534
+ nodeCause: nodeBeforeLast,
535
+ description: `Could not resolve, proably no pairedItem exists`,
536
+ type: 'no pairing info',
537
+ moreInfoLink: true,
538
+ });
434
539
  }
435
540
  taskData =
436
541
  that.runExecutionData.resultData.runData[sourceData.previousNode][(sourceData === null || sourceData === void 0 ? void 0 : sourceData.previousNodeRun) || 0];
437
542
  const previousNodeOutput = sourceData.previousNodeOutput || 0;
438
543
  if (previousNodeOutput >= taskData.data.main.length) {
439
544
  throw createExpressionError('Can’t get data for expression', {
440
- messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’`,
545
+ messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’ field`,
546
+ functionOverrides: {
547
+ message: `Can’t get data`,
548
+ },
441
549
  description: `Item points to a node output which does not exist`,
442
550
  causeDetailed: `The sourceData points to a node output ‘${previousNodeOutput}‘ which does not exist on node ‘${sourceData.previousNode}‘ (output node did probably supply a wrong one)`,
551
+ type: 'invalid pairing info',
443
552
  });
444
553
  }
445
554
  if (pairedItem.item >= taskData.data.main[previousNodeOutput].length) {
446
555
  throw createExpressionError('Can’t get data for expression', {
447
- messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’`,
448
- description: `Item points to an item which does not exist`,
449
- causeDetailed: `The pairedItem data points to an item ‘${pairedItem.item}‘ which does not exist on node ‘${sourceData.previousNode}‘ (output node did probably supply a wrong one)`,
450
- }, nodeBeforeLast);
556
+ messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’ field`,
557
+ functionOverrides: {
558
+ message: `Can’t get data`,
559
+ },
560
+ nodeCause: nodeBeforeLast,
561
+ description: `In node ‘<strong>${nodeBeforeLast}</strong>’, output item ${currentPairedItem.item || 0} ${sourceData.previousNodeRun
562
+ ? `of run ${(sourceData.previousNodeRun || 0).toString()} `
563
+ : ''}points to an input item on node ‘<strong>${sourceData.previousNode}</strong>‘ that doesn’t exist.`,
564
+ type: 'invalid pairing info',
565
+ moreInfoLink: true,
566
+ });
451
567
  }
452
568
  return taskData.data.main[previousNodeOutput][pairedItem.item];
453
569
  };
454
570
  const base = {
455
571
  $: (nodeName) => {
456
572
  if (!nodeName) {
457
- throw new _1.ExpressionError('When calling $(), please specify a node', {
458
- runIndex: that.runIndex,
459
- itemIndex: that.itemIndex,
460
- failExecution: true,
461
- });
573
+ throw createExpressionError('When calling $(), please specify a node');
574
+ }
575
+ const referencedNode = that.workflow.getNode(nodeName);
576
+ if (referencedNode === null) {
577
+ throw createExpressionError(`No node called ‘${nodeName}‘`);
462
578
  }
463
579
  return new Proxy({}, {
464
580
  get(target, property, receiver) {
465
581
  var _a;
466
- if (property === 'pairedItem') {
467
- return (itemIndex) => {
582
+ if (['pairedItem', 'itemMatching', 'item'].includes(property)) {
583
+ const pairedItemMethod = (itemIndex) => {
468
584
  var _a, _b;
469
585
  if (itemIndex === undefined) {
586
+ if (property === 'itemMatching') {
587
+ throw createExpressionError('Missing item index for .itemMatching()', {
588
+ itemIndex,
589
+ });
590
+ }
470
591
  itemIndex = that.itemIndex;
471
592
  }
472
593
  const executionData = that.connectionInputData;
473
594
  const pairedItem = executionData[itemIndex].pairedItem;
474
595
  if (pairedItem === undefined) {
475
- throw new _1.ExpressionError('Can’t get data for expression', {
476
- messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’`,
477
- description: `To fetch the data from other nodes that this expression needs, more information is needed from the node ‘${that.activeNodeName}‘`,
478
- causeDetailed: `Missing pairedItem data (node ‘${that.activeNodeName}‘ did probably not supply it)`,
479
- runIndex: that.runIndex,
596
+ throw createExpressionError('Can’t get data for expression', {
597
+ messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’ field`,
598
+ functionOverrides: {
599
+ description: `To fetch the data from other nodes that this code needs, more information is needed from the node ‘<strong>${that.activeNodeName}</strong>‘`,
600
+ message: `Can’t get data`,
601
+ },
602
+ description: `To fetch the data from other nodes that this expression needs, more information is needed from the node ‘<strong>${that.activeNodeName}</strong>‘`,
603
+ causeDetailed: `Missing pairedItem data (node ‘${that.activeNodeName}‘ probably didn’t supply it)`,
480
604
  itemIndex,
481
- failExecution: true,
482
605
  });
483
606
  }
484
607
  if (!((_a = that.executeData) === null || _a === void 0 ? void 0 : _a.source)) {
485
- throw new _1.ExpressionError('Can’t get data for expression', {
486
- messageTemplate: 'Can’t get data for expression under ‘%%PARAMETER%%’',
608
+ throw createExpressionError('Can’t get data for expression', {
609
+ messageTemplate: 'Can’t get data for expression under ‘%%PARAMETER%%’ field',
610
+ functionOverrides: {
611
+ message: `Can’t get data`,
612
+ },
487
613
  description: `Apologies, this is an internal error. See details for more information`,
488
614
  causeDetailed: `Missing sourceData (probably an internal error)`,
489
- runIndex: that.runIndex,
490
615
  itemIndex,
491
- failExecution: true,
492
616
  });
493
617
  }
494
618
  const parentNodes = that.workflow.getParentNodes(that.activeNodeName);
495
619
  if (!parentNodes.includes(nodeName)) {
496
- throw new _1.ExpressionError('Invalid expression', {
620
+ throw createExpressionError('Invalid expression', {
497
621
  messageTemplate: 'Invalid expression under ‘%%PARAMETER%%’',
498
- description: `The expression uses data in node ‘${nodeName}’ but there is no path back to it. Please check this node is connected to node ‘${that.activeNodeName}’ (there can be other nodes in between).`,
499
- runIndex: that.runIndex,
622
+ functionOverrides: {
623
+ description: `The code uses data in the node <strong>‘${nodeName}’</strong> but there is no path back to it. Please check this node is connected to it (there can be other nodes in between).`,
624
+ message: `No path back to node ‘${nodeName}’`,
625
+ },
626
+ description: `The expression uses data in the node <strong>‘${nodeName}’</strong> but there is no path back to it. Please check this node is connected to it (there can be other nodes in between).`,
500
627
  itemIndex,
501
- failExecution: true,
502
628
  });
503
629
  }
504
630
  const sourceData = (_b = that.executeData) === null || _b === void 0 ? void 0 : _b.source.main[pairedItem.input || 0];
505
631
  return getPairedItem(nodeName, sourceData, pairedItem);
506
632
  };
507
- }
508
- if (property === 'item') {
509
- return (itemIndex, branchIndex, runIndex) => {
510
- if (itemIndex === undefined) {
511
- itemIndex = that.itemIndex;
512
- branchIndex = 0;
513
- runIndex = that.runIndex;
514
- }
515
- const executionData = getNodeOutput(nodeName, branchIndex, runIndex);
516
- if (executionData[itemIndex]) {
517
- return executionData[itemIndex];
518
- }
519
- let errorMessage = '';
520
- if (branchIndex === undefined && runIndex === undefined) {
521
- errorMessage = `
522
- No item found at index ${itemIndex}
523
- (for node "${nodeName}")`;
524
- throw new Error(errorMessage);
525
- }
526
- if (branchIndex === undefined) {
527
- errorMessage = `
528
- No item found at index ${itemIndex}
529
- in run ${runIndex || that.runIndex}
530
- (for node "${nodeName}")`;
531
- throw new Error(errorMessage);
532
- }
533
- if (runIndex === undefined) {
534
- errorMessage = `
535
- No item found at index ${itemIndex}
536
- of branch ${branchIndex || 0}
537
- (for node "${nodeName}")`;
538
- throw new Error(errorMessage);
539
- }
540
- errorMessage = `
541
- No item found at index ${itemIndex}
542
- of branch ${branchIndex || 0}
543
- in run ${runIndex || that.runIndex}
544
- (for node "${nodeName}")`;
545
- throw new Error(errorMessage);
546
- };
633
+ if (property === 'item') {
634
+ return pairedItemMethod();
635
+ }
636
+ return pairedItemMethod;
547
637
  }
548
638
  if (property === 'first') {
549
639
  return (branchIndex, runIndex) => {
@@ -578,23 +668,25 @@ class WorkflowDataProxy {
578
668
  });
579
669
  },
580
670
  $input: new Proxy({}, {
671
+ ownKeys(target) {
672
+ return ['all', 'context', 'first', 'item', 'last', 'params'];
673
+ },
674
+ getOwnPropertyDescriptor(k) {
675
+ return {
676
+ enumerable: true,
677
+ configurable: true,
678
+ };
679
+ },
581
680
  get(target, property, receiver) {
582
- if (property === 'thisItem') {
583
- return that.connectionInputData[that.itemIndex];
584
- }
681
+ var _a, _b, _c;
585
682
  if (property === 'item') {
586
- return (itemIndex) => {
587
- if (itemIndex === undefined)
588
- itemIndex = that.itemIndex;
589
- const result = that.connectionInputData;
590
- if (result[itemIndex]) {
591
- return result[itemIndex];
592
- }
593
- return undefined;
594
- };
683
+ return that.connectionInputData[that.itemIndex];
595
684
  }
596
685
  if (property === 'first') {
597
- return () => {
686
+ return (...args) => {
687
+ if (args.length) {
688
+ throw createExpressionError('$input.first() should have no arguments');
689
+ }
598
690
  const result = that.connectionInputData;
599
691
  if (result[0]) {
600
692
  return result[0];
@@ -603,7 +695,10 @@ class WorkflowDataProxy {
603
695
  };
604
696
  }
605
697
  if (property === 'last') {
606
- return () => {
698
+ return (...args) => {
699
+ if (args.length) {
700
+ throw createExpressionError('$input.last() should have no arguments');
701
+ }
607
702
  const result = that.connectionInputData;
608
703
  if (result.length && result[result.length - 1]) {
609
704
  return result[result.length - 1];
@@ -620,10 +715,29 @@ class WorkflowDataProxy {
620
715
  return [];
621
716
  };
622
717
  }
718
+ if (['context', 'params'].includes(property)) {
719
+ if (!((_a = that.executeData) === null || _a === void 0 ? void 0 : _a.source)) {
720
+ throw createExpressionError('Can’t get data for expression', {
721
+ messageTemplate: 'Can’t get data for expression under ‘%%PARAMETER%%’ field',
722
+ functionOverrides: {
723
+ message: 'Can’t get data',
724
+ },
725
+ description: `Apologies, this is an internal error. See details for more information`,
726
+ causeDetailed: `Missing sourceData (probably an internal error)`,
727
+ runIndex: that.runIndex,
728
+ });
729
+ }
730
+ const sourceData = (_b = that.executeData) === null || _b === void 0 ? void 0 : _b.source.main[0];
731
+ if (property === 'context') {
732
+ return that.nodeContextGetter(sourceData.previousNode);
733
+ }
734
+ if (property === 'params') {
735
+ return (_c = that.workflow.getNode(sourceData.previousNode)) === null || _c === void 0 ? void 0 : _c.parameters;
736
+ }
737
+ }
623
738
  return Reflect.get(target, property, receiver);
624
739
  },
625
740
  }),
626
- $thisItem: that.connectionInputData[that.itemIndex],
627
741
  $binary: {},
628
742
  $data: {},
629
743
  $env: this.envGetter(),
@@ -652,19 +766,23 @@ class WorkflowDataProxy {
652
766
  $node: this.nodeGetter(),
653
767
  $self: this.selfGetter(),
654
768
  $parameter: this.nodeParameterGetter(this.activeNodeName),
655
- $position: this.itemIndex,
769
+ $prevNode: this.prevNodeGetter(),
656
770
  $runIndex: this.runIndex,
657
771
  $mode: this.mode,
658
772
  $workflow: this.workflowGetter(),
659
- $thisRunIndex: this.runIndex,
660
- $thisItemIndex: this.itemIndex,
773
+ $itemIndex: this.itemIndex,
661
774
  $now: luxon_1.DateTime.now(),
662
775
  $today: luxon_1.DateTime.now().set({ hour: 0, minute: 0, second: 0, millisecond: 0 }),
663
- $jmespath: jmespathWrapper,
776
+ $jmesPath: jmespathWrapper,
664
777
  DateTime: luxon_1.DateTime,
665
778
  Interval: luxon_1.Interval,
666
779
  Duration: luxon_1.Duration,
667
780
  ...that.additionalKeys,
781
+ $jmespath: jmespathWrapper,
782
+ $position: this.itemIndex,
783
+ $thisItem: that.connectionInputData[that.itemIndex],
784
+ $thisItemIndex: this.itemIndex,
785
+ $thisRunIndex: this.runIndex,
668
786
  };
669
787
  return new Proxy(base, {
670
788
  get(target, name, receiver) {