Skip to content

Instantly share code, notes, and snippets.

@waptik
Last active August 30, 2023 12:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save waptik/2038ad8f167b7af6d25d34ff9b070a2f to your computer and use it in GitHub Desktop.
Save waptik/2038ad8f167b7af6d25d34ff9b070a2f to your computer and use it in GitHub Desktop.
This is a minimal codebase of getting grammY to work with nextjs pages directory. Please use this version of `next-connect`: `"next-connect": "^0.13.0",`
import { Bot, Context } from "grammy";
export const bot = new Bot<Context>(process.env.TELEGRAM_BOT_TOKEN ?? "");
// attach your middlewaew, commands and other stuff to your bot
// eg. bot.use(myCommands)
// path: /utils/telegram/bot.ts
import { bot } from "./bot";
const WEBAPP_URL = "" // URL to your production main site(eg. https://my-secrete-webapp.tld)
const handleGracefulShutdown = async () => {
const.info("shutdown");
await bot.stop();
process.exit();
};
if (process.env.NODE_ENV==="development") {
// Graceful shutdown handlers
process.once("SIGTERM", handleGracefulShutdown);
process.once("SIGINT", handleGracefulShutdown);
}
export const startTelegramBotInDev = async () => {
if (!bot.isInited()) {
bot
.start({
onStart: ({ username }) => {
logger.info({
msg: "bot running...",
username,
at: new Date(),
});
},
})
.catch((err) => logger.error(err));
}
};
export const startTelegramBotInProduction = async () => {
const webhookUrl = `${WEBAPP_URL}/api/telegram-webhook?token=${env.TELEGRAM_BOT_WEBHOOK_TOKEN}`;
logger.info("fetching webhook info");
const webhookInfo = await bot.api.getWebhookInfo();
logger.info(`existing webhook info fetched: ${webhookInfo.url}`);
if (webhookInfo.url === webhookUrl) {
logger.info("Sorry, same url, i don't wanna waste my time here.");
} else {
logger.info("deleting existing webhook");
await bot.api.deleteWebhook();
console.info("existing webhook deleted");
logger.info(`setting new webhook to: ${webhookUrl}`);
await bot.api.setWebhook(webhookUrl);
console.info(`bot webhook set to: ${webhookUrl}`);
}
} catch (err) {
console.error("failed to delete/set webhook url", err);
}
};
// path: /utils/telegram/start.ts
import { NextApiRequest, NextApiResponse } from "next";
import nc from "next-connect";
import { BotError } from "grammy";
import { startTelegramBotInDev } from ""@/lib/telegram/run";
// this is to test the bot locally by visiting http://localhost:3000/api/telegram-dev?action=start
const handler = nc<NextApiRequest, NextApiResponse>({
attachParams: true,
onError: (err, _req, res, next) => {
if (err instanceof BotError) {
res.status(200).send({});
} else {
console.error(err);
res.status(500).end("Something broke!");
}
next();
},
})
.get((req, _res, next) => {
if (process.env.NODE_ENV==="development") {
next();
}
})
.get(async (req: NextApiRequest, res: NextApiResponse) => {
try {
if (req.query && req.query.action !== "start") {
res.status(500).send({ error: { message: "Wrong gateway." } });
return;
}
await startTelegramBotInDev();
res.status(200).send("ok");
} catch (error) {
res.status(500).json({ error });
}
});
export default handler;
// path: /pages/api/telegram-dev.ts
import { NextApiRequest, NextApiResponse } from "next";
import nc from "next-connect";
import { BotError, webhookCallback } from "grammy";
import { bot } from "@/lib/telegram/bot";
import { startTelegramBotInProduction } from "@/lib/telegram/start";
import { isProd } from "~utils/constants";
const handler = nc<NextApiRequest, NextApiResponse>({
attachParams: true,
onError: (err, _req, res, next) => {
if (err instanceof BotError) {
res.status(200).send({});
} else {
res.status(500).end("Something broke!");
}
next();
},
})
.post((req, _res, next) => {
if (req.query && req.query.token === process.env.TELEGRAM_BOT_WEBHOOK_TOKEN) {
next();
}
})
.post(webhookCallback(bot, "next-js"))
.get(async (req, res) => {
// this is used to automatically setup your webhook by visiting https://my-secrete-webapp.tld/api/telegram-webhook?token=[YOUR-BOT-TOKEN]
// replace [YOUR-BOT-TOKEN] with your telegram bot token
// only do so after you have deployed your bot in production
try {
if (process.env.NODE_ENV !=="production" || (req.query && req.query.token !== process.env.TELEGRAM_BOT_WEBHOOK_TOKEN)) {
return res.status(500).send({ error: { message: "Wrong gateway." } });
}
await startTelegramBotInProduction();
} catch (err) {
console.error("telegram bot error", err);
} finally {
return res.status(200).send("ok");
}
});
export default handler;
// path: /pages/api/telegram-webhook.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment