@n8n/workflow-sdk 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ast-interpreter/validators.js +1 -0
- package/dist/ast-interpreter/validators.js.map +1 -1
- package/dist/build.tsbuildinfo +1 -1
- package/dist/codegen/parse-workflow-code.js +1 -0
- package/dist/codegen/parse-workflow-code.js.map +1 -1
- package/dist/expression/index.d.ts +4 -1
- package/dist/expression/index.js +30 -11
- package/dist/expression/index.js.map +1 -1
- package/dist/expression.d.ts +1 -1
- package/dist/expression.js +2 -1
- package/dist/expression.js.map +1 -1
- package/dist/generate-types/generate-types.d.ts +2 -1
- package/dist/generate-types/generate-types.js +137 -45
- package/dist/generate-types/generate-types.js.map +1 -1
- package/dist/generate-types/generate-zod-schemas.js +95 -102
- package/dist/generate-types/generate-zod-schemas.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/prompts/best-practices/guides/chatbot.js +13 -2
- package/dist/prompts/best-practices/guides/chatbot.js.map +1 -1
- package/dist/prompts/node-guidance/index.d.ts +0 -1
- package/dist/prompts/node-guidance/index.js +0 -1
- package/dist/prompts/node-guidance/index.js.map +1 -1
- package/dist/prompts/node-guidance/parameter-guides/predecessor-output.js +7 -0
- package/dist/prompts/node-guidance/parameter-guides/predecessor-output.js.map +1 -1
- package/dist/prompts/node-guidance/parameter-guides/set-node.js +14 -15
- package/dist/prompts/node-guidance/parameter-guides/set-node.js.map +1 -1
- package/dist/prompts/node-selection/ai-nodes.d.ts +2 -2
- package/dist/prompts/node-selection/ai-nodes.js +10 -10
- package/dist/prompts/node-selection/ai-nodes.js.map +1 -1
- package/dist/prompts/node-selection/connection-parameters.d.ts +1 -1
- package/dist/prompts/node-selection/connection-parameters.js +2 -2
- package/dist/prompts/sdk-reference/additional-functions.d.ts +1 -1
- package/dist/prompts/sdk-reference/additional-functions.js +5 -2
- package/dist/prompts/sdk-reference/additional-functions.js.map +1 -1
- package/dist/prompts/sdk-reference/expressions.d.ts +1 -1
- package/dist/prompts/sdk-reference/expressions.js +14 -1
- package/dist/prompts/sdk-reference/expressions.js.map +1 -1
- package/dist/prompts/sdk-reference/workflow-patterns-detailed.d.ts +1 -1
- package/dist/prompts/sdk-reference/workflow-patterns-detailed.js +9 -7
- package/dist/prompts/sdk-reference/workflow-patterns-detailed.js.map +1 -1
- package/dist/prompts/sdk-reference/workflow-patterns.d.ts +1 -1
- package/dist/prompts/sdk-reference/workflow-patterns.js +114 -44
- package/dist/prompts/sdk-reference/workflow-patterns.js.map +1 -1
- package/dist/prompts/sdk-reference/workflow-rules.d.ts +1 -1
- package/dist/prompts/sdk-reference/workflow-rules.js +24 -7
- package/dist/prompts/sdk-reference/workflow-rules.js.map +1 -1
- package/dist/types/base.d.ts +9 -10
- package/dist/types/base.js.map +1 -1
- package/dist/validation/display-options.js +8 -0
- package/dist/validation/display-options.js.map +1 -1
- package/dist/validation/index.d.ts +2 -2
- package/dist/validation/index.js +112 -6
- package/dist/validation/index.js.map +1 -1
- package/dist/validation/resolve-schema.d.ts +14 -0
- package/dist/validation/resolve-schema.js +20 -0
- package/dist/validation/resolve-schema.js.map +1 -1
- package/dist/validation/schema-helpers.d.ts +89 -11
- package/dist/validation/schema-helpers.js +20 -5
- package/dist/validation/schema-helpers.js.map +1 -1
- package/dist/validation/schema-validator.js +1 -0
- package/dist/validation/schema-validator.js.map +1 -1
- package/dist/validation.d.ts +1 -0
- package/dist/validation.js +3 -1
- package/dist/validation.js.map +1 -1
- package/dist/workflow-builder/control-flow-builders/if-else.d.ts +1 -2
- package/dist/workflow-builder/control-flow-builders/split-in-batches.d.ts +2 -2
- package/dist/workflow-builder/control-flow-builders/split-in-batches.js +26 -0
- package/dist/workflow-builder/control-flow-builders/split-in-batches.js.map +1 -1
- package/dist/workflow-builder/control-flow-builders/switch-case.d.ts +1 -2
- package/dist/workflow-builder/layout-utils.d.ts +1 -2
- package/dist/workflow-builder/layout-utils.js +21 -58
- package/dist/workflow-builder/layout-utils.js.map +1 -1
- package/dist/workflow-builder/node-builders/node-builder.d.ts +3 -2
- package/dist/workflow-builder/node-builders/node-builder.js +65 -14
- package/dist/workflow-builder/node-builders/node-builder.js.map +1 -1
- package/dist/workflow-builder/node-builders/subnode-builders.js +2 -1
- package/dist/workflow-builder/node-builders/subnode-builders.js.map +1 -1
- package/dist/workflow-builder/pin-data-utils.js +2 -3
- package/dist/workflow-builder/pin-data-utils.js.map +1 -1
- package/dist/workflow-builder/plugins/composite-handlers/branch-handler-utils.js +23 -2
- package/dist/workflow-builder/plugins/composite-handlers/branch-handler-utils.js.map +1 -1
- package/dist/workflow-builder/plugins/defaults.js +1 -0
- package/dist/workflow-builder/plugins/defaults.js.map +1 -1
- package/dist/workflow-builder/plugins/serializers/json-serializer.js +18 -1
- package/dist/workflow-builder/plugins/serializers/json-serializer.js.map +1 -1
- package/dist/workflow-builder/plugins/validators/index.d.ts +1 -0
- package/dist/workflow-builder/plugins/validators/index.js +3 -1
- package/dist/workflow-builder/plugins/validators/index.js.map +1 -1
- package/dist/workflow-builder/plugins/validators/memory-session-key-validator.d.ts +2 -0
- package/dist/workflow-builder/plugins/validators/memory-session-key-validator.js +50 -0
- package/dist/workflow-builder/plugins/validators/memory-session-key-validator.js.map +1 -0
- package/dist/workflow-builder/plugins/validators/merge-node-validator.js +1 -1
- package/dist/workflow-builder/plugins/validators/merge-node-validator.js.map +1 -1
- package/dist/workflow-builder/plugins/validators/set-node-validator.js +110 -4
- package/dist/workflow-builder/plugins/validators/set-node-validator.js.map +1 -1
- package/dist/workflow-builder/string-utils.d.ts +2 -0
- package/dist/workflow-builder/string-utils.js +12 -0
- package/dist/workflow-builder/string-utils.js.map +1 -1
- package/dist/workflow-builder/validation-helpers.js +5 -6
- package/dist/workflow-builder/validation-helpers.js.map +1 -1
- package/dist/workflow-builder.js +14 -0
- package/dist/workflow-builder.js.map +1 -1
- package/package.json +4 -10
- package/dist/prompts/node-guidance/node-tips/index.d.ts +0 -3
- package/dist/prompts/node-guidance/node-tips/index.js +0 -8
- package/dist/prompts/node-guidance/node-tips/index.js.map +0 -1
- package/dist/prompts/node-guidance/node-tips/structured-output-parser.d.ts +0 -2
- package/dist/prompts/node-guidance/node-tips/structured-output-parser.js +0 -35
- package/dist/prompts/node-guidance/node-tips/structured-output-parser.js.map +0 -1
- package/dist/prompts/node-guidance/node-tips/types.d.ts +0 -7
- package/dist/prompts/node-guidance/node-tips/types.js +0 -3
- package/dist/prompts/node-guidance/node-tips/types.js.map +0 -1
- package/dist/prompts/node-guidance/node-tips/webhook.d.ts +0 -2
- package/dist/prompts/node-guidance/node-tips/webhook.js +0 -38
- package/dist/prompts/node-guidance/node-tips/webhook.js.map +0 -1
|
@@ -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: {
|
|
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
|
|
@@ -54,15 +65,16 @@ const sourceB = node({ ..., config: { ..., executeOnce: true } });
|
|
|
54
65
|
startTrigger.to(sourceA.to(sourceB.to(processResults)));
|
|
55
66
|
|
|
56
67
|
// FIX 2 - parallel branches + Merge (combine by position)
|
|
68
|
+
// .input(n) is 0-based: .input(0) = first input, .input(1) = second input.
|
|
57
69
|
const combineResults = merge({
|
|
58
70
|
version: 3.2,
|
|
59
71
|
config: { name: 'Combine Results', parameters: { mode: 'combine', combineBy: 'combineByPosition' } }
|
|
60
72
|
});
|
|
61
73
|
export default workflow('id', 'name')
|
|
62
74
|
.add(startTrigger)
|
|
63
|
-
.to(sourceA.to(combineResults.input(0)))
|
|
75
|
+
.to(sourceA.to(combineResults.input(0))) // first input (index 0)
|
|
64
76
|
.add(startTrigger)
|
|
65
|
-
.to(sourceB.to(combineResults.input(1)))
|
|
77
|
+
.to(sourceB.to(combineResults.input(1))) // second input (index 1)
|
|
66
78
|
.add(combineResults)
|
|
67
79
|
.to(processResults);
|
|
68
80
|
|
|
@@ -73,9 +85,9 @@ const allResults = merge({
|
|
|
73
85
|
});
|
|
74
86
|
export default workflow('id', 'name')
|
|
75
87
|
.add(startTrigger)
|
|
76
|
-
.to(sourceA.to(allResults.input(0)))
|
|
88
|
+
.to(sourceA.to(allResults.input(0))) // first input (index 0)
|
|
77
89
|
.add(startTrigger)
|
|
78
|
-
.to(sourceB.to(allResults.input(1)))
|
|
90
|
+
.to(sourceB.to(allResults.input(1))) // second input (index 1)
|
|
79
91
|
.add(allResults)
|
|
80
92
|
.to(processResults);
|
|
81
93
|
\`\`\`
|
|
@@ -83,49 +95,62 @@ export default workflow('id', 'name')
|
|
|
83
95
|
</independent_sources>
|
|
84
96
|
|
|
85
97
|
<zero_item_safety>
|
|
86
|
-
|
|
87
|
-
|
|
98
|
+
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.
|
|
99
|
+
|
|
100
|
+
**\`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.
|
|
101
|
+
|
|
102
|
+
**Correct pattern — no \`alwaysOutputData\`:**
|
|
103
|
+
\`\`\`javascript
|
|
104
|
+
// Scheduler that processes pending work
|
|
105
|
+
workflow('ingest', 'Ingest Worker')
|
|
106
|
+
.add(scheduleTrigger) // fires every 5 min
|
|
107
|
+
.to(getPending) // returns 0..N rows; no alwaysOutputData
|
|
108
|
+
.to(splitInBatches({version: 3, config: {parameters: {batchSize: 1}}})
|
|
109
|
+
.onEachBatch(fetchUrl.to(embed).to(saveChunk))
|
|
110
|
+
);
|
|
111
|
+
// On runs where getPending returns 0 items, the loop simply doesn't execute.
|
|
112
|
+
// On runs where it returns rows, the loop iterates. No gate, no filter needed.
|
|
113
|
+
\`\`\`
|
|
88
114
|
|
|
115
|
+
**Correct pattern — empty case needs its own branch:**
|
|
89
116
|
\`\`\`javascript
|
|
90
|
-
//
|
|
91
|
-
const
|
|
92
|
-
type: 'n8n-nodes-base.
|
|
93
|
-
version:
|
|
117
|
+
// "No matches found" deserves a notification
|
|
118
|
+
const search = node({
|
|
119
|
+
type: 'n8n-nodes-base.httpRequest',
|
|
120
|
+
version: 4.4,
|
|
94
121
|
config: {
|
|
95
|
-
name: '
|
|
96
|
-
alwaysOutputData: true,
|
|
97
|
-
parameters: {
|
|
122
|
+
name: 'Search',
|
|
123
|
+
alwaysOutputData: true, // empty-case branch below needs to execute
|
|
124
|
+
parameters: { /* ... */ }
|
|
98
125
|
}
|
|
99
126
|
});
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const processData = node({
|
|
103
|
-
type: 'n8n-nodes-base.code',
|
|
104
|
-
version: 2,
|
|
127
|
+
const hasResults = ifElse({
|
|
128
|
+
version: 2.2,
|
|
105
129
|
config: {
|
|
106
|
-
name: '
|
|
130
|
+
name: 'Has Results?',
|
|
107
131
|
parameters: {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
// ... handle both cases
|
|
114
|
-
\\\`.trim()
|
|
132
|
+
conditions: {
|
|
133
|
+
options: { caseSensitive: true, typeValidation: 'loose' },
|
|
134
|
+
conditions: [{ leftValue: expr('{{ $json.results }}'), operator: { type: 'array', operation: 'notEmpty' } }],
|
|
135
|
+
combinator: 'and'
|
|
136
|
+
}
|
|
115
137
|
}
|
|
116
138
|
}
|
|
117
139
|
});
|
|
140
|
+
workflow('search', 'Search').add(trigger).to(search).to(
|
|
141
|
+
hasResults.onTrue(processResults).onFalse(notifyNoMatches)
|
|
142
|
+
);
|
|
118
143
|
\`\`\`
|
|
119
144
|
|
|
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
|
|
145
|
+
**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
146
|
|
|
125
147
|
**When NOT to use it:**
|
|
126
|
-
-
|
|
127
|
-
-
|
|
128
|
-
-
|
|
148
|
+
- Scheduled/polling triggers where the "no work" case should silently skip
|
|
149
|
+
- Before a \`splitInBatches\` loop — loops already no-op on empty input
|
|
150
|
+
- Before a \`filter\` — the filter already no-ops on empty input
|
|
151
|
+
- When all you'd do on the empty case is "nothing"
|
|
152
|
+
|
|
153
|
+
**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
154
|
|
|
130
155
|
</zero_item_safety>
|
|
131
156
|
|
|
@@ -142,7 +167,7 @@ const checkValid = ifElse({
|
|
|
142
167
|
parameters: {
|
|
143
168
|
conditions: {
|
|
144
169
|
options: { caseSensitive: true, leftValue: '', typeValidation: 'strict' },
|
|
145
|
-
conditions: [{ leftValue: '
|
|
170
|
+
conditions: [{ leftValue: expr('{{ $json.status }}'), operator: { type: 'string', operation: 'equals' }, rightValue: 'active' }],
|
|
146
171
|
combinator: 'and'
|
|
147
172
|
}
|
|
148
173
|
}
|
|
@@ -169,8 +194,8 @@ const routeByPriority = switchCase({
|
|
|
169
194
|
parameters: {
|
|
170
195
|
rules: {
|
|
171
196
|
values: [
|
|
172
|
-
{ outputKey: 'urgent', conditions: { options: { caseSensitive: true, leftValue: '', typeValidation: 'strict' }, conditions: [{ leftValue: '
|
|
173
|
-
{ outputKey: 'normal', conditions: { options: { caseSensitive: true, leftValue: '', typeValidation: 'strict' }, conditions: [{ leftValue: '
|
|
197
|
+
{ outputKey: 'urgent', conditions: { options: { caseSensitive: true, leftValue: '', typeValidation: 'strict' }, conditions: [{ leftValue: expr('{{ $json.priority }}'), operator: { type: 'string', operation: 'equals' }, rightValue: 'urgent' }], combinator: 'and' } },
|
|
198
|
+
{ outputKey: 'normal', conditions: { options: { caseSensitive: true, leftValue: '', typeValidation: 'strict' }, conditions: [{ leftValue: expr('{{ $json.priority }}'), operator: { type: 'string', operation: 'equals' }, rightValue: 'normal' }], combinator: 'and' } },
|
|
174
199
|
]
|
|
175
200
|
}
|
|
176
201
|
}
|
|
@@ -200,12 +225,13 @@ const branch1 = node({ type: 'n8n-nodes-base.httpRequest', ... });
|
|
|
200
225
|
const branch2 = node({ type: 'n8n-nodes-base.httpRequest', ... });
|
|
201
226
|
const processResults = node({ type: 'n8n-nodes-base.set', ... });
|
|
202
227
|
|
|
203
|
-
// Connect branches to specific merge inputs using .input(n)
|
|
228
|
+
// Connect branches to specific merge inputs using .input(n).
|
|
229
|
+
// Indices are 0-based: .input(0) is the FIRST input, .input(1) is the SECOND.
|
|
204
230
|
export default workflow('id', 'name')
|
|
205
231
|
.add(trigger({ ... }))
|
|
206
|
-
.to(branch1.to(combineResults.input(0))) //
|
|
232
|
+
.to(branch1.to(combineResults.input(0))) // first input (index 0)
|
|
207
233
|
.add(trigger({ ... }))
|
|
208
|
-
.to(branch2.to(combineResults.input(1))) //
|
|
234
|
+
.to(branch2.to(combineResults.input(1))) // second input (index 1)
|
|
209
235
|
.add(combineResults)
|
|
210
236
|
.to(processResults); // Process merged results
|
|
211
237
|
\`\`\`
|
|
@@ -229,7 +255,18 @@ const fetchRecords = node({
|
|
|
229
255
|
const finalizeResults = node({
|
|
230
256
|
type: 'n8n-nodes-base.set',
|
|
231
257
|
version: 3.4,
|
|
232
|
-
config: {
|
|
258
|
+
config: {
|
|
259
|
+
name: 'Finalize',
|
|
260
|
+
parameters: {
|
|
261
|
+
mode: 'manual',
|
|
262
|
+
includeOtherFields: true,
|
|
263
|
+
assignments: {
|
|
264
|
+
assignments: [
|
|
265
|
+
{ id: 'processed-at', name: 'processedAt', value: expr('{{ $now.toISO() }}'), type: 'string' }
|
|
266
|
+
]
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
233
270
|
});
|
|
234
271
|
|
|
235
272
|
const processRecord = node({
|
|
@@ -262,7 +299,18 @@ const webhookTrigger = trigger({
|
|
|
262
299
|
const processWebhook = node({
|
|
263
300
|
type: 'n8n-nodes-base.set',
|
|
264
301
|
version: 3.4,
|
|
265
|
-
config: {
|
|
302
|
+
config: {
|
|
303
|
+
name: 'Process Webhook',
|
|
304
|
+
parameters: {
|
|
305
|
+
mode: 'manual',
|
|
306
|
+
includeOtherFields: true,
|
|
307
|
+
assignments: {
|
|
308
|
+
assignments: [
|
|
309
|
+
{ id: 'source', name: 'source', value: 'webhook', type: 'string' }
|
|
310
|
+
]
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
266
314
|
});
|
|
267
315
|
|
|
268
316
|
const scheduleTrigger = trigger({
|
|
@@ -274,7 +322,18 @@ const scheduleTrigger = trigger({
|
|
|
274
322
|
const processSchedule = node({
|
|
275
323
|
type: 'n8n-nodes-base.set',
|
|
276
324
|
version: 3.4,
|
|
277
|
-
config: {
|
|
325
|
+
config: {
|
|
326
|
+
name: 'Process Schedule',
|
|
327
|
+
parameters: {
|
|
328
|
+
mode: 'manual',
|
|
329
|
+
includeOtherFields: true,
|
|
330
|
+
assignments: {
|
|
331
|
+
assignments: [
|
|
332
|
+
{ id: 'source', name: 'source', value: 'schedule', type: 'string' }
|
|
333
|
+
]
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
278
337
|
});
|
|
279
338
|
|
|
280
339
|
export default workflow('id', 'name')
|
|
@@ -307,7 +366,18 @@ const scheduleTrigger = trigger({
|
|
|
307
366
|
const processData = node({
|
|
308
367
|
type: 'n8n-nodes-base.set',
|
|
309
368
|
version: 3.4,
|
|
310
|
-
config: {
|
|
369
|
+
config: {
|
|
370
|
+
name: 'Process Data',
|
|
371
|
+
parameters: {
|
|
372
|
+
mode: 'manual',
|
|
373
|
+
includeOtherFields: true,
|
|
374
|
+
assignments: {
|
|
375
|
+
assignments: [
|
|
376
|
+
{ id: 'received-at', name: 'receivedAt', value: expr('{{ $now.toISO() }}'), type: 'string' }
|
|
377
|
+
]
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
311
381
|
});
|
|
312
382
|
|
|
313
383
|
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
|
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mCA4hBuB,CAAC;AAEF,oCAhiBrB,6BAAqB,CAgiByB"}
|
|
@@ -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. **
|
|
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 - Never synthesize credential IDs. Do not invent raw IDs such as `WHATSAPP_CREDENTIAL_ID`, `mock-gmail-oauth2`, or any `mock-*` value\n - If `availableCredentials` is provided, treat it as an allow-list: copy an existing credential ID exactly or use `newCredential('Name')` without an ID\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.\n\n5. **Input and output indices are 0-based \u2014 `.input(0)` is the FIRST input**\n - `.input(0)` and `.output(0)` refer to the **first** input/output. `.input(1)` and `.output(1)` refer to the **second**. `.input(1)` is NOT the first input \u2014 it is the second one.\n - This applies everywhere indices are passed: `.input(n)`, `.output(n)`, `.onCase(n, ...)` for switch outputs, and any `outputIndex` argument.\n - When wiring N branches to a Merge node, the indices are `0, 1, ..., N-1` \u2014 never `1, 2, ..., N`.\n - Counter-examples to AVOID:\n - WRONG: `sourceA.to(merge.input(1))` followed by `sourceB.to(merge.input(2))` \u2014 this skips input 0 entirely; the first branch is silently dropped.\n - CORRECT: `sourceA.to(merge.input(0))` followed by `sourceB.to(merge.input(1))`.";
|
|
@@ -6,18 +6,35 @@ exports.WORKFLOW_RULES = `Follow these rules strictly when generating workflows:
|
|
|
6
6
|
1. **Always use newCredential() for authentication**
|
|
7
7
|
- When a node needs credentials, always use \`newCredential('Name')\` in the credentials config
|
|
8
8
|
- NEVER use placeholder strings, fake API keys, or hardcoded auth values
|
|
9
|
+
- Never synthesize credential IDs. Do not invent raw IDs such as \`WHATSAPP_CREDENTIAL_ID\`, \`mock-gmail-oauth2\`, or any \`mock-*\` value
|
|
10
|
+
- If \`availableCredentials\` is provided, treat it as an allow-list: copy an existing credential ID exactly or use \`newCredential('Name')\` without an ID
|
|
9
11
|
- Example: \`credentials: { slackApi: newCredential('Slack Bot') }\`
|
|
10
12
|
- The credential type must match what the node expects
|
|
11
13
|
|
|
12
|
-
2. **
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
14
|
+
2. **Trust empty item lists — don't synthesize fake items**
|
|
15
|
+
- 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.
|
|
16
|
+
- 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.
|
|
17
|
+
- 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.
|
|
18
|
+
- \`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.
|
|
19
|
+
- 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
20
|
|
|
19
21
|
3. **Use \`executeOnce: true\` for single-execution nodes**
|
|
20
22
|
- When a node receives N items but should only execute once (not N times), set \`executeOnce: true\`
|
|
21
23
|
- Common cases: sending a summary notification, generating a report, calling an API that doesn't need per-item execution
|
|
22
|
-
- Example: \`config: { ..., executeOnce: true }
|
|
24
|
+
- Example: \`config: { ..., executeOnce: true }\`
|
|
25
|
+
|
|
26
|
+
4. **Pick the right control-flow primitive**
|
|
27
|
+
- **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.
|
|
28
|
+
- **Drop items that don't match a predicate** → \`filter\`. It emits 0 items when nothing matches, and the chain stops cleanly.
|
|
29
|
+
- **Two mutually exclusive paths that both do real work** → \`IF\` (\`onTrue\` / \`onFalse\`).
|
|
30
|
+
- **Many mutually exclusive paths keyed off a value** → \`switch\` (\`onCase\`).
|
|
31
|
+
- 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.
|
|
32
|
+
|
|
33
|
+
5. **Input and output indices are 0-based — \`.input(0)\` is the FIRST input**
|
|
34
|
+
- \`.input(0)\` and \`.output(0)\` refer to the **first** input/output. \`.input(1)\` and \`.output(1)\` refer to the **second**. \`.input(1)\` is NOT the first input — it is the second one.
|
|
35
|
+
- This applies everywhere indices are passed: \`.input(n)\`, \`.output(n)\`, \`.onCase(n, ...)\` for switch outputs, and any \`outputIndex\` argument.
|
|
36
|
+
- When wiring N branches to a Merge node, the indices are \`0, 1, ..., N-1\` — never \`1, 2, ..., N\`.
|
|
37
|
+
- Counter-examples to AVOID:
|
|
38
|
+
- WRONG: \`sourceA.to(merge.input(1))\` followed by \`sourceB.to(merge.input(2))\` — this skips input 0 entirely; the first branch is silently dropped.
|
|
39
|
+
- CORRECT: \`sourceA.to(merge.input(0))\` followed by \`sourceB.to(merge.input(1))\`.`;
|
|
23
40
|
//# 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
|
|
1
|
+
{"version":3,"file":"workflow-rules.js","sourceRoot":"","sources":["../../../src/prompts/sdk-reference/workflow-rules.ts"],"names":[],"mappings":";;;AAQa,QAAA,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2FAmC6D,CAAC"}
|
package/dist/types/base.d.ts
CHANGED
|
@@ -26,10 +26,6 @@ export interface NewCredentialValue {
|
|
|
26
26
|
readonly name: string;
|
|
27
27
|
readonly id?: string;
|
|
28
28
|
}
|
|
29
|
-
export interface PlaceholderValue {
|
|
30
|
-
readonly __placeholder: true;
|
|
31
|
-
readonly hint: string;
|
|
32
|
-
}
|
|
33
29
|
export type OnError = 'stopWorkflow' | 'continueRegularOutput' | 'continueErrorOutput';
|
|
34
30
|
export interface WorkflowSettings {
|
|
35
31
|
timezone?: string;
|
|
@@ -136,7 +132,9 @@ export interface WorkflowContext {
|
|
|
136
132
|
}
|
|
137
133
|
export interface NodeConfig<TParams = IDataObject> {
|
|
138
134
|
parameters?: TParams;
|
|
139
|
-
credentials?: Record<string, CredentialReference | NewCredentialValue
|
|
135
|
+
credentials?: Record<string, string | CredentialReference | NewCredentialValue | {
|
|
136
|
+
value: string;
|
|
137
|
+
}>;
|
|
140
138
|
name?: string;
|
|
141
139
|
position?: [number, number];
|
|
142
140
|
webhookId?: string;
|
|
@@ -236,8 +234,9 @@ export interface SwitchCaseComposite {
|
|
|
236
234
|
readonly switchNode: NodeInstance<'n8n-nodes-base.switch', string, unknown>;
|
|
237
235
|
readonly cases: Array<NodeInstance<string, string, unknown> | Array<NodeInstance<string, string, unknown>> | null>;
|
|
238
236
|
}
|
|
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
|
|
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
|
|
237
|
+
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> | InputTarget;
|
|
238
|
+
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> | InputTarget;
|
|
239
|
+
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>;
|
|
241
240
|
export interface IfElseBuilder<TOutput = unknown> {
|
|
242
241
|
readonly _isIfElseBuilder: true;
|
|
243
242
|
readonly ifNode: NodeInstance<'n8n-nodes-base.if', string, TOutput>;
|
|
@@ -266,8 +265,8 @@ export interface SplitInBatchesConfig extends NodeConfig {
|
|
|
266
265
|
}
|
|
267
266
|
export interface SplitInBatchesBuilder<TOutput = unknown> {
|
|
268
267
|
readonly sibNode: NodeInstance<'n8n-nodes-base.splitInBatches', string, unknown>;
|
|
269
|
-
onEachBatch(target:
|
|
270
|
-
onDone(target:
|
|
268
|
+
onEachBatch(target: SplitInBatchesTarget): SplitInBatchesBuilder<TOutput>;
|
|
269
|
+
onDone(target: SplitInBatchesTarget): SplitInBatchesBuilder<TOutput>;
|
|
271
270
|
}
|
|
272
271
|
export interface GeneratePinDataOptions {
|
|
273
272
|
beforeWorkflow?: WorkflowJSON;
|
|
@@ -321,7 +320,7 @@ export type WorkflowFn = WorkflowBuilderStatic;
|
|
|
321
320
|
export type NodeFn = <TNode extends NodeInput>(input: TNode) => NodeInstance<TNode['type'], `${TNode['version']}`, unknown>;
|
|
322
321
|
export type TriggerFn = <TTrigger extends TriggerInput>(input: TTrigger) => TriggerInstance<TTrigger['type'], `${TTrigger['version']}`, unknown>;
|
|
323
322
|
export type StickyFn = (content: string, nodes?: Array<NodeInstance<string, string, unknown>>, config?: StickyNoteConfig) => NodeInstance<'n8n-nodes-base.stickyNote', 'v1', void>;
|
|
324
|
-
export type PlaceholderFn = (hint: string) =>
|
|
323
|
+
export type PlaceholderFn = (hint: string) => string;
|
|
325
324
|
export type NewCredentialFn = (name: string, id?: string) => NewCredentialValue;
|
|
326
325
|
export type IfElseFn = (branches: [
|
|
327
326
|
NodeInstance<string, string, unknown> | null,
|
package/dist/types/base.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/types/base.ts"],"names":[],"mappings":";;
|
|
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":";;;;;AA2JA,
|
|
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
|
-
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' | 'MISSING_REQUIRED_INPUT' | 'MAX_NODES_EXCEEDED' | 'INVALID_EXPRESSION_PATH' | 'PARTIAL_EXPRESSION_PATH' | 'INVALID_DATE_METHOD';
|
|
3
|
+
export { setSchemaBaseDirs, validateNodeConfig, type SchemaValidationResult, } 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' | '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;
|