mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-03-23 10:53:07 +00:00
n8n 2.10+ requires webhookId (UUID) on webhook-type nodes for proper webhook URL registration. Without it, webhooks silently fail with 404. The n8n UI always generates webhookId but programmatic creation via n8n-mcp did not. Add ensureWebhookIds() helper that injects crypto.randomUUID() on webhook, webhookTrigger, formTrigger, and chatTrigger nodes when webhookId is missing. Called from both cleanWorkflowForCreate() and cleanWorkflowForUpdate(). Existing webhookId values are preserved. Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
committed by
GitHub
parent
93816fce30
commit
e6cafc659c
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [2.40.5] - 2026-03-22
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **Webhook workflows created via MCP get 404 errors** (Issue #643): Auto-inject `webhookId` (UUID) on webhook-type nodes (`webhook`, `webhookTrigger`, `formTrigger`, `chatTrigger`) during `cleanWorkflowForCreate()` and `cleanWorkflowForUpdate()`. n8n 2.10+ requires this field for proper webhook URL registration; without it, webhooks silently fail with 404. Existing `webhookId` values are preserved.
|
||||||
|
|
||||||
|
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
|
||||||
|
|
||||||
## [2.40.4] - 2026-03-22
|
## [2.40.4] - 2026-03-22
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
2
dist/services/n8n-validation.d.ts.map
vendored
2
dist/services/n8n-validation.d.ts.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"n8n-validation.d.ts","sourceRoot":"","sources":["../../src/services/n8n-validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAM9E,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiB7B,CAAC;AAkBH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCAUpC,CAAC;AAEF,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWjC,CAAC;AAGH,eAAO,MAAM,uBAAuB;;;;;;CAMnC,CAAC;AAGF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY,CAEhE;AAED,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,OAAO,GAAG,kBAAkB,CAEpF;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAElG;AAGD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAsBrF;AAiBD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAoE5E;AAGD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,MAAM,EAAE,CAkQ/E;AAGD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAK7D;AAMD,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,EAAE,CA+F5E;AAMD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CA0D/E;AAGD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAmB/D;AAGD,wBAAgB,2BAA2B,IAAI,MAAM,CA6CpD;AAGD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAmBpE"}
|
{"version":3,"file":"n8n-validation.d.ts","sourceRoot":"","sources":["../../src/services/n8n-validation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAM9E,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiB7B,CAAC;AAkBH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCAUpC,CAAC;AAEF,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWjC,CAAC;AAGH,eAAO,MAAM,uBAAuB;;;;;;CAMnC,CAAC;AAGF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY,CAEhE;AAED,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,OAAO,GAAG,kBAAkB,CAEpF;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAElG;AAmBD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAwBrF;AAiBD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAsE5E;AAGD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,MAAM,EAAE,CAkQ/E;AAGD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAK7D;AAMD,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,EAAE,CA+F5E;AAMD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CA0D/E;AAGD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAmB/D;AAGD,wBAAgB,2BAA2B,IAAI,MAAM,CA6CpD;AAGD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAmBpE"}
|
||||||
21
dist/services/n8n-validation.js
vendored
21
dist/services/n8n-validation.js
vendored
@@ -1,4 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.defaultWorkflowSettings = exports.workflowSettingsSchema = exports.workflowConnectionSchema = exports.workflowNodeSchema = void 0;
|
exports.defaultWorkflowSettings = exports.workflowSettingsSchema = exports.workflowConnectionSchema = exports.workflowNodeSchema = void 0;
|
||||||
exports.validateWorkflowNode = validateWorkflowNode;
|
exports.validateWorkflowNode = validateWorkflowNode;
|
||||||
@@ -13,6 +16,7 @@ exports.validateOperatorStructure = validateOperatorStructure;
|
|||||||
exports.getWebhookUrl = getWebhookUrl;
|
exports.getWebhookUrl = getWebhookUrl;
|
||||||
exports.getWorkflowStructureExample = getWorkflowStructureExample;
|
exports.getWorkflowStructureExample = getWorkflowStructureExample;
|
||||||
exports.getWorkflowFixSuggestions = getWorkflowFixSuggestions;
|
exports.getWorkflowFixSuggestions = getWorkflowFixSuggestions;
|
||||||
|
const crypto_1 = __importDefault(require("crypto"));
|
||||||
const zod_1 = require("zod");
|
const zod_1 = require("zod");
|
||||||
const node_type_utils_1 = require("../utils/node-type-utils");
|
const node_type_utils_1 = require("../utils/node-type-utils");
|
||||||
const node_classification_1 = require("../utils/node-classification");
|
const node_classification_1 = require("../utils/node-classification");
|
||||||
@@ -76,11 +80,27 @@ function validateWorkflowConnections(connections) {
|
|||||||
function validateWorkflowSettings(settings) {
|
function validateWorkflowSettings(settings) {
|
||||||
return exports.workflowSettingsSchema.parse(settings);
|
return exports.workflowSettingsSchema.parse(settings);
|
||||||
}
|
}
|
||||||
|
const WEBHOOK_NODE_TYPES = new Set([
|
||||||
|
'n8n-nodes-base.webhook',
|
||||||
|
'n8n-nodes-base.webhookTrigger',
|
||||||
|
'n8n-nodes-base.formTrigger',
|
||||||
|
'@n8n/n8n-nodes-langchain.chatTrigger',
|
||||||
|
]);
|
||||||
|
function ensureWebhookIds(nodes) {
|
||||||
|
if (!nodes)
|
||||||
|
return;
|
||||||
|
for (const node of nodes) {
|
||||||
|
if (WEBHOOK_NODE_TYPES.has(node.type) && !node.webhookId) {
|
||||||
|
node.webhookId = crypto_1.default.randomUUID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
function cleanWorkflowForCreate(workflow) {
|
function cleanWorkflowForCreate(workflow) {
|
||||||
const { id, createdAt, updatedAt, versionId, meta, active, tags, ...cleanedWorkflow } = workflow;
|
const { id, createdAt, updatedAt, versionId, meta, active, tags, ...cleanedWorkflow } = workflow;
|
||||||
if (!cleanedWorkflow.settings || Object.keys(cleanedWorkflow.settings).length === 0) {
|
if (!cleanedWorkflow.settings || Object.keys(cleanedWorkflow.settings).length === 0) {
|
||||||
cleanedWorkflow.settings = exports.defaultWorkflowSettings;
|
cleanedWorkflow.settings = exports.defaultWorkflowSettings;
|
||||||
}
|
}
|
||||||
|
ensureWebhookIds(cleanedWorkflow.nodes);
|
||||||
return cleanedWorkflow;
|
return cleanedWorkflow;
|
||||||
}
|
}
|
||||||
function cleanWorkflowForUpdate(workflow) {
|
function cleanWorkflowForUpdate(workflow) {
|
||||||
@@ -116,6 +136,7 @@ function cleanWorkflowForUpdate(workflow) {
|
|||||||
else {
|
else {
|
||||||
cleanedWorkflow.settings = { executionOrder: 'v1' };
|
cleanedWorkflow.settings = { executionOrder: 'v1' };
|
||||||
}
|
}
|
||||||
|
ensureWebhookIds(cleanedWorkflow.nodes);
|
||||||
return cleanedWorkflow;
|
return cleanedWorkflow;
|
||||||
}
|
}
|
||||||
function validateWorkflowStructure(workflow) {
|
function validateWorkflowStructure(workflow) {
|
||||||
|
|||||||
2
dist/services/n8n-validation.js.map
vendored
2
dist/services/n8n-validation.js.map
vendored
File diff suppressed because one or more lines are too long
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "n8n-mcp",
|
"name": "n8n-mcp",
|
||||||
"version": "2.37.3",
|
"version": "2.40.5",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "n8n-mcp",
|
"name": "n8n-mcp",
|
||||||
"version": "2.37.3",
|
"version": "2.40.5",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "^1.27.1",
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "n8n-mcp",
|
"name": "n8n-mcp",
|
||||||
"version": "2.40.4",
|
"version": "2.40.5",
|
||||||
"description": "Integration between n8n workflow automation and Model Context Protocol (MCP)",
|
"description": "Integration between n8n workflow automation and Model Context Protocol (MCP)",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import crypto from 'crypto';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { WorkflowNode, WorkflowConnection, Workflow } from '../types/n8n-api';
|
import { WorkflowNode, WorkflowConnection, Workflow } from '../types/n8n-api';
|
||||||
import { isTriggerNode, isActivatableTrigger } from '../utils/node-type-utils';
|
import { isTriggerNode, isActivatableTrigger } from '../utils/node-type-utils';
|
||||||
@@ -87,6 +88,22 @@ export function validateWorkflowSettings(settings: unknown): z.infer<typeof work
|
|||||||
return workflowSettingsSchema.parse(settings);
|
return workflowSettingsSchema.parse(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const WEBHOOK_NODE_TYPES = new Set([
|
||||||
|
'n8n-nodes-base.webhook',
|
||||||
|
'n8n-nodes-base.webhookTrigger',
|
||||||
|
'n8n-nodes-base.formTrigger',
|
||||||
|
'@n8n/n8n-nodes-langchain.chatTrigger',
|
||||||
|
]);
|
||||||
|
|
||||||
|
function ensureWebhookIds(nodes?: WorkflowNode[]): void {
|
||||||
|
if (!nodes) return;
|
||||||
|
for (const node of nodes) {
|
||||||
|
if (WEBHOOK_NODE_TYPES.has(node.type) && !node.webhookId) {
|
||||||
|
node.webhookId = crypto.randomUUID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Clean workflow data for API operations
|
// Clean workflow data for API operations
|
||||||
export function cleanWorkflowForCreate(workflow: Partial<Workflow>): Partial<Workflow> {
|
export function cleanWorkflowForCreate(workflow: Partial<Workflow>): Partial<Workflow> {
|
||||||
const {
|
const {
|
||||||
@@ -109,6 +126,8 @@ export function cleanWorkflowForCreate(workflow: Partial<Workflow>): Partial<Wor
|
|||||||
cleanedWorkflow.settings = defaultWorkflowSettings;
|
cleanedWorkflow.settings = defaultWorkflowSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ensureWebhookIds(cleanedWorkflow.nodes);
|
||||||
|
|
||||||
return cleanedWorkflow;
|
return cleanedWorkflow;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,6 +213,8 @@ export function cleanWorkflowForUpdate(workflow: Workflow): Partial<Workflow> {
|
|||||||
cleanedWorkflow.settings = { executionOrder: 'v1' as const };
|
cleanedWorkflow.settings = { executionOrder: 'v1' as const };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ensureWebhookIds(cleanedWorkflow.nodes);
|
||||||
|
|
||||||
return cleanedWorkflow;
|
return cleanedWorkflow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,14 @@ import { WorkflowBuilder } from '../../utils/builders/workflow.builder';
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { WorkflowNode, WorkflowConnection, Workflow } from '../../../src/types/n8n-api';
|
import { WorkflowNode, WorkflowConnection, Workflow } from '../../../src/types/n8n-api';
|
||||||
|
|
||||||
|
function webhookNode(id: string, name: string, type: string, typeVersion = 2): WorkflowNode {
|
||||||
|
return { id, name, type, typeVersion, position: [250, 300] as [number, number], parameters: {} };
|
||||||
|
}
|
||||||
|
|
||||||
|
function workflowWithNodes(nodes: WorkflowNode[]): Partial<Workflow> {
|
||||||
|
return { name: 'Test', nodes, connections: {} };
|
||||||
|
}
|
||||||
|
|
||||||
describe('n8n-validation', () => {
|
describe('n8n-validation', () => {
|
||||||
describe('Zod Schemas', () => {
|
describe('Zod Schemas', () => {
|
||||||
describe('workflowNodeSchema', () => {
|
describe('workflowNodeSchema', () => {
|
||||||
@@ -301,6 +309,44 @@ describe('n8n-validation', () => {
|
|||||||
const cleaned = cleanWorkflowForCreate(workflow as Workflow);
|
const cleaned = cleanWorkflowForCreate(workflow as Workflow);
|
||||||
expect(cleaned.settings).toEqual(customSettings);
|
expect(cleaned.settings).toEqual(customSettings);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should inject webhookId on webhook nodes missing it', () => {
|
||||||
|
const workflow = workflowWithNodes([
|
||||||
|
webhookNode('1', 'Webhook', 'n8n-nodes-base.webhook'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const cleaned = cleanWorkflowForCreate(workflow as Workflow);
|
||||||
|
expect(cleaned.nodes![0].webhookId).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should preserve existing webhookId on webhook nodes', () => {
|
||||||
|
const workflow = workflowWithNodes([
|
||||||
|
{ ...webhookNode('1', 'Webhook', 'n8n-nodes-base.webhook'), webhookId: 'existing-id' },
|
||||||
|
]);
|
||||||
|
|
||||||
|
const cleaned = cleanWorkflowForCreate(workflow as Workflow);
|
||||||
|
expect(cleaned.nodes![0].webhookId).toBe('existing-id');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should inject webhookId on formTrigger and chatTrigger nodes', () => {
|
||||||
|
const workflow = workflowWithNodes([
|
||||||
|
webhookNode('1', 'Form', 'n8n-nodes-base.formTrigger'),
|
||||||
|
webhookNode('2', 'Chat', '@n8n/n8n-nodes-langchain.chatTrigger'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const cleaned = cleanWorkflowForCreate(workflow as Workflow);
|
||||||
|
expect(cleaned.nodes![0].webhookId).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-/);
|
||||||
|
expect(cleaned.nodes![1].webhookId).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not inject webhookId on non-webhook nodes', () => {
|
||||||
|
const workflow = workflowWithNodes([
|
||||||
|
webhookNode('1', 'Set', 'n8n-nodes-base.set', 3.4),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const cleaned = cleanWorkflowForCreate(workflow as Workflow);
|
||||||
|
expect(cleaned.nodes![0].webhookId).toBeUndefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('cleanWorkflowForUpdate', () => {
|
describe('cleanWorkflowForUpdate', () => {
|
||||||
@@ -533,6 +579,44 @@ describe('n8n-validation', () => {
|
|||||||
});
|
});
|
||||||
expect(cleaned.settings).not.toHaveProperty('someOtherProperty');
|
expect(cleaned.settings).not.toHaveProperty('someOtherProperty');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should inject webhookId on webhook nodes missing it', () => {
|
||||||
|
const workflow = workflowWithNodes([
|
||||||
|
webhookNode('1', 'Webhook', 'n8n-nodes-base.webhook'),
|
||||||
|
]) as any;
|
||||||
|
|
||||||
|
const cleaned = cleanWorkflowForUpdate(workflow);
|
||||||
|
expect(cleaned.nodes![0].webhookId).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should preserve existing webhookId on webhook nodes', () => {
|
||||||
|
const workflow = workflowWithNodes([
|
||||||
|
{ ...webhookNode('1', 'Webhook', 'n8n-nodes-base.webhook'), webhookId: 'existing-id' },
|
||||||
|
]) as any;
|
||||||
|
|
||||||
|
const cleaned = cleanWorkflowForUpdate(workflow);
|
||||||
|
expect(cleaned.nodes![0].webhookId).toBe('existing-id');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should inject webhookId on formTrigger and chatTrigger nodes', () => {
|
||||||
|
const workflow = workflowWithNodes([
|
||||||
|
webhookNode('1', 'Form', 'n8n-nodes-base.formTrigger'),
|
||||||
|
webhookNode('2', 'Chat', '@n8n/n8n-nodes-langchain.chatTrigger'),
|
||||||
|
]) as any;
|
||||||
|
|
||||||
|
const cleaned = cleanWorkflowForUpdate(workflow);
|
||||||
|
expect(cleaned.nodes![0].webhookId).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-/);
|
||||||
|
expect(cleaned.nodes![1].webhookId).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not inject webhookId on non-webhook nodes', () => {
|
||||||
|
const workflow = workflowWithNodes([
|
||||||
|
webhookNode('1', 'Set', 'n8n-nodes-base.set', 3.4),
|
||||||
|
]) as any;
|
||||||
|
|
||||||
|
const cleaned = cleanWorkflowForUpdate(workflow);
|
||||||
|
expect(cleaned.nodes![0].webhookId).toBeUndefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user