@n8n/workflow-sdk 0.11.3 → 0.13.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 (94) hide show
  1. package/dist/ast-interpreter/validators.js +2 -0
  2. package/dist/ast-interpreter/validators.js.map +1 -1
  3. package/dist/build.tsbuildinfo +1 -1
  4. package/dist/codegen/parse-workflow-code.js +1 -0
  5. package/dist/codegen/parse-workflow-code.js.map +1 -1
  6. package/dist/expression/index.d.ts +4 -1
  7. package/dist/expression/index.js +30 -0
  8. package/dist/expression/index.js.map +1 -1
  9. package/dist/expression.d.ts +1 -1
  10. package/dist/expression.js +2 -1
  11. package/dist/expression.js.map +1 -1
  12. package/dist/generate-types/generate-types.d.ts +9 -0
  13. package/dist/generate-types/generate-types.js +208 -51
  14. package/dist/generate-types/generate-types.js.map +1 -1
  15. package/dist/generate-types/generate-zod-schemas.d.ts +6 -1
  16. package/dist/generate-types/generate-zod-schemas.js +199 -90
  17. package/dist/generate-types/generate-zod-schemas.js.map +1 -1
  18. package/dist/index.d.ts +2 -1
  19. package/dist/index.js +3 -2
  20. package/dist/index.js.map +1 -1
  21. package/dist/prompts/best-practices/guides/chatbot.js +11 -0
  22. package/dist/prompts/best-practices/guides/chatbot.js.map +1 -1
  23. package/dist/prompts/best-practices/guides/web-app.d.ts +7 -0
  24. package/dist/prompts/best-practices/guides/web-app.js +206 -0
  25. package/dist/prompts/best-practices/guides/web-app.js.map +1 -0
  26. package/dist/prompts/best-practices/index.d.ts +1 -0
  27. package/dist/prompts/best-practices/index.js +5 -1
  28. package/dist/prompts/best-practices/index.js.map +1 -1
  29. package/dist/prompts/best-practices/types.d.ts +1 -0
  30. package/dist/prompts/best-practices/types.js +2 -0
  31. package/dist/prompts/best-practices/types.js.map +1 -1
  32. package/dist/prompts/node-guidance/parameter-guides/predecessor-output.js +7 -0
  33. package/dist/prompts/node-guidance/parameter-guides/predecessor-output.js.map +1 -1
  34. package/dist/prompts/sdk-reference/additional-functions.d.ts +1 -1
  35. package/dist/prompts/sdk-reference/additional-functions.js +3 -0
  36. package/dist/prompts/sdk-reference/additional-functions.js.map +1 -1
  37. package/dist/prompts/sdk-reference/expressions.d.ts +1 -1
  38. package/dist/prompts/sdk-reference/expressions.js +14 -1
  39. package/dist/prompts/sdk-reference/expressions.js.map +1 -1
  40. package/dist/prompts/sdk-reference/workflow-patterns.d.ts +1 -1
  41. package/dist/prompts/sdk-reference/workflow-patterns.js +102 -34
  42. package/dist/prompts/sdk-reference/workflow-patterns.js.map +1 -1
  43. package/dist/prompts/sdk-reference/workflow-rules.d.ts +1 -1
  44. package/dist/prompts/sdk-reference/workflow-rules.js +14 -7
  45. package/dist/prompts/sdk-reference/workflow-rules.js.map +1 -1
  46. package/dist/types/base.d.ts +14 -5
  47. package/dist/types/base.js +43 -0
  48. package/dist/types/base.js.map +1 -1
  49. package/dist/validation/display-options.js +8 -0
  50. package/dist/validation/display-options.js.map +1 -1
  51. package/dist/validation/index.d.ts +1 -1
  52. package/dist/validation/index.js +125 -2
  53. package/dist/validation/index.js.map +1 -1
  54. package/dist/validation/resolve-schema.d.ts +14 -0
  55. package/dist/validation/resolve-schema.js +20 -0
  56. package/dist/validation/resolve-schema.js.map +1 -1
  57. package/dist/validation/schema-helpers.d.ts +2 -2
  58. package/dist/validation/schema-helpers.js +2 -1
  59. package/dist/validation/schema-helpers.js.map +1 -1
  60. package/dist/validation/schema-validator.js +1 -0
  61. package/dist/validation/schema-validator.js.map +1 -1
  62. package/dist/workflow-builder/connection-utils.js +1 -1
  63. package/dist/workflow-builder/connection-utils.js.map +1 -1
  64. package/dist/workflow-builder/control-flow-builders/if-else.d.ts +1 -2
  65. package/dist/workflow-builder/control-flow-builders/split-in-batches.d.ts +2 -2
  66. package/dist/workflow-builder/control-flow-builders/split-in-batches.js +28 -0
  67. package/dist/workflow-builder/control-flow-builders/split-in-batches.js.map +1 -1
  68. package/dist/workflow-builder/control-flow-builders/switch-case.d.ts +1 -2
  69. package/dist/workflow-builder/node-builders/node-builder.d.ts +1 -0
  70. package/dist/workflow-builder/node-builders/node-builder.js +41 -2
  71. package/dist/workflow-builder/node-builders/node-builder.js.map +1 -1
  72. package/dist/workflow-builder/node-builders/subnode-builders.js +2 -1
  73. package/dist/workflow-builder/node-builders/subnode-builders.js.map +1 -1
  74. package/dist/workflow-builder/pin-data-utils.js.map +1 -1
  75. package/dist/workflow-builder/plugins/defaults.js +1 -0
  76. package/dist/workflow-builder/plugins/defaults.js.map +1 -1
  77. package/dist/workflow-builder/plugins/serializers/json-serializer.js +14 -1
  78. package/dist/workflow-builder/plugins/serializers/json-serializer.js.map +1 -1
  79. package/dist/workflow-builder/plugins/validators/index.d.ts +1 -0
  80. package/dist/workflow-builder/plugins/validators/index.js +3 -1
  81. package/dist/workflow-builder/plugins/validators/index.js.map +1 -1
  82. package/dist/workflow-builder/plugins/validators/memory-session-key-validator.d.ts +2 -0
  83. package/dist/workflow-builder/plugins/validators/memory-session-key-validator.js +50 -0
  84. package/dist/workflow-builder/plugins/validators/memory-session-key-validator.js.map +1 -0
  85. package/dist/workflow-builder/plugins/validators/set-node-validator.js +110 -4
  86. package/dist/workflow-builder/plugins/validators/set-node-validator.js.map +1 -1
  87. package/dist/workflow-builder/validation-helpers.d.ts +1 -0
  88. package/dist/workflow-builder/validation-helpers.js +7 -0
  89. package/dist/workflow-builder/validation-helpers.js.map +1 -1
  90. package/dist/workflow-builder/workflow-import.js +1 -0
  91. package/dist/workflow-builder/workflow-import.js.map +1 -1
  92. package/dist/workflow-builder.js +8 -2
  93. package/dist/workflow-builder.js.map +1 -1
  94. package/package.json +2 -2
