### Create a Minimal Gramio Bot Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/08-quick-start.md A basic example demonstrating how to initialize a bot, respond to the /start command, and start the bot. Ensure your BOT_TOKEN environment variable is set. ```typescript import { Bot } from "gramio"; const bot = new Bot(process.env.BOT_TOKEN || ""); bot.command("start", (ctx) => ctx.send("Hello!")); await bot.start(); ``` -------------------------------- ### onStart Hook Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/02-plugin-class.md The `onStart` hook is executed once when the plugin is initialized and started. It's suitable for setup tasks. ```APIDOC ## onStart() ### Description Triggered when the plugin starts. Ideal for initialization tasks and setting up resources. ### Method Signature ```typescript onStart(handler: Hooks.OnStart): this ``` ### Parameters * `handler` (Hooks.OnStart): The function to execute upon plugin startup. It receives context information about the bot and its plugins. ### Example ```typescript .onStart(({ info, plugins }) => { console.log("Plugin 'analytics' started"); }) ``` ``` -------------------------------- ### Command Configuration with Metadata Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/07-configuration.md Configure a command with detailed metadata including description, locales, and scopes. This example demonstrates setting up a 'start' command with multi-language support and specific visibility scopes. ```typescript bot.command("start", { description: "Start the bot", locales: { ru: "Запустить бота", es: "Iniciar el bot", }, scopes: [ "default", "all_private_chats", ], }, (ctx) => ctx.send("Welcome!")); ``` -------------------------------- ### Basic Bot Setup with Commands and Handlers Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/08-quick-start.md This snippet demonstrates the core setup for a Gramio bot, including importing necessary modules, initializing the bot with a token, and registering command and message handlers. Ensure your BOT_TOKEN is set in your environment variables. ```typescript import { Bot } from "gramio"; import { setupCommands } from "./commands"; import { setupHandlers } from "./handlers"; const bot = new Bot(process.env.BOT_TOKEN!); setupCommands(bot); setupHandlers(bot); await bot.start(); ``` ```typescript export function setupCommands(bot: AnyBot) { bot.command("start", (ctx) => ctx.send("Hello!")); bot.command("help", (ctx) => ctx.send("Help!")); } ``` ```typescript export function setupHandlers(bot: AnyBot) { bot.on("message", (ctx) => ctx.send("Got message")); } ``` -------------------------------- ### Install Gramio with npm, yarn, pnpm, bun, or deno Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/08-quick-start.md Choose the appropriate command for your package manager to install the Gramio library. ```bash # npm npm install gramio ``` ```bash # yarn yarn add gramio ``` ```bash # pnpm pnpm add gramio ``` ```bash # bun bun add gramio ``` ```bash # deno deno add jsr:@gramio/core ``` -------------------------------- ### start() Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/01-bot-class.md Starts the bot to begin receiving updates. It supports both long-polling and webhook methods for receiving updates, with various configuration options. ```APIDOC ## start() ### Description Begin receiving updates via long-polling or webhook. ### Method `start(options?: BotStartOptions): Promise` ### Parameters #### Query Parameters - **options.webhook** (boolean | string | SetWebhookParams) - Optional - Webhook URL or config; omit for long-polling - **options.longPolling** (APIMethodParams<"getUpdates">) - Optional - Long-polling options (timeout, limit, etc.) - **options.dropPendingUpdates** (boolean) - Optional - Drop updates that arrived before bot started - **options.deleteWebhook** (boolean | "on-conflict-with-polling") - Optional - Delete existing webhook; default: `"on-conflict-with-polling"` - **options.allowedUpdates** (AllowedUpdates | "strict" | AllowedUpdatesFilter) - Optional - Which updates to receive ### Request Example ```typescript await bot.start(); // Long-polling with default settings await bot.start({ webhook: "https://example.com/webhook", dropPendingUpdates: true, }); await bot.start({ allowedUpdates: AllowedUpdatesFilter.default.add("poll"), }); await bot.start({ allowedUpdates: "strict", // Only registered handlers }); ``` ``` -------------------------------- ### Example Plugin Initialization Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/02-plugin-class.md Demonstrates initializing a new Plugin instance and chaining hook registrations. ```typescript const plugin = new Plugin("analytics") .preRequest((ctx) => { console.log("API call:", ctx.method); return ctx; }) .onStart(({ info, plugins }) => { console.log("Plugin 'analytics' started"); }); ``` -------------------------------- ### Bot Start Options Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/INDEX.md Configure how the bot starts, including webhook or long polling settings, allowed updates, and options to drop pending updates or delete webhooks. ```typescript bot.start({ webhook?: "url" | { url, secret_token, ... }, longPolling?: { timeout, limit }, allowedUpdates?: "strict" | AllowedUpdatesFilter | [...], dropPendingUpdates?: boolean, deleteWebhook?: boolean | "on-conflict-with-polling", }) ``` -------------------------------- ### Handle Bot Command Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/INDEX.md Use `bot.command` to register a handler for a specific command. This example shows how to respond to the "start" command. ```typescript bot.command("start", (ctx) => ctx.send("Hello!")); ``` -------------------------------- ### Register Webhook and Start Bot Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/INDEX.md Registers a webhook URL and secret token using `setWebhook`, then starts the bot to listen for webhook updates. This allows multiple instances to start immediately. ```typescript await bot.api.setWebhook({ url: "https://example.com/webhook", secret_token: "secret", }); // Then multiple instances can start immediately await bot.start({ webhook: true }); ``` -------------------------------- ### Using AllowedUpdatesFilter Examples Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/05-types.md Demonstrates how to use the AllowedUpdatesFilter to configure bot updates. Examples include adding opt-in types, excluding specific types, and creating filters with only designated types. ```typescript // Default + opt-in to reactions bot.start({ allowedUpdates: AllowedUpdatesFilter.default.add("message_reaction"), }); // All except polls bot.start({ allowedUpdates: AllowedUpdatesFilter.all.except("poll", "poll_answer"), }); // Specific list bot.start({ allowedUpdates: AllowedUpdatesFilter.only("message", "callback_query"), }); ``` -------------------------------- ### Bun.serve Webhook Handler Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/04-webhook-handler.md Set up a webhook handler using Bun.serve. This example shows how to handle POST requests to a specific path. ```typescript import { Bot, webhookHandler } from "gramio"; const bot = new Bot(token).on("message", (ctx) => ctx.send("Hello!")); const handler = webhookHandler(bot, "bun"); Bun.serve({ port: 3000, fetch(req) { const url = new URL(req.url); if (req.method === "POST" && url.pathname === "/telegram-webhook") { return handler(req); } return new Response("Not found", { status: 404 }); }, }); await bot.start({ webhook: "https://example.com:3000/telegram-webhook" }); ``` -------------------------------- ### Start Bot with Webhook and Drop Pending Updates Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/01-bot-class.md Starts the bot using a webhook for receiving updates and configures it to drop any pending updates that arrived before the bot started. Requires a valid webhook URL. ```typescript await bot.start({ webhook: "https://example.com/webhook", dropPendingUpdates: true, }); ``` -------------------------------- ### Create a new GramIO bot project Source: https://github.com/gramiojs/gramio/blob/main/README.md Use this command to scaffold a new GramIO bot project. It allows for customization during setup. ```bash npm create gramio@latest ./bot ``` -------------------------------- ### buildAllowedUpdates Function Example Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/06-utility-functions.md Illustrates how to use `buildAllowedUpdates` to dynamically create an `AllowedUpdatesFilter` from a bot's registered handlers and then use it to start the bot. ```typescript const bot = new Bot(token) .command("start", (ctx) => ctx.send("Hi!")) .callbackQuery("data", (ctx) => ctx.answerCallbackQuery()) .on("inline_query", (ctx) => ctx.answer([])); // Build filter from handlers const allowed = buildAllowedUpdates(bot); // → ["message", "business_message", "callback_query", "inline_query"] // Use with .start() await bot.start({ allowedUpdates: buildAllowedUpdates(bot), }); // Customize before starting await bot.start({ allowedUpdates: buildAllowedUpdates(bot).add("poll"), }); ``` -------------------------------- ### onStart() Hook Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/01-bot-class.md Executes code after the bot has successfully started, typically after calling `.start()` or `.init()`. It provides information about the bot's environment, plugins, and startup details. ```APIDOC ## onStart() ### Description Execute when bot starts (after `.start()` or `.init()`). ### Method Signature ```typescript onStart(handler: Hooks.OnStart): this ``` ### Example ```typescript bot.onStart(({ plugins, info, updatesFrom, bot }) => { console.log(`Bot @${info.username} started via ${updatesFrom}`); console.log(`Plugins: ${plugins.join(", ")}`); }); ``` ``` -------------------------------- ### Start Bot with Specific Allowed Updates (Filter) Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/01-bot-class.md Starts the bot and configures it to receive only specific types of updates using a filter. This can optimize performance by ignoring irrelevant update types. ```typescript await bot.start({ allowedUpdates: AllowedUpdatesFilter.default.add("poll"), }); ``` -------------------------------- ### init() Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/01-bot-class.md Initializes the bot. It automatically calls `getMe` if bot information is not provided. This method is typically called automatically by `.start()` but can be invoked manually if needed before starting the bot. ```APIDOC ## init() ### Description Initialize bot (call `getMe` if info not provided). ### Method `init(): Promise` ### Usage Called automatically by `.start()`. Only call manually if needed before starting. ``` -------------------------------- ### Complete Plugin Example with Rate Limiting Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/02-plugin-class.md Demonstrates creating a custom plugin with a rate limiting macro, custom error handling, derived state, and a status command. The plugin is then extended to a bot, enabling the throttle on a specific command and handling the custom error. ```typescript import { Plugin, type Context } from "gramio"; // Define a custom error class RateLimitError extends Error { constructor(public retryAfter: number) { super(`Rate limited, retry after ${retryAfter}s`); } } // Create plugin const rateLimitPlugin = new Plugin("rate-limit", { dependencies: [], // no dependencies }) .macro("throttle", { preHandler: (ctx, next) => { // Rate limit logic return next(); }, }) .error("RATE_LIMIT", RateLimitError) .derive(() => { const callCount = new Map(); return { callCount }; }) .command("status", (ctx) => { ctx.send("Plugin loaded!"); }); // Extend bot with plugin const bot = new Bot(token) .extend(rateLimitPlugin) .command("start", (ctx) => { ctx.send("Welcome!"); }, { throttle: true }) .onError(({ kind, error }) => { if (kind === "RATE_LIMIT") { console.log("User hit rate limit"); } }); ``` -------------------------------- ### Start Bot with Long-Polling Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/01-bot-class.md Initiates bot operation using long-polling with default settings. This is the simplest way to start receiving updates. ```typescript await bot.start(); // Long-polling with default settings ``` -------------------------------- ### Start Bot with Various Options Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/07-configuration.md Initiates the bot with a combination of webhook, long polling, pending update handling, webhook deletion, and allowed update types. ```typescript await bot.start({ webhook: "https://example.com/webhook", longPolling: { limit: 100 }, dropPendingUpdates: false, deleteWebhook: "on-conflict-with-polling", allowedUpdates: AllowedUpdatesFilter.default, }); ``` -------------------------------- ### Plugin onStart Hook Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/02-plugin-class.md Register a handler for the onStart hook. This hook is executed when the plugin is started. ```typescript onStart(handler: Hooks.OnStart): this ``` -------------------------------- ### Start Bot with Strict Allowed Updates Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/01-bot-class.md Starts the bot and configures it to receive only updates for which handlers are strictly registered. This ensures the bot only processes relevant events. ```typescript await bot.start({ allowedUpdates: "strict", // Only registered handlers }); ``` -------------------------------- ### Configure Bot for Webhook Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/04-webhook-handler.md Set up your bot to use webhook handlers by configuring the Bot.start() method with a webhook URL. This example shows how to integrate with an Express.js server. ```typescript const bot = new Bot(token); // Add handlers... // Option 1: Start with long-polling // await bot.start(); // Option 2: Switch to webhook if (process.env.WEBHOOK_URL) { // Set up web server with webhookHandler app.post("/webhook", webhookHandler(bot, "express")); // Start bot with webhook await bot.start({ webhook: process.env.WEBHOOK_URL, deleteWebhook: "on-conflict-with-polling", // Auto-clean old polling }); } else { // Fallback to long-polling await bot.start(); } ``` -------------------------------- ### Command Metadata with Locales Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/07-configuration.md Example of defining command metadata with a required description and optional localized descriptions. ```typescript locales: { ru: "Запустить бота", es: "Iniciar bot", } ``` -------------------------------- ### Example of Syncing Commands with Options Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/07-configuration.md Demonstrates how to use the SyncCommandsOptions to configure command synchronization, including providing a custom Redis-based storage, enabling scope cleaning, and excluding a 'secret' command. ```typescript await bot.syncCommands({ storage: { get(key) { return redis.get(key); }, set(key, value) { redis.set(key, value); }, }, cleanUnusedScopes: true, exclude: ["secret"], }); ``` -------------------------------- ### AllowedUpdatesFilter Usage Examples Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/06-utility-functions.md Demonstrates various ways to use the `AllowedUpdatesFilter` to configure bot startup with different sets of allowed updates, including defaults, all types, and custom combinations. ```typescript import { AllowedUpdatesFilter } from "gramio"; // Telegram's defaults bot.start({ allowedUpdates: AllowedUpdatesFilter.default }); // All including opt-in bot.start({ allowedUpdates: AllowedUpdatesFilter.all }); // Customize bot.start({ allowedUpdates: AllowedUpdatesFilter.default .add("message_reaction") .except("poll", "poll_answer"), }); // Explicit list bot.start({ allowedUpdates: AllowedUpdatesFilter.only( "message", "callback_query", "inline_query" ), }); ``` -------------------------------- ### Basic GramIO Bot with Start Command Source: https://github.com/gramiojs/gramio/blob/main/README.md A simple GramIO bot that responds to the /start command and logs a message when it begins operation. Ensure your bot token is set in the environment variable `TOKEN`. ```typescript import { Bot } from "gramio"; const bot = new Bot(process.env.TOKEN as string) .command("start", (context) => context.send("Hello!")) .onStart(({ info }) => console.log(`✨ Bot ${info.username} was started!`)); bot.start(); ``` -------------------------------- ### BotStartOptions Interface Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/05-types.md Specifies options for starting the bot, controlling webhook or long-polling behavior, and update filtering. ```typescript interface BotStartOptions { /** Webhook URL or config (omit for long-polling) */ webhook?: true | string | Omit; /** Long-polling options */ longPolling?: Omit, "allowed_updates" | "offset"> /** Drop updates that arrived before bot started */ dropPendingUpdates?: boolean; /** Delete existing webhook before polling */ deleteWebhook?: boolean | "on-conflict-with-polling"; // default: "on-conflict-with-polling" /** Which update types to receive */ allowedUpdates?: AllowedUpdates | "strict" | AllowedUpdatesFilter; } ``` -------------------------------- ### detectOptInUpdates Function Example Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/06-utility-functions.md Demonstrates using `detectOptInUpdates` to find registered opt-in handlers and then combining them with the default allowed updates filter for bot startup. ```typescript const bot = new Bot(token) .on("message_reaction", (ctx) => { ctx.send("Reaction!"); }) .on("chat_member", (ctx) => { ctx.send("Member status changed"); }); const optIn = detectOptInUpdates(bot.updates.composer.registeredEvents()); // → ["message_reaction", "chat_member"] // Telegram default set + auto opt-in await bot.start({ allowedUpdates: AllowedUpdatesFilter.default.add(...optIn), }); ``` -------------------------------- ### On-Start Hook for Bot Initialization Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/01-bot-class.md Execute custom logic when the bot starts using the `onStart` hook. This hook provides information about the bot's environment, plugins, and update sources. ```typescript onStart(handler: Hooks.OnStart): this ``` ```typescript bot.onStart(({ plugins, info, updatesFrom, bot }) => { console.log(`Bot @${info.username} started via ${updatesFrom}`); console.log(`Plugins: ${plugins.join(", ")}`); }); ``` -------------------------------- ### Lazy Loading Plugin Example Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/02-plugin-class.md Shows how to extend a bot with a plugin that is loaded asynchronously using a Promise. The plugin is resolved and initialized during the bot's startup process. ```typescript const plugin = new Promise((resolve) => { setTimeout(() => { resolve(new Plugin("lazy").command("delayed", (ctx) => { ctx.send("Loaded!"); })); }, 1000); }); const bot = new Bot(token) .extend(plugin) // Returns immediately .command("start", (ctx) => ctx.send("Hi!")); await bot.start(); // Plugin loads during init() ``` -------------------------------- ### Synchronizing Commands Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/07-configuration.md Example of synchronizing commands with Telegram after bot initialization. This is typically done within an asynchronous startup function. ```typescript bot.onStart(async () => { await bot.syncCommands(); }); ``` -------------------------------- ### Start Bot with Long-Polling Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/08-quick-start.md Launches a Gramio.js bot using the default long-polling method. Shows basic and advanced configuration options for long-polling. ```typescript const bot = new Bot(process.env.BOT_TOKEN!); bot.command("start", (ctx) => ctx.send("Hello!")); // Simplest: use defaults await bot.start(); // With options await bot.start({ longPolling: { timeout: 60, limit: 50 }, allowedUpdates: "strict", }); ``` -------------------------------- ### Register Command with Locales and Sync Commands Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/INDEX.md Defines a bot command with a description and localized text, and sets up a listener to automatically synchronize commands when the bot starts. ```typescript bot.command("start", { description: "Start bot", locales: { ru: "Запустить бота" }, }, handler); bot.onStart(() => bot.syncCommands()); ``` -------------------------------- ### GramIO Production Bot Configuration Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/07-configuration.md Configure your bot for production using environment variables for token, API URLs, and starting via webhook. The bot will sync commands and log its startup. ```typescript const bot = new Bot({ token: process.env.BOT_TOKEN!, info: { // Skip getMe call in serverless environment id: 123456789, is_bot: true, first_name: "MyBot", username: "mybotname", }, api: { baseURL: process.env.BOT_API_URL || "https://api.telegram.org/bot", fetchOptions: { timeout: 30000, }, }, files: { baseURL: process.env.FILES_URL || "https://files.example.com", }, }); bot.onStart(async ({ info, updatesFrom }) => { console.log(`Production bot @${info.username} started via ${updatesFrom}`); await bot.syncCommands({ cleanUnusedScopes: true }); }); // Start via webhook in production await bot.start({ webhook: process.env.WEBHOOK_URL, allowedUpdates: AllowedUpdatesFilter.default, }); ``` -------------------------------- ### GramIO Development Bot Configuration Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/07-configuration.md Set up your bot for development using long-polling. Includes a middleware for logging request details and starts with pending updates dropped. ```typescript const bot = new Bot(process.env.BOT_TOKEN || ""); bot.use((ctx, next) => { console.log(`[${new Date().toISOString()}] ${ctx.type}`); return next(); }); bot.onStart(({ info }) => { console.log(`Development bot @${info.username} started`); }); // Start via long-polling in development await bot.start({ dropPendingUpdates: true, // Don't clutter logs allowedUpdates: "strict", // Only registered handlers }); ``` -------------------------------- ### Default Webhook Handler Setup Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/07-configuration.md Shows the default configuration for a webhook handler, which processes updates asynchronously without waiting for completion and without a secret token. ```typescript // Default (fast, async) fastify.post("/webhook", webhookHandler(bot, "fastify")); ``` -------------------------------- ### Hono Webhook Handler Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/04-webhook-handler.md Integrate gramio webhook handler with Hono. This example uses the @hono/node-server for running the Hono app. ```typescript import { Hono } from "hono"; import { serve } from "@hono/node-server"; import { Bot, webhookHandler } from "gramio"; const bot = new Bot(token).on("message", (ctx) => ctx.send("Hello!")); const app = new Hono(); app.post("/telegram-webhook", webhookHandler(bot, "hono")); serve(app, { port: 3000 }); await bot.start({ webhook: "https://example.com:3000/telegram-webhook" }); ``` -------------------------------- ### GramIO Bot with User Context and Formatted Messages Source: https://github.com/gramiojs/gramio/blob/main/README.md This example demonstrates deriving user context before handling messages and sending formatted responses using `format`, `bold`, and `code`. It assumes a `findOrRegisterUser` utility function exists. ```typescript import { Bot, format, bold, code } from "gramio"; import { findOrRegisterUser } from "./utils"; const bot = new Bot(process.env.BOT_TOKEN as string) .derive("message", async () => { const user = await findOrRegisterUser(); return { user, }; }) .on("message", (context) => { context.user; // typed return context.send(format` Hi, ${bold(context.user.name)}! You balance: ${code(context.user.balance)}`); }); ``` -------------------------------- ### Deno std/http Webhook Handler Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/04-webhook-handler.md Integrate gramio webhook handler with Deno's std/http module. This example uses Deno.serve for handling requests. ```typescript import { Bot, webhookHandler } from "gramio"; const bot = new Bot(token).on("message", (ctx) => ctx.send("Hello!")); const handler = webhookHandler(bot, "std/http"); Deno.serve({ port: 3000 }, async (req) => { const url = new URL(req.url); if (req.method === "POST" && url.pathname === "/telegram-webhook") { return await handler(req); } return new Response("Not found", { status: 404 }); }); await bot.start({ webhook: "https://example.com:3000/telegram-webhook" }); ``` -------------------------------- ### Hono Webhook with Multiple Routes Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/04-webhook-handler.md Integrate Gramio's webhook handler with Hono, a lightweight web framework. This example demonstrates setting up a dedicated webhook endpoint alongside health and status checks. ```typescript import { Hono } from "hono"; import { serve } from "@hono/node-server"; import { Bot, webhookHandler } from "gramio"; const bot = new Bot(process.env.BOT_TOKEN!); const app = new Hono(); // Webhook endpoint app.post("/tg-webhook", webhookHandler(bot, "hono")); // Health check app.get("/health", (c) => c.text("OK")); // Status endpoint app.get("/status", async (c) => { if (!bot.info) { return c.json({ status: "not_started" }, 503); } return c.json({ status: "running", bot: bot.info.username, }); }); serve(app); ``` -------------------------------- ### Example Usage of Handler Type Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/05-types.md Illustrates how to declare and use a handler function with a specific context type. The handler can perform actions before and after calling the next middleware. ```typescript const handler: Handler > = async (ctx, next) => { console.log("Before"); const result = await next(); console.log("After"); return result; }; bot.on("message", handler); ``` -------------------------------- ### Horizontal Scaling with Pre-loaded Bot Info Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/08-quick-start.md Configure Gramio for horizontal scaling by pre-loading bot information to avoid redundant `getMe` calls. This allows multiple instances to start immediately. ```typescript // Use pre-loaded bot info to skip getMe call const bot = new Bot({ token: process.env.BOT_TOKEN!, info: { id: 123456789, is_bot: true, first_name: "Bot", username: "mybotname", }, }); // Register webhook once (outside app) // await bot.api.setWebhook({ url: "https://load-balancer/webhook" }); // Multiple instances can now start immediately await bot.start({ webhook: true }); ``` -------------------------------- ### Handle Messages with Start Payload using filters.startPayload Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/03-filters.md Use `filters.startPayload` to process messages that contain a parsed `/start` command payload. The payload is accessible via `ctx.startPayload`. ```typescript bot.on(filters.startPayload, (ctx) => { ctx.startPayload; // string ctx.send("Start payload: " + ctx.startPayload); }); ``` -------------------------------- ### Instantiate Bot with Token Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/01-bot-class.md Creates a new Bot instance using only the Telegram bot token. Ensure the token is securely provided, for example, via environment variables. ```typescript const bot = new Bot(process.env.TOKEN || ""); ``` -------------------------------- ### Initialize Bot with Token and Info Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/07-configuration.md Instantiate the Bot class with the bot's access token and basic bot information. ```typescript const bot = new Bot({ token: "YOUR_BOT_TOKEN", info: { id: 123, is_bot: true, first_name: "MyBot", username: "mybot", }, }); ``` -------------------------------- ### startParameter() Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/01-bot-class.md Registers a handler specifically for `/start` commands that include a particular parameter. The parameter can be a string, an array of strings, or a regular expression. ```APIDOC ## startParameter() ### Description Register handler for `/start` messages with a specific payload. ### Method Signature ```typescript startParameter & { rawStartPayload: string }, Macros> = {}>(parameter: RegExp | string | string[], handler: Handler & { rawStartPayload: string } & DeriveFromOptions>, options?: TOptions): this ``` ### Example ```typescript bot.startParameter("hello", (ctx) => { ctx.send("You started with: hello"); }); bot.startParameter(/^ref_(.+)$/, (ctx) => { const ref = ctx.rawStartPayload; ctx.send(`Reference: ${ref}`); }); ``` ``` -------------------------------- ### Get File Link with Custom Base URL Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/06-utility-functions.md Demonstrates how to get a shareable file link when a custom `baseURL` is configured for file downloads. The resulting URL will not contain the bot token. ```typescript bot.on("message", async (ctx) => { if (!ctx.document) return; const url = await bot.getFileLink(ctx.document.file_id); console.log("Public URL:", url); // https://files.example.com/... }); ``` -------------------------------- ### Initialize Bot with Pre-Loaded Info Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/INDEX.md Initializes a new Bot instance with pre-loaded bot information, useful in serverless or scaling environments where calling `getMe` might be expensive. ```typescript const bot = new Bot({ token, info: { id: 123, is_bot: true, first_name: "Bot", username: "mybot" }, }); ``` -------------------------------- ### Registering `/start` Parameter Handlers with `startParameter()` Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/01-bot-class.md Handle `/start` commands with specific parameters using `startParameter()`. This method allows matching against exact strings, arrays of strings, or regular expressions, providing access to the raw payload. ```typescript bot.startParameter("hello", (ctx) => { ctx.send("You started with: hello"); }); ``` ```typescript bot.startParameter(/^ref_(.+)$/, (ctx) => { const ref = ctx.rawStartPayload; ctx.send(`Reference: ${ref}`); }); ``` -------------------------------- ### Accessing Specific Context Type Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/INDEX.md Demonstrates how to get the specific context type for a given update, such as 'message'. ```typescript type MessageContext = ContextType; ``` -------------------------------- ### Register a simple command handler Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/01-bot-class.md Shows how to register a handler for a specific command (e.g., '/start') using `bot.command()`. It demonstrates accessing command arguments. ```typescript bot.command("start", (ctx) => { ctx.args; // string or null ctx.send("Hello " + (ctx.args || "World")); }); ``` -------------------------------- ### Express Webhook Handler Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/04-webhook-handler.md Integrate gramio webhook handler with Express. This is a common setup for Node.js applications. ```typescript import express from "express"; import { Bot, webhookHandler } from "gramio"; const bot = new Bot(token).on("message", (ctx) => ctx.send("Hello!")); const app = express(); app.post("/telegram-webhook", webhookHandler(bot, "express")); app.listen(3000); await bot.start({ webhook: "https://example.com:3000/telegram-webhook" }); ``` -------------------------------- ### Elysia Webhook Handler Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/04-webhook-handler.md Integrate gramio webhook handler with Elysia. This setup is straightforward for Elysia applications. ```typescript import { Elysia } from "elysia"; import { Bot, webhookHandler } from "gramio"; const bot = new Bot(token).on("message", (ctx) => ctx.send("Hello!")); const app = new Elysia(); app.post("/telegram-webhook", webhookHandler(bot, "elysia")); app.listen(3000); await bot.start({ webhook: "https://example.com:3000/telegram-webhook" }); ``` -------------------------------- ### Koa Webhook Handler Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/04-webhook-handler.md Integrate gramio webhook handler with Koa. This example uses @koa/router for defining routes. ```typescript import Koa from "koa"; import Router from "@koa/router"; import { Bot, webhookHandler } from "gramio"; const bot = new Bot(token).on("message", (ctx) => ctx.send("Hello!")); const app = new Koa(); const router = new Router(); router.post("/telegram-webhook", webhookHandler(bot, "koa")); app.use(router.routes()); app.listen(3000); await bot.start({ webhook: "https://example.com:3000/telegram-webhook" }); ``` -------------------------------- ### Get File Link with Gramio Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/01-bot-class.md Use `bot.getFileLink()` to obtain a shareable, token-less download URL for a file if `files.baseURL` is configured. ```typescript bot.on("message", async (ctx) => { if (!ctx.document) return; const link = await bot.getFileLink(ctx.document.file_id); await ctx.reply(`Download: ${link}`); }); ``` -------------------------------- ### Instantiate Bot with Options Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/01-bot-class.md Creates a new Bot instance with a token and custom API configuration, including a pre-loaded bot info object and a local API base URL. ```typescript const bot2 = new Bot({ token: process.env.TOKEN || "", info: { id: 123, is_bot: true, first_name: "MyBot" }, api: { baseURL: "http://localhost:8081/bot" }, }); ``` -------------------------------- ### Negate a Filter with NOT Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/03-filters.md Use `filters.not()` to exclude messages that match a specific filter. This example triggers for messages not sent by a bot. ```typescript const notBot = filters.not(filters.isBot); bot.on(notBot, (ctx) => { ctx.send("Real user!"); // Boolean filter, no narrowing }); ``` -------------------------------- ### Create Inline Keyboard with Buttons Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/08-quick-start.md Responds to the /start command by sending a message with inline buttons. Handles callback queries from button presses. ```typescript import { InlineKeyboard } from "gramio"; bot.command("start", (ctx) => ctx.send("Choose:", { reply_markup: new InlineKeyboard() .text("Option 1", "opt1") .text("Option 2", "opt2"), }) ); bot.callbackQuery("opt1", (ctx) => { ctx.answerCallbackQuery({ text: "You chose 1" }); ctx.editText("Option 1 selected"); }); ``` -------------------------------- ### Handle Basic Text Messages Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/08-quick-start.md Echoes back any non-command text message received by the bot. Skips messages starting with '/'. ```typescript bot.on("message", (ctx) => { if (ctx.text?.startsWith("/")) return; // Skip commands ctx.send("Echo: " + ctx.text); }); ``` -------------------------------- ### Configure Bot File Handling Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/07-configuration.md Set up custom URLs for serving files, local storage directories, and file download strategies. ```typescript const bot = new Bot(token, { files: { baseURL: "https://files.example.com", // Public file server URL localDir: "/var/lib/telegram-bot-api", // Bot API working directory mountDir: "/mnt/bot-files", // Mount path (if different from localDir) source: "auto", // File download strategy }, }); ``` -------------------------------- ### Bot Initialization Options Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/INDEX.md Configure the bot with various options during initialization. This includes API settings, file handling, plugins, and bot information. ```typescript new Bot(token, { api: { baseURL, useTest, retryGetUpdatesWait, fetchOptions }, files: { baseURL, localDir, mountDir, source }, plugins: { format }, info: { id, is_bot, username }, }) ``` -------------------------------- ### Set Up Webhook with Express Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/08-quick-start.md Configures a Gramio.js bot to receive updates via webhooks using an Express server. Requires BOT_TOKEN and a public URL. ```typescript import express from "express"; import { Bot, webhookHandler } from "gramio"; const bot = new Bot(process.env.BOT_TOKEN!); const app = express(); bot.command("start", (ctx) => ctx.send("Hello!")); app.post("/webhook", webhookHandler(bot, "express")); app.listen(3000); await bot.start({ webhook: "https://example.com/webhook", }); ``` -------------------------------- ### BotOptions Interface Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/05-types.md Defines the configuration options for initializing a Gramio Bot instance. Includes token, API settings, and file handling configurations. ```typescript interface BotOptions { /** Bot token */ token: string; /** Pre-loaded bot info (skips getMe call) */ info?: TelegramUser; /** Plugin configuration */ plugins?: { format?: boolean; // default: true }; /** API configuration */ api: { baseURL?: string; // default: "https://api.telegram.org/bot" useTest?: boolean; // default: false retryGetUpdatesWait?: number; // default: 1000 fetchOptions?: Parameters[1]; }; /** File download/serving options */ files?: { source?: FileSource; // "auto" | "fetch" | "disk" | "rewrite" baseURL?: string; localDir?: string; // default: "/var/lib/telegram-bot-api" mountDir?: string; }; } ``` -------------------------------- ### Get File Shareable Link with Gramio Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/08-quick-start.md Obtain a shareable URL for a file sent to the bot. This is useful for providing direct download links. ```typescript // Get shareable link bot.on("message", async (ctx) => { if (!ctx.document) return; const url = await bot.getFileLink(ctx.document); ctx.reply(`Download: ${url}`); }); ``` -------------------------------- ### Combine Filters with OR Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/03-filters.md Use `filters.or()` to create a filter that matches if any of the provided conditions are met. This example matches messages from public chat types. ```typescript const publicChat = filters.or( filters.chat("group"), filters.chat("supergroup"), filters.chat("channel") ); bot.on(publicChat, (ctx) => { ctx.chatType; // "group" | "supergroup" | "channel" ctx.send("Public message"); }); ``` -------------------------------- ### Create Reply Keyboards Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/06-utility-functions.md Use the `ReplyKeyboard` class to build keyboards with buttons that send text messages or request user contact information. Import `ReplyKeyboard` from `@gramio/keyboards`. ```typescript import { ReplyKeyboard } from "gramio"; const keyboard = new ReplyKeyboard() .text("Option 1") .text("Option 2") .requestContact("Share contact"); ctx.send("Choose:", { reply_markup: keyboard }); ``` -------------------------------- ### Cloudflare Workers Webhook Handler Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/04-webhook-handler.md Implement a webhook handler for Cloudflare Workers. This example exports a fetch handler to process incoming requests. ```typescript import { Bot, webhookHandler } from "gramio"; const bot = new Bot(token).on("message", (ctx) => ctx.send("Hello!")); const handler = webhookHandler(bot, "cloudflare"); export default { async fetch(request: Request) { const url = new URL(request.url); if (request.method === "POST" && url.pathname === "/webhook") { return await handler(request); } return new Response("Not found", { status: 404 }); }, }; ``` -------------------------------- ### AllowedUpdatesFilter Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/06-utility-functions.md A fluent builder for constructing `allowed_updates` lists, providing static methods to get all or default types, and instance methods to add or remove types. ```APIDOC ## Class: AllowedUpdatesFilter ### Description Fluent builder for constructing `allowed_updates` lists. ### Static Methods #### `all` Returns an `AllowedUpdatesFilter` containing all 24 update types, including opt-in types. #### `default` Returns an `AllowedUpdatesFilter` containing Telegram's default set of 21 update types, excluding opt-in types. #### `only(...types: AllowedUpdateName[])` Creates an `AllowedUpdatesFilter` containing only the specified `types`. ### Instance Methods #### `add(...types: AllowedUpdateName[])` Returns a new `AllowedUpdatesFilter` with the specified `types` added to the existing filter. #### `except(...types: AllowedUpdateName[])` Returns a new `AllowedUpdatesFilter` with the specified `types` removed from the existing filter. #### `toArray()` Converts the `AllowedUpdatesFilter` to a plain `AllowedUpdateName[]` array. ``` -------------------------------- ### Registering multiple commands with advanced scope configuration Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/01-bot-class.md Demonstrates registering multiple commands under a single handler and configuring their visibility scopes using `bot.command()` with metadata. ```typescript bot.command( ["cmd1", "cmd2"], { description: "Multi-command", scopes: ["default", "all_private_chats"] }, (ctx) => ctx.send("Matched!") ); ``` -------------------------------- ### Build Project with Pkgroll Source: https://github.com/gramiojs/gramio/blob/main/CLAUDE.md Build the project using pkgroll, which supports dual CJS/ESM output. ```bash bunx pkgroll ``` -------------------------------- ### Registering middleware for all updates Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/01-bot-class.md Demonstrates how to use the `bot.use()` method to register middleware that will be executed for every incoming update. It shows logging the update type before proceeding. ```typescript bot.use((ctx, next) => { console.log("Update type:", ctx.update); return next(); }); ``` -------------------------------- ### Create Inline Keyboards Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/06-utility-functions.md Use the `InlineKeyboard` class to build keyboards with buttons that trigger callbacks, open URLs, or initiate inline queries. Import `InlineKeyboard` from `@gramio/keyboards`. ```typescript import { InlineKeyboard } from "gramio"; const keyboard = new InlineKeyboard() .text("Click me", "callback_data") .url("Visit", "https://example.com") .switchInline("Inline", "query"); ctx.send("Choose:", { reply_markup: keyboard }); ``` -------------------------------- ### Plugin Constructor Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/02-plugin-class.md Initializes a new Plugin instance. Plugins can have a name and optional dependencies on other plugins that must be extended first. ```APIDOC ## Plugin Constructor ```typescript constructor(name: string, options?: { dependencies?: string[] }) ``` ### Parameters: | Parameter | Type | Required | Description | |---|---|---|---| | name | string | ✓ | Plugin name (unique identifier) | | options.dependencies | string[] | — | Names of plugins that must be extended first | ### Example: ```typescript const myPlugin = new Plugin("my-feature"); const pluginWithDeps = new Plugin("advanced", { dependencies: ["base-plugin"], }); // Base plugin const basePlugin = new Plugin("base-plugin"); // This will throw if base-plugin isn't extended first const bot = new Bot(token) .extend(pluginWithDeps); // Error: missing base-plugin // Correct order const bot2 = new Bot(token) .extend(basePlugin) .extend(pluginWithDeps); // OK ``` ``` -------------------------------- ### Combine Filters with AND Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/03-filters.md Use `filters.and()` to combine multiple filters, ensuring all conditions are met. This example narrows the context to messages with text, entities, and specific hashtags. ```typescript import { filters } from "gramio"; const textWithHashtags = filters.and( filters.text, filters.entities, (ctx) => ctx.entities.some((e) => e.type === "hashtag") ); bot.on(textWithHashtags, (ctx) => { ctx.text; // string (narrowed) ctx.entities; // MessageEntity[] (narrowed) const hashtags = ctx.entities.filter((e) => e.type === "hashtag"); }); ``` -------------------------------- ### Handle Messages with Entities using filters.entities Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/03-filters.md Use `filters.entities` to process messages that contain any type of text entities. You can then filter these entities further, for example, to find URLs. ```typescript bot.on(filters.entities, (ctx) => { const urls = ctx.entities.filter((e) => e.type === "url"); ctx.send(`Found ${urls.length} URLs`); }); ``` -------------------------------- ### Download Files with Gramio Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/08-quick-start.md This snippet demonstrates how to download a file sent to the bot. Ensure the './downloads' directory exists. ```typescript // Download file bot.on("message", async (ctx) => { if (!ctx.document) return; const path = await bot.downloadFile(ctx.document, "./downloads/file.pdf"); ctx.reply(`Saved to: ${path}`); }); ``` -------------------------------- ### Define OnStart Hook Type Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/05-types.md Defines the type for an on-start hook, executed when the bot begins operation. It provides context including loaded plugins, user information, and the update source. ```typescript namespace Hooks { type OnStart = (context: { plugins: string[]; info: TelegramUser; updatesFrom: "webhook" | "long-polling"; bot: BotLike; }) => unknown; } ``` -------------------------------- ### Node.js HTTP Webhook Handler Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/04-webhook-handler.md Create a webhook handler using Node.js's built-in http module. This example sets up a basic HTTP server. ```typescript import http from "http"; import { Bot, webhookHandler } from "gramio"; const bot = new Bot(token).on("message", (ctx) => ctx.send("Hello!")); const handler = webhookHandler(bot, "http"); const server = http.createServer(async (req, res) => { if (req.method === "POST" && req.url === "/telegram-webhook") { await handler(req, res); } else { res.writeHead(404); res.end("Not found"); } }); server.listen(3000); await bot.start({ webhook: "https://example.com:3000/telegram-webhook" }); ``` -------------------------------- ### Configure Webhook Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/07-configuration.md Sets up the bot to use a webhook. This can be a simple URL, a full configuration object, or indicate that a webhook is already registered. ```typescript webhook?: true | string | { url: string; certificate?: InputFile; secret_token?: string; max_connections?: number; allowed_updates?: AllowedUpdates; drop_pending_updates?: boolean; } ``` ```typescript // Simple webhook await bot.start({ webhook: "https://example.com/webhook", }); ``` ```typescript // With secret token await bot.start({ webhook: { url: "https://example.com/webhook", secret_token: "my-secret", }, }); ``` ```typescript // Already registered (just start receiving) await bot.start({ webhook: true }); ``` -------------------------------- ### Registering a general message handler Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/01-bot-class.md Illustrates how to use `bot.on()` without any filters to handle all incoming 'message' updates. ```typescript // No filter bot.on("message", (ctx) => { ctx.send("Any message"); }); ``` -------------------------------- ### Handle Pending Updates Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/07-configuration.md Determines whether to receive updates that arrived while the bot was offline. Use `true` to drop old updates, typically for testing or starting fresh. ```typescript dropPendingUpdates?: boolean ``` -------------------------------- ### Automate Gramio Release with GitHub Actions Source: https://github.com/gramiojs/gramio/blob/main/CLAUDE.md Use `gh` CLI to trigger and monitor the `publish.yml` workflow for releasing Gramio. This process includes version bumping, testing, building, and publishing to npm. Ensure you have pushed version bumps to `origin/main` before triggering. ```bash # 1. bump version in package.json, commit, push to origin/main git push origin main # 2. kick off the workflow (workflow_dispatch) gh workflow run publish.yml --repo gramiojs/gramio --ref main # 3. grab the run id and watch it until it exits gh run list --repo gramiojs/gramio --workflow=publish.yml --limit 1 gh run watch --repo gramiojs/gramio --exit-status # on failure, pull only the error lines (avoid dumping the full log) gh run view --repo gramiojs/gramio --log-failed | grep "error TS" # confirm the new version landed on npm curl -s https://registry.npmjs.org/gramio/latest | jq -r .version ``` -------------------------------- ### Download File with Gramio Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/01-bot-class.md Use `ctx.download()` to save files to local storage or retrieve them as an ArrayBuffer. Specify a path to save locally, otherwise, it returns a buffer. ```typescript bot.on("message", async (ctx) => { if (!ctx.document) return; const filePath = await ctx.download("my-file.pdf"); const buffer = await ctx.download(); }); ``` -------------------------------- ### Filter messages by multiple criteria using .on() Source: https://github.com/gramiojs/gramio/blob/main/_autodocs/08-quick-start.md Combine update type filtering with specific filters. This example replies to voice messages when the update type is 'message'. ```typescript bot.on("message", filters.voice, (ctx) => ctx.reply("Voice!")); ```