UNPKG

n8n

Version:

n8n Workflow Automation Tool

192 lines 9.35 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.WebhookService = void 0; const di_1 = require("@n8n/di"); const n8n_core_1 = require("n8n-core"); const n8n_workflow_1 = require("n8n-workflow"); const webhook_repository_1 = require("../databases/repositories/webhook.repository"); const node_types_1 = require("../node-types"); const cache_service_1 = require("../services/cache/cache.service"); let WebhookService = class WebhookService { constructor(logger, webhookRepository, cacheService, nodeTypes) { this.logger = logger; this.webhookRepository = webhookRepository; this.cacheService = cacheService; this.nodeTypes = nodeTypes; } async populateCache() { const allWebhooks = await this.webhookRepository.find(); if (!allWebhooks) return; void this.cacheService.setMany(allWebhooks.map((w) => [w.cacheKey, w])); } async findCached(method, path) { const cacheKey = `webhook:${method}-${path}`; const cachedWebhook = await this.cacheService.get(cacheKey); if (cachedWebhook) return this.webhookRepository.create(cachedWebhook); let dbWebhook = await this.findStaticWebhook(method, path); if (dbWebhook === null) { dbWebhook = await this.findDynamicWebhook(method, path); } void this.cacheService.set(cacheKey, dbWebhook); return dbWebhook; } async findStaticWebhook(method, path) { return await this.webhookRepository.findOneBy({ webhookPath: path, method }); } async findDynamicWebhook(method, path) { const [uuidSegment, ...otherSegments] = path.split('/'); const dynamicWebhooks = await this.webhookRepository.findBy({ webhookId: uuidSegment, method, pathLength: otherSegments.length, }); if (dynamicWebhooks.length === 0) return null; const requestSegments = new Set(otherSegments); const { webhook } = dynamicWebhooks.reduce((acc, dw) => { const allStaticSegmentsMatch = dw.staticSegments.every((s) => requestSegments.has(s)); if (allStaticSegmentsMatch && dw.staticSegments.length > acc.maxMatches) { acc.maxMatches = dw.staticSegments.length; acc.webhook = dw; return acc; } else if (dw.staticSegments.length === 0 && !acc.webhook) { acc.webhook = dw; } return acc; }, { webhook: null, maxMatches: 0 }); return webhook; } async findWebhook(method, path) { return await this.findCached(method, path); } async storeWebhook(webhook) { void this.cacheService.set(webhook.cacheKey, webhook); await this.webhookRepository.upsert(webhook, ['method', 'webhookPath']); } createWebhook(data) { return this.webhookRepository.create(data); } async deleteWorkflowWebhooks(workflowId) { const webhooks = await this.webhookRepository.findBy({ workflowId }); return await this.deleteWebhooks(webhooks); } async deleteWebhooks(webhooks) { void this.cacheService.deleteMany(webhooks.map((w) => w.cacheKey)); return await this.webhookRepository.remove(webhooks); } async getWebhookMethods(path) { return await this.webhookRepository .find({ select: ['method'], where: { webhookPath: path } }) .then((rows) => rows.map((r) => r.method)); } getNodeWebhooks(workflow, node, additionalData, ignoreRestartWebhooks = false) { if (node.disabled === true) { return []; } const nodeType = this.nodeTypes.getByNameAndVersion(node.type, node.typeVersion); if (nodeType.description.webhooks === undefined) { return []; } const workflowId = workflow.id || '__UNSAVED__'; const mode = 'internal'; const returnData = []; for (const webhookDescription of nodeType.description.webhooks) { if (ignoreRestartWebhooks && webhookDescription.restartWebhook === true) { continue; } let nodeWebhookPath = workflow.expression.getSimpleParameterValue(node, webhookDescription.path, mode, {}); if (nodeWebhookPath === undefined) { this.logger.error(`No webhook path could be found for node "${node.name}" in workflow "${workflowId}".`); continue; } nodeWebhookPath = nodeWebhookPath.toString(); if (nodeWebhookPath.startsWith('/')) { nodeWebhookPath = nodeWebhookPath.slice(1); } if (nodeWebhookPath.endsWith('/')) { nodeWebhookPath = nodeWebhookPath.slice(0, -1); } const isFullPath = workflow.expression.getSimpleParameterValue(node, webhookDescription.isFullPath, 'internal', {}, undefined, false); const restartWebhook = workflow.expression.getSimpleParameterValue(node, webhookDescription.restartWebhook, 'internal', {}, undefined, false); const path = n8n_workflow_1.NodeHelpers.getNodeWebhookPath(workflowId, node, nodeWebhookPath, isFullPath, restartWebhook); const webhookMethods = workflow.expression.getSimpleParameterValue(node, webhookDescription.httpMethod, mode, {}, undefined, 'GET'); if (webhookMethods === undefined) { this.logger.error(`The webhook "${path}" for node "${node.name}" in workflow "${workflowId}" could not be added because the httpMethod is not defined.`); continue; } let webhookId; if ((path.startsWith(':') || path.includes('/:')) && node.webhookId) { webhookId = node.webhookId; } String(webhookMethods) .split(',') .forEach((httpMethod) => { if (!httpMethod) return; returnData.push({ httpMethod: httpMethod.trim(), node: node.name, path, webhookDescription, workflowId, workflowExecuteAdditionalData: additionalData, webhookId, }); }); } return returnData; } async createWebhookIfNotExists(workflow, webhookData, mode, activation) { const webhookExists = await this.runWebhookMethod('checkExists', workflow, webhookData, mode, activation); if (!webhookExists) { await this.runWebhookMethod('create', workflow, webhookData, mode, activation); } } async deleteWebhook(workflow, webhookData, mode, activation) { await this.runWebhookMethod('delete', workflow, webhookData, mode, activation); } async runWebhookMethod(method, workflow, webhookData, mode, activation) { const node = workflow.getNode(webhookData.node); if (!node) return; const nodeType = this.nodeTypes.getByNameAndVersion(node.type, node.typeVersion); const webhookFn = nodeType.webhookMethods?.[webhookData.webhookDescription.name]?.[method]; if (webhookFn === undefined) return; const context = new n8n_core_1.HookContext(workflow, node, webhookData.workflowExecuteAdditionalData, mode, activation, webhookData); return (await webhookFn.call(context)); } async runWebhook(workflow, webhookData, node, additionalData, mode, runExecutionData) { const nodeType = this.nodeTypes.getByNameAndVersion(node.type, node.typeVersion); if (nodeType.webhook === undefined) { throw new n8n_workflow_1.UnexpectedError('Node does not have any webhooks defined', { extra: { nodeName: node.name }, }); } const context = new n8n_core_1.WebhookContext(workflow, node, additionalData, mode, webhookData, [], runExecutionData ?? null); return nodeType instanceof n8n_workflow_1.Node ? await nodeType.webhook(context) : (await nodeType.webhook.call(context)); } }; exports.WebhookService = WebhookService; exports.WebhookService = WebhookService = __decorate([ (0, di_1.Service)(), __metadata("design:paramtypes", [n8n_core_1.Logger, webhook_repository_1.WebhookRepository, cache_service_1.CacheService, node_types_1.NodeTypes]) ], WebhookService); //# sourceMappingURL=webhook.service.js.map