@@ -22,7 +22,18 @@ const fetchData = node({
22
22
  const processData = node({
23
23
  type: 'n8n-nodes-base.set',
24
24
  version: 3.4,
25
- config: { name: 'Process Data', parameters: {} }
25
+ config: {
26
+ name: 'Process Data',
27
+ parameters: {
28
+ mode: 'manual',
29
+ includeOtherFields: true,
30
+ assignments: {
31
+ assignments: [
32
+ { id: 'processed-title', name: 'processedTitle', value: expr('{{ $json.title }}'), type: 'string' }
33
+ ]
34
+ }
35
+ }
36
+ }
26
37
  });
27
38
 
28
39
  // 2. Compose workflow
@@ -83,49 +94,62 @@ export default workflow('id', 'name')
83
94
  </independent_sources>
84
95
 
85
96
  <zero_item_safety>
86
- Nodes that fetch or filter data may return 0 items, which stops the entire downstream chain.
87
- Use \`alwaysOutputData: true\` on data-fetching nodes to ensure the chain continues with an empty item \`{json: {}}\`.
97
+ When a node returns 0 items, downstream nodes are skipped for that execution. **This is usually the correct behavior** — the scheduler / trigger fires again later, and when there is data, the chain runs normally. Don't paper over an empty result with \`alwaysOutputData: true\` by default.
98
+
99
+ **\`alwaysOutputData: true\` forces a synthetic \`{json: {}}\` item downstream.** This is a footgun: downstream nodes will try to read fields that don't exist, HTTP requests will hit \`GET undefined\`, and loops will run once on a fake item. Use it *only* when the empty case has its own dedicated branch that you want to execute.
100
+
101
+ **Correct pattern — no \`alwaysOutputData\`:**
102
+ \`\`\`javascript
103
+ // Scheduler that processes pending work
104
+ workflow('ingest', 'Ingest Worker')
105
+ .add(scheduleTrigger) // fires every 5 min
106
+ .to(getPending) // returns 0..N rows; no alwaysOutputData
107
+ .to(splitInBatches({version: 3, config: {parameters: {batchSize: 1}}})
108
+ .onEachBatch(fetchUrl.to(embed).to(saveChunk))
109
+ );
110
+ // On runs where getPending returns 0 items, the loop simply doesn't execute.
111
+ // On runs where it returns rows, the loop iterates. No gate, no filter needed.
112
+ \`\`\`
88
113
 
114
+ **Correct pattern — empty case needs its own branch:**
89
115
  \`\`\`javascript
90
- // Data Table might be empty (fresh table, no matching rows)
91
- const getReflections = node({
92
- type: 'n8n-nodes-base.dataTable',
93
- version: 1.1,
116
+ // "No matches found" deserves a notification
117
+ const search = node({
118
+ type: 'n8n-nodes-base.httpRequest',
119
+ version: 4.4,
94
120
  config: {
95
- name: 'Get Reflections',
96
- alwaysOutputData: true, // Chain continues even if table is empty
97
- parameters: { resource: 'row', operation: 'get', returnAll: true }
121
+ name: 'Search',
122
+ alwaysOutputData: true, // empty-case branch below needs to execute
123
+ parameters: { /* ... */ }
98
124
  }
99
125
  });
100
-
101
- // Downstream Code node handles the empty case
102
- const processData = node({
103
- type: 'n8n-nodes-base.code',
104
- version: 2,
126
+ const hasResults = ifElse({
127
+ version: 2.2,
105
128
  config: {
106
- name: 'Process Data',
129
+ name: 'Has Results?',
107
130
  parameters: {
108
- mode: 'runOnceForAllItems',
109
- jsCode: \\\`
110
- const items = $input.all();
111
- // items will be [{json: {}}] if upstream had no data
112
- const hasData = items.length > 0 && Object.keys(items[0].json).length > 0;
113
- // ... handle both cases
114
- \\\`.trim()
131
+ conditions: {
132
+ options: { caseSensitive: true, typeValidation: 'loose' },
133
+ conditions: [{ leftValue: '={{ $json.results }}', operator: { type: 'array', operation: 'notEmpty' } }],
134
+ combinator: 'and'
135
+ }
115
136
  }
116
137
  }
117
138
  });
139
+ workflow('search', 'Search').add(trigger).to(search).to(
140
+ hasResults.onTrue(processResults).onFalse(notifyNoMatches)
141
+ );
118
142
  \`\`\`
119
143
 
120
- **When to use \`alwaysOutputData: true\`:**
121
- - Data Table with \`operation: 'get'\` (table may be empty or freshly created)
122
- - Any lookup/search/filter node whose result feeds into downstream processing
123
- - HTTP Request that may return an empty array
144
+ **When to use \`alwaysOutputData: true\`:** only when you've paired it with an explicit empty-case branch, AND the downstream branch doesn't blindly read item fields.
124
145
 
125
146
  **When NOT to use it:**
126
- - Trigger nodes (they always produce output)
127
- - Code nodes (handle empty input in your code logic instead)
128
- - Nodes at the end of the chain (no downstream to protect)
147
+ - Scheduled/polling triggers where the "no work" case should silently skip
148
+ - Before a \`splitInBatches\` loop loops already no-op on empty input
149
+ - Before a \`filter\` the filter already no-ops on empty input
150
+ - When all you'd do on the empty case is "nothing"
151
+
152
+ **Don't gate loops with an \`IF\`.** \`ifElse.onTrue(splitInBatches)\` to check "are there items?" is redundant — the loop already does the right thing with 0 items. Drop the IF.
129
153
 
130
154
  </zero_item_safety>
131
155
 
@@ -229,7 +253,18 @@ const fetchRecords = node({
229
253
  const finalizeResults = node({
230
254
  type: 'n8n-nodes-base.set',
231
255
  version: 3.4,
232
- config: { name: 'Finalize', parameters: {} }
256
+ config: {
257
+ name: 'Finalize',
258
+ parameters: {
259
+ mode: 'manual',
260
+ includeOtherFields: true,
261
+ assignments: {
262
+ assignments: [
263
+ { id: 'processed-at', name: 'processedAt', value: expr('{{ $now.toISO() }}'), type: 'string' }
264
+ ]
265
+ }
266
+ }
267
+ }
233
268
  });
234
269
 
235
270
  const processRecord = node({
@@ -262,7 +297,18 @@ const webhookTrigger = trigger({
262
297
  const processWebhook = node({
263
298
  type: 'n8n-nodes-base.set',
264
299
  version: 3.4,
265
- config: { name: 'Process Webhook', parameters: {} }
300
+ config: {
301
+ name: 'Process Webhook',
302
+ parameters: {
303
+ mode: 'manual',
304
+ includeOtherFields: true,
305
+ assignments: {
306
+ assignments: [
307
+ { id: 'source', name: 'source', value: 'webhook', type: 'string' }
308
+ ]
309
+ }
310
+ }
311
+ }
266
312
  });
267
313
 
268
314
  const scheduleTrigger = trigger({
@@ -274,7 +320,18 @@ const scheduleTrigger = trigger({
274
320
  const processSchedule = node({
275
321
  type: 'n8n-nodes-base.set',
276
322
  version: 3.4,
277
- config: { name: 'Process Schedule', parameters: {} }
323
+ config: {
324
+ name: 'Process Schedule',
325
+ parameters: {
326
+ mode: 'manual',
327
+ includeOtherFields: true,
328
+ assignments: {
329
+ assignments: [
330
+ { id: 'source', name: 'source', value: 'schedule', type: 'string' }
331
+ ]
332
+ }
333
+ }
334
+ }
278
335
  });
279
336
 
280
337
  export default workflow('id', 'name')
@@ -307,7 +364,18 @@ const scheduleTrigger = trigger({
307
364
  const processData = node({
308
365
  type: 'n8n-nodes-base.set',
309
366
  version: 3.4,
310
- config: { name: 'Process Data', parameters: {} }
367
+ config: {
368
+ name: 'Process Data',
369
+ parameters: {
370
+ mode: 'manual',
371
+ includeOtherFields: true,
372
+ assignments: {
373
+ assignments: [
374
+ { id: 'received-at', name: 'receivedAt', value: expr('{{ $now.toISO() }}'), type: 'string' }
375
+ ]
376
+ }
377
+ }
378
+ }
311
379
  });
312
380
 
313
381
  const sendNotification = node({
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-patterns.js","sourceRoot":"","sources":["../../../src/prompts/sdk-reference/workflow-patterns.ts"],"names":[],"mappings":";;;AAUA,MAAM,UAAU,GACf,8RAA8R,CAAC;AAMnR,QAAA,qBAAqB,GAAG;;EAEnC,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mCAsduB,CAAC;AAEF,oCA1drB,6BAAqB,CA0dyB"}
1
+ {"version":3,"file":"workflow-patterns.js","sourceRoot":"","sources":["../../../src/prompts/sdk-reference/workflow-patterns.ts"],"names":[],"mappings":";;;AAUA,MAAM,UAAU,GACf,8RAA8R,CAAC;AAMnR,QAAA,qBAAqB,GAAG;;EAEnC,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mCA0hBuB,CAAC;AAEF,oCA9hBrB,6BAAqB,CA8hByB"}
@@ -1 +1 @@
1
- export declare const WORKFLOW_RULES = "Follow these rules strictly when generating workflows:\n\n1. **Always use newCredential() for authentication**\n - When a node needs credentials, always use `newCredential('Name')` in the credentials config\n - NEVER use placeholder strings, fake API keys, or hardcoded auth values\n - Example: `credentials: { slackApi: newCredential('Slack Bot') }`\n - The credential type must match what the node expects\n\n2. **Handle empty outputs with `alwaysOutputData: true`**\n - Nodes that query data (Data Table get, Google Sheets lookup, HTTP Request, etc.) may return 0 items\n - When a node returns 0 items, all downstream nodes are SKIPPED \u2014 the workflow chain breaks silently\n - Set `alwaysOutputData: true` on any node whose output feeds downstream nodes and might return empty results\n - Common cases: fresh/empty Data Tables, filtered queries, conditional lookups, API searches with no matches\n - Example: `config: { ..., alwaysOutputData: true }`\n\n3. **Use `executeOnce: true` for single-execution nodes**\n - When a node receives N items but should only execute once (not N times), set `executeOnce: true`\n - Common cases: sending a summary notification, generating a report, calling an API that doesn't need per-item execution\n - Example: `config: { ..., executeOnce: true }`";
1
+ export declare const WORKFLOW_RULES = "Follow these rules strictly when generating workflows:\n\n1. **Always use newCredential() for authentication**\n - When a node needs credentials, always use `newCredential('Name')` in the credentials config\n - NEVER use placeholder strings, fake API keys, or hardcoded auth values\n - Example: `credentials: { slackApi: newCredential('Slack Bot') }`\n - The credential type must match what the node expects\n\n2. **Trust empty item lists \u2014 don't synthesize fake items**\n - When a query returns 0 items, downstream nodes simply don't run for that execution. For scheduled or polling triggers this is the correct \"nothing to do this round\" signal \u2014 the next run will execute normally when data appears.\n - DO NOT add `alwaysOutputData: true` just to \"keep the chain alive.\" Forcing an empty `{}` item downstream is what causes `undefined` reads, failed HTTP calls to `GET undefined`, and Code-node crashes on missing fields.\n - DO NOT add an IF gate before a loop to check \"has items?\" \u2014 loops (`splitInBatches`, per-item nodes, `filter`) already no-op on empty input. The gate is redundant and adds a failure surface.\n - `alwaysOutputData: true` is only correct when you specifically need a downstream branch to run on the \"empty\" case \u2014 e.g. a dedicated \"no matches found\" notification path. In that case, pair it with an `IF` that explicitly checks for the empty case and routes accordingly. Never use it as a default.\n - To drop invalid items mid-pipeline, use a `filter` node. A `filter` that rejects everything emits 0 items and the chain correctly stops \u2014 no `IF` + `splitInBatches` composition needed.\n\n3. **Use `executeOnce: true` for single-execution nodes**\n - When a node receives N items but should only execute once (not N times), set `executeOnce: true`\n - Common cases: sending a summary notification, generating a report, calling an API that doesn't need per-item execution\n - Example: `config: { ..., executeOnce: true }`\n\n4. **Pick the right control-flow primitive**\n - **Per-item loop with side effects (fetch, embed, write)** \u2192 `splitInBatches` with `batchSize: 1` feeding the per-item work, loop back via `nextBatch`. No `IF` gate before it.\n - **Drop items that don't match a predicate** \u2192 `filter`. It emits 0 items when nothing matches, and the chain stops cleanly.\n - **Two mutually exclusive paths that both do real work** \u2192 `IF` (`onTrue` / `onFalse`).\n - **Many mutually exclusive paths keyed off a value** \u2192 `switch` (`onCase`).\n - Nested control flow is supported: `ifNode.onTrue(loopBuilder)`, `switchNode.onCase(0, loopBuilder)`, and `splitInBatches(sib).onEachBatch(ifElseBuilder)` all compile and wire correctly. Use them when the semantics genuinely call for it, not as a workaround for empty-list handling.";
@@ -9,15 +9,22 @@ exports.WORKFLOW_RULES = `Follow these rules strictly when generating workflows:
9
9
  - Example: \`credentials: { slackApi: newCredential('Slack Bot') }\`
10
10
  - The credential type must match what the node expects
11
11
 
12
- 2. **Handle empty outputs with \`alwaysOutputData: true\`**
13
- - Nodes that query data (Data Table get, Google Sheets lookup, HTTP Request, etc.) may return 0 items
14
- - When a node returns 0 items, all downstream nodes are SKIPPED the workflow chain breaks silently
15
- - Set \`alwaysOutputData: true\` on any node whose output feeds downstream nodes and might return empty results
16
- - Common cases: fresh/empty Data Tables, filtered queries, conditional lookups, API searches with no matches
17
- - Example: \`config: { ..., alwaysOutputData: true }\`
12
+ 2. **Trust empty item lists don't synthesize fake items**
13
+ - When a query returns 0 items, downstream nodes simply don't run for that execution. For scheduled or polling triggers this is the correct "nothing to do this round" signal — the next run will execute normally when data appears.
14
+ - DO NOT add \`alwaysOutputData: true\` just to "keep the chain alive." Forcing an empty \`{}\` item downstream is what causes \`undefined\` reads, failed HTTP calls to \`GET undefined\`, and Code-node crashes on missing fields.
15
+ - DO NOT add an IF gate before a loop to check "has items?" — loops (\`splitInBatches\`, per-item nodes, \`filter\`) already no-op on empty input. The gate is redundant and adds a failure surface.
16
+ - \`alwaysOutputData: true\` is only correct when you specifically need a downstream branch to run on the "empty" case e.g. a dedicated "no matches found" notification path. In that case, pair it with an \`IF\` that explicitly checks for the empty case and routes accordingly. Never use it as a default.
17
+ - To drop invalid items mid-pipeline, use a \`filter\` node. A \`filter\` that rejects everything emits 0 items and the chain correctly stops — no \`IF\` + \`splitInBatches\` composition needed.
18
18
 
19
19
  3. **Use \`executeOnce: true\` for single-execution nodes**
20
20
  - When a node receives N items but should only execute once (not N times), set \`executeOnce: true\`
21
21
  - Common cases: sending a summary notification, generating a report, calling an API that doesn't need per-item execution
22
- - Example: \`config: { ..., executeOnce: true }\``;
22
+ - Example: \`config: { ..., executeOnce: true }\`
23
+
24
+ 4. **Pick the right control-flow primitive**
25
+ - **Per-item loop with side effects (fetch, embed, write)** → \`splitInBatches\` with \`batchSize: 1\` feeding the per-item work, loop back via \`nextBatch\`. No \`IF\` gate before it.
26
+ - **Drop items that don't match a predicate** → \`filter\`. It emits 0 items when nothing matches, and the chain stops cleanly.
27
+ - **Two mutually exclusive paths that both do real work** → \`IF\` (\`onTrue\` / \`onFalse\`).
28
+ - **Many mutually exclusive paths keyed off a value** → \`switch\` (\`onCase\`).
29
+ - Nested control flow is supported: \`ifNode.onTrue(loopBuilder)\`, \`switchNode.onCase(0, loopBuilder)\`, and \`splitInBatches(sib).onEachBatch(ifElseBuilder)\` all compile and wire correctly. Use them when the semantics genuinely call for it, not as a workaround for empty-list handling.`;
23
30
  //# sourceMappingURL=workflow-rules.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-rules.js","sourceRoot":"","sources":["../../../src/prompts/sdk-reference/workflow-rules.ts"],"names":[],"mappings":";;;AAQa,QAAA,cAAc,GAAG;;;;;;;;;;;;;;;;;;qDAkBuB,CAAC"}
1
+ {"version":3,"file":"workflow-rules.js","sourceRoot":"","sources":["../../../src/prompts/sdk-reference/workflow-rules.ts"],"names":[],"mappings":";;;AAQa,QAAA,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;qSAyBuQ,CAAC"}
@@ -57,6 +57,13 @@ export interface INodeConnections {
57
57
  export interface IConnections {
58
58
  [key: string]: INodeConnections;
59
59
  }
60
+ interface ErrorIndexNodeInfo {
61
+ name?: string;
62
+ type: string;
63
+ parameters?: IDataObject;
64
+ }
65
+ export declare function resolveErrorOutputIndex(type: string, parameters?: IDataObject): number;
66
+ export declare function foldLegacyErrorConnections(connections: IConnections, nodes?: readonly ErrorIndexNodeInfo[]): void;
60
67
  export declare function normalizeConnections(connections: IConnections): void;
61
68
  export declare function generateUniqueName(baseName: string, exists: (name: string) => boolean): string;
62
69
  export interface NodeJSON {
@@ -129,7 +136,7 @@ export interface WorkflowContext {
129
136
  }
130
137
  export interface NodeConfig<TParams = IDataObject> {
131
138
  parameters?: TParams;
132
- credentials?: Record<string, CredentialReference | NewCredentialValue>;
139
+ credentials?: Record<string, CredentialReference | NewCredentialValue | PlaceholderValue>;
133
140
  name?: string;
134
141
  position?: [number, number];
135
142
  webhookId?: string;
@@ -229,8 +236,9 @@ export interface SwitchCaseComposite {
229
236
  readonly switchNode: NodeInstance<'n8n-nodes-base.switch', string, unknown>;
230
237
  readonly cases: Array<NodeInstance<string, string, unknown> | Array<NodeInstance<string, string, unknown>> | null>;
231
238
  }
232
- export type IfElseTarget = null | NodeInstance<string, string, unknown> | NodeChain<NodeInstance<string, string, unknown>, NodeInstance<string, string, unknown>> | Array<NodeInstance<string, string, unknown> | NodeChain<NodeInstance<string, string, unknown>, NodeInstance<string, string, unknown>>> | IfElseBuilder<unknown> | SwitchCaseBuilder<unknown>;
233
- export type SwitchCaseTarget = null | NodeInstance<string, string, unknown> | NodeChain<NodeInstance<string, string, unknown>, NodeInstance<string, string, unknown>> | Array<NodeInstance<string, string, unknown> | NodeChain<NodeInstance<string, string, unknown>, NodeInstance<string, string, unknown>>> | IfElseBuilder<unknown> | SwitchCaseBuilder<unknown>;
239
+ export type IfElseTarget = null | NodeInstance<string, string, unknown> | NodeChain<NodeInstance<string, string, unknown>, NodeInstance<string, string, unknown>> | Array<NodeInstance<string, string, unknown> | NodeChain<NodeInstance<string, string, unknown>, NodeInstance<string, string, unknown>>> | IfElseBuilder<unknown> | SwitchCaseBuilder<unknown> | SplitInBatchesBuilder<unknown>;
240
+ export type SwitchCaseTarget = null | NodeInstance<string, string, unknown> | NodeChain<NodeInstance<string, string, unknown>, NodeInstance<string, string, unknown>> | Array<NodeInstance<string, string, unknown> | NodeChain<NodeInstance<string, string, unknown>, NodeInstance<string, string, unknown>>> | IfElseBuilder<unknown> | SwitchCaseBuilder<unknown> | SplitInBatchesBuilder<unknown>;
241
+ export type SplitInBatchesTarget = null | NodeInstance<string, string, unknown> | NodeChain<NodeInstance<string, string, unknown>, NodeInstance<string, string, unknown>> | Array<NodeInstance<string, string, unknown> | NodeChain<NodeInstance<string, string, unknown>, NodeInstance<string, string, unknown>>> | IfElseBuilder<unknown> | SwitchCaseBuilder<unknown> | SplitInBatchesBuilder<unknown>;
234
242
  export interface IfElseBuilder<TOutput = unknown> {
235
243
  readonly _isIfElseBuilder: true;
236
244
  readonly ifNode: NodeInstance<'n8n-nodes-base.if', string, TOutput>;
@@ -259,8 +267,8 @@ export interface SplitInBatchesConfig extends NodeConfig {
259
267
  }
260
268
  export interface SplitInBatchesBuilder<TOutput = unknown> {
261
269
  readonly sibNode: NodeInstance<'n8n-nodes-base.splitInBatches', string, unknown>;
262
- onEachBatch(target: null | NodeInstance<string, string, unknown> | NodeChain<NodeInstance<string, string, unknown>, NodeInstance<string, string, unknown>> | Array<NodeInstance<string, string, unknown> | NodeChain<NodeInstance<string, string, unknown>, NodeInstance<string, string, unknown>>>): SplitInBatchesBuilder<TOutput>;
263
- onDone(target: null | NodeInstance<string, string, unknown> | NodeChain<NodeInstance<string, string, unknown>, NodeInstance<string, string, unknown>> | Array<NodeInstance<string, string, unknown> | NodeChain<NodeInstance<string, string, unknown>, NodeInstance<string, string, unknown>>>): SplitInBatchesBuilder<TOutput>;
270
+ onEachBatch(target: SplitInBatchesTarget): SplitInBatchesBuilder<TOutput>;
271
+ onDone(target: SplitInBatchesTarget): SplitInBatchesBuilder<TOutput>;
264
272
  }
265
273
  export interface GeneratePinDataOptions {
266
274
  beforeWorkflow?: WorkflowJSON;
@@ -372,3 +380,4 @@ export type RunOnceForEachItemFn = <T = unknown>(fn: (ctx: EachItemContext) => {
372
380
  json: T;
373
381
  } | null) => CodeResult<T>;
374
382
  export type FromAIArgumentType = 'string' | 'number' | 'boolean' | 'json';
383
+ export {};
@@ -1,9 +1,52 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveErrorOutputIndex = resolveErrorOutputIndex;
4
+ exports.foldLegacyErrorConnections = foldLegacyErrorConnections;
3
5
  exports.normalizeConnections = normalizeConnections;
4
6
  exports.generateUniqueName = generateUniqueName;
5
7
  exports.isNodeChain = isNodeChain;
6
8
  exports.isNodeInstance = isNodeInstance;
9
+ function resolveErrorOutputIndex(type, parameters) {
10
+ if (type === 'n8n-nodes-base.if')
11
+ return 2;
12
+ if (type === 'n8n-nodes-base.switch') {
13
+ const rules = parameters?.rules;
14
+ const rulesArray = rules?.rules ?? rules?.values;
15
+ const numCases = Array.isArray(rulesArray) ? rulesArray.length : 4;
16
+ return numCases + 1;
17
+ }
18
+ if (type === 'n8n-nodes-base.splitInBatches')
19
+ return 2;
20
+ if (type === 'n8n-nodes-base.merge')
21
+ return 1;
22
+ return 1;
23
+ }
24
+ function foldLegacyErrorConnections(connections, nodes) {
25
+ const nodeLookup = new Map();
26
+ if (nodes) {
27
+ for (const n of nodes) {
28
+ if (n.name)
29
+ nodeLookup.set(n.name, n);
30
+ }
31
+ }
32
+ for (const [nodeName, nodeConns] of Object.entries(connections)) {
33
+ const errorOutputs = nodeConns.error;
34
+ if (!Array.isArray(errorOutputs) || errorOutputs.length === 0)
35
+ continue;
36
+ const errorTargets = errorOutputs[0];
37
+ delete nodeConns.error;
38
+ if (!Array.isArray(errorTargets) || errorTargets.length === 0)
39
+ continue;
40
+ const node = nodeLookup.get(nodeName);
41
+ const targetIndex = node ? resolveErrorOutputIndex(node.type, node.parameters) : 1;
42
+ const main = Array.isArray(nodeConns.main) ? nodeConns.main : [];
43
+ while (main.length < targetIndex)
44
+ main.push([]);
45
+ const existing = main[targetIndex] ?? [];
46
+ main[targetIndex] = [...existing, ...errorTargets];
47
+ nodeConns.main = main;
48
+ }
49
+ }
7
50
  function normalizeConnections(connections) {
8
51
  for (const nodeConns of Object.values(connections)) {
9
52
  for (const [connType, outputs] of Object.entries(nodeConns)) {
@@ -1 +1 @@
1
- {"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/types/base.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/types/base.ts"],"names":[],"mappings":"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"}
@@ -80,15 +80,23 @@ function checkConditions(conditions, actualValues) {
80
80
  return propertyValue >= from && propertyValue <= to;
81
81
  }
82
82
  if (key === 'includes') {
83
+ if (typeof propertyValue !== 'string')
84
+ return false;
83
85
  return propertyValue.includes(targetValue);
84
86
  }
85
87
  if (key === 'startsWith') {
88
+ if (typeof propertyValue !== 'string')
89
+ return false;
86
90
  return propertyValue.startsWith(targetValue);
87
91
  }
88
92
  if (key === 'endsWith') {
93
+ if (typeof propertyValue !== 'string')
94
+ return false;
89
95
  return propertyValue.endsWith(targetValue);
90
96
  }
91
97
  if (key === 'regex') {
98
+ if (typeof propertyValue !== 'string')
99
+ return false;
92
100
  return new RegExp(targetValue).test(propertyValue);
93
101
  }
94
102
  if (key === 'exists') {
@@ -1 +1 @@
1
- {"version":3,"file":"display-options.js","sourceRoot":"","sources":["../../src/validation/display-options.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"display-options.js","sourceRoot":"","sources":["../../src/validation/display-options.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import type { INodeTypes } from 'n8n-workflow';
2
2
  import type { WorkflowBuilder, WorkflowJSON } from '../types/base';
3
3
  export { setSchemaBaseDirs } from './schema-validator';
4
- export type ValidationErrorCode = 'NO_NODES' | 'MISSING_TRIGGER' | 'DISCONNECTED_NODE' | 'MISSING_PARAMETER' | 'INVALID_CONNECTION' | 'CIRCULAR_REFERENCE' | 'INVALID_EXPRESSION' | 'AGENT_STATIC_PROMPT' | 'AGENT_NO_SYSTEM_MESSAGE' | 'HARDCODED_CREDENTIALS' | 'SET_CREDENTIAL_FIELD' | 'MERGE_SINGLE_INPUT' | 'TOOL_NO_PARAMETERS' | 'FROM_AI_IN_NON_TOOL' | 'MISSING_EXPRESSION_PREFIX' | 'INVALID_PARAMETER' | 'INVALID_INPUT_INDEX' | 'SUBNODE_NOT_CONNECTED' | 'SUBNODE_PARAMETER_MISMATCH' | 'UNSUPPORTED_SUBNODE_INPUT' | 'MAX_NODES_EXCEEDED' | 'INVALID_EXPRESSION_PATH' | 'PARTIAL_EXPRESSION_PATH' | 'INVALID_DATE_METHOD';
4
+ export type ValidationErrorCode = 'NO_NODES' | 'MISSING_TRIGGER' | 'DISCONNECTED_NODE' | 'MISSING_PARAMETER' | 'INVALID_CONNECTION' | 'CIRCULAR_REFERENCE' | 'INVALID_EXPRESSION' | 'AGENT_STATIC_PROMPT' | 'AGENT_NO_SYSTEM_MESSAGE' | 'HARDCODED_CREDENTIALS' | 'SET_CREDENTIAL_FIELD' | 'MERGE_SINGLE_INPUT' | 'TOOL_NO_PARAMETERS' | 'FROM_AI_IN_NON_TOOL' | 'MISSING_EXPRESSION_PREFIX' | 'INVALID_PARAMETER' | 'INVALID_INPUT_INDEX' | 'SUBNODE_NOT_CONNECTED' | 'SUBNODE_PARAMETER_MISMATCH' | 'UNSUPPORTED_SUBNODE_INPUT' | 'MISSING_REQUIRED_INPUT' | 'INVALID_OUTPUT_FOR_MODE' | 'MAX_NODES_EXCEEDED' | 'INVALID_EXPRESSION_PATH' | 'PARTIAL_EXPRESSION_PATH' | 'INVALID_DATE_METHOD';
5
5
  export declare class ValidationError {
6
6
  readonly code: ValidationErrorCode;
7
7
  readonly message: string;
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.ValidationWarning = exports.ValidationError = exports.setSchemaBaseDirs = void 0;
4
7
  exports.validateWorkflow = validateWorkflow;
8
+ const get_1 = __importDefault(require("lodash/get"));
5
9
  const n8n_workflow_1 = require("n8n-workflow");
6
10
  const display_options_1 = require("./display-options");
7
11
  const input_resolver_1 = require("./input-resolver");
@@ -244,6 +248,8 @@ function validateWorkflow(workflowOrJson, options = {}) {
244
248
  checkNodeInputIndices(json, options.nodeTypesProvider, warnings);
245
249
  validateSubnodeParameters(json, options.nodeTypesProvider, warnings);
246
250
  validateParentSupportsInputs(json, options.nodeTypesProvider, warnings);
251
+ validateRequiredInputsConnected(json, options.nodeTypesProvider, errors);
252
+ validateOutputUsage(json, options.nodeTypesProvider, warnings);
247
253
  }
248
254
  checkMergeNodeInputCount(json, warnings);
249
255
  return {
@@ -341,6 +347,9 @@ function validateSubnodeParameters(json, nodeTypesProvider, warnings) {
341
347
  continue;
342
348
  const { matches, mismatches } = checkDisplayOptionsMatch(subnode.parameters, inputConfig.displayOptions);
343
349
  if (!matches) {
350
+ const subnodeOwnsAnyParam = mismatches.some((m) => m.actual !== undefined);
351
+ if (!subnodeOwnsAnyParam)
352
+ continue;
344
353
  const sdkFn = AI_CONNECTION_TO_SDK_FUNCTION[connectionType] || connectionType;
345
354
  const mismatchDetails = mismatches
346
355
  .map((m) => `${m.param}='${String(m.actual)}' (expected: ${m.expected.map((v) => `'${String(v)}'`).join(' or ')})`)
@@ -359,12 +368,22 @@ function buildConditionSummary(displayOptions, parentParams) {
359
368
  for (const [paramName, expectedValues] of Object.entries(displayOptions.show)) {
360
369
  if (!expectedValues)
361
370
  continue;
362
- const actual = parentParams[paramName];
371
+ const actual = (0, get_1.default)(parentParams, paramName);
363
372
  const expectedStr = expectedValues.map((v) => `'${String(v)}'`).join(' or ');
364
373
  parts.push(`${paramName} should be ${expectedStr} (currently '${String(actual)}')`);
365
374
  }
366
375
  return parts.length > 0 ? `Required: ${parts.join(', ')}.` : '';
367
376
  }
377
+ function buildTriggeringConditionSummary(displayOptions, parentParams) {
378
+ if (!displayOptions.show)
379
+ return '';
380
+ const parts = [];
381
+ for (const [paramName, _expectedValues] of Object.entries(displayOptions.show)) {
382
+ const actual = (0, get_1.default)(parentParams, paramName);
383
+ parts.push(`${paramName}='${String(actual)}'`);
384
+ }
385
+ return parts.join(', ');
386
+ }
368
387
  function validateParentSupportsInputs(json, nodeTypesProvider, warnings) {
369
388
  const nodesByName = new Map();
370
389
  for (const node of json.nodes) {
@@ -406,12 +425,116 @@ function validateParentSupportsInputs(json, nodeTypesProvider, warnings) {
406
425
  const subnodeName = conn.node;
407
426
  const subnodeField = AI_CONNECTION_TO_SUBNODE_FIELD[connectionType] || connectionType;
408
427
  const conditionDetails = buildConditionSummary(inputConfig.displayOptions, (parentNode.parameters ?? {}));
409
- warnings.push(new ValidationWarning('UNSUPPORTED_SUBNODE_INPUT', `'${subnodeName}' is connected to '${parentNode.name}' as ${subnodeField}, but '${parentNode.name}' does not support ${subnodeField} in its current configuration. ${conditionDetails}`, parentNode.name, undefined, undefined, 'major'));
428
+ warnings.push(new ValidationWarning('UNSUPPORTED_SUBNODE_INPUT', `'${parentNode.name}' has a ${subnodeField} subnode ('${subnodeName}') connected, but its current configuration does not accept one. ${conditionDetails} These parameters must be set on '${parentNode.name}' itself, NOT on the ${subnodeField} subnode. Alternatively, remove the ${subnodeField} connection if this capability isn't needed.`, parentNode.name, undefined, undefined, 'major'));
410
429
  }
411
430
  }
412
431
  }
413
432
  }
414
433
  }
434
+ function validateRequiredInputsConnected(json, nodeTypesProvider, errors) {
435
+ const connectionsByDest = (0, n8n_workflow_1.mapConnectionsByDestination)(json.connections);
436
+ for (const parentNode of json.nodes) {
437
+ if (!parentNode.name)
438
+ continue;
439
+ const version = typeof parentNode.typeVersion === 'string'
440
+ ? parseFloat(parentNode.typeVersion)
441
+ : (parentNode.typeVersion ?? 1);
442
+ const parentNodeType = nodeTypesProvider.getByNameAndVersion(parentNode.type, version);
443
+ const builderHintInputs = parentNodeType?.description?.builderHint?.inputs;
444
+ if (!builderHintInputs)
445
+ continue;
446
+ const parentContext = {
447
+ parameters: (parentNode.parameters ?? {}),
448
+ nodeVersion: version,
449
+ rootParameters: (parentNode.parameters ?? {}),
450
+ };
451
+ for (const [connectionType, inputConfig] of Object.entries(builderHintInputs)) {
452
+ if (!connectionType.startsWith('ai_'))
453
+ continue;
454
+ if (!inputConfig?.required)
455
+ continue;
456
+ if (inputConfig.displayOptions) {
457
+ const conditionsMet = (0, display_options_1.matchesDisplayOptions)(parentContext, inputConfig.displayOptions);
458
+ if (!conditionsMet)
459
+ continue;
460
+ }
461
+ const incoming = connectionsByDest[parentNode.name]?.[connectionType];
462
+ const hasConnection = Array.isArray(incoming) && incoming.some((slot) => Array.isArray(slot) && slot.length > 0);
463
+ if (hasConnection)
464
+ continue;
465
+ const subnodeField = AI_CONNECTION_TO_SUBNODE_FIELD[connectionType] || connectionType;
466
+ const triggerDetails = inputConfig.displayOptions
467
+ ? ` (triggered by ${buildTriggeringConditionSummary(inputConfig.displayOptions, (parentNode.parameters ?? {}))})`
468
+ : '';
469
+ const alternative = inputConfig.displayOptions
470
+ ? ` Either connect a ${subnodeField} subnode, or change those parameters to remove the requirement.`
471
+ : '';
472
+ errors.push(new ValidationError('MISSING_REQUIRED_INPUT', `'${parentNode.name}' requires a ${subnodeField} subnode connected to its ${connectionType} input${triggerDetails}, but none is connected.${alternative}`, parentNode.name, undefined, 'major'));
473
+ }
474
+ }
475
+ }
476
+ function describeOutputWiring(connectionType, target = false) {
477
+ if (connectionType === 'main')
478
+ return target ? '.to(...)' : 'wired with .to()';
479
+ const field = AI_CONNECTION_TO_SUBNODE_FIELD[connectionType];
480
+ if (field)
481
+ return target ? `subnodes.${field}` : `attached as subnodes.${field}`;
482
+ return target ? connectionType : `connected via ${connectionType}`;
483
+ }
484
+ function findEnabledAlternativeOutput(outputsHint, ctx, excludeType) {
485
+ for (const [type, cfg] of Object.entries(outputsHint)) {
486
+ if (type === excludeType)
487
+ continue;
488
+ if (!cfg)
489
+ continue;
490
+ if (cfg.displayOptions && !(0, display_options_1.matchesDisplayOptions)(ctx, cfg.displayOptions)) {
491
+ continue;
492
+ }
493
+ return type;
494
+ }
495
+ return undefined;
496
+ }
497
+ function validateOutputUsage(json, nodeTypesProvider, warnings) {
498
+ for (const sourceNode of json.nodes) {
499
+ if (!sourceNode.name)
500
+ continue;
501
+ const outgoing = json.connections[sourceNode.name];
502
+ if (!outgoing)
503
+ continue;
504
+ const version = typeof sourceNode.typeVersion === 'string'
505
+ ? parseFloat(sourceNode.typeVersion)
506
+ : (sourceNode.typeVersion ?? 1);
507
+ const nodeType = nodeTypesProvider.getByNameAndVersion(sourceNode.type, version);
508
+ const outputsHint = nodeType?.description?.builderHint?.outputs;
509
+ if (!outputsHint)
510
+ continue;
511
+ const ctx = {
512
+ parameters: (sourceNode.parameters ?? {}),
513
+ nodeVersion: version,
514
+ rootParameters: (sourceNode.parameters ?? {}),
515
+ };
516
+ for (const [connectionType, cfg] of Object.entries(outputsHint)) {
517
+ if (!cfg?.displayOptions)
518
+ continue;
519
+ const edges = outgoing[connectionType];
520
+ if (!edges)
521
+ continue;
522
+ const hasEdges = edges.some((slot) => Array.isArray(slot) && slot.length > 0);
523
+ if (!hasEdges)
524
+ continue;
525
+ const enabled = (0, display_options_1.matchesDisplayOptions)(ctx, cfg.displayOptions);
526
+ if (enabled)
527
+ continue;
528
+ const conditionDetails = buildConditionSummary(cfg.displayOptions, (sourceNode.parameters ?? {}));
529
+ const usedWiring = describeOutputWiring(connectionType);
530
+ const enabledAlt = findEnabledAlternativeOutput(outputsHint, ctx, connectionType);
531
+ const altSuggestion = enabledAlt
532
+ ? ` To use this node as-is, attach it as ${describeOutputWiring(enabledAlt, true)} of a parent (it exposes ${enabledAlt} in this configuration).`
533
+ : '';
534
+ warnings.push(new ValidationWarning('INVALID_OUTPUT_FOR_MODE', `'${sourceNode.name}' is ${usedWiring} but its current parameters disable that output. ${conditionDetails}${altSuggestion}`, sourceNode.name, undefined, undefined, 'major'));
535
+ }
536
+ }
537
+ }
415
538
  function checkNodeInputIndices(json, nodeTypesProvider, warnings) {
416
539
  const nodesByName = new Map();
417
540
  for (const node of json.nodes) {