From 20f24270d9237bac46ea1bec8b2b0673658768d8 Mon Sep 17 00:00:00 2001 From: yiekheng Date: Sat, 9 May 2026 16:15:17 +0800 Subject: [PATCH] feat(bot): add telegram bot with whitelist, /start, /help, audit --- apps/bot/src/index.ts | 8 ++++ apps/bot/src/telegram/bot.ts | 23 ++++++++++++ apps/bot/src/telegram/commands/help.ts | 13 +++++++ apps/bot/src/telegram/commands/start.ts | 8 ++++ apps/bot/src/telegram/middleware/audit.ts | 21 +++++++++++ .../src/telegram/middleware/whitelist.test.ts | 37 +++++++++++++++++++ apps/bot/src/telegram/middleware/whitelist.ts | 14 +++++++ 7 files changed, 124 insertions(+) create mode 100644 apps/bot/src/telegram/bot.ts create mode 100644 apps/bot/src/telegram/commands/help.ts create mode 100644 apps/bot/src/telegram/commands/start.ts create mode 100644 apps/bot/src/telegram/middleware/audit.ts create mode 100644 apps/bot/src/telegram/middleware/whitelist.test.ts create mode 100644 apps/bot/src/telegram/middleware/whitelist.ts diff --git a/apps/bot/src/index.ts b/apps/bot/src/index.ts index f4c0ea6..7246579 100644 --- a/apps/bot/src/index.ts +++ b/apps/bot/src/index.ts @@ -1,13 +1,21 @@ import { logger } from "./logger.js"; import { pool } from "./db.js"; import { startHealthServer } from "./health.js"; +import { createTelegramBot } from "./telegram/bot.js"; async function main(): Promise { logger.info("bot starting"); const health = startHealthServer(); + const tg = createTelegramBot(); + + void tg.start({ + onStart: (info) => logger.info({ username: info.username }, "telegram polling started"), + drop_pending_updates: true, + }); const shutdown = async (signal: string): Promise => { logger.info({ signal }, "shutting down"); + await tg.stop(); health.close(); await pool.end(); process.exit(0); diff --git a/apps/bot/src/telegram/bot.ts b/apps/bot/src/telegram/bot.ts new file mode 100644 index 0000000..a59d385 --- /dev/null +++ b/apps/bot/src/telegram/bot.ts @@ -0,0 +1,23 @@ +import { Bot } from "grammy"; +import { env } from "../env.js"; +import { logger } from "../logger.js"; +import { makeWhitelistMiddleware } from "./middleware/whitelist.js"; +import { auditMiddleware } from "./middleware/audit.js"; +import { handleStart } from "./commands/start.js"; +import { handleHelp } from "./commands/help.js"; + +export function createTelegramBot(): Bot { + const bot = new Bot(env.TELEGRAM_BOT_TOKEN); + + bot.use(makeWhitelistMiddleware(env.TELEGRAM_OPERATOR_WHITELIST)); + bot.use(auditMiddleware); + + bot.command("start", handleStart); + bot.command("help", handleHelp); + + bot.catch((err) => { + logger.error({ err }, "telegram error"); + }); + + return bot; +} diff --git a/apps/bot/src/telegram/commands/help.ts b/apps/bot/src/telegram/commands/help.ts new file mode 100644 index 0000000..61555a7 --- /dev/null +++ b/apps/bot/src/telegram/commands/help.ts @@ -0,0 +1,13 @@ +import type { Context } from "grammy"; + +export async function handleHelp(ctx: Context): Promise { + await ctx.reply( + "Available commands:\n\n" + + "/start — show the welcome message\n" + + "/help — show this help\n" + + "/pair