import { Bot, Context, session, SessionFlavor } from 'grammy';
import { run } from '@grammyjs/runner';
// ============================================
// Types
// ============================================
interface SessionData {
step: 'idle' | 'waiting_for_name';
counter: number;
}
type MyContext = Context & SessionFlavor<SessionData>;
// ============================================
// Setup
// ============================================
const token = process.env.TELEGRAM_BOT_TOKEN;
if (!token) throw new Error('TELEGRAM_BOT_TOKEN is missing');
const bot = new Bot<MyContext>(token);
// ============================================
// Middleware
// ============================================
// Session middleware
bot.use(session({
initial: (): SessionData => ({ step: 'idle', counter: 0 }),
}));
// Logging middleware
bot.use(async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
console.log(`Response time: ${ms}ms`);
});
// ============================================
// Commands
// ============================================
bot.command('start', async (ctx) => {
await ctx.reply('Welcome! Use /help to see available commands.');
});
bot.command('help', async (ctx) => {
await ctx.reply(
'Available commands:\n' +
'/start - Start the bot\n' +
'/count - Increment counter\n' +
'/reset - Reset counter\n' +
'/ask - Interactive conversation'
);
});
bot.command('count', async (ctx) => {
ctx.session.counter++;
await ctx.reply(`Counter: ${ctx.session.counter}`);
});
bot.command('reset', async (ctx) => {
ctx.session.counter = 0;
await ctx.reply('Counter reset to 0');
});
bot.command('ask', async (ctx) => {
ctx.session.step = 'waiting_for_name';
await ctx.reply('What is your name?');
});
// ============================================
// Message Handler (Conversation logic)
// ============================================
bot.on('message:text', async (ctx) => {
const text = ctx.message.text;
if (ctx.session.step === 'waiting_for_name') {
await ctx.reply(`Nice to meet you, ${text}!`);
ctx.session.step = 'idle';
return;
}
// Default response
// await ctx.reply('I did not understand that. Try /help');
});
// ============================================
// Error Handling
// ============================================
bot.catch((err) => {
console.error(`Error while handling update ${err.ctx.update.update_id}:`);
console.error(err.error);
});
// ============================================
// Start
// ============================================
// For Long Polling (Development)
if (process.env.NODE_ENV !== 'production') {
console.log('🤖 Bot started (Long Polling)');
run(bot);
}
// Export for Webhook (Production)
export const webhookCallback = (req: any, res: any) => {
// Adapter logic for your specific server (Express, Hono, etc.)
// return webhookCallback(bot, 'express')(req, res);
};
export { bot };