/** * Telegram webhook controller. * * Receives webhook requests from Telegram Bot API. */ import { Controller, Inject, Logger, Post, Req, Res, Headers } from "@nestjs/common"; import { TelegramService } from "./telegram.service.js"; // Minimal Express types for webhook handling interface ExpressRequest { body: unknown; header: (name: string) => string | undefined; } interface ExpressResponse { status: (code: number) => ExpressResponse; json: (data: unknown) => void; headersSent: boolean; } @Controller("telegram") export class TelegramController { private readonly logger = new Logger(TelegramController.name); constructor(@Inject(TelegramService) private readonly telegramService: TelegramService) {} @Post("webhook") async handleWebhook( @Req() req: ExpressRequest, @Res() res: ExpressResponse, @Headers("x-telegram-bot-api-secret-token") secretToken?: string ): Promise { // Check if Telegram is configured if (!this.telegramService.isConfigured()) { this.logger.warn("Telegram webhook called but bot not configured"); res.status(503).json({ error: "Telegram not configured" }); return; } // Validate secret token if configured const expectedToken = process.env["TELEGRAM_WEBHOOK_SECRET_TOKEN"]; if (expectedToken && secretToken !== expectedToken) { this.logger.warn("Invalid Telegram webhook secret token"); res.status(401).json({ error: "Unauthorized" }); return; } // Get grammY webhook callback const callback = this.telegramService.getWebhookCallback(); if (!callback) { res.status(503).json({ error: "Telegram not configured" }); return; } // Let grammY handle the request try { await callback(req, res); } catch (error) { const message = error instanceof Error ? error.message : String(error); this.logger.error(`Telegram webhook error: ${message}`); if (!res.headersSent) { res.status(500).json({ error: "Internal server error" }); } } } }