mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-02-06 21:43:07 +00:00
chore: add pre-built dist folder for npx usage
This commit is contained in:
committed by
Romuald Członkowski
parent
a70d96a373
commit
5057481e70
21
dist/triggers/handlers/base-handler.d.ts
vendored
Normal file
21
dist/triggers/handlers/base-handler.d.ts
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
import { z } from 'zod';
|
||||
import { Workflow } from '../../types/n8n-api';
|
||||
import { InstanceContext } from '../../types/instance-context';
|
||||
import { N8nApiClient } from '../../services/n8n-api-client';
|
||||
import { TriggerType, TriggerResponse, TriggerHandlerCapabilities, DetectedTrigger, BaseTriggerInput } from '../types';
|
||||
export type TriggerHandlerConstructor = new (client: N8nApiClient, context?: InstanceContext) => BaseTriggerHandler;
|
||||
export declare abstract class BaseTriggerHandler<T extends BaseTriggerInput = BaseTriggerInput> {
|
||||
protected client: N8nApiClient;
|
||||
protected context?: InstanceContext;
|
||||
abstract readonly triggerType: TriggerType;
|
||||
abstract readonly capabilities: TriggerHandlerCapabilities;
|
||||
abstract readonly inputSchema: z.ZodSchema<T>;
|
||||
constructor(client: N8nApiClient, context?: InstanceContext);
|
||||
validate(input: unknown): T;
|
||||
abstract execute(input: T, workflow: Workflow, triggerInfo?: DetectedTrigger): Promise<TriggerResponse>;
|
||||
protected getBaseUrl(): string | undefined;
|
||||
protected getApiKey(): string | undefined;
|
||||
protected normalizeResponse(result: unknown, input: T, startTime: number, extra?: Partial<TriggerResponse>): TriggerResponse;
|
||||
protected errorResponse(input: BaseTriggerInput, error: string, startTime: number, extra?: Partial<TriggerResponse>): TriggerResponse;
|
||||
}
|
||||
//# sourceMappingURL=base-handler.d.ts.map
|
||||
1
dist/triggers/handlers/base-handler.d.ts.map
vendored
Normal file
1
dist/triggers/handlers/base-handler.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"base-handler.d.ts","sourceRoot":"","sources":["../../../src/triggers/handlers/base-handler.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,OAAO,EACL,WAAW,EACX,eAAe,EACf,0BAA0B,EAC1B,eAAe,EACf,gBAAgB,EACjB,MAAM,UAAU,CAAC;AAKlB,MAAM,MAAM,yBAAyB,GAAG,KACtC,MAAM,EAAE,YAAY,EACpB,OAAO,CAAC,EAAE,eAAe,KACtB,kBAAkB,CAAC;AAUxB,8BAAsB,kBAAkB,CAAC,CAAC,SAAS,gBAAgB,GAAG,gBAAgB;IACpF,SAAS,CAAC,MAAM,EAAE,YAAY,CAAC;IAC/B,SAAS,CAAC,OAAO,CAAC,EAAE,eAAe,CAAC;IAGpC,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAG3C,QAAQ,CAAC,QAAQ,CAAC,YAAY,EAAE,0BAA0B,CAAC;IAG3D,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;gBAElC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,eAAe;IAS3D,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,CAAC;IAW3B,QAAQ,CAAC,OAAO,CACd,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,QAAQ,EAClB,WAAW,CAAC,EAAE,eAAe,GAC5B,OAAO,CAAC,eAAe,CAAC;IAK3B,SAAS,CAAC,UAAU,IAAI,MAAM,GAAG,SAAS;IAgB1C,SAAS,CAAC,SAAS,IAAI,MAAM,GAAG,SAAS;IAazC,SAAS,CAAC,iBAAiB,CACzB,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,CAAC,EACR,SAAS,EAAE,MAAM,EACjB,KAAK,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAC/B,eAAe;IAmBlB,SAAS,CAAC,aAAa,CACrB,KAAK,EAAE,gBAAgB,EACvB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,KAAK,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAC/B,eAAe;CAenB"}
|
||||
60
dist/triggers/handlers/base-handler.js
vendored
Normal file
60
dist/triggers/handlers/base-handler.js
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.BaseTriggerHandler = void 0;
|
||||
const n8n_api_1 = require("../../config/n8n-api");
|
||||
class BaseTriggerHandler {
|
||||
constructor(client, context) {
|
||||
this.client = client;
|
||||
this.context = context;
|
||||
}
|
||||
validate(input) {
|
||||
return this.inputSchema.parse(input);
|
||||
}
|
||||
getBaseUrl() {
|
||||
if (this.context?.n8nApiUrl) {
|
||||
return this.context.n8nApiUrl.replace(/\/api\/v1\/?$/, '');
|
||||
}
|
||||
const config = (0, n8n_api_1.getN8nApiConfig)();
|
||||
if (config?.baseUrl) {
|
||||
return config.baseUrl.replace(/\/api\/v1\/?$/, '');
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
getApiKey() {
|
||||
if (this.context?.n8nApiKey) {
|
||||
return this.context.n8nApiKey;
|
||||
}
|
||||
const config = (0, n8n_api_1.getN8nApiConfig)();
|
||||
return config?.apiKey;
|
||||
}
|
||||
normalizeResponse(result, input, startTime, extra) {
|
||||
const endTime = Date.now();
|
||||
const duration = endTime - startTime;
|
||||
return {
|
||||
success: true,
|
||||
triggerType: this.triggerType,
|
||||
workflowId: input.workflowId,
|
||||
data: result,
|
||||
metadata: {
|
||||
duration,
|
||||
},
|
||||
...extra,
|
||||
};
|
||||
}
|
||||
errorResponse(input, error, startTime, extra) {
|
||||
const endTime = Date.now();
|
||||
const duration = endTime - startTime;
|
||||
return {
|
||||
success: false,
|
||||
triggerType: this.triggerType,
|
||||
workflowId: input.workflowId,
|
||||
error,
|
||||
metadata: {
|
||||
duration,
|
||||
},
|
||||
...extra,
|
||||
};
|
||||
}
|
||||
}
|
||||
exports.BaseTriggerHandler = BaseTriggerHandler;
|
||||
//# sourceMappingURL=base-handler.js.map
|
||||
1
dist/triggers/handlers/base-handler.js.map
vendored
Normal file
1
dist/triggers/handlers/base-handler.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"base-handler.js","sourceRoot":"","sources":["../../../src/triggers/handlers/base-handler.ts"],"names":[],"mappings":";;;AAQA,kDAAuD;AAyBvD,MAAsB,kBAAkB;IAatC,YAAY,MAAoB,EAAE,OAAyB;QACzD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAMD,QAAQ,CAAC,KAAc;QACrB,OAAO,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;IAkBS,UAAU;QAElB,IAAI,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;QAC7D,CAAC;QAED,MAAM,MAAM,GAAG,IAAA,yBAAe,GAAE,CAAC;QACjC,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACpB,OAAO,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAKS,SAAS;QAEjB,IAAI,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;QAChC,CAAC;QAED,MAAM,MAAM,GAAG,IAAA,yBAAe,GAAE,CAAC;QACjC,OAAO,MAAM,EAAE,MAAM,CAAC;IACxB,CAAC;IAKS,iBAAiB,CACzB,MAAe,EACf,KAAQ,EACR,SAAiB,EACjB,KAAgC;QAEhC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;QAErC,OAAO;YACL,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,IAAI,EAAE,MAAM;YACZ,QAAQ,EAAE;gBACR,QAAQ;aACT;YACD,GAAG,KAAK;SACT,CAAC;IACJ,CAAC;IAKS,aAAa,CACrB,KAAuB,EACvB,KAAa,EACb,SAAiB,EACjB,KAAgC;QAEhC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;QAErC,OAAO;YACL,OAAO,EAAE,KAAK;YACd,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,KAAK;YACL,QAAQ,EAAE;gBACR,QAAQ;aACT;YACD,GAAG,KAAK;SACT,CAAC;IACJ,CAAC;CACF;AAnHD,gDAmHC"}
|
||||
38
dist/triggers/handlers/chat-handler.d.ts
vendored
Normal file
38
dist/triggers/handlers/chat-handler.d.ts
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
import { z } from 'zod';
|
||||
import { Workflow } from '../../types/n8n-api';
|
||||
import { TriggerType, TriggerResponse, TriggerHandlerCapabilities, DetectedTrigger, ChatTriggerInput } from '../types';
|
||||
import { BaseTriggerHandler } from './base-handler';
|
||||
export declare class ChatHandler extends BaseTriggerHandler<ChatTriggerInput> {
|
||||
readonly triggerType: TriggerType;
|
||||
readonly capabilities: TriggerHandlerCapabilities;
|
||||
readonly inputSchema: z.ZodObject<{
|
||||
workflowId: z.ZodString;
|
||||
triggerType: z.ZodLiteral<"chat">;
|
||||
message: z.ZodString;
|
||||
sessionId: z.ZodOptional<z.ZodString>;
|
||||
data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
||||
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
||||
timeout: z.ZodOptional<z.ZodNumber>;
|
||||
waitForResponse: z.ZodOptional<z.ZodBoolean>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
workflowId: string;
|
||||
triggerType: "chat";
|
||||
message: string;
|
||||
sessionId?: string | undefined;
|
||||
data?: Record<string, unknown> | undefined;
|
||||
headers?: Record<string, string> | undefined;
|
||||
timeout?: number | undefined;
|
||||
waitForResponse?: boolean | undefined;
|
||||
}, {
|
||||
workflowId: string;
|
||||
triggerType: "chat";
|
||||
message: string;
|
||||
sessionId?: string | undefined;
|
||||
data?: Record<string, unknown> | undefined;
|
||||
headers?: Record<string, string> | undefined;
|
||||
timeout?: number | undefined;
|
||||
waitForResponse?: boolean | undefined;
|
||||
}>;
|
||||
execute(input: ChatTriggerInput, workflow: Workflow, triggerInfo?: DetectedTrigger): Promise<TriggerResponse>;
|
||||
}
|
||||
//# sourceMappingURL=chat-handler.d.ts.map
|
||||
1
dist/triggers/handlers/chat-handler.d.ts.map
vendored
Normal file
1
dist/triggers/handlers/chat-handler.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"chat-handler.d.ts","sourceRoot":"","sources":["../../../src/triggers/handlers/chat-handler.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EACL,WAAW,EACX,eAAe,EACf,0BAA0B,EAC1B,eAAe,EACf,gBAAgB,EACjB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AA2BpD,qBAAa,WAAY,SAAQ,kBAAkB,CAAC,gBAAgB,CAAC;IACnE,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAU;IAE3C,QAAQ,CAAC,YAAY,EAAE,0BAA0B,CAG/C;IAEF,QAAQ,CAAC,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;OAAmB;IAEjC,OAAO,CACX,KAAK,EAAE,gBAAgB,EACvB,QAAQ,EAAE,QAAQ,EAClB,WAAW,CAAC,EAAE,eAAe,GAC5B,OAAO,CAAC,eAAe,CAAC;CAgF5B"}
|
||||
129
dist/triggers/handlers/chat-handler.js
vendored
Normal file
129
dist/triggers/handlers/chat-handler.js
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ChatHandler = void 0;
|
||||
const zod_1 = require("zod");
|
||||
const axios_1 = __importDefault(require("axios"));
|
||||
const base_handler_1 = require("./base-handler");
|
||||
const trigger_detector_1 = require("../trigger-detector");
|
||||
const chatInputSchema = zod_1.z.object({
|
||||
workflowId: zod_1.z.string(),
|
||||
triggerType: zod_1.z.literal('chat'),
|
||||
message: zod_1.z.string(),
|
||||
sessionId: zod_1.z.string().optional(),
|
||||
data: zod_1.z.record(zod_1.z.unknown()).optional(),
|
||||
headers: zod_1.z.record(zod_1.z.string()).optional(),
|
||||
timeout: zod_1.z.number().optional(),
|
||||
waitForResponse: zod_1.z.boolean().optional(),
|
||||
});
|
||||
function generateSessionId() {
|
||||
return `session_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
|
||||
}
|
||||
class ChatHandler extends base_handler_1.BaseTriggerHandler {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.triggerType = 'chat';
|
||||
this.capabilities = {
|
||||
requiresActiveWorkflow: true,
|
||||
canPassInputData: true,
|
||||
};
|
||||
this.inputSchema = chatInputSchema;
|
||||
}
|
||||
async execute(input, workflow, triggerInfo) {
|
||||
const startTime = Date.now();
|
||||
try {
|
||||
const baseUrl = this.getBaseUrl();
|
||||
if (!baseUrl) {
|
||||
return this.errorResponse(input, 'Cannot determine n8n base URL', startTime);
|
||||
}
|
||||
let chatUrl;
|
||||
if (triggerInfo?.webhookPath) {
|
||||
chatUrl = (0, trigger_detector_1.buildTriggerUrl)(baseUrl, triggerInfo, 'production');
|
||||
}
|
||||
else {
|
||||
chatUrl = `${baseUrl.replace(/\/+$/, '')}/webhook/${input.workflowId}`;
|
||||
}
|
||||
const { SSRFProtection } = await Promise.resolve().then(() => __importStar(require('../../utils/ssrf-protection')));
|
||||
const validation = await SSRFProtection.validateWebhookUrl(chatUrl);
|
||||
if (!validation.valid) {
|
||||
return this.errorResponse(input, `SSRF protection: ${validation.reason}`, startTime);
|
||||
}
|
||||
const sessionId = input.sessionId || generateSessionId();
|
||||
const chatPayload = {
|
||||
action: 'sendMessage',
|
||||
sessionId,
|
||||
chatInput: input.message,
|
||||
...input.data,
|
||||
};
|
||||
const config = {
|
||||
method: 'POST',
|
||||
url: chatUrl,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...input.headers,
|
||||
},
|
||||
data: chatPayload,
|
||||
timeout: input.timeout || (input.waitForResponse !== false ? 120000 : 30000),
|
||||
validateStatus: (status) => status < 500,
|
||||
};
|
||||
const response = await axios_1.default.request(config);
|
||||
const chatResponse = response.data;
|
||||
return this.normalizeResponse(chatResponse, input, startTime, {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
metadata: {
|
||||
duration: Date.now() - startTime,
|
||||
sessionId,
|
||||
webhookPath: triggerInfo?.webhookPath,
|
||||
},
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
||||
const errorDetails = error?.response?.data;
|
||||
const executionId = errorDetails?.executionId || errorDetails?.id;
|
||||
return this.errorResponse(input, errorMessage, startTime, {
|
||||
executionId,
|
||||
code: error?.code,
|
||||
details: errorDetails,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.ChatHandler = ChatHandler;
|
||||
//# sourceMappingURL=chat-handler.js.map
|
||||
1
dist/triggers/handlers/chat-handler.js.map
vendored
Normal file
1
dist/triggers/handlers/chat-handler.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"chat-handler.js","sourceRoot":"","sources":["../../../src/triggers/handlers/chat-handler.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AASA,6BAAwB;AACxB,kDAAkD;AASlD,iDAAoD;AACpD,0DAAsD;AAKtD,MAAM,eAAe,GAAG,OAAC,CAAC,MAAM,CAAC;IAC/B,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE;IACtB,WAAW,EAAE,OAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IAC9B,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;IACnB,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,IAAI,EAAE,OAAC,CAAC,MAAM,CAAC,OAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE;IACtC,OAAO,EAAE,OAAC,CAAC,MAAM,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACxC,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,eAAe,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CACxC,CAAC,CAAC;AAKH,SAAS,iBAAiB;IACxB,OAAO,WAAW,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;AAChF,CAAC;AAKD,MAAa,WAAY,SAAQ,iCAAoC;IAArE;;QACW,gBAAW,GAAgB,MAAM,CAAC;QAElC,iBAAY,GAA+B;YAClD,sBAAsB,EAAE,IAAI;YAC5B,gBAAgB,EAAE,IAAI;SACvB,CAAC;QAEO,gBAAW,GAAG,eAAe,CAAC;IAsFzC,CAAC;IApFC,KAAK,CAAC,OAAO,CACX,KAAuB,EACvB,QAAkB,EAClB,WAA6B;QAE7B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE7B,IAAI,CAAC;YAEH,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YAClC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,+BAA+B,EAAE,SAAS,CAAC,CAAC;YAC/E,CAAC;YAGD,IAAI,OAAe,CAAC;YACpB,IAAI,WAAW,EAAE,WAAW,EAAE,CAAC;gBAC7B,OAAO,GAAG,IAAA,kCAAe,EAAC,OAAO,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC;YAChE,CAAC;iBAAM,CAAC;gBAEN,OAAO,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,YAAY,KAAK,CAAC,UAAU,EAAE,CAAC;YACzE,CAAC;YAGD,MAAM,EAAE,cAAc,EAAE,GAAG,wDAAa,6BAA6B,GAAC,CAAC;YACvE,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YACpE,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;gBACtB,OAAO,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,oBAAoB,UAAU,CAAC,MAAM,EAAE,EAAE,SAAS,CAAC,CAAC;YACvF,CAAC;YAGD,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,iBAAiB,EAAE,CAAC;YAGzD,MAAM,WAAW,GAAG;gBAClB,MAAM,EAAE,aAAa;gBACrB,SAAS;gBACT,SAAS,EAAE,KAAK,CAAC,OAAO;gBAExB,GAAG,KAAK,CAAC,IAAI;aACd,CAAC;YAGF,MAAM,MAAM,GAAuB;gBACjC,MAAM,EAAE,MAAM;gBACd,GAAG,EAAE,OAAO;gBACZ,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,GAAG,KAAK,CAAC,OAAO;iBACjB;gBACD,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,eAAe,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;gBAC5E,cAAc,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,GAAG,GAAG;aACzC,CAAC;YAGF,MAAM,QAAQ,GAAG,MAAM,eAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAG7C,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC;YAEnC,OAAO,IAAI,CAAC,iBAAiB,CAAC,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE;gBAC5D,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;gBAC/B,QAAQ,EAAE;oBACR,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;oBAChC,SAAS;oBACT,WAAW,EAAE,WAAW,EAAE,WAAW;iBACtC;aACF,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YAG9E,MAAM,YAAY,GAAI,KAAa,EAAE,QAAQ,EAAE,IAAI,CAAC;YACpD,MAAM,WAAW,GAAG,YAAY,EAAE,WAAW,IAAI,YAAY,EAAE,EAAE,CAAC;YAElE,OAAO,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE;gBACxD,WAAW;gBACX,IAAI,EAAG,KAAa,EAAE,IAAI;gBAC1B,OAAO,EAAE,YAAY;aACtB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF;AA9FD,kCA8FC"}
|
||||
35
dist/triggers/handlers/form-handler.d.ts
vendored
Normal file
35
dist/triggers/handlers/form-handler.d.ts
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
import { z } from 'zod';
|
||||
import { Workflow } from '../../types/n8n-api';
|
||||
import { TriggerType, TriggerResponse, TriggerHandlerCapabilities, DetectedTrigger, FormTriggerInput } from '../types';
|
||||
import { BaseTriggerHandler } from './base-handler';
|
||||
export declare class FormHandler extends BaseTriggerHandler<FormTriggerInput> {
|
||||
readonly triggerType: TriggerType;
|
||||
readonly capabilities: TriggerHandlerCapabilities;
|
||||
readonly inputSchema: z.ZodObject<{
|
||||
workflowId: z.ZodString;
|
||||
triggerType: z.ZodLiteral<"form">;
|
||||
formData: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
||||
data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
||||
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
||||
timeout: z.ZodOptional<z.ZodNumber>;
|
||||
waitForResponse: z.ZodOptional<z.ZodBoolean>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
workflowId: string;
|
||||
triggerType: "form";
|
||||
data?: Record<string, unknown> | undefined;
|
||||
headers?: Record<string, string> | undefined;
|
||||
timeout?: number | undefined;
|
||||
waitForResponse?: boolean | undefined;
|
||||
formData?: Record<string, unknown> | undefined;
|
||||
}, {
|
||||
workflowId: string;
|
||||
triggerType: "form";
|
||||
data?: Record<string, unknown> | undefined;
|
||||
headers?: Record<string, string> | undefined;
|
||||
timeout?: number | undefined;
|
||||
waitForResponse?: boolean | undefined;
|
||||
formData?: Record<string, unknown> | undefined;
|
||||
}>;
|
||||
execute(input: FormTriggerInput, workflow: Workflow, triggerInfo?: DetectedTrigger): Promise<TriggerResponse>;
|
||||
}
|
||||
//# sourceMappingURL=form-handler.d.ts.map
|
||||
1
dist/triggers/handlers/form-handler.d.ts.map
vendored
Normal file
1
dist/triggers/handlers/form-handler.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"form-handler.d.ts","sourceRoot":"","sources":["../../../src/triggers/handlers/form-handler.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,QAAQ,EAAgB,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EACL,WAAW,EACX,eAAe,EACf,0BAA0B,EAC1B,eAAe,EACf,gBAAgB,EACjB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAwMpD,qBAAa,WAAY,SAAQ,kBAAkB,CAAC,gBAAgB,CAAC;IACnE,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAU;IAE3C,QAAQ,CAAC,YAAY,EAAE,0BAA0B,CAG/C;IAEF,QAAQ,CAAC,WAAW;;;;;;;;;;;;;;;;;;;;;;;;OAAmB;IAEjC,OAAO,CACX,KAAK,EAAE,gBAAgB,EACvB,QAAQ,EAAE,QAAQ,EAClB,WAAW,CAAC,EAAE,eAAe,GAC5B,OAAO,CAAC,eAAe,CAAC;CAiO5B"}
|
||||
362
dist/triggers/handlers/form-handler.js
vendored
Normal file
362
dist/triggers/handlers/form-handler.js
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.FormHandler = void 0;
|
||||
const zod_1 = require("zod");
|
||||
const axios_1 = __importDefault(require("axios"));
|
||||
const form_data_1 = __importDefault(require("form-data"));
|
||||
const base_handler_1 = require("./base-handler");
|
||||
const formInputSchema = zod_1.z.object({
|
||||
workflowId: zod_1.z.string(),
|
||||
triggerType: zod_1.z.literal('form'),
|
||||
formData: zod_1.z.record(zod_1.z.unknown()).optional(),
|
||||
data: zod_1.z.record(zod_1.z.unknown()).optional(),
|
||||
headers: zod_1.z.record(zod_1.z.string()).optional(),
|
||||
timeout: zod_1.z.number().optional(),
|
||||
waitForResponse: zod_1.z.boolean().optional(),
|
||||
});
|
||||
const FORM_FIELD_TYPES = {
|
||||
TEXT: 'text',
|
||||
TEXTAREA: 'textarea',
|
||||
EMAIL: 'email',
|
||||
NUMBER: 'number',
|
||||
PASSWORD: 'password',
|
||||
DATE: 'date',
|
||||
DROPDOWN: 'dropdown',
|
||||
CHECKBOX: 'checkbox',
|
||||
FILE: 'file',
|
||||
HIDDEN: 'hiddenField',
|
||||
HTML: 'html',
|
||||
};
|
||||
const MAX_FILE_SIZE_BYTES = 10 * 1024 * 1024;
|
||||
function isValidBase64(str) {
|
||||
if (!str || str.length === 0) {
|
||||
return false;
|
||||
}
|
||||
const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
|
||||
if (!base64Regex.test(str)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const decoded = Buffer.from(str, 'base64');
|
||||
return decoded.toString('base64') === str;
|
||||
}
|
||||
catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function extractFormFields(workflow, triggerNode) {
|
||||
const node = triggerNode || workflow.nodes.find(n => n.type.toLowerCase().includes('formtrigger'));
|
||||
const params = node?.parameters;
|
||||
const formFields = params?.formFields;
|
||||
if (!formFields?.values) {
|
||||
return [];
|
||||
}
|
||||
const fields = [];
|
||||
let fieldIndex = 0;
|
||||
for (const rawField of formFields.values) {
|
||||
const field = rawField;
|
||||
const fieldType = field.fieldType || FORM_FIELD_TYPES.TEXT;
|
||||
const def = {
|
||||
index: fieldIndex,
|
||||
fieldName: `field-${fieldIndex}`,
|
||||
label: field.fieldLabel || field.fieldName || field.elementName || `field-${fieldIndex}`,
|
||||
type: fieldType,
|
||||
required: field.requiredField === true,
|
||||
};
|
||||
if (field.fieldOptions?.values) {
|
||||
def.options = field.fieldOptions.values.map((v) => v.option);
|
||||
}
|
||||
fields.push(def);
|
||||
fieldIndex++;
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
function generateFormUsageHint(fields) {
|
||||
if (fields.length === 0) {
|
||||
return 'No form fields detected in workflow.';
|
||||
}
|
||||
const lines = ['Form fields (use these keys in data parameter):'];
|
||||
for (const field of fields) {
|
||||
let hint = ` "${field.fieldName}": `;
|
||||
switch (field.type) {
|
||||
case FORM_FIELD_TYPES.CHECKBOX:
|
||||
hint += `["${field.options?.[0] || 'option1'}", ...]`;
|
||||
if (field.options) {
|
||||
hint += ` (options: ${field.options.join(', ')})`;
|
||||
}
|
||||
break;
|
||||
case FORM_FIELD_TYPES.DROPDOWN:
|
||||
hint += `"${field.options?.[0] || 'value'}"`;
|
||||
if (field.options) {
|
||||
hint += ` (options: ${field.options.join(', ')})`;
|
||||
}
|
||||
break;
|
||||
case FORM_FIELD_TYPES.DATE:
|
||||
hint += '"YYYY-MM-DD"';
|
||||
break;
|
||||
case FORM_FIELD_TYPES.EMAIL:
|
||||
hint += '"user@example.com"';
|
||||
break;
|
||||
case FORM_FIELD_TYPES.NUMBER:
|
||||
hint += '123';
|
||||
break;
|
||||
case FORM_FIELD_TYPES.FILE:
|
||||
hint += '{ filename: "test.txt", content: "base64..." } or skip (sends empty file)';
|
||||
break;
|
||||
case FORM_FIELD_TYPES.PASSWORD:
|
||||
hint += '"secret"';
|
||||
break;
|
||||
case FORM_FIELD_TYPES.TEXTAREA:
|
||||
hint += '"multi-line text..."';
|
||||
break;
|
||||
case FORM_FIELD_TYPES.HTML:
|
||||
hint += '"" (display-only, can be omitted)';
|
||||
break;
|
||||
case FORM_FIELD_TYPES.HIDDEN:
|
||||
hint += '"value" (hidden field)';
|
||||
break;
|
||||
default:
|
||||
hint += '"text value"';
|
||||
}
|
||||
hint += field.required ? ' [REQUIRED]' : '';
|
||||
hint += ` // ${field.label}`;
|
||||
lines.push(hint);
|
||||
}
|
||||
return lines.join('\n');
|
||||
}
|
||||
class FormHandler extends base_handler_1.BaseTriggerHandler {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.triggerType = 'form';
|
||||
this.capabilities = {
|
||||
requiresActiveWorkflow: true,
|
||||
canPassInputData: true,
|
||||
};
|
||||
this.inputSchema = formInputSchema;
|
||||
}
|
||||
async execute(input, workflow, triggerInfo) {
|
||||
const startTime = Date.now();
|
||||
const formFieldDefs = extractFormFields(workflow, triggerInfo?.node);
|
||||
try {
|
||||
const baseUrl = this.getBaseUrl();
|
||||
if (!baseUrl) {
|
||||
return this.errorResponse(input, 'Cannot determine n8n base URL', startTime, {
|
||||
details: {
|
||||
formFields: formFieldDefs,
|
||||
hint: generateFormUsageHint(formFieldDefs),
|
||||
},
|
||||
});
|
||||
}
|
||||
const formPath = triggerInfo?.webhookPath || triggerInfo?.node?.parameters?.path || input.workflowId;
|
||||
const formUrl = `${baseUrl.replace(/\/+$/, '')}/form/${formPath}`;
|
||||
const inputFields = {
|
||||
...input.data,
|
||||
...input.formData,
|
||||
};
|
||||
const { SSRFProtection } = await Promise.resolve().then(() => __importStar(require('../../utils/ssrf-protection')));
|
||||
const validation = await SSRFProtection.validateWebhookUrl(formUrl);
|
||||
if (!validation.valid) {
|
||||
return this.errorResponse(input, `SSRF protection: ${validation.reason}`, startTime);
|
||||
}
|
||||
const formData = new form_data_1.default();
|
||||
const warnings = [];
|
||||
for (const fieldDef of formFieldDefs) {
|
||||
const value = inputFields[fieldDef.fieldName];
|
||||
switch (fieldDef.type) {
|
||||
case FORM_FIELD_TYPES.CHECKBOX:
|
||||
if (Array.isArray(value)) {
|
||||
for (const item of value) {
|
||||
formData.append(`${fieldDef.fieldName}[]`, String(item ?? ''));
|
||||
}
|
||||
}
|
||||
else if (value !== undefined && value !== null) {
|
||||
formData.append(`${fieldDef.fieldName}[]`, String(value));
|
||||
}
|
||||
else if (fieldDef.required) {
|
||||
warnings.push(`Required checkbox field "${fieldDef.fieldName}" (${fieldDef.label}) not provided`);
|
||||
}
|
||||
break;
|
||||
case FORM_FIELD_TYPES.FILE:
|
||||
if (value && typeof value === 'object' && 'content' in value) {
|
||||
const fileObj = value;
|
||||
let buffer;
|
||||
if (typeof fileObj.content === 'string') {
|
||||
if (!isValidBase64(fileObj.content)) {
|
||||
warnings.push(`Invalid base64 encoding for file field "${fieldDef.fieldName}" (${fieldDef.label})`);
|
||||
buffer = Buffer.from('');
|
||||
}
|
||||
else {
|
||||
buffer = Buffer.from(fileObj.content, 'base64');
|
||||
if (buffer.length > MAX_FILE_SIZE_BYTES) {
|
||||
warnings.push(`File too large for "${fieldDef.fieldName}" (${fieldDef.label}): ${Math.round(buffer.length / 1024 / 1024)}MB exceeds ${MAX_FILE_SIZE_BYTES / 1024 / 1024}MB limit`);
|
||||
buffer = Buffer.from('');
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
buffer = fileObj.content;
|
||||
if (buffer.length > MAX_FILE_SIZE_BYTES) {
|
||||
warnings.push(`File too large for "${fieldDef.fieldName}" (${fieldDef.label}): ${Math.round(buffer.length / 1024 / 1024)}MB exceeds ${MAX_FILE_SIZE_BYTES / 1024 / 1024}MB limit`);
|
||||
buffer = Buffer.from('');
|
||||
}
|
||||
}
|
||||
formData.append(fieldDef.fieldName, buffer, {
|
||||
filename: fileObj.filename || 'file.txt',
|
||||
contentType: 'application/octet-stream',
|
||||
});
|
||||
}
|
||||
else if (value && typeof value === 'string') {
|
||||
if (!isValidBase64(value)) {
|
||||
warnings.push(`Invalid base64 encoding for file field "${fieldDef.fieldName}" (${fieldDef.label})`);
|
||||
formData.append(fieldDef.fieldName, Buffer.from(''), {
|
||||
filename: 'empty.txt',
|
||||
contentType: 'text/plain',
|
||||
});
|
||||
}
|
||||
else {
|
||||
const buffer = Buffer.from(value, 'base64');
|
||||
if (buffer.length > MAX_FILE_SIZE_BYTES) {
|
||||
warnings.push(`File too large for "${fieldDef.fieldName}" (${fieldDef.label}): ${Math.round(buffer.length / 1024 / 1024)}MB exceeds ${MAX_FILE_SIZE_BYTES / 1024 / 1024}MB limit`);
|
||||
formData.append(fieldDef.fieldName, Buffer.from(''), {
|
||||
filename: 'empty.txt',
|
||||
contentType: 'text/plain',
|
||||
});
|
||||
}
|
||||
else {
|
||||
formData.append(fieldDef.fieldName, buffer, {
|
||||
filename: 'file.txt',
|
||||
contentType: 'application/octet-stream',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
formData.append(fieldDef.fieldName, Buffer.from(''), {
|
||||
filename: 'empty.txt',
|
||||
contentType: 'text/plain',
|
||||
});
|
||||
if (fieldDef.required) {
|
||||
warnings.push(`Required file field "${fieldDef.fieldName}" (${fieldDef.label}) not provided - sending empty placeholder`);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FORM_FIELD_TYPES.HTML:
|
||||
formData.append(fieldDef.fieldName, String(value ?? ''));
|
||||
break;
|
||||
case FORM_FIELD_TYPES.HIDDEN:
|
||||
formData.append(fieldDef.fieldName, String(value ?? ''));
|
||||
break;
|
||||
default:
|
||||
if (value !== undefined && value !== null) {
|
||||
formData.append(fieldDef.fieldName, String(value));
|
||||
}
|
||||
else if (fieldDef.required) {
|
||||
warnings.push(`Required field "${fieldDef.fieldName}" (${fieldDef.label}) not provided`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
const definedFieldNames = new Set(formFieldDefs.map(f => f.fieldName));
|
||||
for (const [key, value] of Object.entries(inputFields)) {
|
||||
if (!definedFieldNames.has(key)) {
|
||||
if (Array.isArray(value)) {
|
||||
for (const item of value) {
|
||||
formData.append(`${key}[]`, String(item ?? ''));
|
||||
}
|
||||
}
|
||||
else {
|
||||
formData.append(key, String(value ?? ''));
|
||||
}
|
||||
}
|
||||
}
|
||||
const config = {
|
||||
method: 'POST',
|
||||
url: formUrl,
|
||||
headers: {
|
||||
...formData.getHeaders(),
|
||||
...input.headers,
|
||||
},
|
||||
data: formData,
|
||||
timeout: input.timeout || (input.waitForResponse !== false ? 120000 : 30000),
|
||||
validateStatus: (status) => status < 500,
|
||||
};
|
||||
const response = await axios_1.default.request(config);
|
||||
const result = this.normalizeResponse(response.data, input, startTime, {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
metadata: {
|
||||
duration: Date.now() - startTime,
|
||||
},
|
||||
});
|
||||
result.details = {
|
||||
...result.details,
|
||||
fieldsSubmitted: formFieldDefs.length,
|
||||
};
|
||||
if (warnings.length > 0) {
|
||||
result.details = {
|
||||
...result.details,
|
||||
warnings,
|
||||
};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
||||
const errorDetails = error?.response?.data;
|
||||
const executionId = errorDetails?.executionId || errorDetails?.id;
|
||||
return this.errorResponse(input, errorMessage, startTime, {
|
||||
executionId,
|
||||
code: error?.code,
|
||||
details: {
|
||||
...errorDetails,
|
||||
formFields: formFieldDefs.map(f => ({
|
||||
name: f.fieldName,
|
||||
label: f.label,
|
||||
type: f.type,
|
||||
required: f.required,
|
||||
options: f.options,
|
||||
})),
|
||||
hint: generateFormUsageHint(formFieldDefs),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.FormHandler = FormHandler;
|
||||
//# sourceMappingURL=form-handler.js.map
|
||||
1
dist/triggers/handlers/form-handler.js.map
vendored
Normal file
1
dist/triggers/handlers/form-handler.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
38
dist/triggers/handlers/webhook-handler.d.ts
vendored
Normal file
38
dist/triggers/handlers/webhook-handler.d.ts
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
import { z } from 'zod';
|
||||
import { Workflow } from '../../types/n8n-api';
|
||||
import { TriggerType, TriggerResponse, TriggerHandlerCapabilities, DetectedTrigger, WebhookTriggerInput } from '../types';
|
||||
import { BaseTriggerHandler } from './base-handler';
|
||||
export declare class WebhookHandler extends BaseTriggerHandler<WebhookTriggerInput> {
|
||||
readonly triggerType: TriggerType;
|
||||
readonly capabilities: TriggerHandlerCapabilities;
|
||||
readonly inputSchema: z.ZodObject<{
|
||||
workflowId: z.ZodString;
|
||||
triggerType: z.ZodLiteral<"webhook">;
|
||||
httpMethod: z.ZodOptional<z.ZodEnum<["GET", "POST", "PUT", "DELETE"]>>;
|
||||
webhookPath: z.ZodOptional<z.ZodString>;
|
||||
data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
||||
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
||||
timeout: z.ZodOptional<z.ZodNumber>;
|
||||
waitForResponse: z.ZodOptional<z.ZodBoolean>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
workflowId: string;
|
||||
triggerType: "webhook";
|
||||
httpMethod?: "GET" | "POST" | "PUT" | "DELETE" | undefined;
|
||||
webhookPath?: string | undefined;
|
||||
data?: Record<string, unknown> | undefined;
|
||||
headers?: Record<string, string> | undefined;
|
||||
timeout?: number | undefined;
|
||||
waitForResponse?: boolean | undefined;
|
||||
}, {
|
||||
workflowId: string;
|
||||
triggerType: "webhook";
|
||||
httpMethod?: "GET" | "POST" | "PUT" | "DELETE" | undefined;
|
||||
webhookPath?: string | undefined;
|
||||
data?: Record<string, unknown> | undefined;
|
||||
headers?: Record<string, string> | undefined;
|
||||
timeout?: number | undefined;
|
||||
waitForResponse?: boolean | undefined;
|
||||
}>;
|
||||
execute(input: WebhookTriggerInput, workflow: Workflow, triggerInfo?: DetectedTrigger): Promise<TriggerResponse>;
|
||||
}
|
||||
//# sourceMappingURL=webhook-handler.d.ts.map
|
||||
1
dist/triggers/handlers/webhook-handler.d.ts.map
vendored
Normal file
1
dist/triggers/handlers/webhook-handler.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"webhook-handler.d.ts","sourceRoot":"","sources":["../../../src/triggers/handlers/webhook-handler.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAkB,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EACL,WAAW,EACX,eAAe,EACf,0BAA0B,EAC1B,eAAe,EACf,mBAAmB,EACpB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAoBpD,qBAAa,cAAe,SAAQ,kBAAkB,CAAC,mBAAmB,CAAC;IACzE,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAa;IAE9C,QAAQ,CAAC,YAAY,EAAE,0BAA0B,CAI/C;IAEF,QAAQ,CAAC,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;OAAsB;IAEpC,OAAO,CACX,KAAK,EAAE,mBAAmB,EAC1B,QAAQ,EAAE,QAAQ,EAClB,WAAW,CAAC,EAAE,eAAe,GAC5B,OAAO,CAAC,eAAe,CAAC;CAuE5B"}
|
||||
115
dist/triggers/handlers/webhook-handler.js
vendored
Normal file
115
dist/triggers/handlers/webhook-handler.js
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.WebhookHandler = void 0;
|
||||
const zod_1 = require("zod");
|
||||
const base_handler_1 = require("./base-handler");
|
||||
const trigger_detector_1 = require("../trigger-detector");
|
||||
const webhookInputSchema = zod_1.z.object({
|
||||
workflowId: zod_1.z.string(),
|
||||
triggerType: zod_1.z.literal('webhook'),
|
||||
httpMethod: zod_1.z.enum(['GET', 'POST', 'PUT', 'DELETE']).optional(),
|
||||
webhookPath: zod_1.z.string().optional(),
|
||||
data: zod_1.z.record(zod_1.z.unknown()).optional(),
|
||||
headers: zod_1.z.record(zod_1.z.string()).optional(),
|
||||
timeout: zod_1.z.number().optional(),
|
||||
waitForResponse: zod_1.z.boolean().optional(),
|
||||
});
|
||||
class WebhookHandler extends base_handler_1.BaseTriggerHandler {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.triggerType = 'webhook';
|
||||
this.capabilities = {
|
||||
requiresActiveWorkflow: true,
|
||||
supportedMethods: ['GET', 'POST', 'PUT', 'DELETE'],
|
||||
canPassInputData: true,
|
||||
};
|
||||
this.inputSchema = webhookInputSchema;
|
||||
}
|
||||
async execute(input, workflow, triggerInfo) {
|
||||
const startTime = Date.now();
|
||||
try {
|
||||
const baseUrl = this.getBaseUrl();
|
||||
if (!baseUrl) {
|
||||
return this.errorResponse(input, 'Cannot determine n8n base URL', startTime);
|
||||
}
|
||||
let webhookUrl;
|
||||
if (input.webhookPath) {
|
||||
webhookUrl = `${baseUrl.replace(/\/+$/, '')}/webhook/${input.webhookPath}`;
|
||||
}
|
||||
else if (triggerInfo?.webhookPath) {
|
||||
webhookUrl = (0, trigger_detector_1.buildTriggerUrl)(baseUrl, triggerInfo, 'production');
|
||||
}
|
||||
else {
|
||||
return this.errorResponse(input, 'No webhook path available. Provide webhookPath parameter or ensure workflow has a webhook trigger.', startTime);
|
||||
}
|
||||
const httpMethod = input.httpMethod || triggerInfo?.httpMethod || 'POST';
|
||||
const { SSRFProtection } = await Promise.resolve().then(() => __importStar(require('../../utils/ssrf-protection')));
|
||||
const validation = await SSRFProtection.validateWebhookUrl(webhookUrl);
|
||||
if (!validation.valid) {
|
||||
return this.errorResponse(input, `SSRF protection: ${validation.reason}`, startTime);
|
||||
}
|
||||
const webhookRequest = {
|
||||
webhookUrl,
|
||||
httpMethod: httpMethod,
|
||||
data: input.data,
|
||||
headers: input.headers,
|
||||
waitForResponse: input.waitForResponse ?? true,
|
||||
};
|
||||
const response = await this.client.triggerWebhook(webhookRequest);
|
||||
return this.normalizeResponse(response, input, startTime, {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
metadata: {
|
||||
duration: Date.now() - startTime,
|
||||
webhookPath: input.webhookPath || triggerInfo?.webhookPath,
|
||||
httpMethod,
|
||||
},
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
||||
const errorDetails = error?.details;
|
||||
const executionId = errorDetails?.executionId || errorDetails?.id;
|
||||
return this.errorResponse(input, errorMessage, startTime, {
|
||||
executionId,
|
||||
code: error?.code,
|
||||
details: errorDetails,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.WebhookHandler = WebhookHandler;
|
||||
//# sourceMappingURL=webhook-handler.js.map
|
||||
1
dist/triggers/handlers/webhook-handler.js.map
vendored
Normal file
1
dist/triggers/handlers/webhook-handler.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"webhook-handler.js","sourceRoot":"","sources":["../../../src/triggers/handlers/webhook-handler.ts"],"names":[],"mappings":"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"}
|
||||
Reference in New Issue
Block a user