fix(core): Apply no-builder-hint-leakage rule to nodes and SDK prompts

Enable the rule in nodes-base, nodes-langchain, and workflow-sdk, and
fix the violations it surfaces:

- IfV2 conditions builderHint: rewrite the example from JSON wire-form
  (\`"={{ \$json.field }}"\`) to SDK-form (\`expr('{{ \$json.field }}')\`).
- ChainLLM text builderHint: same wire → SDK-form rewrite.
- workflow-sdk SDK-facing prompts (sdk-reference, node-selection,
  best-practices, node-tips): replace ={{...}} with expr('{{...}}') and
  wire-format connection names (ai_tool, ai_memory, etc.) with their
  SDK helpers (tool(), memory(), etc.).

The legacy multi-agent parameter-guides directory still documents
wire-format parameters because that's what its consumer
(parameter-updater chain) generates; it is exempted in the workflow-sdk
eslint config.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mutasem Aldmour 2026-05-08 11:07:04 +02:00
parent 06cee7046b
commit a08f67aca6
No known key found for this signature in database
GPG Key ID: 3DFA8122BB7FD6B8
13 changed files with 66 additions and 45 deletions

View File

@ -24,6 +24,7 @@ export default defineConfig(
'import-x/extensions': 'warn',
'n8n-local-rules/no-argument-spread': 'warn', // TODO: mark error
'@n8n/community-nodes/no-builder-hint-leakage': 'error',
'@n8n/community-nodes/credential-documentation-url': ['error', { allowSlugs: true }],

View File

@ -132,7 +132,7 @@ export const nodeProperties: INodeProperties[] = [
},
builderHint: {
message:
'Use expressions to include dynamic data from previous nodes (e.g., "={{ $json.input }}"). Static text prompts ignore incoming data.',
"Use expressions to include dynamic data from previous nodes (e.g., expr('{{ $json.input }}')). Static text prompts ignore incoming data.",
},
displayOptions: {
show: {

View File

@ -1,7 +1,11 @@
import { defineConfig, globalIgnores } from 'eslint/config';
import { nodeConfig } from '@n8n/eslint-config/node';
import { n8nCommunityNodesPlugin } from '@n8n/eslint-plugin-community-nodes';
export default defineConfig(globalIgnores(['test-fixtures/**', 'scripts/**']), nodeConfig, {
plugins: {
'@n8n/community-nodes': n8nCommunityNodesPlugin,
},
rules: {
// Allow PascalCase for object literal property names (n8n node names and AST types)
'@typescript-eslint/naming-convention': [
@ -61,5 +65,21 @@ export default defineConfig(globalIgnores(['test-fixtures/**', 'scripts/**']), n
'n8n-local-rules/no-interpolation-in-regular-string': 'off',
// These identifiers are used as object keys for type mappings
'id-denylist': 'off',
// Default scope (`builderHint`) won't fire here because workflow-sdk source has no
// builderHint properties; the prompts override below switches on `scope: 'all'`.
'@n8n/community-nodes/no-builder-hint-leakage': 'error',
},
}, {
files: ['src/prompts/**/*.ts'],
rules: {
'@n8n/community-nodes/no-builder-hint-leakage': ['error', { scope: 'all' }],
},
}, {
// Multi-agent parameter guides intentionally document wire-format parameters
// (consumed by the legacy parameter-updater chain in ai-workflow-builder.ee,
// not by the code-builder or instance-ai SDK paths).
files: ['src/prompts/node-guidance/parameter-guides/**/*.ts'],
rules: {
'@n8n/community-nodes/no-builder-hint-leakage': 'off',
},
});

View File

@ -93,6 +93,7 @@
"dist/**/*"
],
"devDependencies": {
"@n8n/eslint-plugin-community-nodes": "workspace:*",
"@n8n/typescript-config": "workspace:*",
"@types/adm-zip": "^0.5.7",
"@types/estree": "^1.0.8",

View File

@ -16,8 +16,8 @@ Most chatbots run through external platforms like Slack, Telegram, or WhatsApp r
CRITICAL: The user may ask to be able to chat to a workflow as well as trigger it via some other method, for example scheduling information gathering but also being able to chat with the agent - in scenarios like this the two separate workflows MUST be connected through shared memory, vector stores, data storage, or direct connections.
Example pattern:
- Schedule Trigger News Gathering Agent [memory node via ai_memory]
- Chat Trigger Chatbot Agent [SAME memory node via ai_memory]
- Schedule Trigger News Gathering Agent [memory node via memory()]
- Chat Trigger Chatbot Agent [SAME memory node via memory()]
- Result: Both agents share conversation/context history, enabling the chatbot to discuss gathered news
For the chatbot always use the same chat node type as used for response. If Telegram has been requested trigger the chatbot via telegram AND

View File

@ -16,7 +16,7 @@ export const structuredOutputParser: NodeGuidance = {
connections: `When Discovery results include AI Agent or Structured Output Parser:
1. Create the Structured Output Parser node
2. Set AI Agent's hasOutputParser: true in initialParameters
3. Connect: Structured Output Parser AI Agent (ai_outputParser connection)`,
3. Connect: Structured Output Parser AI Agent (outputParser() connection)`,
configuration: `WHEN TO SET hasOutputParser: true on AI Agent:
- Discovery found Structured Output Parser node MUST set hasOutputParser: true

View File

@ -3,30 +3,30 @@ export const AI_NODE_SELECTION = `AI node selection guidance:
AI Agent: Use for text analysis, summarization, classification, or any AI reasoning tasks.
OpenAI node: Use only for DALL-E, Whisper, Sora, or embeddings (these are specialized APIs that AI Agent cannot access).
Default chat model: OpenAI Chat Model provides the lowest setup friction for new users.
Tool nodes (ending in "Tool"): Connect to AI Agent via ai_tool for agent-controlled actions.
Tool nodes (ending in "Tool"): Connect to AI Agent via tool() for agent-controlled actions.
Text Classifier vs AI Agent: Text Classifier for simple categorization with fixed categories; AI Agent for complex multi-step classification requiring reasoning.
Memory nodes: Include with chatbot AI Agents to maintain conversation context across messages.
Structured Output Parser: Prefer this over manually extracting/parsing AI output with Set or Code nodes. Define the desired schema and the LLM handles parsing automatically. Use for classification, data extraction, or any workflow where AI output feeds into database storage, API calls, or Switch routing.
Multi-agent systems:
AI Agent Tool (@n8n/n8n-nodes-langchain.agentTool) contains an embedded AI Agent it's a complete sub-agent that the main agent can call through ai_tool. Each AgentTool needs its own Chat Model. Node selection: 1 AI Agent + N AgentTools + (N+1) Chat Models.`;
AI Agent Tool (@n8n/n8n-nodes-langchain.agentTool) contains an embedded AI Agent it's a complete sub-agent that the main agent can call through tool(). Each AgentTool needs its own Chat Model. Node selection: 1 AI Agent + N AgentTools + (N+1) Chat Models.`;
export const AI_TOOL_PATTERNS = `AI Agent tool connection patterns:
When AI Agent needs external capabilities, use TOOL nodes (not regular nodes):
- Research: SerpAPI Tool, Perplexity Tool -> AI Agent [ai_tool]
- Calendar: Google Calendar Tool -> AI Agent [ai_tool]
- Messaging: Slack Tool, Gmail Tool -> AI Agent [ai_tool]
- HTTP calls: HTTP Request Tool -> AI Agent [ai_tool]
- Calculations: Calculator Tool -> AI Agent [ai_tool]
- Sub-agents: AI Agent Tool -> AI Agent [ai_tool] (for multi-agent systems)
- Research: SerpAPI Tool, Perplexity Tool -> AI Agent [tool()]
- Calendar: Google Calendar Tool -> AI Agent [tool()]
- Messaging: Slack Tool, Gmail Tool -> AI Agent [tool()]
- HTTP calls: HTTP Request Tool -> AI Agent [tool()]
- Calculations: Calculator Tool -> AI Agent [tool()]
- Sub-agents: AI Agent Tool -> AI Agent [tool()] (for multi-agent systems)
Tool nodes: AI Agent decides when/if to use them based on reasoning.
Regular nodes: Execute at that workflow step regardless of context.
Vector Store patterns:
- Insert documents: Document Loader -> Vector Store (mode='insert') [ai_document]
- RAG with AI Agent: Vector Store (mode='retrieve-as-tool') -> AI Agent [ai_tool]
- Insert documents: Document Loader -> Vector Store (mode='insert') [documentLoader()]
- RAG with AI Agent: Vector Store (mode='retrieve-as-tool') -> AI Agent [tool()]
The retrieve-as-tool mode makes the Vector Store act as a tool the Agent can call.
Structured Output Parser: Connect to AI Agent when structured JSON output is required.`;

View File

@ -1,8 +1,8 @@
export const CONNECTION_CHANGING_PARAMETERS = `Connection-changing parameters (affect node inputs/outputs):
Common connection-changing parameters:
- Vector Store: mode (insert/retrieve/retrieve-as-tool) changes output type between main, ai_vectorStore, and ai_tool
- AI Agent: hasOutputParser (true/false) enables ai_outputParser input
- Vector Store: mode (insert/retrieve/retrieve-as-tool) changes output type between main, vectorStore(), and tool()
- AI Agent: hasOutputParser (true/false) enables outputParser() input
- Merge: numberInputs (default 2) requires mode="append" OR mode="combine" + combineBy="combineByPosition"
- Switch: mode (expression/rules) affects routing behavior

View File

@ -10,7 +10,7 @@ export const EXPRESSION_REFERENCE = `Available variables inside \`expr('{{ ... }
- \`$json\` — current item's JSON data from the immediate predecessor node
- \`$('NodeName').item.json\` — access any node's output by name
- \`nodeJson(node, 'field.path')\` — SDK helper that creates \`={{ $('NodeName').item.json.field.path }}\`
- \`nodeJson(node, 'field.path')\` — SDK helper equivalent to \`expr('{{ $("NodeName").item.json.field.path }}')\`
- \`$input.first()\` — first item from immediate predecessor
- \`$input.all()\` — all items from immediate predecessor
- \`$input.item\` — current item being processed

View File

@ -144,7 +144,7 @@ const hasResults = ifElse({
parameters: {
conditions: {
options: { caseSensitive: true, typeValidation: 'loose' },
conditions: [{ leftValue: '={{ $json.results }}', operator: { type: 'array', operation: 'notEmpty' } }],
conditions: [{ leftValue: expr('{{ $json.results }}'), operator: { type: 'array', operation: 'notEmpty' } }],
combinator: 'and'
}
}
@ -180,7 +180,7 @@ const checkValid = ifElse({
parameters: {
conditions: {
options: { caseSensitive: true, leftValue: '', typeValidation: 'strict' },
conditions: [{ leftValue: '={{ $json.status }}', operator: { type: 'string', operation: 'equals' }, rightValue: 'active' }],
conditions: [{ leftValue: expr('{{ $json.status }}'), operator: { type: 'string', operation: 'equals' }, rightValue: 'active' }],
combinator: 'and'
}
}
@ -207,8 +207,8 @@ const routeByPriority = switchCase({
parameters: {
rules: {
values: [
{ outputKey: 'urgent', conditions: { options: { caseSensitive: true, leftValue: '', typeValidation: 'strict' }, conditions: [{ leftValue: '={{ $json.priority }}', operator: { type: 'string', operation: 'equals' }, rightValue: 'urgent' }], combinator: 'and' } },
{ outputKey: 'normal', conditions: { options: { caseSensitive: true, leftValue: '', typeValidation: 'strict' }, conditions: [{ leftValue: '={{ $json.priority }}', operator: { type: 'string', operation: 'equals' }, rightValue: 'normal' }], combinator: 'and' } },
{ outputKey: 'urgent', conditions: { options: { caseSensitive: true, leftValue: '', typeValidation: 'strict' }, conditions: [{ leftValue: expr('{{ $json.priority }}'), operator: { type: 'string', operation: 'equals' }, rightValue: 'urgent' }], combinator: 'and' } },
{ outputKey: 'normal', conditions: { options: { caseSensitive: true, leftValue: '', typeValidation: 'strict' }, conditions: [{ leftValue: expr('{{ $json.priority }}'), operator: { type: 'string', operation: 'equals' }, rightValue: 'normal' }], combinator: 'and' } },
]
}
}

View File

@ -39,6 +39,7 @@ export default defineConfig(
'import-x/no-extraneous-dependencies': 'warn',
'n8n-local-rules/no-argument-spread': 'warn', // TODO: mark error
'@n8n/community-nodes/no-builder-hint-leakage': 'error',
'@typescript-eslint/ban-ts-comment': ['warn', { 'ts-ignore': true }],
'@typescript-eslint/naming-convention': ['warn'],

View File

@ -45,10 +45,10 @@ export class IfV2 implements INodeType {
},
builderHint: {
message: `Must always contain these three sibling keys:
- "combinator": "and" or "or", default to "and"
- "conditions": [ {a list of condition objects } ]
- "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 1 }
e.g.: { "combinator": "and", "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [{ "leftValue": "={{ $json.field }}", "rightValue": "value", "operator": { "type": "string", "operation": "equals" } }] }`,
- combinator: 'and' or 'or', default to 'and'
- conditions: [ a list of condition objects ]
- options: { caseSensitive: true, leftValue: '', typeValidation: 'strict', version: 1 }
e.g.: { combinator: 'and', options: { caseSensitive: true, leftValue: '', typeValidation: 'strict', version: 2 }, conditions: [{ leftValue: expr('{{ $json.field }}'), rightValue: 'value', operator: { type: 'string', operation: 'equals' } }] }`,
},
},
{

View File

@ -875,7 +875,7 @@ importers:
version: link:../vitest-config
'@vitest/coverage-v8':
specifier: 'catalog:'
version: 4.1.1(vitest@4.1.1)
version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3)))
vitest:
specifier: 'catalog:'
version: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(@vitest/browser-playwright@4.0.16)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3))
@ -1049,7 +1049,7 @@ importers:
version: link:../vitest-config
'@vitest/coverage-v8':
specifier: 'catalog:'
version: 4.1.1(vitest@4.1.1)
version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3)))
vitest:
specifier: 'catalog:'
version: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(@vitest/browser-playwright@4.0.16)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3))
@ -1777,7 +1777,7 @@ importers:
version: 7.0.15
'@vitest/coverage-v8':
specifier: 'catalog:'
version: 4.1.1(vitest@4.1.1)
version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3)))
vitest:
specifier: 'catalog:'
version: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(@vitest/browser-playwright@4.0.16)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3))
@ -2265,7 +2265,7 @@ importers:
version: 0.9.4
'@vitest/coverage-v8':
specifier: 'catalog:'
version: 4.1.1(vitest@4.1.1)
version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3)))
fast-glob:
specifier: 'catalog:'
version: 3.2.12
@ -2293,7 +2293,7 @@ importers:
version: link:../vitest-config
'@vitest/coverage-v8':
specifier: 'catalog:'
version: 4.1.1(vitest@4.1.1)
version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3)))
vitest:
specifier: 'catalog:'
version: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(@vitest/browser-playwright@4.0.16)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3))
@ -2358,7 +2358,7 @@ importers:
version: link:../vitest-config
'@vitest/coverage-v8':
specifier: 'catalog:'
version: 4.1.1(vitest@4.1.1)
version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3)))
rimraf:
specifier: 'catalog:'
version: 6.0.1
@ -2451,7 +2451,7 @@ importers:
version: 20.19.21
'@vitest/coverage-v8':
specifier: 'catalog:'
version: 4.1.1(vitest@4.1.1)
version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3)))
nodemon:
specifier: ^2.0.20
version: 2.0.22
@ -2547,6 +2547,9 @@ importers:
specifier: 3.25.67
version: 3.25.67
devDependencies:
'@n8n/eslint-plugin-community-nodes':
specifier: workspace:*
version: link:../eslint-plugin-community-nodes
'@n8n/typescript-config':
specifier: workspace:*
version: link:../typescript-config
@ -3288,7 +3291,7 @@ importers:
version: 5.2.4(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3))(vue@3.5.26(typescript@6.0.2))
'@vitest/coverage-v8':
specifier: 'catalog:'
version: 4.1.1(vitest@4.1.1)
version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3)))
unplugin-icons:
specifier: ^0.19.0
version: 0.19.0(@vue/compiler-sfc@3.5.26)
@ -3728,7 +3731,7 @@ importers:
version: 4.0.16(bufferutil@4.0.9)(playwright@1.58.0)(utf-8-validate@5.0.10)(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3))(vitest@4.1.1)
'@vitest/coverage-v8':
specifier: 'catalog:'
version: 4.1.1(vitest@4.1.1)
version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3)))
'@vue/tsconfig':
specifier: catalog:frontend
version: 0.7.0(typescript@6.0.2)(vue@3.5.26(typescript@6.0.2))
@ -4095,7 +4098,7 @@ importers:
version: 5.2.4(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3))(vue@3.5.26(typescript@6.0.2))
'@vitest/coverage-v8':
specifier: 'catalog:'
version: 4.1.1(vitest@4.1.1)
version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3)))
browserslist-to-esbuild:
specifier: ^2.1.1
version: 2.1.1(browserslist@4.28.1)
@ -4520,7 +4523,7 @@ importers:
version: link:../../@n8n/vitest-config
'@vitest/coverage-v8':
specifier: 'catalog:'
version: 4.1.1(vitest@4.1.1)
version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3)))
fast-glob:
specifier: 'catalog:'
version: 3.2.12
@ -4584,7 +4587,7 @@ importers:
version: 20.19.21
'@vitest/coverage-v8':
specifier: 'catalog:'
version: 4.1.1(vitest@4.1.1)
version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3)))
ts-morph:
specifier: 'catalog:'
version: 27.0.2
@ -4716,7 +4719,7 @@ importers:
version: link:../../@n8n/vitest-config
'@vitest/coverage-v8':
specifier: 'catalog:'
version: 4.1.1(vitest@4.1.1)
version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3)))
tsx:
specifier: 'catalog:'
version: 4.19.3
@ -26205,7 +26208,7 @@ snapshots:
'@currents/commit-info': 1.0.1-beta.0
async-retry: 1.3.3
axios: 1.16.0(debug@4.4.3)
axios-retry: 4.5.0(axios@1.16.0(debug@4.4.3))
axios-retry: 4.5.0(axios@1.16.0)
c12: 1.11.2(magicast@0.3.5)
chalk: 4.1.2
commander: 12.1.0
@ -32648,7 +32651,7 @@ snapshots:
tinyrainbow: 3.0.3
vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.89.2)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3))
'@vitest/coverage-v8@4.1.1(vitest@4.1.1)':
'@vitest/coverage-v8@4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3)))':
dependencies:
'@bcoe/v8-coverage': 1.0.2
'@vitest/utils': 4.1.1
@ -33547,11 +33550,6 @@ snapshots:
axe-core@4.7.2: {}
axios-retry@4.5.0(axios@1.16.0(debug@4.4.3)):
dependencies:
axios: 1.16.0(debug@4.4.3)
is-retry-allowed: 2.2.0
axios-retry@4.5.0(axios@1.16.0):
dependencies:
axios: 1.16.0