(req: Request, res: Response, next: NextFunction)
| 15 | import logger from '../../utils/logger' |
| 16 | |
| 17 | const createWebhook = async (req: Request, res: Response, next: NextFunction) => { |
| 18 | try { |
| 19 | if (typeof req.params === 'undefined' || !req.params.id) { |
| 20 | throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: webhookController.createWebhook - id not provided!`) |
| 21 | } |
| 22 | |
| 23 | const workspaceId = req.user?.activeWorkspaceId |
| 24 | |
| 25 | // For form-encoded requests, unwrap JSON encoded in a `payload` field (e.g. GitHub webhooks) |
| 26 | // so $webhook.body.* resolves against the actual payload fields. |
| 27 | const contentType = (req.headers['content-type'] ?? '').toLowerCase() |
| 28 | let body = req.body |
| 29 | if (contentType.startsWith('application/x-www-form-urlencoded') && typeof body?.payload === 'string') { |
| 30 | try { |
| 31 | body = JSON.parse(body.payload) |
| 32 | } catch { |
| 33 | // leave body as-is if payload isn't valid JSON |
| 34 | } |
| 35 | } |
| 36 | |
| 37 | const isResume = body?.humanInput != null |
| 38 | |
| 39 | const { responseMode, callbackUrl, callbackSecret } = await webhookService.validateWebhookChatflow( |
| 40 | req.params.id, |
| 41 | workspaceId, |
| 42 | body, |
| 43 | req.method, |
| 44 | req.headers, |
| 45 | req.query, |
| 46 | (req as any).rawBody, |
| 47 | isResume ? { skipFieldValidation: true } : undefined |
| 48 | ) |
| 49 | |
| 50 | // Namespace the webhook payload so $webhook.body.*, $webhook.headers.*, $webhook.query.* can coexist |
| 51 | req.body = { |
| 52 | webhook: { |
| 53 | body, |
| 54 | headers: redactSensitiveHeaders(req.headers as Record<string, any>), |
| 55 | query: req.query |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | const { humanInput, chatId: bodyChatId, sessionId } = body ?? {} |
| 60 | if (humanInput != null) req.body.humanInput = humanInput |
| 61 | if (bodyChatId != null) req.body.chatId = bodyChatId |
| 62 | if (sessionId != null) req.body.sessionId = sessionId |
| 63 | |
| 64 | const executionChatId: string = (bodyChatId as string | undefined) ?? uuidv4() |
| 65 | req.body.chatId = executionChatId |
| 66 | |
| 67 | // Mirror this execution's events to any UI panels currently listening to this flow. |
| 68 | try { |
| 69 | await getWebhookListenerRegistry().bindExecution(req.params.id, executionChatId) |
| 70 | } catch (err) { |
| 71 | logger.warn(`[webhookController] Failed to bind webhook listeners: ${getErrorMessage(err)}`) |
| 72 | } |
| 73 | |
| 74 | if (responseMode === 'stream') { |
nothing calls this directly
no test coverage detected