/** * Telegram Local Polling Bridge * * This script runs locally in Node and pulls messages from the Telegram Bot API, * forwarding them to the NestJS API webhook container. This lets you test the * bot locally without needing public tunneling tools like Ngrok! * * Usage: * node scripts/telegram-poll.js */ import { readFileSync } from "node:fs"; import { resolve, dirname } from "node:path"; import { fileURLToPath } from "node:url"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const envPath = resolve(__dirname, "../infra/.env"); // 1. Simple Env Loader function loadEnv() { try { const raw = readFileSync(envPath, "utf8"); for (const line of raw.split("\n")) { const trimmed = line.trim(); if (!trimmed || trimmed.startsWith("#")) continue; const eqIdx = trimmed.indexOf("="); if (eqIdx === -1) continue; const key = trimmed.slice(0, eqIdx).trim(); const val = trimmed.slice(eqIdx + 1).trim(); if (!process.env[key]) { process.env[key] = val; } } } catch (err) { console.warn("Could not load infra/.env file. Using system environment variables."); } } loadEnv(); const token = process.env.TELEGRAM_BOT_TOKEN; if (!token) { console.error("āŒ ERROR: TELEGRAM_BOT_TOKEN is not set in infra/.env"); process.exit(1); } const API_URL = `https://api.telegram.org/bot${token}`; const WEBHOOK_URL = `http://localhost:3001/api/webhooks/telegram`; async function main() { console.log("šŸš€ Starting Telegram bot local polling bridge..."); console.log(`šŸ¤– Targeting webhook: ${WEBHOOK_URL}`); // Clear any existing remote webhook registration so polling is allowed try { const response = await fetch(`${API_URL}/deleteWebhook`); const resJson = await response.json(); if (resJson.ok) { console.log("āœ… Cleared any active remote webhook registrations."); } } catch (err) { console.error("āš ļø Failed to delete webhook registration:", err.message); } let offset = 0; while (true) { try { const response = await fetch(`${API_URL}/getUpdates?offset=${offset}&timeout=15`); const data = await response.json(); if (!data.ok) { console.error("āŒ Telegram API returned error:", data.description); await new Promise((resolve) => setTimeout(resolve, 5000)); continue; } if (data.result && data.result.length > 0) { for (const update of data.result) { offset = update.update_id + 1; console.log(`\nšŸ“„ Received Telegram update_id: ${update.update_id}`); try { const postResponse = await fetch(WEBHOOK_URL, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(update), }); const postResult = await postResponse.json(); console.log(`šŸ“¤ Forwarded to webhook. API response code: ${postResponse.status}`, postResult); } catch (postErr) { console.error("āŒ Failed to forward update to local API webhook:", postErr.message); } } } } catch (err) { console.error("āš ļø Connection error during polling:", err.message); await new Promise((resolve) => setTimeout(resolve, 5000)); } } } main().catch((err) => { console.error("šŸ’„ Fatal error:", err); process.exit(1); });