### Basic Bot with Middleware Source: https://grammy.dev/guide/middleware This example demonstrates a basic bot setup using middleware for sessions, commands, and text/photo handling. Middleware is executed in the order it's registered. ```typescript const bot = new Bot(""); bot.use(session()); bot.command("start", (ctx) => ctx.reply("Started!")); bot.command("help", (ctx) => ctx.reply("Help text")); bot.on(":text", (ctx) => ctx.reply("Text!")); // (*) bot.on(":photo", (ctx) => ctx.reply("Photo!")); bot.start(); ``` -------------------------------- ### Full TypeScript Setup with Custom Context Source: https://grammy.dev/guide/context This comprehensive example integrates middleware for context customization, custom type definitions, bot instantiation with the custom type, and a handler that utilizes the custom context properties. ```typescript const BOT_DEVELOPER = 123456; // bot developer chat identifier // Define custom context type. interface BotConfig { botDeveloper: number; isDeveloper: boolean; } type MyContext = Context & { config: BotConfig; }; const bot = new Bot(""); // Set custom properties on context objects. bot.use(async (ctx, next) => { ctx.config = { botDeveloper: BOT_DEVELOPER, isDeveloper: ctx.from?.id === BOT_DEVELOPER, }; await next(); }); // Define handlers for custom context objects. bot.command("start", async (ctx) => { if (ctx.config.isDeveloper) await ctx.reply("Hi mom!"); else await ctx.reply("Welcome"); }); ``` -------------------------------- ### Full JavaScript Setup with Custom Context Source: https://grammy.dev/guide/context This JavaScript example demonstrates setting custom properties on the context object using middleware and defining a command handler that accesses these properties. Note that TypeScript type definitions are not applicable here. ```javascript const BOT_DEVELOPER = 123456; // bot developer chat identifier const bot = new Bot(""); // Set custom properties on context objects. bot.use(async (ctx, next) => { ctx.config = { botDeveloper: BOT_DEVELOPER, isDeveloper: ctx.from?.id === BOT_DEVELOPER, }; await next(); }); // Define handlers for custom context objects. bot.command("start", async (ctx) => { if (ctx.config.isDeveloper) await ctx.reply("Hi mom!"); else await ctx.reply("Welcome"); }); ``` -------------------------------- ### Install grammY with npm Source: https://grammy.dev/guide/getting-started Install the grammY package using npm. This command also sets up TypeScript if you are using it. ```sh # Create a new directory and change into it. mkdir my-bot cd my-bot # Set up TypeScript (skip if you use JavaScript). npm install -D typescript npx tsc --init # Install grammY. npm install grammy ``` -------------------------------- ### Initialize Deno Project Source: https://grammy.dev/guide/introduction After opening your project directory in VS Code, use this command to initialize it as a Deno project. This action should display the installed Deno version. ```bash deno init ``` -------------------------------- ### Install grammY with pnpm Source: https://grammy.dev/guide/getting-started Install the grammY package using pnpm. This command also sets up TypeScript if you are using it. ```sh # Create a new directory and change into it. mkdir my-bot cd my-bot # Set up TypeScript (skip if you use JavaScript). pnpm add -D typescript pnpm exec tsc --init # Install grammY. pnpm add grammy ``` -------------------------------- ### Install grammY with Yarn Source: https://grammy.dev/guide/getting-started Install the grammY package using Yarn. This command also sets up TypeScript if you are using it. ```sh # Create a new directory and change into it. mkdir my-bot cd my-bot # Set up TypeScript (skip if you use JavaScript). yarn add typescript -D npx tsc --init # Install grammY. yarn add grammy ``` -------------------------------- ### Complete Game Integration Example Source: https://grammy.dev/guide/games Combines listening for game callbacks with sending the game using `replyWithGame` and a custom keyboard. Ensure proper error handling before deployment. ```typescript bot.on("callback_query:game_short_name", async (ctx) => { await ctx.answerCallbackQuery({ url: "your_game_url" }); }); bot.command("start", async (ctx) => { await ctx.replyWithGame("my_game", { reply_markup: keyboard, // Or you can use the api method here, according to your needs. }); }); ``` -------------------------------- ### Create InputFile from Local Path (Deno) Source: https://grammy.dev/guide/files Example of creating an `InputFile` instance from a local file path or a `Deno.FsFile` in a Deno environment. This is used for uploading files. ```typescript // Send a local file. new InputFile("/path/to/file"); // Send a `Deno.FsFile` instance. new InputFile(await Deno.open("/path/to/file")); ``` -------------------------------- ### Install Custom Error Handler with bot.catch Source: https://grammy.dev/guide/errors Install a custom error handler using `bot.catch` to manage errors thrown in your middleware. This example demonstrates how to differentiate between GrammyError, HttpError, and other unknown errors. ```typescript bot.catch((err) => { const ctx = err.ctx; console.error(`Error while handling update ${ctx.update.update_id}:`); const e = err.error; if (e instanceof GrammyError) { console.error("Error in request:", e.description); } else if (e instanceof HttpError) { console.error("Could not contact Telegram:", e); } else { console.error("Unknown error:", e); } }); ``` -------------------------------- ### Create InputFile from Local Path (Node.js) Source: https://grammy.dev/guide/files Example of creating an `InputFile` instance from a local file path or a read stream in a Node.js environment. This is used for uploading files. ```typescript import { createReadStream } from "fs"; // Send a local file. new InputFile("/path/to/file"); // Send from a read stream. new InputFile(createReadStream("/path/to/file")); ``` -------------------------------- ### Subclassing Context Source: https://grammy.dev/guide/context Demonstrates how to subclass the Context class to add custom properties. This approach is less flexible for plugin installation compared to middleware customization. ```typescript class MyContext extends Context { // etc } ``` -------------------------------- ### Custom Context Constructor (Deno) Source: https://grammy.dev/guide/context Provides an example of a custom context class in Deno, utilizing specific import paths for GrammY. The custom constructor is passed to the Bot options. ```typescript import { Bot, Context } from "https://deno.land/x/grammy@v1.44.0/mod.ts"; import type { Update, UserFromGetMe, } from "https://deno.land/x/grammy@v1.44.0/types.ts"; // Define a custom context class. class MyContext extends Context { // Set some custom properties. public readonly customProp: number; constructor(update: Update, api: Api, me: UserFromGetMe) { super(update, api, me); this.customProp = me.username.length * 42; } } // Pass the constructor of the custom context class as an option. const bot = new Bot("", { ContextConstructor: MyContext, }); bot.on("message", async (ctx) => { // `ctx` is now of type `MyContext`. const prop = ctx.customProp; }); bot.start(); ``` -------------------------------- ### Register Middleware with Bot (TypeScript) Source: https://grammy.dev/guide/middleware Installs a custom middleware function into the bot instance. Ensure this is done before other listeners. ```typescript bot.use(responseTime); ``` -------------------------------- ### Send Blob or Raw Binary Data with InputFile (Deno) Source: https://grammy.dev/guide/files In Deno, you can send `Blob` objects directly using `InputFile`. This example also shows sending a Buffer or an iterator yielding Buffers. ```typescript // Send a blob. const blob = new Blob(["ABC"], { type: "text/plain" }); new InputFile(blob); // Send a buffer or a byte array. const buffer = Uint8Array.from([65, 66, 67]); new InputFile(buffer); // "ABC" // Send an iterable. new InputFile(function* () { // "ABCABCABCABC" for (let i = 0; i < 4; i++) yield buffer; }); ``` -------------------------------- ### Combine Filter Queries with Commands Source: https://grammy.dev/guide/filter-queries Integrate filter queries with other Composer methods like 'command' for advanced message handling. This example handles forwarded '/help' commands. ```typescript bot.on(":forward_origin").command("help"); // forwarded /help commands ``` -------------------------------- ### Integrate grammY Bot with Oak (Deno) Source: https://grammy.dev/guide/deployment-types Integrate your grammY bot with an Oak server using Deno. Ensure Oak is installed and imported. ```typescript import { Application } from "https://deno.land/x/oak/mod.ts"; const app = new Application(); // or whatever you're using // Make sure to specify the framework you use. app.use(webhookCallback(bot, "oak")); ``` -------------------------------- ### Start Bot with Long Polling Source: https://grammy.dev/guide/deployment-types Call `bot.start()` to run your bot using a simple form of long polling. This processes all updates sequentially, making debugging easier due to the absence of concurrency. ```typescript bot.start(); ``` -------------------------------- ### Applying Error Boundary Directly to a Composer Source: https://grammy.dev/guide/errors This example shows how to apply an error boundary directly to a composer instance using `composer.errorBoundary`. The `boundaryHandler` will catch errors from middlewares installed on the `protected` composer instance (middleware B). The `errorHandler` catches errors from middleware C. ```typescript const composer = new Composer(); const protected = composer.errorBoundary(boundaryHandler); protected.use(/* B */); bot.use(composer); bot.use(/* C */); bot.catch(errorHandler); function boundaryHandler(err: BotError, next: NextFunction) { console.error("Error in B!", err); } function errorHandler(err: BotError) { console.error("Error in C!", err); } ``` -------------------------------- ### Accessing and Filtering Message Entities Source: https://grammy.dev/guide/context Demonstrates how to get all message entities using `ctx.entities()` and how to filter them by type, such as 'email' or 'phone_number'. ```typescript bot.on("message:entities", async (ctx) => { // Get all the entities. const entities = ctx.entities(); // Get the first entity's text. entities[0].text; // Get email entities. const emails = ctx.entities("email"); // Get phone and email entities. const phonesAndEmails = ctx.entities(["email", "phone_number"]); }); ``` -------------------------------- ### Get Bot Information Source: https://grammy.dev/guide/basics Retrieve information about the bot itself using `bot.api.getMe()`. ```typescript // Get information about the bot itself. const me = await bot.api.getMe(); ``` -------------------------------- ### Using `ctx.msg` Shortcut for Message Text Source: https://grammy.dev/guide/context Illustrates the use of the `ctx.msg.text` shortcut to get the text of a message, which works for both new and edited messages. ```typescript bot.on("message", async (ctx) => { // Get the text of the message. const text = ctx.msg.text; }); bot.on("edited_message", async (ctx) => { // Get the new, edited, text of the message. const editedText = ctx.msg.text; }); ``` -------------------------------- ### Configure grammY for Local Bot API Server Source: https://grammy.dev/guide/api Configure grammY to use a local Bot API server by specifying the `apiRoot` in the client options. This example assumes the server is running on localhost:8081. ```javascript const bot = new Bot("", { // <-- use the same token as before client: { apiRoot: "http://localhost:8081" }, }); ``` -------------------------------- ### Configure Webhook Reply for Specific Methods Source: https://grammy.dev/guide/deployment-types Use the `canUseWebhookReply` option to specify which methods can utilize webhook replies. This example allows webhook replies only for the `sendChatAction` method. ```typescript const bot = new Bot("", { client: { // We accept the drawback of webhook replies for typing status. canUseWebhookReply: (method) => method === "sendChatAction", }, }); ``` -------------------------------- ### Send Game via api.sendGame Source: https://grammy.dev/guide/games Use the `api.sendGame` method to send a game to a specific chat. You can obtain the `chatId` from the incoming context, for example, `ctx.from.id`. ```typescript bot.command("start", async (ctx) => { // You can get the chat identifier of the user to send your game to with `ctx.from.id`. // which gives you the chat identifier of the user who invoked the start command. const chatId = ctx.from.id; await ctx.api.sendGame(chatid, "my_game"); }); ``` -------------------------------- ### Integrate grammY Bot with Express (TypeScript) Source: https://grammy.dev/guide/deployment-types Use this snippet to integrate your grammY bot with an Express.js server using TypeScript. Ensure express is installed and imported. ```typescript import express from "express"; const app = express(); // or whatever you're using app.use(express.json()); // parse the JSON request body // "express" is also used as default if no argument is given. app.use(webhookCallback(bot, "express")); ``` -------------------------------- ### Mixing Additive and Transformative Flavors Source: https://grammy.dev/guide/context This example shows how to combine both additive and transformative context flavors. It's important to follow the specified pattern to avoid type errors, typically by applying transformative flavors to the result of combining additive flavors. ```typescript type MyContext = FlavorX< FlavorY< FlavorZ< Context & FlavorA & FlavorB & FlavorC > > >; ``` -------------------------------- ### Transformative Context Flavor Example Source: https://grammy.dev/guide/context This demonstrates a transformative context flavor where a plugin's type 'SomeFlavorA' is applied to the base 'Context' type. This is a more powerful way to modify the context compared to additive flavors. ```typescript import { Context } from "grammy"; import { SomeFlavorA } from "my-plugin"; type MyContext = SomeFlavorA; ``` -------------------------------- ### Integrate grammY Bot with Express (JavaScript) Source: https://grammy.dev/guide/deployment-types Use this snippet to integrate your grammY bot with an Express.js server using JavaScript. Ensure express is installed and imported. ```javascript const express = require("express"); const app = express(); // or whatever you're using app.use(express.json()); // parse the JSON request body // "express" is also used as default if no argument is given. app.use(webhookCallback(bot, "express")); ``` -------------------------------- ### Flavoring Context with Session Data Source: https://grammy.dev/guide/context This example shows how to declare a custom context type 'MyContext' that includes session data and how to pass this type to the Grammy Bot instance. This allows the bot to recognize and utilize the session property. ```typescript import { Context, SessionFlavor } from "grammy"; // Declare `ctx.session` to be of type `string`. type MyContext = Context & SessionFlavor; // Pass the type to your bot instance. const bot = new Bot(""); ``` -------------------------------- ### Instantiate Composer with Custom Context Type Source: https://grammy.dev/guide/context This example shows how to create a new Grammy Composer instance, specifying a custom context type 'MyContext'. This is necessary when using composers with custom context properties. ```typescript const composer = new Composer(); ``` -------------------------------- ### Instantiate Bot with Custom Context Type Source: https://grammy.dev/guide/context This example shows how to create a new Grammy bot instance, specifying the custom context type 'MyContext'. This allows TypeScript to recognize the custom properties added by middleware. ```typescript const bot = new Bot(""); ``` -------------------------------- ### Middleware Order Matters Source: https://grammy.dev/guide/middleware This example highlights the importance of middleware order. If a text handler is registered before a command handler, the command will be treated as text and handled by the text middleware, preventing the command middleware from being invoked. ```typescript const bot = new Bot(""); bot.on(":text", (ctx) => ctx.reply("Text!")); bot.command("start", (ctx) => ctx.reply("Command!")); bot.start(); ``` -------------------------------- ### Filter Commands by Chat Type Source: https://grammy.dev/guide/filter-queries Use chat type filters to restrict command handling to specific chat types, such as private chats. This example sets up '/start' and '/help' commands only for private chats. ```typescript // Only handle commands in private chats. const pm = bot.chatType("private"); pm.command("start"); pm.command("help"); ``` -------------------------------- ### Create Project Directory and Files Source: https://grammy.dev/guide/getting-started Use these shell commands to set up a new directory and an empty bot file for your Deno project. ```shell mkdir ./my-bot cd ./my-bot touch bot.ts ``` -------------------------------- ### Create Bot Project Directory Source: https://grammy.dev/guide/introduction Use this command to create a new directory for your bot project and navigate into it. Ensure you have 'code' command available in your PATH. ```bash mkdir ./my-bot cd ./my-bot code . ``` -------------------------------- ### Run the Bot Source: https://grammy.dev/guide/getting-started Execute your compiled JavaScript bot file using Node.js. ```sh node bot.js ``` -------------------------------- ### Handle Commands and Text Matches Source: https://grammy.dev/guide/basics Handle specific commands like `/start` using `bot.command()` or match message text against strings or regular expressions with `bot.hears()`. ```typescript // Handles commands, such as /start. bot.command("start", async (ctx) => {/* ... */}); // Matches the message text against a string or a regular expression. bot.hears(/echo *(.+)?/, async (ctx) => {/* ... */}); ``` -------------------------------- ### Enable Reaction Updates in Bot Startup Source: https://grammy.dev/guide/reactions Configure your bot to receive `message_reaction` and `message_reaction_count` updates by specifying them in the `allowed_updates` array during bot startup. This is necessary for handling user reactions. ```typescript bot.start({ allowed_updates: ["message", "message_reaction", "message_reaction_count"], }); ``` -------------------------------- ### Using Middleware with grammY Bot and Composer Source: https://grammy.dev/guide/middleware Demonstrates how to register middleware functions directly with a grammY Bot instance and how to use a Composer instance to group and register multiple middleware functions. ```typescript const bot = new Bot(""); bot.use(/*...*/); bot.use(/*...*/); const composer = new Composer(); composer.use(/*...*/); composer.use(/*...*/); composer.use(/*...*/); bot.use(composer); // composer is a middleware object! bot.use(/*...*/); bot.use(/*...*/); // ... ``` -------------------------------- ### Run Deno Bot with Permissions Source: https://grammy.dev/guide/getting-started Execute your bot script using Deno, specifying the necessary permissions for network access and importing modules. The -IN flag is shorthand for --allow-import --allow-net. ```shell deno -IN bot.ts ``` -------------------------------- ### Custom Context Constructor (JavaScript) Source: https://grammy.dev/guide/context Illustrates using a custom context class in JavaScript. The custom class extends Context and its constructor is provided when initializing the Bot. ```javascript const { Bot, Context } = require("grammy"); // Define a custom context class. class MyContext extends Context { // Set some custom properties. public readonly customProp; constructor(update, api, me) { super(update, api, me); this.customProp = me.username.length * 42; } } // Pass the constructor of the custom context class as an option. const bot = new Bot("", { ContextConstructor: MyContext, }); bot.on("message", async (ctx) => { // `ctx` is now of type `MyContext`. const prop = ctx.customProp; }); bot.start(); ``` -------------------------------- ### Using the `:media` Shortcut Source: https://grammy.dev/guide/filter-queries The `:media` shortcut groups photo and video messages, allowing you to handle both types of media messages or edited channel posts with media using a single filter. ```typescript bot.on("message:media"); // photo and video messages ``` ```typescript bot.on("edited_channel_post:media"); // edited channel posts with media ``` ```typescript bot.on(":media"); // media messages or channel posts ``` -------------------------------- ### Using the `:file` Shortcut Source: https://grammy.dev/guide/filter-queries The `:file` shortcut groups all messages containing a file, ensuring that `await ctx.getFile()` will yield a file object. This includes photos, animations, documents, and more. ```typescript bot.on(":file"); // files in messages or channel posts ``` ```typescript bot.on("edit:file"); // edits to file messages or file channel posts ``` -------------------------------- ### Listen for Game Button Callback Source: https://grammy.dev/guide/games Handle game button presses by listening to the `callback_query:game_short_name` event. Use `ctx.answerCallbackQuery` to redirect the user to the game URL. ```typescript // Pass your game url here that should be already hosted on the web. bot.on("callback_query:game_short_name", async (ctx) => { await ctx.answerCallbackQuery({ url: "your_game_url" }); }); ``` -------------------------------- ### Upload Photo using InputFile in grammY Source: https://grammy.dev/guide/files Shows how to send a photo by uploading a local file using grammY's `InputFile` class. Pass an instance of `InputFile` to methods like `ctx.replyWithPhoto` to upload the file. ```typescript // Send a file via local path await ctx.replyWithPhoto(new InputFile("/tmp/picture.jpg")); // alternatively, use bot.api.sendPhoto() or ctx.api.sendPhoto() ``` -------------------------------- ### Send a Message using Bot API (Deno) Source: https://grammy.dev/guide/api Demonstrates how to send a simple message and a message with a response to a specific chat ID using the grammY API in a Deno environment. It also shows how to create a standalone Api instance. ```ts import { Api, Bot } from "https://deno.land/x/grammy@v1.44.0/mod.ts"; const bot = new Bot(""); async function sendHelloTo12345() { // Send a message to 12345. await bot.api.sendMessage(12345, "Hello!"); // Send a message and store the response, which contains info about the sent message. const sentMessage = await bot.api.sendMessage(12345, "Hello again!"); console.log(sentMessage.message_id); // Send a message without the `bot` object. const api = new Api(""); // <-- put your bot token between the "" await api.sendMessage(12345, "Yo!"); } ``` -------------------------------- ### Run Deno Bot with Environment Variable Permissions Source: https://grammy.dev/guide/getting-started Run your bot script with Deno, including permissions to allow environment variables (--allow-env) and network access/imports (--allow-import --allow-net). This is required for grammY to detect the DEBUG variable. ```shell deno -EIN bot.ts ``` -------------------------------- ### Sending a Message with Options Source: https://grammy.dev/guide/api Illustrates how to send a message with additional options, such as specifying the `parse_mode` for rich text formatting. ```APIDOC ## POST /sendMessage with Options ### Description Sends text messages with additional formatting options. ### Method POST ### Endpoint `https://api.telegram.org/bot/sendMessage` ### Parameters #### Path Parameters - **token** (string) - Required - Your bot's API token. #### Query Parameters - **chat_id** (string or number) - Required - Unique identifier for the target chat or username of the target channel (in the format `@channelusername`). - **text** (string) - Required - Text of the message to be sent. - **other** (object) - Optional - Additional options for the message. Example: `{ "parse_mode": "HTML" }`. ``` -------------------------------- ### Listen for Any Message Source: https://grammy.dev/guide/basics Use `bot.on("message")` to listen for all incoming messages. The message object is available via `ctx.message`. ```typescript bot.on("message", async (ctx) => { const message = ctx.message; // the message object }); ``` -------------------------------- ### Send a Reply Using Context Shortcut Source: https://grammy.dev/guide/context Demonstrates the shorter way to reply to a message using `ctx.reply`, which infers the chat ID automatically. This is the preferred method for simple replies. ```typescript bot.on("message", async (ctx) => { await ctx.reply("I got your message!"); }); // Or, even shorter: bot.on("message", (ctx) => ctx.reply("Gotcha!")); ``` -------------------------------- ### Using the `msg` Shortcut Source: https://grammy.dev/guide/filter-queries The `msg` shortcut is equivalent to listening for both `"message"` and `"channel_post"` events, simplifying the filtering for any new message or channel post. ```typescript bot.on("msg"); // any message or channel post ``` ```typescript bot.on("msg:text"); // exactly the same as ":text" ``` -------------------------------- ### Using bot.errorBoundary with a Composer Source: https://grammy.dev/guide/errors This snippet demonstrates how to apply an error boundary to a specific composer instance. The `boundaryHandler` will catch errors from middlewares installed on the composer, such as X, Y, and Z. The `errorHandler` catches errors from middlewares A, B, C, and D. ```typescript const bot = new Bot(""); bot.use(/* A */); bot.use(/* B */); const composer = new Composer(); composer.use(/* X */); composer.use(/* Y */); composer.use(/* Z */); bot.errorBoundary(boundaryHandler /* , Q */).use(composer); bot.use(/* C */); bot.use(/* D */); bot.catch(errorHandler); function boundaryHandler(err: BotError, next: NextFunction) { console.error("Error in Q, X, Y, or Z!", err); /* * You could call `next` if you want to run * the middleware at C in case of an error: */ // await next() } function errorHandler(err: BotError) { console.error("Error in A, B, C, or D!", err); } ``` -------------------------------- ### Send a Message using Bot API (TypeScript) Source: https://grammy.dev/guide/api Demonstrates how to send a simple message and a message with a response to a specific chat ID using the grammY API. It also shows how to create a standalone Api instance. ```ts import { Api, Bot } from "grammy"; const bot = new Bot(""); async function sendHelloTo12345() { // Send a message to 12345. await bot.api.sendMessage(12345, "Hello!"); // Send a message and store the response, which contains info about the sent message. const sentMessage = await bot.api.sendMessage(12345, "Hello again!"); console.log(sentMessage.message_id); // Send a message without the `bot` object. const api = new Api(""); // <-- put your bot token between the "" await api.sendMessage(12345, "Yo!"); } ``` -------------------------------- ### Combine Queries with AND Source: https://grammy.dev/guide/filter-queries Chain calls to bot.on() to trigger middleware only if all provided queries match. The order does not matter. ```typescript // Matches forwarded URLs bot.on("::url").on(":forward_origin" /* , ... */); // Matches photos that contain a hashtag in a photo's caption bot.on(":photo").on("::hashtag" /* , ... */); ``` -------------------------------- ### Send Game via replyWithGame Source: https://grammy.dev/guide/games Use the `replyWithGame` method to send a game to the user who invoked the command. Pass the game name as registered with BotFather. ```typescript bot.command("start", async (ctx) => { // Pass the name of the game you created in BotFather, for example "my_game". await ctx.replyWithGame("my_game"); }); ``` -------------------------------- ### Set Suggested Commands for Users Source: https://grammy.dev/guide/commands Use `bot.api.setMyCommands()` to configure a list of suggested commands that will appear in the Telegram client's text input field. This helps users discover bot functionality. ```typescript await bot.api.setMyCommands([ { command: "start", description: "Start the bot" }, { command: "help", description: "Show help text" }, { command: "settings", description: "Open settings" }, ]); ``` -------------------------------- ### Send Raw Binary Data with InputFile Source: https://grammy.dev/guide/files Use `InputFile` to send raw binary data as a Buffer or an iterator yielding Buffers. This is suitable for Node.js environments. ```typescript // Send a buffer or a byte array. const buffer = Uint8Array.from([65, 66, 67]); new InputFile(buffer); // "ABC" // Send an iterable. new InputFile(function* () { // "ABCABCABCABC" for (let i = 0; i < 4; i++) yield buffer; }); ``` -------------------------------- ### Combine Queries with OR Source: https://grammy.dev/guide/filter-queries Use an array of queries with bot.on() to trigger middleware if any of the provided queries match. The order does not matter. ```typescript // Runs if the update is about a message OR an edit to a message bot.on(["message", "edited_message"] /* , ... */); // Runs if a hashtag OR email OR mention entity is found in text or caption bot.on(["::hashtag", "::email", "::mention"] /* , ... */); ``` -------------------------------- ### Send Game with Custom Inline Keyboard Source: https://grammy.dev/guide/games Customize the game button using `InlineKeyboard.game()`. The first button in the keyboard must be the play button. ```typescript // Define a new inline keyboard. You can write any text to be shown // on the button, but make sure that the first button should always // be the play button! const keyboard = new InlineKeyboard().game("Start my_game"); // Notice that we have used game() unlike a normal inline keyboard // where we use url() or text() // Via the `replyWithGame` method await ctx.replyWithGame("my_game", { reply_markup: keyboard }); // Via the `api.sendGame` method await ctx.api.sendGame(chatId, "my_game", { reply_markup: keyboard }); ``` -------------------------------- ### Basic grammY Bot in TypeScript Source: https://grammy.dev/guide/getting-started A simple grammY bot written in TypeScript that responds to the /start command and any other messages. Remember to replace the empty string with your bot token. ```typescript import { Bot } from "grammy"; // Create an instance of the `Bot` class and pass your bot token to it. const bot = new Bot(""); // <-- put your bot token between the "" // You can now register listeners on your bot object `bot`. // grammY will call the listeners when users send messages to your bot. // Handle the /start command. bot.command("start", (ctx) => ctx.reply("Welcome! Up and running.")); // Handle other messages. bot.on("message", (ctx) => ctx.reply("Got another message!")); // Now that you specified how to handle messages, you can start your bot. // This will connect to the Telegram servers and wait for messages. // Start the bot. bot.start(); ``` -------------------------------- ### Send Formatted Message with Options Source: https://grammy.dev/guide/api Shows how to send a message with HTML formatting and specify additional options like parse mode. ```ts async function sendHelloTo12345() { await bot.api.sendMessage(12345, "Hello!", { parse_mode: "HTML", }); } ``` -------------------------------- ### Basic Grammy Bot on Deno Source: https://grammy.dev/guide/getting-started This TypeScript code initializes a Grammy bot with your token and sets up basic message handlers for '/start' commands and general messages. Ensure you replace the empty string with your actual bot token. ```typescript import { Bot } from "https://deno.land/x/grammy@v1.44.0/mod.ts"; // Create an instance of the `Bot` class and pass your bot token to it. const bot = new Bot(""); // <-- put your bot token between the "" // You can now register listeners on your bot object `bot`. // grammY will call the listeners when users send messages to your bot. // Handle the /start command. bot.command("start", (ctx) => ctx.reply("Welcome! Up and running.")); // Handle other messages. bot.on("message", (ctx) => ctx.reply("Got another message!")); // Now that you specified how to handle messages, you can start your bot. // This will connect to the Telegram servers and wait for messages. // Start the bot. bot.start(); ``` -------------------------------- ### Send a Message using Bot API (JavaScript) Source: https://grammy.dev/guide/api Demonstrates how to send a simple message and a message with a response to a specific chat ID using the grammY API. It also shows how to create a standalone Api instance. ```js const { Api, Bot } = require("grammy"); const bot = new Bot(""); async function sendHelloTo12345() { // Send a message to 12345. await bot.api.sendMessage(12345, "Hello!"); // Send a message and store the response, which contains info about the sent message. const sentMessage = await bot.api.sendMessage(12345, "Hello again!"); console.log(sentMessage.message_id); // Send a message without the `bot` object. const api = new Api(""); // <-- put your bot token between the "" await api.sendMessage(12345, "Yo!"); } ``` -------------------------------- ### Custom Context Constructor (TypeScript) Source: https://grammy.dev/guide/context Shows how to define and use a custom context class that extends GrammY's Context. The custom constructor is passed during bot instantiation. The bot's context type is automatically inferred. ```typescript import { Bot, Context } from "grammy"; import type { Update, UserFromGetMe } from "grammy/types"; // Define a custom context class. class MyContext extends Context { // Set some custom properties. public readonly customProp: number; constructor(update: Update, api: Api, me: UserFromGetMe) { super(update, api, me); this.customProp = me.username.length * 42; } } // Pass the constructor of the custom context class as an option. const bot = new Bot("", { ContextConstructor: MyContext, }); bot.on("message", async (ctx) => { // `ctx` is now of type `MyContext`. const prop = ctx.customProp; }); bot.start(); ``` -------------------------------- ### Run Deno Bot Script Source: https://grammy.dev/guide/introduction Once your bot code is written in a file (e.g., 'bot.ts'), you can execute it using this command in your terminal. Press Ctrl+C to stop the bot. ```bash deno -IN bot.ts ``` -------------------------------- ### Enable Debug Logging Source: https://grammy.dev/guide/getting-started Enable debug logging for grammY by setting the DEBUG environment variable before running your bot. ```sh export DEBUG="grammy*" ``` -------------------------------- ### Send a Reply with Telegram Reply Parameters Source: https://grammy.dev/guide/context Shows how to use `ctx.reply` to make a message a reply to a specific previous message by utilizing the `reply_parameters` option. ```typescript await ctx.reply("^ This is a message!", { reply_parameters: { message_id: ctx.msg.message_id }, }); ``` -------------------------------- ### Enable All Update Types Source: https://grammy.dev/guide/reactions To receive all possible update types, including reaction updates, import `API_CONSTANTS` and set `allowed_updates` to `API_CONSTANTS.ALL_UPDATE_TYPES`. This simplifies configuration when you need all updates. ```typescript allowed_updates: API_CONSTANTS.ALL_UPDATE_TYPES; ``` -------------------------------- ### Inspect Reaction Changes with ctx.reactions() Source: https://grammy.dev/guide/reactions Utilize the `ctx.reactions()` shortcut to easily determine which emoji were added, removed, or kept, and to check for paid reactions. This simplifies handling complex reaction changes. ```typescript bot.on("message_reaction", async (ctx) => { const { emoji, emojiAdded, emojiRemoved } = ctx.reactions(); if (emojiRemoved.includes("👍")) { // Upvote was removed! Unacceptable. if (emoji.includes("👌")) { // Still okay, do not punish await ctx.reply("I forgive you"); } else { // How dare they. await ctx.banAuthor(); } } }); ``` -------------------------------- ### Complete Response Time Middleware (JavaScript) Source: https://grammy.dev/guide/middleware A fully implemented middleware function in JavaScript that measures and logs the bot's response time. It's crucial to `await next()` to ensure proper execution order and data handling. ```javascript /** Measures the response time of the bot, and logs it to `console` */ async function responseTime(ctx, next) { // take time before const before = Date.now(); // milliseconds // invoke downstream middleware await next(); // make sure to `await`! // take time after const after = Date.now(); // milliseconds // log difference console.log(`Response time: ${after - before} ms`); } bot.use(responseTime); ``` -------------------------------- ### Handling Message Reactions Source: https://grammy.dev/guide/context Shows how to use `ctx.reactions()` to access added emojis and respond to specific reactions, like a party popper. ```typescript bot.on("message_reaction", async (ctx) => { const { emojiAdded } = ctx.reactions(); if (emojiAdded.includes("🎉")) { await ctx.reply("partY"); } }); ``` -------------------------------- ### Handle Paid Star Reactions Source: https://grammy.dev/guide/reactions Handle paid star reactions by using `bot.reaction` with an object specifying `type: "paid"`. This allows your bot to respond when a user applies a star reaction. ```typescript bot.reaction({ type: "paid" }, (ctx) => ctx.reply("Thanks!")); ``` -------------------------------- ### Complete Response Time Middleware (TypeScript) Source: https://grammy.dev/guide/middleware A fully implemented middleware function that measures and logs the bot's response time. It's crucial to `await next()` to ensure proper execution order and data handling. ```typescript /** Measures the response time of the bot, and logs it to `console` */ async function responseTime( ctx: Context, next: NextFunction, // is an alias for: () => Promise ): Promise { // take time before const before = Date.now(); // milliseconds // invoke downstream middleware await next(); // make sure to `await`! // take time after const after = Date.now(); // milliseconds // log difference console.log(`Response time: ${after - before} ms`); } bot.use(responseTime); ``` -------------------------------- ### Registering a Message Listener Source: https://grammy.dev/guide/context This snippet shows the basic structure for registering a listener that will receive a context object when a message is received. ```typescript bot.on("message", async (ctx) => { // `ctx` is the `Context` object. }); ``` -------------------------------- ### Set Webhook URL via Browser Source: https://grammy.dev/guide/deployment-types This is the URL format to set your webhook directly via a browser. Replace `` with your bot token and `` with your server's public endpoint. ```text https://api.telegram.org/bot/setWebhook?url= ``` -------------------------------- ### Compile TypeScript to JavaScript Source: https://grammy.dev/guide/getting-started Compile your TypeScript bot code into a JavaScript file using the TypeScript compiler. ```sh npx tsc ``` -------------------------------- ### Sending a Message Source: https://grammy.dev/guide/api Demonstrates how to send a simple text message to a specified chat ID using `bot.api.sendMessage`. It also shows how to capture and use the response object. ```APIDOC ## POST /sendMessage ### Description Sends text messages, apps, and games to a chat. ### Method POST ### Endpoint `https://api.telegram.org/bot/sendMessage` ### Parameters #### Path Parameters - **token** (string) - Required - Your bot's API token. #### Query Parameters - **chat_id** (string or number) - Required - Unique identifier for the target chat or username of the target channel (in the format `@channelusername`). - **text** (string) - Required - Text of the message to be sent. - **other** (object) - Optional - Additional options for the message, such as `parse_mode`. ``` -------------------------------- ### Basic grammY Bot in JavaScript Source: https://grammy.dev/guide/getting-started A simple grammY bot written in JavaScript that responds to the /start command and any other messages. Remember to replace the empty string with your bot token. ```javascript const { Bot } = require("grammy"); // Create an instance of the `Bot` class and pass your bot token to it. const bot = new Bot(""); // <-- put your bot token between the "" // You can now register listeners on your bot object `bot`. // grammY will call the listeners when users send messages to your bot. // Handle the /start command. bot.command("start", (ctx) => ctx.reply("Welcome! Up and running.")); // Handle other messages. bot.on("message", (ctx) => ctx.reply("Got another message!")); // Now that you specified how to handle messages, you can start your bot. // This will connect to the Telegram servers and wait for messages. // Start the bot. bot.start(); ``` -------------------------------- ### Importing Chat Type in Deno Source: https://grammy.dev/guide/api Import type definitions from `types.ts` when using grammY on Deno. ```typescript import { type Chat } from "https://deno.land/x/grammy@v1.44.0/types.ts"; ``` -------------------------------- ### Basic Message and Text Message Filtering Source: https://grammy.dev/guide/filter-queries Use `bot.on("message")` to catch any message, or `bot.on("message:text")` to specifically handle text messages. The latter ensures `ctx.msg.text` is always defined. ```typescript bot.on("message", async (ctx) => { // Could be undefined if the received message has no text. const text: string | undefined = ctx.msg.text; }); ``` ```typescript bot.on("message:text", async (ctx) => { // Text is always present because this handler is called when a text message is received. const text: string = ctx.msg.text; }); ``` -------------------------------- ### Combining Additive Context Flavors Source: https://grammy.dev/guide/context When using multiple additive context flavors, they can be combined using the '&' operator. The order in which they are listed does not affect the final context type. ```typescript type MyContext = Context & FlavorA & FlavorB & FlavorC; ``` -------------------------------- ### Making a Raw API Call to Send a Message Source: https://grammy.dev/guide/api Use `bot.api.raw.sendMessage` to make a direct call to the Telegram Bot API, passing parameters as an object. ```typescript async function sendHelloTo12345() { await bot.api.raw.sendMessage({ chat_id: 12345, text: "Hello!", parse_mode: "HTML", }); } ``` -------------------------------- ### Send a Basic Reply to a Message Source: https://grammy.dev/guide/context This snippet shows how to send a simple text reply to a user's message using `ctx.reply`. It automatically uses the correct chat ID. ```typescript bot.on("message", async (ctx) => { // Get the chat identifier. const chatId = ctx.msg.chat.id; // The text to reply with const text = "I got your message!"; // Send the reply. await bot.api.sendMessage(chatId, text); }); ``` -------------------------------- ### Combining Transformative Context Flavors Source: https://grammy.dev/guide/context Multiple transformative context flavors can be chained together. The order of application matters here, as each flavor transforms the result of the previous one. ```typescript type MyContext = FlavorX< FlavorY< FlavorZ > >; ``` -------------------------------- ### Access Command Arguments Source: https://grammy.dev/guide/commands When a user sends a command with arguments, such as `/add item`, the argument string can be accessed via `ctx.match`. For deep linking, `ctx.match` will contain the payload. ```typescript bot.command("add", async (ctx) => { // `item` will be "apple pie" if a user sends "/add apple pie". const item = ctx.match; }); ``` -------------------------------- ### Listen for Voice Messages in grammY Source: https://grammy.dev/guide/files This snippet shows how to listen for incoming voice messages using `bot.on('message:voice')`. It extracts voice message duration, file ID, and file path, and demonstrates replying with this information. ```typescript bot.on("message:voice", async (ctx) => { const voice = ctx.msg.voice; const duration = voice.duration; // in seconds await ctx.reply(`Your voice message is ${duration} seconds long.`); const fileId = voice.file_id; await ctx.reply("The file identifier of your voice message is: " + fileId); const file = await ctx.getFile(); // valid for at least 1 hour const path = file.file_path; // file path on Bot API server await ctx.reply("Download your own file again: " + path); }); ``` -------------------------------- ### Configuring tsconfig.json for Node.js Module Resolution Source: https://grammy.dev/guide/api Adjust your `tsconfig.json` to use `moduleResolution: "node16"` or `"nodenext"` for proper sub-path imports in Node.js. ```json { "compilerOptions": { // ... "moduleResolution": "node16" // ... } } ``` -------------------------------- ### React to Messages with `ctx.react` Source: https://grammy.dev/guide/reactions Use `ctx.react` within a handler to add an emoji reaction to the message that triggered the handler. This is the simplest way to react to the current message. ```typescript bot.command("start", (ctx) => ctx.react("😍")); bot.on("message", (ctx) => ctx.react("👍")); ``` -------------------------------- ### Middleware Function Signature (JavaScript) Source: https://grammy.dev/guide/middleware Defines the basic structure for a middleware function in JavaScript, accepting context and a next function. ```javascript /** Measures the response time of the bot, and logs it to `console` */ async function responseTime(ctx, next) { // TODO: implement } ``` -------------------------------- ### Reuse Filter Query Logic with matchFilter Source: https://grammy.dev/guide/filter-queries Import and use `matchFilter` to compile filter queries into predicate functions. This allows for reusing filter logic, such as dropping all updates that match a specific query. ```typescript // Drop all text messages or text channel posts. bot.drop(matchFilter(":text")); ```