diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
new file mode 100644
index 0000000..239f5ba
--- /dev/null
+++ b/.github/workflows/codeql.yml
@@ -0,0 +1,101 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL Advanced"
+
+on:
+ push:
+ branches: [ "main" ]
+ pull_request:
+ branches: [ "main" ]
+ schedule:
+ - cron: '39 13 * * 3'
+
+jobs:
+ analyze:
+ name: Analyze (${{ matrix.language }})
+ # Runner size impacts CodeQL analysis time. To learn more, please see:
+ # - https://gh.io/recommended-hardware-resources-for-running-codeql
+ # - https://gh.io/supported-runners-and-hardware-resources
+ # - https://gh.io/using-larger-runners (GitHub.com only)
+ # Consider using larger runners or machines with greater resources for possible analysis time improvements.
+ runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
+ permissions:
+ # required for all workflows
+ security-events: write
+
+ # required to fetch internal or private CodeQL packs
+ packages: read
+
+ # only required for workflows in private repositories
+ actions: read
+ contents: read
+
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - language: actions
+ build-mode: none
+ - language: javascript-typescript
+ build-mode: none
+ # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift'
+ # Use `c-cpp` to analyze code written in C, C++ or both
+ # Use 'java-kotlin' to analyze code written in Java, Kotlin or both
+ # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
+ # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
+ # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
+ # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
+ # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v7
+
+ # Add any setup steps before running the `github/codeql-action/init` action.
+ # This includes steps like installing compilers or runtimes (`actions/setup-node`
+ # or others). This is typically only required for manual builds.
+ # - name: Setup runtime (example)
+ # uses: actions/setup-example@v1
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v4
+ with:
+ languages: ${{ matrix.language }}
+ build-mode: ${{ matrix.build-mode }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+
+ # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
+ # queries: security-extended,security-and-quality
+
+ # If the analyze step fails for one of the languages you are analyzing with
+ # "We were unable to automatically build your code", modify the matrix above
+ # to set the build mode to "manual" for that language. Then modify this step
+ # to build your code.
+ # βΉοΈ Command-line programs to run using the OS shell.
+ # π See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
+ - name: Run manual build steps
+ if: matrix.build-mode == 'manual'
+ shell: bash
+ run: |
+ echo 'If you are using a "manual" build mode for one or more of the' \
+ 'languages you are analyzing, replace this with the commands to build' \
+ 'your code, for example:'
+ echo ' make bootstrap'
+ echo ' make release'
+ exit 1
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v4
+ with:
+ category: "/language:${{matrix.language}}"
diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml
new file mode 100644
index 0000000..9256486
--- /dev/null
+++ b/.github/workflows/docker-image.yml
@@ -0,0 +1,21 @@
+name: Docker Image CI
+
+on:
+ push:
+ branches: [ "main" ]
+ pull_request:
+ branches: [ "main" ]
+
+permissions:
+ contents: read
+
+jobs:
+
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Build the Docker image
+ run: docker build . --file Dockerfile --tag my-image-name:$(date +%s)
diff --git a/.github/workflows/hadolint.yml b/.github/workflows/hadolint.yml
new file mode 100644
index 0000000..e0c212f
--- /dev/null
+++ b/.github/workflows/hadolint.yml
@@ -0,0 +1,47 @@
+# This workflow uses actions that are not certified by GitHub.
+# They are provided by a third-party and are governed by
+# separate terms of service, privacy policy, and support
+# documentation.
+# hadoint is a Dockerfile linter written in Haskell
+# that helps you build best practice Docker images.
+# More details at https://github.com/hadolint/hadolint
+
+name: Hadolint
+
+on:
+ push:
+ branches: [ "main" ]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: [ "main" ]
+ schedule:
+ - cron: '35 17 * * 1'
+
+permissions:
+ contents: read
+
+jobs:
+ hadolint:
+ name: Run hadolint scanning
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read # for actions/checkout to fetch code
+ security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
+ actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Run hadolint
+ uses: hadolint/hadolint-action@f988afea3da57ee48710a9795b6bb677cc901183
+ with:
+ dockerfile: ./Dockerfile
+ format: sarif
+ output-file: hadolint-results.sarif
+ no-fail: true
+
+ - name: Upload analysis results to GitHub
+ uses: github/codeql-action/upload-sarif@v3
+ with:
+ sarif_file: hadolint-results.sarif
+ wait-for-processing: true
diff --git a/.github/workflows/jekyll-gh-pages.yml b/.github/workflows/jekyll-gh-pages.yml
new file mode 100644
index 0000000..67be9b0
--- /dev/null
+++ b/.github/workflows/jekyll-gh-pages.yml
@@ -0,0 +1,51 @@
+# Sample workflow for building and deploying a Jekyll site to GitHub Pages
+name: Deploy Jekyll with GitHub Pages dependencies preinstalled
+
+on:
+ # Runs on pushes targeting the default branch
+ push:
+ branches: ["main"]
+
+ # Allows you to run this workflow manually from the Actions tab
+ workflow_dispatch:
+
+# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
+# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
+concurrency:
+ group: "pages"
+ cancel-in-progress: false
+
+jobs:
+ # Build job
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ - name: Setup Pages
+ uses: actions/configure-pages@v5
+ - name: Build with Jekyll
+ uses: actions/jekyll-build-pages@v1
+ with:
+ source: ./
+ destination: ./_site
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v3
+
+ # Deployment job
+ deploy:
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: ubuntu-latest
+ needs: build
+ steps:
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v5
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 34d311f..51d4251 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -10,6 +10,9 @@ on:
pull_request:
workflow_dispatch:
+permissions:
+ contents: read
+
jobs:
entrypoint:
runs-on: ubuntu-latest
diff --git a/deploy-pages-368f82528645a54fb793d4d04e342629a3f51346.tar.gz b/deploy-pages-368f82528645a54fb793d4d04e342629a3f51346.tar.gz
new file mode 100644
index 0000000..9a55eb0
Binary files /dev/null and b/deploy-pages-368f82528645a54fb793d4d04e342629a3f51346.tar.gz differ
diff --git a/example-bot/telegram.md b/example-bot/telegram.md
new file mode 100644
index 0000000..3485430
--- /dev/null
+++ b/example-bot/telegram.md
@@ -0,0 +1,33 @@
+
+
+
+
+
+ 404 | GramIO
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/local.md b/local.md
new file mode 100644
index 0000000..4671621
--- /dev/null
+++ b/local.md
@@ -0,0 +1,280 @@
+---
+url: 'https://gramio.dev/bot-api/local.md'
+---
+
+# Local Bot API Server
+
+By default GramIO talks to Telegram's cloud Bot API at `https://api.telegram.org`. You can instead run **your own** [Telegram Bot API server](https://github.com/tdlib/telegram-bot-api) and point GramIO at it.
+
+GramIO publishes a ready-to-use image: **`ghcr.io/gramiojs/telegram-bot-api`** (also on Docker Hub as `gramiojs/telegram-bot-api`) β multi-arch, non-root, healthchecked, signed, and rebuilt automatically when upstream updates.
+
+> \[!TIP]
+> Need **user mode** (drive a real account as a userbot), message search, `getChats`, or message scheduling? Those live in the [tdlight fork](/bot-api/tdlight) β use the typed [`@gramio/tdlight`](/bot-api/tdlight) layer. For a normal bot with bigger file limits, the official image on this page is the simpler, battle-tested choice.
+
+## Why self-host
+
+| | Cloud API | Local server (`--local`) |
+|---|---|---|
+| Upload | 50 MB | **2 GB** |
+| Download | 20 MB | **unlimited** |
+| Upload from disk | β | **`file://` local path** |
+| `getFile` result | download URL | **absolute path on disk** |
+| Webhooks | HTTPS, fixed ports | **HTTP, any IP/port** |
+
+If you only need small files and standard limits, the cloud API is simpler β stick with it.
+
+## Prerequisites
+
+You need **two different credentials** β don't mix them up:
+
+| Credential | Identifies | Where to get it |
+|---|---|---|
+| `BOT_TOKEN` | your **bot** | [@BotFather](https://t.me/BotFather) β `/newbot` (you already have this) |
+| `api_id` + `api_hash` | your **application** (required to run a local server) | [my.telegram.org](https://my.telegram.org) β steps below |
+
+**Getting `api_id` / `api_hash` (one-time, ~1 min):**
+
+1. Open [my.telegram.org](https://my.telegram.org) and log in with **your Telegram account's phone number** (your own account, *not* the bot β a login code arrives in your Telegram).
+2. Click **API development tools**.
+3. Fill in any **App title** and **Short name** (platform: *Other*) β **Create application**.
+4. Copy **`api_id`** (a number) and **`api_hash`** (a long string). Keep the hash secret.
+
+Then **log out of the cloud API first** β a bot token can't be used on the cloud and a local server at the same time. Call [`logOut`](/telegram/methods/logOut) once, then start your local server. Cloud login stays unavailable for ~10 minutes afterwards.
+
+```ts twoslash
+import { Bot } from "gramio";
+
+const cloudBot = new Bot(process.env.BOT_TOKEN as string);
+// ---cut---
+// Run once on the cloud API, before switching to your local server
+await cloudBot.api.logOut();
+```
+
+## Run the server
+
+::: code-group
+
+```sh [docker run]
+docker run -d --name telegram-bot-api \
+ -e TELEGRAM_API_ID=123456 \
+ -e TELEGRAM_API_HASH=your_api_hash \
+ -p 8081:8081 \
+ -v telegram-bot-api-data:/var/lib/telegram-bot-api \
+ ghcr.io/gramiojs/telegram-bot-api:latest
+```
+
+```yaml [docker-compose.yml]
+services:
+ telegram-bot-api:
+ image: ghcr.io/gramiojs/telegram-bot-api:latest
+ restart: unless-stopped
+ environment:
+ TELEGRAM_API_ID: ${TELEGRAM_API_ID}
+ TELEGRAM_API_HASH: ${TELEGRAM_API_HASH}
+ volumes:
+ - telegram-bot-api-data:/var/lib/telegram-bot-api
+ ports:
+ - "8081:8081"
+
+volumes:
+ telegram-bot-api-data:
+```
+
+:::
+
+The image runs with `--local` enabled by default. Set `TELEGRAM_LOCAL=0` to keep the cloud-style URL download flow (see [Downloading files](#downloading-files)).
+
+The image is a small (~50 MB) Alpine build, multi-arch (`amd64` + `arm64`), non-root, and signed.
+
+## Connect GramIO
+
+Point `api.baseURL` at your server. **Keep the `/bot` suffix** β GramIO appends the token to it.
+
+```ts twoslash
+import { Bot } from "gramio";
+// ---cut---
+const bot = new Bot(process.env.BOT_TOKEN as string, {
+ api: {
+ baseURL: "http://localhost:8081/bot",
+ },
+});
+```
+
+In Docker, use the service name instead of `localhost`, e.g. `http://telegram-bot-api:8081/bot`.
+
+## Downloading files
+
+This is the part that trips people up. In `--local` mode, [`getFile`](/telegram/methods/getFile) returns an **absolute path on the server's filesystem** (e.g. `/var/lib/telegram-bot-api//documents/file_5.jpg`) β **not** a download URL.
+
+If your bot runs in a **separate container/host from the server** (the common case), it can't read that path off disk, and `ctx.download()` / `bot.downloadFile()` β which build a `β¦/file/bot/` URL β won't work against `--local`.
+
+### Easiest: the bundled file server (`FILE_SERVER=1`)
+
+The image can serve files itself β no sidecar, no extra service. Set `FILE_SERVER=1` and the container also runs an nginx that serves the working dir over HTTP at **path-based, token-less** URLs (`http://host:8080//documents/file.jpg`). It's **off by default**; one env var turns it on. This is the simplest option on single-image platforms (Coolify, Dokploy, Railway, β¦):
+
+```sh
+docker run -d --name telegram-bot-api \
+ -e TELEGRAM_API_ID=123456 \
+ -e TELEGRAM_API_HASH=your_api_hash \
+ -e FILE_SERVER=1 \
+ -p 8081:8081 -p 8080:8080 \
+ -v telegram-bot-api-data:/var/lib/telegram-bot-api \
+ ghcr.io/gramiojs/telegram-bot-api:latest
+```
+
+Then turn the absolute `file_path` into a download URL (prefix swap), pointing at the file-server port:
+
+```ts
+const file = await bot.api.getFile({ file_id: ctx.document!.fileId });
+const rel = file.file_path!.replace("/var/lib/telegram-bot-api/", "");
+const url = `http://telegram-bot-api:8080/${rel}`; // token-less
+```
+
+`FILE_SERVER_PORT` (default `8080`) changes the port. Want one process per container instead? Use the nginx **sidecar** below.
+
+### Alternative: a separate nginx sidecar
+
+Run an `nginx` sidecar that shares the server's working-dir volume **read-only** and serves it over HTTP. The URLs are path-based, so the **bot token never appears in them**.
+
+`nginx/telegram-files.conf`:
+
+```nginx
+server {
+ listen 80;
+ location / {
+ root /var/lib/telegram-bot-api; # mounted read-only
+ autoindex off;
+ }
+}
+```
+
+Compose overlay:
+
+```yaml
+services:
+ nginx:
+ image: nginx:alpine
+ depends_on:
+ telegram-bot-api:
+ condition: service_healthy
+ volumes:
+ - telegram-bot-api-data:/var/lib/telegram-bot-api:ro
+ - ./nginx/telegram-files.conf:/etc/nginx/conf.d/default.conf:ro
+ ports:
+ - "8080:80"
+```
+
+Then turn the absolute `file_path` into a download URL by swapping the working-dir prefix for the nginx base URL:
+
+```ts
+import { Bot } from "gramio";
+
+const FILES_BASE_URL = "http://localhost:8080";
+const WORK_DIR = "/var/lib/telegram-bot-api";
+
+const bot = new Bot(process.env.BOT_TOKEN as string, {
+ api: { baseURL: "http://telegram-bot-api:8081/bot" },
+});
+
+bot.on("message", async (ctx) => {
+ const fileId = ctx.document?.fileId;
+ if (!fileId) return;
+
+ const file = await bot.api.getFile({ file_id: fileId });
+ if (!file.file_path) return;
+
+ // /var/lib/telegram-bot-api/123/documents/x.pdf -> http://localhost:8080/123/documents/x.pdf
+ const rel = file.file_path.replace(`${WORK_DIR}/`, "");
+ const url = `${FILES_BASE_URL}/${rel}`;
+
+ await ctx.reply(`Download: ${url}`); // no token in this link
+});
+```
+
+nginx serves [range requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests) natively, so multi-GB downloads resume correctly. Want access control? Add HTTP basic auth, an IP allow-list, or nginx `secure_link` β all optional and off by default.
+
+### Alternatives
+
+* **Bot shares the volume.** If the bot container mounts the same volume, just read `file.file_path` off disk with `fs`/`Bun.file` β no nginx needed.
+* **Disable `--local`.** With `TELEGRAM_LOCAL=0` the server downloads files itself and serves them at the familiar `β¦/file/bot/` URL, so `ctx.download()` keeps working β but you lose 2 GB uploads and unlimited downloads.
+
+## Uploading large files
+
+A local server raises the upload limit to **2 GB** (the cloud API caps documents at 50 MB β no way around that without a local server). Against a local server a **normal upload works up to 2 GB** β nothing special required:
+
+```ts
+import { Bot, MediaUpload } from "gramio";
+
+const bot = new Bot(process.env.BOT_TOKEN as string, {
+ api: { baseURL: "http://localhost:8081/bot" },
+});
+
+bot.on("message", (ctx) =>
+ // streamed over HTTP to your local server β up to 2 GB
+ ctx.sendDocument(MediaUpload.path("./big-archive.zip")),
+);
+```
+
+If the file already lives **on the server's own disk** (bot co-located, or a shared volume), `MediaUpload.localPath()` is an **optimization** β the server reads it directly via the `file://` scheme, so the bytes never travel over HTTP:
+
+```ts
+ctx.sendDocument(MediaUpload.localPath("/var/data/big-archive.zip"));
+```
+
+See the [media upload guide](/files/media-upload) and [`sendDocument`](/telegram/methods/sendDocument).
+
+> \[!TIP]
+> For very large files prefer `MediaUpload.stream(...)` over `MediaUpload.path(...)` β the latter currently reads the whole file into memory.
+
+## Webhooks
+
+A local server accepts **HTTP** webhooks on any IP and port (the cloud API requires HTTPS on a fixed set of ports). See [Webhook](/updates/webhook).
+
+## Environment variables
+
+Every `telegram-bot-api` option is exposed as an environment variable β the rule is `--some-option` β `TELEGRAM_SOME_OPTION`.
+
+| Variable | Flag | Default | Description |
+|---|---|---|---|
+| `TELEGRAM_API_ID` *(required)* | `--api-id` | β | application identifier from [my.telegram.org](https://my.telegram.org) |
+| `TELEGRAM_API_HASH` *(required)* | `--api-hash` | β | application hash from [my.telegram.org](https://my.telegram.org) |
+| `TELEGRAM_LOCAL` | `--local` | `1` | enable local mode (set `0` to disable) |
+| `FILE_SERVER` | *(bundled nginx)* | `0` | serve the working dir over HTTP (`1` to enable) |
+| `FILE_SERVER_PORT` | *(bundled nginx)* | `8080` | port for the bundled file server |
+| `TELEGRAM_WORK_DIR` | `--dir` | `/var/lib/telegram-bot-api` | server working directory |
+| `TELEGRAM_TEMP_DIR` | `--temp-dir` | `/tmp/telegram-bot-api` | directory for temporary files |
+| `TELEGRAM_HTTP_PORT` | `--http-port` | `8081` | HTTP listening port |
+| `TELEGRAM_STAT_PORT` | `--http-stat-port` | `8082` | HTTP statistics port (the healthcheck uses it) |
+| `TELEGRAM_HTTP_IP_ADDRESS` | `--http-ip-address` | β | local IP to accept HTTP connections on |
+| `TELEGRAM_HTTP_STAT_IP_ADDRESS` | `--http-stat-ip-address` | β | local IP to accept statistics connections on |
+| `TELEGRAM_FILTER` | `--filter` | β | `/` β shard bots across servers |
+| `TELEGRAM_MAX_WEBHOOK_CONNECTIONS` | `--max-webhook-connections` | β | default max webhook connections per bot |
+| `TELEGRAM_MAX_CONNECTIONS` | `--max-connections` | β | maximum number of open file descriptors |
+| `TELEGRAM_PROXY` | `--proxy` | β | HTTP proxy for outgoing webhook requests (`http://host:port`) |
+| `TELEGRAM_LOG_FILE` | `--log` | β | path to the log file |
+| `TELEGRAM_LOG_MAX_FILE_SIZE` | `--log-max-file-size` | `2000000000` | max log file size in bytes before rotation |
+| `TELEGRAM_VERBOSITY` | `--verbosity` | β | log verbosity level |
+| `TELEGRAM_MEMORY_VERBOSITY` | `--memory-verbosity` | `3` | in-memory log verbosity level |
+| `TELEGRAM_USERNAME` | `--username` | β | effective user name to switch to |
+| `TELEGRAM_GROUPNAME` | `--groupname` | β | effective group name to switch to |
+| `TELEGRAM_CPU_AFFINITY` | `--cpu-affinity` | β | CPU affinity as a 64-bit mask |
+| `TELEGRAM_MAIN_THREAD_AFFINITY` | `--main-thread-affinity` | β | CPU affinity of the main thread |
+
+`TELEGRAM_API_ID` / `TELEGRAM_API_HASH` also accept a `_FILE` suffix to read the value from a file (Docker/Kubernetes secrets). Any extra arguments passed to the container are appended to `telegram-bot-api` verbatim.
+
+## Verify it works
+
+```sh
+# stats endpoint responds
+curl http://localhost:8082/
+
+# container is healthy
+docker inspect --format '{{.State.Health.Status}}' telegram-bot-api
+```
+
+## See also
+
+* [Download files](/files/download) β GramIO download helpers
+* [`logOut`](/telegram/methods/logOut) Β· [`close`](/telegram/methods/close) β migrate off the cloud API
+* [`getFile`](/telegram/methods/getFile) Β· [`sendDocument`](/telegram/methods/sendDocument)
+* [tdlight Bot API Server](/bot-api/tdlight) β fork with user mode, extra methods, and unlimited file size
diff --git a/src/README.md b/src/README.md
new file mode 100644
index 0000000..e2d19f5
--- /dev/null
+++ b/src/README.md
@@ -0,0 +1,41 @@
+# grammY
+
+The grammY module lets you easily write Telegram bots. Here is a quickstart for you to get started, but note that a better explanation is [in our repo on GitHub](https://github.com/grammyjs/grammY).
+
+You may also want to check out the [docs](https://grammy.dev).
+
+## Quickstart
+
+Talk to [@BotFather](https://t.me/BotFather) to create a new Telegram bot and obtain a _bot token_.
+
+Paste the following code into a new file `bot.ts`.
+
+```ts
+import { Bot } from "https://deno.land/x/grammy/mod.ts";
+
+// Create bot object
+const bot = new Bot(""); // <-- place your bot token inside this string
+
+// Listen for messages
+bot.command("start", (ctx) => ctx.reply("Welcome! Send me a photo!"));
+bot.on("message:text", (ctx) => ctx.reply("That is text and not a photo!"));
+bot.on("message:photo", (ctx) => ctx.reply("Nice photo! Is that you?"));
+bot.on(
+ "edited_message",
+ (ctx) =>
+ ctx.reply("Ha! Gotcha! You just edited this!", {
+ reply_parameters: { message_id: ctx.editedMessage.message_id },
+ }),
+);
+
+// Launch!
+bot.start();
+```
+
+**Congratulations!** You have successfully created your first Telegram bot.
+
+You can run it like so:
+
+```bash
+deno run --allow-net bot.ts
+```
diff --git a/src/api.ts b/src/api.ts
new file mode 100644
index 0000000..1c58515
--- /dev/null
+++ b/src/api.ts
@@ -0,0 +1,4219 @@
+// deno-lint-ignore-file camelcase
+import {
+ type AcceptedGiftTypes,
+ type BotCommand,
+ type ChatPermissions,
+ type InlineQueryResult,
+ type InputChecklist,
+ type InputFile,
+ type InputMedia,
+ type InputMediaAudio,
+ type InputMediaDocument,
+ type InputMediaLivePhoto,
+ type InputMediaPhoto,
+ type InputMediaVideo,
+ type InputMediaWithoutUpload,
+ type InputPaidMedia,
+ type InputPollOption,
+ type InputProfilePhoto,
+ type InputRichMessage,
+ type InputRichMessageWithoutUpload,
+ type InputSticker,
+ type InputStoryContent,
+ type KeyboardButton,
+ type LabeledPrice,
+ type MaskPosition,
+ type PassportElementError,
+ type ReactionType,
+} from "../types.ts";
+import {
+ type ApiClientOptions,
+ createRawApi,
+ type Methods,
+ type Payload,
+ type RawApi,
+ type Transformer,
+ type TransformerConsumer,
+ type WebhookReplyEnvelope,
+} from "./client.ts";
+
+/**
+ * Helper type to derive remaining properties of a given API method call M,
+ * given that some properties X have already been specified.
+ */
+export type Other<
+ R extends RawApi,
+ M extends Methods,
+ X extends string = never,
+> = Omit, X>;
+/**
+ * This class provides access to the full Telegram Bot API. All methods of the
+ * API have an equivalent on this class, with the most important parameters
+ * pulled up into the function signature, and the other parameters captured by
+ * an object.
+ *
+ * In addition, this class has a property `raw` that provides raw access to the
+ * complete Telegram API, with the method signatures 1:1 represented as
+ * documented on the website (https://core.telegram.org/bots/api).
+ *
+ * Every method takes an optional `AbortSignal` object that allows you to cancel
+ * the request if desired.
+ *
+ * In advanced use cases, this class allows to install transformers that can
+ * modify the method and payload on the fly before sending it to the Telegram
+ * servers. Confer the `config` property for this.
+ */
+export class Api {
+ /**
+ * Provides access to all methods of the Telegram Bot API exactly as
+ * documented on the website (https://core.telegram.org/bots/api). No
+ * arguments are pulled up in the function signature for convenience.
+ *
+ * If you suppress compiler warnings, this also allows for raw api calls to
+ * undocumented methods with arbitrary parametersβuse only if you know what
+ * you are doing.
+ */
+ public readonly raw: R;
+
+ /**
+ * Configuration object for the API instance, used as a namespace to
+ * separate those API operations that are related to grammY from methods of
+ * the Telegram Bot API. Contains advanced options!
+ */
+ public readonly config: {
+ /**
+ * Allows to install an API request transformer function. A transformer
+ * function has access to every API call before it is being performed.
+ * This includes the method as string, the payload as object and the
+ * upstream transformer function.
+ *
+ * _Note that using transformer functions is an advanced feature of
+ * grammY that most bots will not need to make use of._
+ */
+ readonly use: TransformerConsumer;
+ /**
+ * Provides read access to all currently installed transformers (those
+ * that have previously been passed to `config.use`).
+ *
+ * _Note that using transformer functions is an advanced feature of
+ * grammY that most bots will not need to make use of._
+ */
+ readonly installedTransformers: () => Transformer[];
+ };
+
+ /**
+ * Constructs a new instance of `Api`. It is independent from all other
+ * instances of this class. For example, this lets you install a custom set
+ * of transformers.
+ *
+ * @param token Bot API token obtained from [@BotFather](https://t.me/BotFather)
+ * @param options Optional API client options for the underlying client instance
+ * @param webhookReplyEnvelope Optional envelope to handle webhook replies
+ */
+ constructor(
+ public readonly token: string,
+ public readonly options?: ApiClientOptions,
+ webhookReplyEnvelope?: WebhookReplyEnvelope,
+ ) {
+ const { raw, use, installedTransformers } = createRawApi(
+ token,
+ options,
+ webhookReplyEnvelope,
+ );
+ this.raw = raw;
+ this.config = {
+ use,
+ installedTransformers: () => installedTransformers.slice(),
+ };
+ }
+
+ /**
+ * Use this method to receive incoming updates using long polling (wiki). Returns an Array of Update objects.
+ *
+ * Notes
+ * 1. This method will not work if an outgoing webhook is set up.
+ * 2. In order to avoid getting duplicate updates, recalculate offset after each server response.
+ *
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getupdates
+ */
+ getUpdates(other?: Other, signal?: AbortSignal) {
+ return this.raw.getUpdates({ ...other }, signal);
+ }
+
+ /**
+ * Use this method to specify a URL and receive incoming updates via an outgoing webhook. Whenever there is an update for the bot, we will send an HTTPS POST request to the specified URL, containing a JSON-serialized Update. In case of an unsuccessful request, we will give up after a reasonable amount of attempts. Returns True on success.
+ *
+ * If you'd like to make sure that the webhook was set by you, you can specify secret data in the parameter secret_token. If specified, the request will contain a header βX-Telegram-Bot-Api-Secret-Tokenβ with the secret token as content.
+ *
+ * Notes
+ * 1. You will not be able to receive updates using getUpdates for as long as an outgoing webhook is set up.
+ * 2. To use a self-signed certificate, you need to upload your public key certificate using certificate parameter. Please upload as InputFile, sending a String will not work.
+ * 3. Ports currently supported for Webhooks: 443, 80, 88, 8443.
+ *
+ * If you're having any trouble setting up webhooks, please check out this amazing guide to webhooks.
+ *
+ * @param url HTTPS url to send updates to. Use an empty string to remove webhook integration.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setwebhook
+ */
+ setWebhook(
+ url: string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setWebhook({ url, ...other }, signal);
+ }
+
+ /**
+ * Use this method to remove webhook integration if you decide to switch back to getUpdates. Returns True on success.
+ *
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#deletewebhook
+ */
+ deleteWebhook(other?: Other, signal?: AbortSignal) {
+ return this.raw.deleteWebhook({ ...other }, signal);
+ }
+
+ /**
+ * Use this method to get current webhook status. Requires no parameters. On success, returns a WebhookInfo object. If the bot is using getUpdates, will return an object with the url field empty.
+ *
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getwebhookinfo
+ */
+ getWebhookInfo(signal?: AbortSignal) {
+ return this.raw.getWebhookInfo(signal);
+ }
+
+ /**
+ * A simple method for testing your bot's authentication token. Requires no parameters. Returns basic information about the bot in form of a User object.
+ *
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getme
+ */
+ getMe(signal?: AbortSignal) {
+ return this.raw.getMe(signal);
+ }
+
+ /**
+ * Use this method to log out from the cloud Bot API server before launching the bot locally. You must log out the bot before running it locally, otherwise there is no guarantee that the bot will receive updates. After a successful call, you can immediately log in on a local server, but will not be able to log in back to the cloud Bot API server for 10 minutes. Returns True on success. Requires no parameters.
+ *
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#logout
+ */
+ logOut(signal?: AbortSignal) {
+ return this.raw.logOut(signal);
+ }
+
+ /**
+ * Use this method to close the bot instance before moving it from one local server to another. You need to delete the webhook before calling this method to ensure that the bot isn't launched again after server restart. The method will return error 429 in the first 10 minutes after the bot is launched. Returns True on success. Requires no parameters.
+ *
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#close
+ */
+ close(signal?: AbortSignal) {
+ return this.raw.close(signal);
+ }
+
+ /**
+ * Use this method to send text messages. On success, the sent Message is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param text Text of the message to be sent, 1-4096 characters after entities parsing
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendmessage
+ */
+ sendMessage(
+ chat_id: number | string,
+ text: string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendMessage({ chat_id, text, ...other }, signal);
+ }
+
+ /**
+ * Use this method to send rich messages. If the message contains a block with a media element, then the bot must have the right to send the media to the chat. On success, the sent Message is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format \@username
+ * @param rich_message The message to be sent
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendrichmessage
+ */
+ sendRichMessage(
+ chat_id: number | string,
+ rich_message: InputRichMessage,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendRichMessage(
+ { chat_id, rich_message, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to forward messages of any kind. Service messages and messages with protected content can't be forwarded. On success, the sent Message is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param from_chat_id Unique identifier for the chat where the original message was sent (or username of the target bot, supergroup or channel in the format `@username`)
+ * @param message_id Message identifier in the chat specified in from_chat_id
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#forwardmessage
+ */
+ forwardMessage(
+ chat_id: number | string,
+ from_chat_id: number | string,
+ message_id: number,
+ other?: Other<
+ R,
+ "forwardMessage",
+ "chat_id" | "from_chat_id" | "message_id"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.forwardMessage(
+ { chat_id, from_chat_id, message_id, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to forward multiple messages of any kind. If some of the specified messages can't be found or forwarded, they are skipped. Service messages and messages with protected content can't be forwarded. Album grouping is kept for forwarded messages. On success, an Array of MessageId of the sent messages is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param from_chat_id Unique identifier for the chat where the original messages were sent (or username of the target bot, supergroup or channel in the format `@username`)
+ * @param message_ids A list of 1-100 identifiers of messages in the chat from_chat_id to forward. The identifiers must be specified in a strictly increasing order.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#forwardmessages
+ */
+ forwardMessages(
+ chat_id: number | string,
+ from_chat_id: number | string,
+ message_ids: number[],
+ other?: Other<
+ R,
+ "forwardMessages",
+ "chat_id" | "from_chat_id" | "message_ids"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.forwardMessages({
+ chat_id,
+ from_chat_id,
+ message_ids,
+ ...other,
+ }, signal);
+ }
+
+ /**
+ * Use this method to copy messages of any kind. Service messages, paid media messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied. A quiz poll can be copied only if the value of the field correct_option_id is known to the bot. The method is analogous to the method forwardMessage, but the copied message doesn't have a link to the original message. Returns the MessageId of the sent message on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param from_chat_id Unique identifier for the chat where the original message was sent (or username of the target bot, supergroup or channel in the format `@username`)
+ * @param message_id Message identifier in the chat specified in from_chat_id
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#copymessage
+ */
+ copyMessage(
+ chat_id: number | string,
+ from_chat_id: number | string,
+ message_id: number,
+ other?: Other<
+ R,
+ "copyMessage",
+ "chat_id" | "from_chat_id" | "message_id"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.copyMessage(
+ { chat_id, from_chat_id, message_id, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to copy messages of any kind. If some of the specified messages can't be found or copied, they are skipped. Service messages, paid media messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied. A quiz poll can be copied only if the value of the field correct_option_id is known to the bot. The method is analogous to the method forwardMessages, but the copied messages don't have a link to the original message. Album grouping is kept for copied messages. On success, an Array of MessageId of the sent messages is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param from_chat_id Unique identifier for the chat where the original messages were sent (or username of the target bot, supergroup or channel in the format `@username`)
+ * @param message_ids A list of 1-100 identifiers of messages in the chat from_chat_id to copy. The identifiers must be specified in a strictly increasing order.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#copymessages
+ */
+ copyMessages(
+ chat_id: number | string,
+ from_chat_id: number | string,
+ message_ids: number[],
+ other?: Other<
+ R,
+ "copyMessages",
+ "chat_id" | "from_chat_id" | "message_ids"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.copyMessages({
+ chat_id,
+ from_chat_id,
+ message_ids,
+ ...other,
+ }, signal);
+ }
+
+ /**
+ * Use this method to send photos. On success, the sent Message is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param photo Photo to send. Pass a file_id as String to send a photo that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a photo from the Internet, or upload a new photo using multipart/form-data. The photo must be at most 10 MB in size. The photo's width and height must not exceed 10000 in total. Width and height ratio must be at most 20.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendphoto
+ */
+ sendPhoto(
+ chat_id: number | string,
+ photo: InputFile | string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendPhoto({ chat_id, photo, ...other }, signal);
+ }
+
+ /**
+ * Use this method to send live photos. On success, the sent Message is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param live_photo Live photo video to send. Pass a file_id as String to send a video that exists on the Telegram servers (recommended) or upload a new video using multipart/form-data. Sending live photos by a URL is currently unsupported.
+ * @param photo The static photo to send. Pass a file_id as String to send a photo that exists on the Telegram servers (recommended) or upload a new video using multipart/form-data. Sending live photos by a URL is currently unsupported.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendlivephoto
+ */
+ sendLivePhoto(
+ chat_id: number | string,
+ live_photo: InputFile | string,
+ photo: InputFile | string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendLivePhoto(
+ { chat_id, live_photo, photo, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to send audio files, if you want Telegram clients to display them in the music player. Your audio must be in the .MP3 or .M4A format. On success, the sent Message is returned. Bots can currently send audio files of up to 50 MB in size, this limit may be changed in the future.
+ *
+ * For sending voice messages, use the sendVoice method instead.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param audio Audio file to send. Pass a file_id as String to send an audio file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get an audio file from the Internet, or upload a new one using multipart/form-data.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendaudio
+ */
+ sendAudio(
+ chat_id: number | string,
+ audio: InputFile | string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendAudio({ chat_id, audio, ...other }, signal);
+ }
+
+ /**
+ * Use this method to send general files. On success, the sent Message is returned. Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param document File to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#senddocument
+ */
+ sendDocument(
+ chat_id: number | string,
+ document: InputFile | string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendDocument({ chat_id, document, ...other }, signal);
+ }
+
+ /**
+ * Use this method to send video files, Telegram clients support mp4 videos (other formats may be sent as Document). On success, the sent Message is returned. Bots can currently send video files of up to 50 MB in size, this limit may be changed in the future.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param video Video to send. Pass a file_id as String to send a video that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a video from the Internet, or upload a new video using multipart/form-data.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendvideo
+ */
+ sendVideo(
+ chat_id: number | string,
+ video: InputFile | string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendVideo({ chat_id, video, ...other }, signal);
+ }
+
+ /**
+ * Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). On success, the sent Message is returned. Bots can currently send animation files of up to 50 MB in size, this limit may be changed in the future.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param animation Animation to send. Pass a file_id as String to send an animation that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get an animation from the Internet, or upload a new animation using multipart/form-data.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendanimation
+ */
+ sendAnimation(
+ chat_id: number | string,
+ animation: InputFile | string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendAnimation({ chat_id, animation, ...other }, signal);
+ }
+
+ /**
+ * Use this method to send audio files, if you want Telegram clients to display the file as a playable voice message. For this to work, your audio must be in an .OGG file encoded with OPUS (other formats may be sent as Audio or Document). On success, the sent Message is returned. Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param voice Audio file to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendvoice
+ */
+ sendVoice(
+ chat_id: number | string,
+ voice: InputFile | string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendVoice({ chat_id, voice, ...other }, signal);
+ }
+
+ /**
+ * Use this method to send video messages. On success, the sent Message is returned.
+ * As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1 minute long.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param video_note Video note to send. Pass a file_id as String to send a video note that exists on the Telegram servers (recommended) or upload a new video using multipart/form-data.. Sending video notes by a URL is currently unsupported
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendvideonote
+ */
+ sendVideoNote(
+ chat_id: number | string,
+ video_note: InputFile | string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendVideoNote(
+ { chat_id, video_note, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to send paid media. On success, the sent Message is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param star_count The number of Telegram Stars that must be paid to buy access to the media
+ * @param media An Array describing the media to be sent; up to 10 items
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendpaidmedia
+ */
+ sendPaidMedia(
+ chat_id: number | string,
+ star_count: number,
+ media: InputPaidMedia[],
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendPaidMedia(
+ { chat_id, star_count, media, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to send a group of photos, live photos, videos, documents or audios as an album. Documents and audio files can be only grouped in an album with messages of the same type. On success, an Array of Message objects that were sent is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param media An Array describing messages to be sent, must include 2-10 items
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendmediagroup
+ */
+ sendMediaGroup(
+ chat_id: number | string,
+ media:
+ | ReadonlyArray
+ | ReadonlyArray
+ | ReadonlyArray<
+ | InputMediaLivePhoto
+ | InputMediaPhoto
+ | InputMediaVideo
+ >,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendMediaGroup({ chat_id, media, ...other }, signal);
+ }
+
+ /**
+ * Use this method to send point on the map. On success, the sent Message is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param latitude Latitude of the location
+ * @param longitude Longitude of the location
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendlocation
+ */
+ sendLocation(
+ chat_id: number | string,
+ latitude: number,
+ longitude: number,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendLocation(
+ { chat_id, latitude, longitude, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to edit live location messages. A location can be edited until its live_period expires or editing is explicitly disabled by a call to stopMessageLiveLocation. On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param message_id Identifier of the message to edit
+ * @param latitude Latitude of new location
+ * @param longitude Longitude of new location
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#editmessagelivelocation
+ */
+ editMessageLiveLocation(
+ chat_id: number | string,
+ message_id: number,
+ latitude: number,
+ longitude: number,
+ other?: Other<
+ R,
+ "editMessageLiveLocation",
+ | "chat_id"
+ | "message_id"
+ | "inline_message_id"
+ | "latitude"
+ | "longitude"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editMessageLiveLocation(
+ { chat_id, message_id, latitude, longitude, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to edit live location inline messages. A location can be edited until its live_period expires or editing is explicitly disabled by a call to stopMessageLiveLocation. On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned.
+ *
+ * @param inline_message_id Identifier of the inline message
+ * @param latitude Latitude of new location
+ * @param longitude Longitude of new location
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#editmessagelivelocation
+ */
+ editMessageLiveLocationInline(
+ inline_message_id: string,
+ latitude: number,
+ longitude: number,
+ other?: Other<
+ R,
+ "editMessageLiveLocation",
+ | "chat_id"
+ | "message_id"
+ | "inline_message_id"
+ | "latitude"
+ | "longitude"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editMessageLiveLocation(
+ { inline_message_id, latitude, longitude, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to stop updating a live location message before live_period expires. On success, if the message is not an inline message, the edited Message is returned, otherwise True is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param message_id Identifier of the message with live location to stop
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#stopmessagelivelocation
+ */
+ stopMessageLiveLocation(
+ chat_id: number | string,
+ message_id: number,
+ other?: Other<
+ R,
+ "stopMessageLiveLocation",
+ "chat_id" | "message_id" | "inline_message_id"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.stopMessageLiveLocation(
+ { chat_id, message_id, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to stop updating a live location message before live_period expires. On success, if the message is not an inline message, the edited Message is returned, otherwise True is returned.
+ *
+ * @param inline_message_id Identifier of the inline message
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#stopmessagelivelocation
+ */
+ stopMessageLiveLocationInline(
+ inline_message_id: string,
+ other?: Other<
+ R,
+ "stopMessageLiveLocation",
+ "chat_id" | "message_id" | "inline_message_id"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.stopMessageLiveLocation(
+ { inline_message_id, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to send information about a venue. On success, the sent Message is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param latitude Latitude of the venue
+ * @param longitude Longitude of the venue
+ * @param title Name of the venue
+ * @param address Address of the venue
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendvenue
+ */
+ sendVenue(
+ chat_id: number | string,
+ latitude: number,
+ longitude: number,
+ title: string,
+ address: string,
+ other?: Other<
+ R,
+ "sendVenue",
+ "chat_id" | "latitude" | "longitude" | "title" | "address"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendVenue(
+ { chat_id, latitude, longitude, title, address, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to send phone contacts. On success, the sent Message is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param phone_number Contact's phone number
+ * @param first_name Contact's first name
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendcontact
+ */
+ sendContact(
+ chat_id: number | string,
+ phone_number: string,
+ first_name: string,
+ other?: Other<
+ R,
+ "sendContact",
+ "chat_id" | "phone_number" | "first_name"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendContact(
+ { chat_id, phone_number, first_name, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to send a native poll. On success, the sent Message is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param question Poll question, 1-300 characters
+ * @param options A list of answer options, 1-12 strings 1-100 characters each
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendpoll
+ */
+ sendPoll(
+ chat_id: number | string,
+ question: string,
+ options: (string | InputPollOption)[],
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ const opts = options.map((o) =>
+ typeof o === "string" ? { text: o } : o
+ );
+ return this.raw.sendPoll(
+ { chat_id, question, options: opts, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to send a checklist on behalf of a connected business account. On success, the sent Message is returned.
+ *
+ * @param business_connection_id Unique identifier of the business connection on behalf of which the message will be sent
+ * @param chat_id Unique identifier for the target chat or username of the target bot in the format `@username`
+ * @param checklist An object for the checklist to send
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendchecklist
+ */
+ sendChecklist(
+ business_connection_id: string,
+ chat_id: number | string,
+ checklist: InputChecklist,
+ other?: Other<
+ R,
+ "sendChecklist",
+ "business_connection_id" | "chat_id" | "checklist"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendChecklist({
+ business_connection_id,
+ chat_id,
+ checklist,
+ ...other,
+ }, signal);
+ }
+
+ /**
+ * Use this method to edit a checklist on behalf of a connected business account. On success, the edited Message is returned.
+ *
+ * @param business_connection_id Unique identifier of the business connection on behalf of which the message will be sent
+ * @param chat_id Unique identifier for the target chat or username of the target bot in the format `@username`
+ * @param message_id Unique identifier for the target message
+ * @param checklist An object for the new checklist
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#editmessagechecklist
+ */
+ editMessageChecklist(
+ business_connection_id: string,
+ chat_id: number | string,
+ message_id: number,
+ checklist: InputChecklist,
+ other?: Other<
+ R,
+ "editMessageChecklist",
+ "business_connection_id" | "chat_id" | "messaage_id" | "checklist"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editMessageChecklist({
+ business_connection_id,
+ chat_id,
+ message_id,
+ checklist,
+ ...other,
+ }, signal);
+ }
+
+ /**
+ * Use this method to send an animated emoji that will display a random value. On success, the sent Message is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param emoji Emoji on which the dice throw animation is based. Currently, must be one of βπ²β, βπ―β, βπβ, ββ½β, βπ³β, or βπ°β. Dice can have values 1-6 for βπ²β, βπ―β and βπ³β, values 1-5 for βπβ and ββ½β, and values 1-64 for βπ°β. Defaults to βπ²β.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#senddice
+ */
+ sendDice(
+ chat_id: number | string,
+ emoji:
+ | (string & Record)
+ | "π²"
+ | "π―"
+ | "π"
+ | "β½"
+ | "π³"
+ | "π°",
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendDice({ chat_id, emoji, ...other }, signal);
+ }
+
+ /**
+ * Use this method to change the chosen reactions on a message. Service messages of some types can't be reacted to. Automatically forwarded messages from a channel to its discussion group have the same available reactions as messages in the channel. Bots can't use paid reactions. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target channel (in the format @channelusername)
+ * @param message_id Identifier of the target message
+ * @param reaction A list of reaction types to set on the message. Currently, as non-premium users, bots can set up to one reaction per message. A custom emoji reaction can be used if it is either already present on the message or explicitly allowed by chat administrators. Paid reactions can't be used by bots.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setmessagereaction
+ */
+ setMessageReaction(
+ chat_id: number | string,
+ message_id: number,
+ reaction: ReactionType[],
+ other?: Other<
+ R,
+ "setMessageReaction",
+ "chat_id" | "message_id" | "reaction"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setMessageReaction({
+ chat_id,
+ message_id,
+ reaction,
+ ...other,
+ }, signal);
+ }
+
+ /**
+ * Use this method to stream a partial message to a user while the message is being generated. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target private chat
+ * @param draft_id Unique identifier of the message draft; must be non-zero. Changes to drafts with the same identifier are animated.
+ * @param text Text of the message to be sent, 1-4096 characters after entities parsing
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendmessagedraft
+ */
+ sendMessageDraft(
+ chat_id: number,
+ draft_id: number,
+ text: string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendMessageDraft(
+ { chat_id, draft_id, text, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to stream a partial rich message to a user while the message is being generated. Note that the streamed draft is ephemeral and acts as a temporary 30-second preview - once the output is finalized, you must call sendRichMessage with the complete message to persist it in the user's chat. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target private chat
+ * @param draft_id Unique identifier of the message draft; must be non-zero. Changes to drafts with the same identifier are animated.
+ * @param rich_message The partial message to be streamed
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendrichmessagedraft
+ */
+ sendRichMessageDraft(
+ chat_id: number,
+ draft_id: number,
+ rich_message: InputRichMessageWithoutUpload,
+ other?: Other<
+ R,
+ "sendRichMessageDraft",
+ "chat_id" | "draft_id" | "rich_message"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendRichMessageDraft(
+ { chat_id, draft_id, rich_message, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method when you need to tell the user that something is happening on the bot's side. The status is set for 5 seconds or less (when a message arrives from your bot, Telegram clients clear its typing status). Returns True on success.
+ *
+ * Example: The ImageBot needs some time to process a request and upload the image. Instead of sending a text message along the lines of βRetrieving image, please waitβ¦β, the bot may use sendChatAction with action = upload_photo. The user will see a βsending photoβ status for the bot.
+ *
+ * We only recommend using this method when a response from the bot will take a noticeable amount of time to arrive.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot or supergroup in the format `@username`
+ * @param action Type of action to broadcast. Choose one, depending on what the user is about to receive: typing for text messages, upload_photo for photos, record_video or upload_video for videos, record_voice or upload_voice for voice notes, upload_document for general files, choose_sticker for stickers, find_location for location data, record_video_note or upload_video_note for video notes.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendchataction
+ */
+ sendChatAction(
+ chat_id: number | string,
+ action:
+ | "typing"
+ | "upload_photo"
+ | "record_video"
+ | "upload_video"
+ | "record_voice"
+ | "upload_voice"
+ | "upload_document"
+ | "choose_sticker"
+ | "find_location"
+ | "record_video_note"
+ | "upload_video_note",
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendChatAction({ chat_id, action, ...other }, signal);
+ }
+
+ /**
+ * Use this method to get a list of profile pictures for a user. Returns a UserProfilePhotos object.
+ *
+ * @param user_id Unique identifier of the target user
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getuserprofilephotos
+ */
+ getUserProfilePhotos(
+ user_id: number,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.getUserProfilePhotos({ user_id, ...other }, signal);
+ }
+
+ /**
+ * Use this method to get a list of profile audios for a user. Returns a UserProfileAudios object.
+ *
+ * @param user_id Unique identifier of the target user
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getuserprofileaudios
+ */
+ getUserProfileAudios(
+ user_id: number,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.getUserProfileAudios({ user_id, ...other }, signal);
+ }
+
+ /**
+ * Changes the emoji status for a given user that previously allowed the bot to manage their emoji status via the Mini App method requestEmojiStatusAccess. Returns True on success.
+ *
+ * @param user_id Unique identifier of the target user
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setuseremojistatus
+ */
+ setUserEmojiStatus(
+ user_id: number,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setUserEmojiStatus({ user_id, ...other }, signal);
+ }
+
+ /**
+ * Use this method to get the list of boosts added to a chat by a user. Requires administrator rights in the chat. Returns a UserChatBoosts object.
+ *
+ * @param chat_id Unique identifier for the chat or username of the channel (in the format @channelusername)
+ * @param user_id Unique identifier of the target user
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getuserchatboosts
+ */
+ getUserChatBoosts(
+ chat_id: number | string,
+ user_id: number,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.getUserChatBoosts({ chat_id, user_id }, signal);
+ }
+
+ /**
+ * Returns the gifts owned and hosted by a user. Returns OwnedGifts on success.
+ *
+ * @param user_id Unique identifier of the user
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getusergifts
+ */
+ getUserGifts(
+ user_id: number,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.getUserGifts({ user_id, ...other }, signal);
+ }
+
+ /**
+ * Returns the gifts owned by a chat. Returns OwnedGifts on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target channel in the format `@username`
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getchatgifts
+ */
+ getChatGifts(
+ chat_id: number,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.getChatGifts({ chat_id, ...other }, signal);
+ }
+
+ /**
+ * Use this method to get information about the connection of the bot with a business account. Returns a BusinessConnection object on success.
+ *
+ * @param business_connection_id Unique identifier of the business connection
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getbusinessconnection
+ */
+ getBusinessConnection(
+ business_connection_id: string,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.getBusinessConnection(
+ { business_connection_id },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to get the token of a managed bot. Returns the token as String on success.
+ *
+ * @param user_id User identifier of the managed bot whose token will be returned
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getmanagedbottoken
+ */
+ getManagedBotToken(user_id: number, signal?: AbortSignal) {
+ return this.raw.getManagedBotToken({ user_id }, signal);
+ }
+
+ /**
+ * Use this method to revoke the current token of a managed bot and generate a new one. Returns the new token as String on success.
+ *
+ * @param user_id User identifier of the managed bot whose token will be replaced
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#replacemanagedbottoken
+ */
+ replaceManagedBotToken(user_id: number, signal?: AbortSignal) {
+ return this.raw.replaceManagedBotToken({ user_id }, signal);
+ }
+
+ /**
+ * Use this method to get the access settings of a managed bot. Returns a BotAccessSettings object on success.
+ *
+ * @param user_id User identifier of the managed bot whose access settings will be returned
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getmanagedbotaccesssettings
+ */
+ getManagedBotAccessSettings(user_id: number, signal?: AbortSignal) {
+ return this.raw.getManagedBotAccessSettings({ user_id }, signal);
+ }
+
+ /**
+ * Use this method to change the access settings of a managed bot. Returns True on success.
+ *
+ * @param user_id User identifier of the managed bot whose access settings will be changed
+ * @param is_access_restricted Pass True, if only selected users can access the bot
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setmanagedbotaccesssettingsrestricted
+ */
+ setManagedBotAccessSettings(
+ user_id: number,
+ is_access_restricted: boolean,
+ other?: Other<
+ R,
+ "setManagedBotAccessSettings",
+ "user_id" | "is_access_restricted"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setManagedBotAccessSettings({
+ user_id,
+ is_access_restricted,
+ ...other,
+ }, signal);
+ }
+
+ /**
+ * Use this method to get basic info about a file and prepare it for downloading. For the moment, bots can download files of up to 20MB in size. On success, a File object is returned. The file can then be downloaded via the link `https://api.telegram.org/file/bot/`, where `` is taken from the response. It is guaranteed that the link will be valid for at least 1 hour. When the link expires, a new one can be requested by calling getFile again.
+ *
+ * Note: This function may not preserve the original file name and MIME type. You should save the file's MIME type and name (if available) when the File object is received.
+ *
+ * @param file_id File identifier to get info about
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getfile
+ */
+ getFile(file_id: string, signal?: AbortSignal) {
+ return this.raw.getFile({ file_id }, signal);
+ }
+
+ /** @deprecated Use `banChatMember` instead. */
+ kickChatMember(...args: Parameters) {
+ return this.banChatMember(...args);
+ }
+
+ /**
+ * Use this method to ban a user in a group, a supergroup or a channel. In the case of supergroups and channels, the user will not be able to return to the chat on their own using invite links, etc., unless unbanned first. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target group or username of the target supergroup or channel in the format `@username`
+ * @param user_id Unique identifier of the target user
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#banchatmember
+ */
+ banChatMember(
+ chat_id: number | string,
+ user_id: number,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.banChatMember({ chat_id, user_id, ...other }, signal);
+ }
+
+ /**
+ * Use this method to unban a previously banned user in a supergroup or channel. The user will not return to the group or channel automatically, but will be able to join via link, etc. The bot must be an administrator for this to work. By default, this method guarantees that after the call the user is not a member of the chat, but will be able to join it. So if the user is a member of the chat they will also be removed from the chat. If you don't want this, use the parameter only_if_banned. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target group or username of the target supergroup or channel in the format `@username`
+ * @param user_id Unique identifier of the target user
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#unbanchatmember
+ */
+ unbanChatMember(
+ chat_id: number | string,
+ user_id: number,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.unbanChatMember({ chat_id, user_id, ...other }, signal);
+ }
+
+ /**
+ * Use this method to restrict a user in a supergroup. The bot must be an administrator in the supergroup for this to work and must have the appropriate administrator rights. Pass True for all permissions to lift restrictions from a user. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param user_id Unique identifier of the target user
+ * @param permissions An object for new user permissions
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#restrictchatmember
+ */
+ restrictChatMember(
+ chat_id: number | string,
+ user_id: number,
+ permissions: ChatPermissions,
+ other?: Other<
+ R,
+ "restrictChatMember",
+ "chat_id" | "user_id" | "permissions"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.restrictChatMember(
+ { chat_id, user_id, permissions, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to promote or demote a user in a supergroup or a channel. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Pass False for all boolean parameters to demote a user. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target channel in the format `@username`
+ * @param user_id Unique identifier of the target user
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#promotechatmember
+ */
+ promoteChatMember(
+ chat_id: number | string,
+ user_id: number,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.promoteChatMember(
+ { chat_id, user_id, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to set a custom title for an administrator in a supergroup promoted by the bot. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param user_id Unique identifier of the target user
+ * @param custom_title New custom title for the administrator; 0-16 characters, emoji are not allowed
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setchatadministratorcustomtitle
+ */
+ setChatAdministratorCustomTitle(
+ chat_id: number | string,
+ user_id: number,
+ custom_title: string,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setChatAdministratorCustomTitle(
+ { chat_id, user_id, custom_title },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to set a tag for a regular member in a group or a supergroup. The bot must be an administrator in the chat for this to work and must have the βcan_manage_tagsβ administrator right. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param user_id Unique identifier of the target user
+ * @param tag New tag for the member; 0-16 characters, emoji are not allowed
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setChatMemberTag
+ */
+ setChatMemberTag(
+ chat_id: number | string,
+ user_id: number,
+ tag: string,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setChatMemberTag({ chat_id, user_id, tag }, signal);
+ }
+
+ /**
+ * Use this method to ban a channel chat in a supergroup or a channel. Until the chat is unbanned, the owner of the banned chat won't be able to send messages on behalf of any of their channels. The bot must be an administrator in the supergroup or channel for this to work and must have the appropriate administrator rights. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target channel in the format `@username`
+ * @param sender_chat_id Unique identifier of the target sender chat
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#banchatsenderchat
+ */
+ banChatSenderChat(
+ chat_id: number | string,
+ sender_chat_id: number,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.banChatSenderChat({ chat_id, sender_chat_id }, signal);
+ }
+
+ /**
+ * Use this method to unban a previously banned channel chat in a supergroup or channel. The bot must be an administrator for this to work and must have the appropriate administrator rights. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target channel in the format `@username`
+ * @param sender_chat_id Unique identifier of the target sender chat
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#unbanchatsenderchat
+ */
+ unbanChatSenderChat(
+ chat_id: number | string,
+ sender_chat_id: number,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.unbanChatSenderChat(
+ { chat_id, sender_chat_id },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to set default chat permissions for all members. The bot must be an administrator in the group or a supergroup for this to work and must have the can_restrict_members administrator rights. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param permissions New default chat permissions
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setchatpermissions
+ */
+ setChatPermissions(
+ chat_id: number | string,
+ permissions: ChatPermissions,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setChatPermissions(
+ { chat_id, permissions, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to generate a new primary invite link for a chat; any previously generated primary link is revoked. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns the new invite link as String on success.
+ *
+ * Note: Each administrator in a chat generates their own invite links. Bots can't use invite links generated by other administrators. If you want your bot to work with invite links, it will need to generate its own link using exportChatInviteLink or by calling the getChat method. If your bot needs to generate a new primary invite link replacing its previous one, use exportChatInviteLink again.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target channel in the format `@username`
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#exportchatinvitelink
+ */
+ exportChatInviteLink(chat_id: number | string, signal?: AbortSignal) {
+ return this.raw.exportChatInviteLink({ chat_id }, signal);
+ }
+
+ /**
+ * Use this method to create an additional invite link for a chat. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. The link can be revoked using the method revokeChatInviteLink. Returns the new invite link as ChatInviteLink object.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target channel in the format `@username`
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#createchatinvitelink
+ */
+ createChatInviteLink(
+ chat_id: number | string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.createChatInviteLink({ chat_id, ...other }, signal);
+ }
+
+ /**
+ * Use this method to edit a non-primary invite link created by the bot. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns the edited invite link as a ChatInviteLink object.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target channel in the format `@username`
+ * @param invite_link The invite link to edit
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#editchatinvitelink
+ */
+ editChatInviteLink(
+ chat_id: number | string,
+ invite_link: string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editChatInviteLink(
+ { chat_id, invite_link, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to create a subscription invite link for a channel chat. The bot must have the can_invite_users administrator rights. The link can be edited using the method editChatSubscriptionInviteLink or revoked using the method revokeChatInviteLink. Returns the new invite link as a ChatInviteLink object.
+ *
+ * @param chat_id Unique identifier for the target channel chat or username of the target channel in the format `@username`
+ * @param subscription_period The number of seconds the subscription will be active for before the next payment. Currently, it must always be 2592000 (30 days).
+ * @param subscription_price The amount of Telegram Stars a user must pay initially and after each subsequent subscription period to be a member of the chat; 1-2500
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#createchatsubscriptioninvitelink
+ */
+ createChatSubscriptionInviteLink(
+ chat_id: number | string,
+ subscription_period: number,
+ subscription_price: number,
+ other?: Other<
+ R,
+ "createChatSubscriptionInviteLink",
+ "chat_id" | "subscription_period" | "subscription_price"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.createChatSubscriptionInviteLink(
+ { chat_id, subscription_period, subscription_price, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to edit a subscription invite link created by the bot. The bot must have the can_invite_users administrator rights. Returns the edited invite link as a ChatInviteLink object.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target channel in the format `@username`
+ * @param invite_link The invite link to edit
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#editchatsubscriptioninvitelink
+ */
+ editChatSubscriptionInviteLink(
+ chat_id: number | string,
+ invite_link: string,
+ other?: Other<
+ R,
+ "editChatSubscriptionInviteLink",
+ "chat_id" | "invite_link"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editChatSubscriptionInviteLink(
+ { chat_id, invite_link, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to revoke an invite link created by the bot. If the primary link is revoked, a new link is automatically generated. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns the revoked invite link as ChatInviteLink object.
+ *
+ * @param chat_id Unique identifier of the target chat or username of the target channel in the format `@username`
+ * @param invite_link The invite link to revoke
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#revokechatinvitelink
+ */
+ revokeChatInviteLink(
+ chat_id: number | string,
+ invite_link: string,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.revokeChatInviteLink({ chat_id, invite_link }, signal);
+ }
+
+ /**
+ * Use this method to approve a chat join request. The bot must be an administrator in the chat for this to work and must have the can_invite_users administrator right. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target channel in the format `@username`
+ * @param user_id Unique identifier of the target user
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#approvechatjoinrequest
+ */
+ approveChatJoinRequest(
+ chat_id: number | string,
+ user_id: number,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.approveChatJoinRequest({ chat_id, user_id }, signal);
+ }
+
+ /**
+ * Use this method to decline a chat join request. The bot must be an administrator in the chat for this to work and must have the can_invite_users administrator right. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target channel in the format `@username`
+ * @param user_id Unique identifier of the target user
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#declinechatjoinrequest
+ */
+ declineChatJoinRequest(
+ chat_id: number | string,
+ user_id: number,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.declineChatJoinRequest({ chat_id, user_id }, signal);
+ }
+
+ /**
+ * Use this method to process a received chat join request query. Returns True on success.
+ *
+ * @param chat_join_request_query_id Unique identifier of the join request query
+ * @param result Result of the query. Must be either βapproveβ to allow the user to join the chat, βdeclineβ to disallow the user to join the chat, or βqueueβ to leave the decision to other administrators.
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#answerchatjoinrequestquery
+ */
+ answerChatJoinRequestQuery(
+ chat_join_request_query_id: string,
+ result: "approve" | "decline" | "queue",
+ signal?: AbortSignal,
+ ) {
+ return this.raw.answerChatJoinRequestQuery(
+ { chat_join_request_query_id, result },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to process a received chat join request query by showing a Mini App to the user before deciding the outcome. Returns True on success.
+ *
+ * @param chat_join_request_query_id Unique identifier of the join request query
+ * @param web_app_url The URL of the Mini App to be opened
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendchatjoinrequestwebapp
+ */
+ sendChatJoinRequestWebApp(
+ chat_join_request_query_id: string,
+ web_app_url: string,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendChatJoinRequestWebApp(
+ { chat_join_request_query_id, web_app_url },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to approve a suggested post in a direct messages chat. The bot must have the 'can_post_messages' administrator right in the corresponding channel chat. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target direct messages chat
+ * @param message_id Identifier of a suggested post message to approve
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#approvesuggestedpost
+ */
+ approveSuggestedPost(
+ chat_id: number,
+ message_id: number,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.approveSuggestedPost(
+ { chat_id, message_id, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to decline a suggested post in a direct messages chat. The bot must have the 'can_manage_direct_messages' administrator right in the corresponding channel chat. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target direct messages chat
+ * @param message_id Identifier of a suggested post message to decline
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#declinesuggestedpost
+ */
+ declineSuggestedPost(
+ chat_id: number,
+ message_id: number,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.declineSuggestedPost(
+ { chat_id, message_id, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to set a new profile photo for the chat. Photos can't be changed for private chats. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target channel in the format `@username`
+ * @param photo New chat photo, uploaded using multipart/form-data
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setchatphoto
+ */
+ setChatPhoto(
+ chat_id: number | string,
+ photo: InputFile,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setChatPhoto({ chat_id, photo }, signal);
+ }
+
+ /**
+ * Use this method to delete a chat photo. Photos can't be changed for private chats. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target channel in the format `@username`
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#deletechatphoto
+ */
+ deleteChatPhoto(chat_id: number | string, signal?: AbortSignal) {
+ return this.raw.deleteChatPhoto({ chat_id }, signal);
+ }
+
+ /**
+ * Use this method to change the title of a chat. Titles can't be changed for private chats. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target channel in the format `@username`
+ * @param title New chat title, 1-255 characters
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setchattitle
+ */
+ setChatTitle(
+ chat_id: number | string,
+ title: string,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setChatTitle({ chat_id, title }, signal);
+ }
+
+ /**
+ * Use this method to change the description of a group, a supergroup or a channel. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target channel in the format `@username`
+ * @param description New chat description, 0-255 characters
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setchatdescription
+ */
+ setChatDescription(
+ chat_id: number | string,
+ description?: string,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setChatDescription({ chat_id, description }, signal);
+ }
+
+ /**
+ * Use this method to add a message to the list of pinned messages in a chat. In private chats and channel direct messages chats, all non-service messages can be pinned. Conversely, the bot must be an administrator with the 'can_pin_messages' right or the 'can_edit_messages' right to pin messages in groups and channels respectively. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target channel in the format `@username`
+ * @param message_id Identifier of a message to pin
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#pinchatmessage
+ */
+ pinChatMessage(
+ chat_id: number | string,
+ message_id: number,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.pinChatMessage(
+ { chat_id, message_id, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to remove a message from the list of pinned messages in a chat. In private chats and channel direct messages chats, all messages can be unpinned. Conversely, the bot must be an administrator with the 'can_pin_messages' right or the 'can_edit_messages' right to unpin messages in groups and channels respectively. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target channel in the format `@username`
+ * @param message_id Identifier of a message to unpin. If not specified, the most recent pinned message (by sending date) will be unpinned.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#unpinchatmessage
+ */
+ unpinChatMessage(
+ chat_id: number | string,
+ message_id?: number,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.unpinChatMessage(
+ { chat_id, message_id, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to clear the list of pinned messages in a chat. In private chats and channel direct messages chats, no additional rights are required to unpin all pinned messages. Conversely, the bot must be an administrator with the 'can_pin_messages' right or the 'can_edit_messages' right to unpin all pinned messages in groups and channels respectively. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target channel in the format `@username`
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#unpinallchatmessages
+ */
+ unpinAllChatMessages(chat_id: number | string, signal?: AbortSignal) {
+ return this.raw.unpinAllChatMessages({ chat_id }, signal);
+ }
+
+ /**
+ * Use this method for your bot to leave a group, supergroup or channel. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup or channel in the format `@username`. Channel direct messages chats aren't supported; leave the corresponding channel instead.
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#leavechat
+ */
+ leaveChat(chat_id: number | string, signal?: AbortSignal) {
+ return this.raw.leaveChat({ chat_id }, signal);
+ }
+
+ /**
+ * Use this method to get up to date information about the chat (current name of the user for one-on-one conversations, current username of a user, group or channel, etc.). Returns a Chat object on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup or channel in the format `@username`
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getchat
+ */
+ getChat(chat_id: number | string, signal?: AbortSignal) {
+ return this.raw.getChat({ chat_id }, signal);
+ }
+
+ /**
+ * Use this method to get a list of administrators in a chat. Returns an Array of ChatMember objects.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup or channel in the format `@username`
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getchatadministrators
+ */
+ getChatAdministrators(
+ chat_id: number | string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.getChatAdministrators({ chat_id, ...other }, signal);
+ }
+
+ /** @deprecated Use `getChatMemberCount` instead. */
+ getChatMembersCount(...args: Parameters) {
+ return this.getChatMemberCount(...args);
+ }
+
+ /**
+ * Use this method to get the number of members in a chat. Returns Integer on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup or channel in the format `@username`
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getchatmembercount
+ */
+ getChatMemberCount(chat_id: number | string, signal?: AbortSignal) {
+ return this.raw.getChatMemberCount({ chat_id }, signal);
+ }
+
+ /**
+ * Use this method to get information about a member of a chat. The method is guaranteed to work only if the bot is an administrator in the chat. Returns a ChatMember object on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup or channel (in the format @channelusername)
+ * @param user_id Unique identifier of the target user
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getchatmember
+ */
+ getChatMember(
+ chat_id: number | string,
+ user_id: number,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.getChatMember({ chat_id, user_id }, signal);
+ }
+
+ /**
+ * Use this method to get the last messages from the personal chat (i.e., the chat currently added to their profile) of a given user. On success, an Array of Message objects is returned.
+ *
+ * @param user_id Unique identifier for the target user
+ * @param limit The maximum number of messages to return; 1-20
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getuserpersonalchatmessages
+ */
+ getUserPersonalChatMessages(
+ user_id: number,
+ limit: number,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.getUserPersonalChatMessages({ user_id, limit }, signal);
+ }
+
+ /**
+ * Use this method to set a new group sticker set for a supergroup. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Use the field can_set_sticker_set ly returned in getChat requests to check if the bot can use this method. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param sticker_set_name Name of the sticker set to be set as the group sticker set
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setchatstickerset
+ */
+ setChatStickerSet(
+ chat_id: number | string,
+ sticker_set_name: string,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setChatStickerSet(
+ { chat_id, sticker_set_name },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to delete a group sticker set from a supergroup. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Use the field can_set_sticker_set ly returned in getChat requests to check if the bot can use this method. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#deletechatstickerset
+ */
+ deleteChatStickerSet(chat_id: number | string, signal?: AbortSignal) {
+ return this.raw.deleteChatStickerSet({ chat_id }, signal);
+ }
+
+ /**
+ * Use this method to get custom emoji stickers, which can be used as a forum topic icon by any user. Requires no parameters. Returns an Array of Sticker objects.
+ *
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getforumtopiciconstickers
+ */
+ getForumTopicIconStickers(signal?: AbortSignal) {
+ return this.raw.getForumTopicIconStickers(signal);
+ }
+
+ /**
+ * Use this method to create a topic in a forum supergroup chat or a private chat with a user. In the case of a supergroup chat the bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator right. Returns information about the created topic as a ForumTopic object.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param name Topic name, 1-128 characters
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#createforumtopic
+ */
+ createForumTopic(
+ chat_id: number | string,
+ name: string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.createForumTopic({ chat_id, name, ...other }, signal);
+ }
+
+ /**
+ * Use this method to edit name and icon of a topic in a forum supergroup chat or a private chat with a user. In the case of a supergroup chat the bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights, unless it is the creator of the topic. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param message_thread_id Unique identifier for the target message thread of the forum topic
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#editforumtopic
+ */
+ editForumTopic(
+ chat_id: number | string,
+ message_thread_id: number,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editForumTopic(
+ { chat_id, message_thread_id, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to close an open topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights, unless it is the creator of the topic. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param message_thread_id Unique identifier for the target message thread of the forum topic
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#closeforumtopic
+ */
+ closeForumTopic(
+ chat_id: number | string,
+ message_thread_id: number,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.closeForumTopic({ chat_id, message_thread_id }, signal);
+ }
+
+ /**
+ * Use this method to reopen a closed topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights, unless it is the creator of the topic. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param message_thread_id Unique identifier for the target message thread of the forum topic
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#reopenforumtopic
+ */
+ reopenForumTopic(
+ chat_id: number | string,
+ message_thread_id: number,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.reopenForumTopic(
+ { chat_id, message_thread_id },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to delete a forum topic along with all its messages in a forum supergroup chat or a private chat with a user. In the case of a supergroup chat the bot must be an administrator in the chat for this to work and must have the can_delete_messages administrator rights. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param message_thread_id Unique identifier for the target message thread of the forum topic
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#deleteforumtopic
+ */
+ deleteForumTopic(
+ chat_id: number | string,
+ message_thread_id: number,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.deleteForumTopic(
+ { chat_id, message_thread_id },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to clear the list of pinned messages in a forum topic in a forum supergroup chat or a private chat with a user. In the case of a supergroup chat the bot must be an administrator in the chat for this to work and must have the can_pin_messages administrator right in the supergroup. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param message_thread_id Unique identifier for the target message thread of the forum topic
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#unpinallforumtopicmessages
+ */
+ unpinAllForumTopicMessages(
+ chat_id: number | string,
+ message_thread_id: number,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.unpinAllForumTopicMessages(
+ { chat_id, message_thread_id },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to edit the name of the 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param name New topic name, 1-128 characters
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#editgeneralforumtopic
+ */
+ editGeneralForumTopic(
+ chat_id: number | string,
+ name: string,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editGeneralForumTopic({ chat_id, name }, signal);
+ }
+
+ /**
+ * Use this method to close an open 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#closegeneralforumtopic
+ */
+ closeGeneralForumTopic(chat_id: number | string, signal?: AbortSignal) {
+ return this.raw.closeGeneralForumTopic({ chat_id }, signal);
+ }
+
+ /**
+ * Use this method to reopen a closed 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights. The topic will be automatically unhidden if it was hidden. Returns True on success. *
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#reopengeneralforumtopic
+ */
+ reopenGeneralForumTopic(chat_id: number | string, signal?: AbortSignal) {
+ return this.raw.reopenGeneralForumTopic({ chat_id }, signal);
+ }
+
+ /**
+ * Use this method to hide the 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights. The topic will be automatically closed if it was open. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#hidegeneralforumtopic
+ */
+ hideGeneralForumTopic(chat_id: number | string, signal?: AbortSignal) {
+ return this.raw.hideGeneralForumTopic({ chat_id }, signal);
+ }
+
+ /**
+ * Use this method to unhide the 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#unhidegeneralforumtopic
+ */
+ unhideGeneralForumTopic(chat_id: number | string, signal?: AbortSignal) {
+ return this.raw.unhideGeneralForumTopic({ chat_id }, signal);
+ }
+
+ /**
+ * Use this method to clear the list of pinned messages in a General forum topic. The bot must be an administrator in the chat for this to work and must have the can_pin_messages administrator right in the supergroup. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#unpinallgeneralforumtopicmessages
+ */
+ unpinAllGeneralForumTopicMessages(
+ chat_id: number | string,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.unpinAllGeneralForumTopicMessages({ chat_id }, signal);
+ }
+
+ /**
+ * Use this method to send answers to callback queries sent from inline keyboards. The answer will be displayed to the user as a notification at the top of the chat screen or as an alert. On success, True is returned.
+ *
+ * Alternatively, the user can be redirected to the specified Game URL. For this option to work, you must first create a game for your bot via @BotFather and accept the terms. Otherwise, you may use links like t.me/your_bot?start=XXXX that open your bot with a parameter.
+ *
+ * @param callback_query_id Unique identifier for the query to be answered
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#answercallbackquery
+ */
+ answerCallbackQuery(
+ callback_query_id: string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.answerCallbackQuery(
+ { callback_query_id, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to reply to a received guest message. On success, a SentGuestMessage object is returned.
+ *
+ * @param guest_query_id Unique identifier for the query to be answered
+ * @param result An object describing the message to be sent
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#answerguestquery
+ */
+ answerGuestQuery(
+ guest_query_id: string,
+ result: InlineQueryResult,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.answerGuestQuery({ guest_query_id, result }, signal);
+ }
+
+ /**
+ * Use this method to change the bot's name. Returns True on success.
+ *
+ * @param name New bot name; 0-64 characters. Pass an empty string to remove the dedicated name for the given language.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setmyname
+ */
+ setMyName(
+ name: string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setMyName({ name, ...other }, signal);
+ }
+
+ /**
+ * Use this method to get the current bot name for the given user language. Returns BotName on success.
+ *
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getmyname
+ */
+ getMyName(other?: Other, signal?: AbortSignal) {
+ return this.raw.getMyName(other ?? {}, signal);
+ }
+
+ /**
+ * Use this method to change the list of the bot's commands. See https://core.telegram.org/bots/features#commands for more details about bot commands. Returns True on success.
+ *
+ * @param commands A list of bot commands to be set as the list of the bot's commands. At most 100 commands can be specified.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setmycommands
+ */
+ setMyCommands(
+ commands: readonly BotCommand[],
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setMyCommands({ commands, ...other }, signal);
+ }
+
+ /**
+ * Use this method to delete the list of the bot's commands for the given scope and user language. After deletion, higher level commands will be shown to affected users. Returns True on success.
+ *
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#deletemycommands
+ */
+ deleteMyCommands(
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.deleteMyCommands({ ...other }, signal);
+ }
+
+ /**
+ * Use this method to get the current list of the bot's commands for the given scope and user language. Returns an Array of BotCommand objects. If commands aren't set, an empty list is returned.
+ *
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getmycommands
+ */
+ getMyCommands(other?: Other, signal?: AbortSignal) {
+ return this.raw.getMyCommands({ ...other }, signal);
+ }
+
+ /**
+ * Use this method to change the bot's description, which is shown in the chat with the bot if the chat is empty. Returns True on success.
+ *
+ * @param description New bot description; 0-512 characters. Pass an empty string to remove the dedicated description for the given language.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setmydescription
+ */
+ setMyDescription(
+ description: string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setMyDescription({ description, ...other }, signal);
+ }
+
+ /**
+ * Use this method to get the current bot description for the given user language. Returns BotDescription on success.
+ *
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getmydescription
+ */
+ getMyDescription(
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.getMyDescription({ ...other }, signal);
+ }
+
+ /**
+ * Use this method to change the bot's short description, which is shown on the bot's profile page and is sent together with the link when users share the bot. Returns True on success.
+ *
+ * @param short_description New short description for the bot; 0-120 characters. Pass an empty string to remove the dedicated short description for the given language.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setmyshortdescription
+ */
+ setMyShortDescription(
+ short_description: string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setMyShortDescription(
+ { short_description, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to get the current bot short description for the given user language. Returns BotShortDescription on success.
+ *
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getmyshortdescription
+ */
+ getMyShortDescription(
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.getMyShortDescription({ ...other }, signal);
+ }
+
+ /**
+ * Changes the profile photo of the bot. Returns True on success.
+ *
+ * @param photo The new profile photo to set
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setmyprofilephoto
+ */
+ setMyProfilePhoto(
+ photo: InputProfilePhoto,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setMyProfilePhoto({ photo }, signal);
+ }
+
+ /**
+ * Removes the profile photo of the bot. Requires no parameters. Returns True on success.
+ *
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#removemyprofilephoto
+ */
+ removeMyProfilePhoto(signal?: AbortSignal) {
+ return this.raw.removeMyProfilePhoto(signal);
+ }
+
+ /**
+ * Use this method to change the bot's menu button in a private chat, or the default menu button. Returns True on success.
+ *
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setchatmenubutton
+ */
+ setChatMenuButton(
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setChatMenuButton({ ...other }, signal);
+ }
+
+ /**
+ * Use this method to get the current value of the bot's menu button in a private chat, or the default menu button. Returns MenuButton on success.
+ *
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getchatmenubutton
+ */
+ getChatMenuButton(
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.getChatMenuButton({ ...other }, signal);
+ }
+
+ /**
+ * Use this method to the change the default administrator rights requested by the bot when it's added as an administrator to groups or channels. These rights will be suggested to users, but they are are free to modify the list before adding the bot. Returns True on success.
+ *
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setmydefaultadministratorrights
+ */
+ setMyDefaultAdministratorRights(
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setMyDefaultAdministratorRights({ ...other }, signal);
+ }
+
+ /**
+ * Use this method to get the current default administrator rights of the bot. Returns ChatAdministratorRights on success.
+ *
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getmydefaultadministratorrights
+ */
+ getMyDefaultAdministratorRights(
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.getMyDefaultAdministratorRights({ ...other }, signal);
+ }
+
+ /**
+ * A method to get the current Telegram Stars balance of the bot. Requires no parameters. On success, returns a StarAmount object.
+ *
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getmystarbalance
+ */
+ getMyStarBalance(signal?: AbortSignal) {
+ return this.raw.getMyStarBalance(signal);
+ }
+
+ /**
+ * Use this method to edit text, rich and game messages. On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within 48 hours from the time they were sent.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param message_id Identifier of the message to edit
+ * @param text_or_rich_message New text or rich content of the message, a string maps to the `text` parameter and an object maps to the `rich_message` parameter
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#editmessagetext
+ */
+ editMessageText(
+ chat_id: number | string,
+ message_id: number,
+ text_or_rich_message: string | InputRichMessage,
+ other?: Other<
+ R,
+ "editMessageText",
+ | "chat_id"
+ | "message_id"
+ | "inline_message_id"
+ | "text"
+ | "rich_message"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editMessageText(
+ typeof text_or_rich_message === "string"
+ ? { chat_id, message_id, text: text_or_rich_message, ...other }
+ : {
+ chat_id,
+ message_id,
+ rich_message: text_or_rich_message,
+ ...other,
+ },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to edit text, rich and game inline messages. On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within 48 hours from the time they were sent.
+ *
+ * @param inline_message_id Identifier of the inline message
+ * @param text_or_rich_message New text or rich content of the message, a string maps to the `text` parameter and an object maps to the `rich_message` parameter
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#editmessagetext
+ */
+ editMessageTextInline(
+ inline_message_id: string,
+ text_or_rich_message: string | InputRichMessage,
+ other?: Other<
+ R,
+ "editMessageText",
+ | "chat_id"
+ | "message_id"
+ | "inline_message_id"
+ | "text"
+ | "rich_message"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editMessageText(
+ typeof text_or_rich_message === "string"
+ ? { inline_message_id, text: text_or_rich_message, ...other }
+ : {
+ inline_message_id,
+ rich_message: text_or_rich_message,
+ ...other,
+ },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to edit captions of messages. On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within 48 hours from the time they were sent.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param message_id Identifier of the message to edit
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#editmessagecaption
+ */
+ editMessageCaption(
+ chat_id: number | string,
+ message_id: number,
+ other?: Other<
+ R,
+ "editMessageCaption",
+ "chat_id" | "message_id" | "inline_message_id"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editMessageCaption(
+ { chat_id, message_id, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to edit captions of inline messages. On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within 48 hours from the time they were sent.
+ *
+ * @param inline_message_id Identifier of the inline message
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#editmessagecaption
+ */
+ editMessageCaptionInline(
+ inline_message_id: string,
+ other?: Other<
+ R,
+ "editMessageCaption",
+ "chat_id" | "message_id" | "inline_message_id"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editMessageCaption(
+ { inline_message_id, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to edit animation, audio, document, live photo, photo, or video messages, or to replace a text or a rich message with a media. If a message is part of a message album, then it can be edited only to an audio for audio albums, only to a document for document albums and to a photo, a live photo, or a video otherwise. When an inline message is edited, a new file can't be uploaded; use a previously uploaded file via its file_id or specify a URL. On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within 48 hours from the time they were sent.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param message_id Identifier of the message to edit
+ * @param media An object for a new media content of the message
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#editmessagemedia
+ */
+ editMessageMedia(
+ chat_id: number | string,
+ message_id: number,
+ media: InputMedia,
+ other?: Other<
+ R,
+ "editMessageMedia",
+ "chat_id" | "message_id" | "inline_message_id" | "media"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editMessageMedia(
+ { chat_id, message_id, media, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to edit animation, audio, document, live photo, photo, or video inline messages, or to replace a text or a rich message with a media. If a message is part of a message album, then it can be edited only to an audio for audio albums, only to a document for document albums and to a photo, a live photo, or a video otherwise. When an inline message is edited, a new file can't be uploaded; use a previously uploaded file via its file_id or specify a URL. On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within 48 hours from the time they were sent.
+ *
+ * @param inline_message_id Identifier of the inline message
+ * @param media An object for a new media content of the message
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#editmessagemedia
+ */
+ editMessageMediaInline(
+ inline_message_id: string,
+ media: InputMedia,
+ other?: Other<
+ R,
+ "editMessageMedia",
+ "chat_id" | "message_id" | "inline_message_id" | "media"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editMessageMedia(
+ { inline_message_id, media, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to edit only the reply markup of messages. On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within 48 hours from the time they were sent.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param message_id Identifier of the message to edit
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#editmessagereplymarkup
+ */
+ editMessageReplyMarkup(
+ chat_id: number | string,
+ message_id: number,
+ other?: Other<
+ R,
+ "editMessageReplyMarkup",
+ "chat_id" | "message_id" | "inline_message_id"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editMessageReplyMarkup(
+ { chat_id, message_id, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to edit only the reply markup of inline messages. On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within 48 hours from the time they were sent.
+ *
+ * @param inline_message_id Identifier of the inline message
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#editmessagereplymarkup
+ */
+ editMessageReplyMarkupInline(
+ inline_message_id: string,
+ other?: Other<
+ R,
+ "editMessageReplyMarkup",
+ "chat_id" | "message_id" | "inline_message_id"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editMessageReplyMarkup(
+ { inline_message_id, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to stop a poll which was sent by the bot. On success, the stopped Poll is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param message_id Identifier of the original message with the poll
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#stoppoll
+ */
+ stopPoll(
+ chat_id: number | string,
+ message_id: number,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.stopPoll({ chat_id, message_id, ...other }, signal);
+ }
+
+ /**
+ * Use this method to edit an ephemeral text message. Note that it is not guaranteed that the user will receive the message edit event, especially if they are offline. On success, True is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param receiver_user_id Identifier of the user who received the message
+ * @param ephemeral_message_id Identifier of the ephemeral message to edit
+ * @param text New text of the message, 1-4096 characters after entity parsing
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#editephemeralmessagetext
+ */
+ editEphemeralMessageText(
+ chat_id: number | string,
+ receiver_user_id: number,
+ ephemeral_message_id: number,
+ text: string,
+ other?: Other<
+ R,
+ "editEphemeralMessageText",
+ "chat_id" | "receiver_user_id" | "ephemeral_message_id" | "text"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editEphemeralMessageText(
+ { chat_id, receiver_user_id, ephemeral_message_id, text, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to edit the media of an ephemeral message. Note that it is not guaranteed that the user will receive the message edit event, especially if they are offline. On success, True is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param receiver_user_id Identifier of the user who received the message
+ * @param ephemeral_message_id Identifier of the ephemeral message to edit
+ * @param media An object for the new media content of the message. A new file can't be uploaded; use a previously uploaded file via its file_id or specify a URL.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#editephemeralmessagemedia
+ */
+ editEphemeralMessageMedia(
+ chat_id: number | string,
+ receiver_user_id: number,
+ ephemeral_message_id: number,
+ media: InputMediaWithoutUpload,
+ other?: Other<
+ R,
+ "editEphemeralMessageMedia",
+ "chat_id" | "receiver_user_id" | "ephemeral_message_id" | "media"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editEphemeralMessageMedia({
+ chat_id,
+ receiver_user_id,
+ ephemeral_message_id,
+ media,
+ ...other,
+ }, signal);
+ }
+
+ /**
+ * Use this method to edit the caption of an ephemeral message. Note that it is not guaranteed that the user will receive the message edit event, especially if they are offline. On success, True is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param receiver_user_id Identifier of the user who received the message
+ * @param ephemeral_message_id Identifier of the ephemeral message to edit
+ * @param caption New caption of the message, 0-1024 characters after entities parsing
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#editephemeralmessagecaption
+ */
+ editEphemeralMessageCaption(
+ chat_id: number | string,
+ receiver_user_id: number,
+ ephemeral_message_id: number,
+ caption: string,
+ other?: Other<
+ R,
+ "editEphemeralMessageCaption",
+ "chat_id" | "receiver_user_id" | "ephemeral_message_id" | "caption"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editEphemeralMessageCaption({
+ chat_id,
+ receiver_user_id,
+ ephemeral_message_id,
+ caption,
+ ...other,
+ }, signal);
+ }
+
+ /**
+ * Use this method to edit only the reply markup of an ephemeral message. Note that it is not guaranteed that the user will receive the message edit event, especially if they are offline. On success, True is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param receiver_user_id Identifier of the user who received the message
+ * @param ephemeral_message_id Identifier of the ephemeral message to edit
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#editephemeralmessagecaption
+ */
+ editEphemeralMessageReplyMarkup(
+ chat_id: number | string,
+ receiver_user_id: number,
+ ephemeral_message_id: number,
+ other?: Other<
+ R,
+ "editEphemeralMessageReplyMarkup",
+ "chat_id" | "receiver_user_id" | "ephemeral_message_id"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editEphemeralMessageReplyMarkup(
+ { chat_id, receiver_user_id, ephemeral_message_id, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to delete a message, including service messages, with the following limitations:
+ * - A message can only be deleted if it was sent less than 48 hours ago.
+ * - A dice message in a private chat can only be deleted if it was sent more than 24 hours ago.
+ * - Bots can delete outgoing messages in private chats, groups, and supergroups.
+ * - Bots can delete incoming messages in private chats.
+ * - Bots granted can_post_messages permissions can delete outgoing messages in channels.
+ * - If the bot is an administrator of a group, it can delete any message there.
+ * - If the bot has can_delete_messages administrator right in a supergroup or a channel, it can delete any message there.
+ * - If the bot has can_manage_direct_messages administrator right in a channel, it can delete any message in the corresponding direct messages chat.
+ * Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param message_id Identifier of the message to delete
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#deletemessage
+ */
+ deleteMessage(
+ chat_id: number | string,
+ message_id: number,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.deleteMessage({ chat_id, message_id }, signal);
+ }
+
+ /**
+ * Use this method to delete multiple messages simultaneously. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param message_ids A list of 1-100 identifiers of messages to delete. See deleteMessage for limitations on which messages can be deleted
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#deletemessages
+ */
+ deleteMessages(
+ chat_id: number | string,
+ message_ids: number[],
+ signal?: AbortSignal,
+ ) {
+ return this.raw.deleteMessages({ chat_id, message_ids }, signal);
+ }
+
+ /**
+ * Use this method to delete an ephemeral message. Note that it is not guaranteed that the user will receive the message deletion event, especially if they are offline. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param receiver_user_id Identifier of the user who received the message
+ * @param ephemeral_message_id Identifier of the ephemeral message to delete
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#deleteephemeralmessage
+ */
+ deleteEphemeralMessage(
+ chat_id: number | string,
+ receiver_user_id: number,
+ ephemeral_message_id: number,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.deleteEphemeralMessage(
+ { chat_id, receiver_user_id, ephemeral_message_id },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to remove a reaction from a message in a group or a supergroup chat. The bot must have the 'can_delete_messages' administrator right in the chat. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param message_id Identifier of the target message
+ * @param user_id Identifier of the user whose reaction will be removed
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#deletemessagereaction
+ */
+ deleteMessageReactionUser(
+ chat_id: number | string,
+ message_id: number,
+ user_id: number,
+ other?: Other<
+ R,
+ "deleteMessageReaction",
+ "chat_id" | "message_id" | "user_id"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.deleteMessageReaction({
+ chat_id,
+ message_id,
+ user_id,
+ ...other,
+ }, signal);
+ }
+
+ /**
+ * Use this method to remove a reaction from a message in a group or a supergroup chat. The bot must have the 'can_delete_messages' administrator right in the chat. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param message_id Identifier of the target message
+ * @param actor_chat_id Identifier of the chat whose reaction will be removed
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#deletemessagereaction
+ */
+ deleteMessageReactionChat(
+ chat_id: number | string,
+ message_id: number,
+ actor_chat_id: number,
+ other?: Other<
+ R,
+ "deleteMessageReaction",
+ "chat_id" | "message_id" | "actor_chat_id"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.deleteMessageReaction({
+ chat_id,
+ message_id,
+ actor_chat_id,
+ ...other,
+ }, signal);
+ }
+
+ /**
+ * Use this method to remove up to 10000 recent reactions in a group or a supergroup chat added by a given user. The bot must have the 'can_delete_messages' administrator right in the chat. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param user_id Identifier of the user whose reactions will be removed, if the reactions were added by a user
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#deleteallmessagereactions
+ */
+ deleteAllMessageReactionsUser(
+ chat_id: number | string,
+ user_id: number,
+ other?: Other<
+ R,
+ "deleteAllMessageReactions",
+ "chat_id" | "message_id" | "user_id"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.deleteAllMessageReactions({
+ chat_id,
+ user_id,
+ ...other,
+ }, signal);
+ }
+
+ /**
+ * Use this method to remove up to 10000 recent reactions in a group or a supergroup chat added by a given chat. The bot must have the 'can_delete_messages' administrator right in the chat. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target supergroup in the format `@username`
+ * @param actor_chat_id Identifier of the chat whose reactions will be removed, if the reactions were added by a chat
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#deleteallmessagereactions
+ */
+ deleteAllMessageReactionsChat(
+ chat_id: number | string,
+ actor_chat_id: number,
+ other?: Other<
+ R,
+ "deleteAllMessageReactions",
+ "chat_id" | "message_id" | "actor_chat_id"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.deleteAllMessageReactions({
+ chat_id,
+ actor_chat_id,
+ ...other,
+ }, signal);
+ }
+
+ /**
+ * Delete messages on behalf of a business account. Requires the can_delete_outgoing_messages business bot right to delete messages sent by the bot itself, or the can_delete_all_messages business bot right to delete any message. Returns True on success.
+ *
+ * @param business_connection_id Unique identifier of the business connection on behalf of which to delete the messages
+ * @param message_ids A list of 1-100 identifiers of messages to delete. All messages must be from the same chat. See deleteMessage for limitations on which messages can be deleted
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#deletebusinessmessages
+ */
+ deleteBusinessMessages(
+ business_connection_id: string,
+ message_ids: number[],
+ signal?: AbortSignal,
+ ) {
+ return this.raw.deleteBusinessMessages(
+ { business_connection_id, message_ids },
+ signal,
+ );
+ }
+
+ /**
+ * Changes the first and last name of a managed business account. Requires the can_change_name business bot right. Returns True on success.
+ *
+ * @param business_connection_id Unique identifier of the business connection
+ * @param first_name The new value of the first name for the business account; 1-64 characters
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setbusinessaccountname
+ */
+ setBusinessAccountName(
+ business_connection_id: string,
+ first_name: string,
+ other: Other<
+ R,
+ "setBusinessAccountName",
+ "business_connection_id" | "first_name"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setBusinessAccountName(
+ { business_connection_id, first_name, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Changes the username of a managed business account. Requires the can_change_username business bot right. Returns True on success.
+ *
+ * @param business_connection_id Unique identifier of the business connection *
+ * @param username The new value of the username for the business account; 0-32 characters
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setbusinessaccountusername
+ */
+ setBusinessAccountUsername(
+ business_connection_id: string,
+ username: string,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setBusinessAccountUsername(
+ { business_connection_id, username },
+ signal,
+ );
+ }
+
+ /**
+ * Changes the bio of a managed business account. Requires the can_change_bio business bot right. Returns True on success.
+ *
+ * @param business_connection_id Unique identifier of the business connection
+ * @param bio The new value of the bio for the business account; 0-140 characters
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setbusinessaccountbio
+ */
+ setBusinessAccountBio(
+ business_connection_id: string,
+ bio: string,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setBusinessAccountBio(
+ { business_connection_id, bio },
+ signal,
+ );
+ }
+
+ /**
+ * Changes the profile photo of a managed business account. Requires the can_edit_profile_photo business bot right. Returns True on success.
+ *
+ * @param business_connection_id Unique identifier of the business connection
+ * @param photo The new profile photo to set
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setbusinessaccountprofilephoto
+ */
+ setBusinessAccountProfilePhoto(
+ business_connection_id: string,
+ photo: InputProfilePhoto,
+ other: Other<
+ R,
+ "setBusinessAccountProfilePhoto",
+ "business_connection_id" | "photo"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setBusinessAccountProfilePhoto(
+ { business_connection_id, photo, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Removes the current profile photo of a managed business account. Requires the can_edit_profile_photo business bot right. Returns True on success.
+ *
+ * @param business_connection_id Unique identifier of the business connection
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#removebusinessaccountprofilephoto
+ */
+ removeBusinessAccountProfilePhoto(
+ business_connection_id: string,
+ other: Other<
+ R,
+ "removeBusinessAccountProfilePhoto",
+ "business_connection_id"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.removeBusinessAccountProfilePhoto(
+ { business_connection_id, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Changes the privacy settings pertaining to incoming gifts in a managed business account. Requires the can_change_gift_settings business bot right. Returns True on success.
+ *
+ * @param business_connection_id Unique identifier of the business connection
+ * @param show_gift_button Pass True, if a button for sending a gift to the user or by the business account must always be shown in the input field
+ * @param accepted_gift_types Types of gifts accepted by the business account
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setbusinessaccountgiftsettings
+ */
+ setBusinessAccountGiftSettings(
+ business_connection_id: string,
+ show_gift_button: boolean,
+ accepted_gift_types: AcceptedGiftTypes,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setBusinessAccountGiftSettings(
+ { business_connection_id, show_gift_button, accepted_gift_types },
+ signal,
+ );
+ }
+
+ /**
+ * Returns the amount of Telegram Stars owned by a managed business account. Requires the can_view_gifts_and_stars business bot right. Returns StarAmount on success.
+ *
+ * @param business_connection_id Unique identifier of the business connection
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getbusinessaccountstarbalance
+ */
+ getBusinessAccountStarBalance(
+ business_connection_id: string,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.getBusinessAccountStarBalance(
+ { business_connection_id },
+ signal,
+ );
+ }
+
+ /**
+ * Transfers Telegram Stars from the business account balance to the bot's balance. Requires the can_transfer_stars business bot right. Returns True on success.
+ *
+ * @param business_connection_id Unique identifier of the business connection
+ * @param star_count Number of Telegram Stars to transfer; 1-10000
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#transferbusinessaccountstars
+ */
+ transferBusinessAccountStars(
+ business_connection_id: string,
+ star_count: number,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.transferBusinessAccountStars(
+ { business_connection_id, star_count },
+ signal,
+ );
+ }
+
+ /**
+ * Returns the gifts received and owned by a managed business account. Requires the can_view_gifts_and_stars business bot right. Returns OwnedGifts on success.
+ *
+ * @param business_connection_id Unique identifier of the business connection
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getbusinessaccountgifts
+ */
+ getBusinessAccountGifts(
+ business_connection_id: string,
+ other: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.getBusinessAccountGifts(
+ { business_connection_id, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Converts a given regular gift to Telegram Stars. Requires the can_convert_gifts_to_stars business bot right. Returns True on success.
+ *
+ * @param business_connection_id Unique identifier of the business connection
+ * @param owned_gift_id Unique identifier of the regular gift that should be converted to Telegram Stars
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#convertgifttostars
+ */
+ convertGiftToStars(
+ business_connection_id: string,
+ owned_gift_id: string,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.convertGiftToStars(
+ { business_connection_id, owned_gift_id },
+ signal,
+ );
+ }
+
+ /**
+ * Upgrades a given regular gift to a unique gift. Requires the can_transfer_and_upgrade_gifts business bot right. Additionally requires the can_transfer_stars business bot right if the upgrade is paid. Returns True on success.
+ *
+ * @param business_connection_id Unique identifier of the business connection
+ * @param owned_gift_id Unique identifier of the regular gift that should be upgraded to a unique one
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#upgradegift
+ */
+ upgradeGift(
+ business_connection_id: string,
+ owned_gift_id: string,
+ other: Other<
+ R,
+ "getBusinessAccountGifts",
+ "business_connection_id" | "owned_gift_id"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.upgradeGift(
+ { business_connection_id, owned_gift_id, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Transfers an owned unique gift to another user. Requires the can_transfer_and_upgrade_gifts business bot right. Requires can_transfer_stars business bot right if the transfer is paid. Returns True on success.
+ *
+ * @param business_connection_id Unique identifier of the business connection
+ * @param owned_gift_id Unique identifier of the regular gift that should be transferred
+ * @param new_owner_chat_id Unique identifier of the chat which will own the gift. The chat must be active in the last 24 hours.
+ * @param star_count The amount of Telegram Stars that will be paid for the transfer from the business account balance. If positive, then the can_transfer_stars business bot right is required.
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#transfergift
+ */
+ transferGift(
+ business_connection_id: string,
+ owned_gift_id: string,
+ new_owner_chat_id: number,
+ star_count: number,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.transferGift({
+ business_connection_id,
+ owned_gift_id,
+ new_owner_chat_id,
+ star_count,
+ }, signal);
+ }
+
+ /**
+ * Posts a story on behalf of a managed business account. Requires the can_manage_stories business bot right. Returns Story on success.
+ *
+ * @param business_connection_id Unique identifier of the business connection
+ * @param content Content of the story
+ * @param active_period Period after which the story is moved to the archive, in seconds; must be one of 6 * 3600, 12 * 3600, 86400, or 2 * 86400
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#poststory
+ */
+ postStory(
+ business_connection_id: string,
+ content: InputStoryContent,
+ active_period: number,
+ other: Other<
+ R,
+ "postStory",
+ "business_connection_id" | "content" | "active_period"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.postStory(
+ { business_connection_id, content, active_period, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Reposts a story on behalf of a business account from another business account. Both business accounts must be managed by the same bot, and the story on the source account must have been posted (or reposted) by the bot. Requires the can_manage_stories business bot right for both business accounts. Returns Story on success.
+ *
+ * @param business_connection_id Unique identifier of the business connection
+ * @param from_chat_id Unique identifier of the chat which posted the story that should be reposted
+ * @param from_story_id Unique identifier of the story that should be reposted
+ * @param active_period Period after which the story is moved to the archive, in seconds; must be one of 6 * 3600, 12 * 3600, 86400, or 2 * 86400
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#repoststory
+ */
+ repostStory(
+ business_connection_id: string,
+ from_chat_id: number,
+ from_story_id: number,
+ active_period: number,
+ other: Other<
+ R,
+ "repostStory",
+ | "business_connection_id"
+ | "from_chat_id"
+ | "from_story_id"
+ | "active_period"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.repostStory({
+ business_connection_id,
+ from_chat_id,
+ from_story_id,
+ active_period,
+ ...other,
+ }, signal);
+ }
+
+ /**
+ * Edits a story previously posted by the bot on behalf of a managed business account. Requires the can_manage_stories business bot right. Returns Story on success.
+ *
+ * @param business_connection_id Unique identifier of the business connection
+ * @param story_id Unique identifier of the story to edit
+ * @param content Content of the story
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#editstory
+ */
+ editStory(
+ business_connection_id: string,
+ story_id: number,
+ content: InputStoryContent,
+ other: Other<
+ R,
+ "editStory",
+ "business_connection_id" | "story_id" | "content"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editStory(
+ { business_connection_id, story_id, content, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Deletes a story previously posted by the bot on behalf of a managed business account. Requires the can_manage_stories business bot right. Returns True on success.
+ *
+ * @param business_connection_id Unique identifier of the business connection
+ * @param story_id Unique identifier of the story to delete
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#deletestory
+ */
+ deleteStory(
+ business_connection_id: string,
+ story_id: number,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.deleteStory(
+ { business_connection_id, story_id },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to send static .WEBP, animated .TGS, or video .WEBM stickers. On success, the sent Message is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param sticker Sticker to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a .WEBP sticker from the Internet, or upload a new .WEBP, .TGS, or .WEBM sticker using multipart/form-data. Video and animated stickers can't be sent via an HTTP URL.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendsticker
+ */
+ sendSticker(
+ chat_id: number | string,
+ sticker: InputFile | string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendSticker({ chat_id, sticker, ...other }, signal);
+ }
+
+ /**
+ * Use this method to get a sticker set. On success, a StickerSet object is returned.
+ *
+ * @param name Name of the sticker set
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getstickerset
+ */
+ getStickerSet(name: string, signal?: AbortSignal) {
+ return this.raw.getStickerSet({ name }, signal);
+ }
+
+ /**
+ * Use this method to get information about custom emoji stickers by their identifiers. Returns an Array of Sticker objects.
+ *
+ * @param custom_emoji_ids A list of custom emoji identifiers
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getcustomemojistickers
+ */
+ getCustomEmojiStickers(custom_emoji_ids: string[], signal?: AbortSignal) {
+ return this.raw.getCustomEmojiStickers({ custom_emoji_ids }, signal);
+ }
+
+ /**
+ * Use this method to upload a file with a sticker for later use in the createNewStickerSet, addStickerToSet, or replaceStickerInSet methods (the file can be used multiple times). Returns the uploaded File on success.
+ *
+ * @param user_id User identifier of sticker file owner
+ * @param sticker_format Format of the sticker, must be one of βstaticβ, βanimatedβ, βvideoβ
+ * @param sticker A file with the sticker in .WEBP, .PNG, .TGS, or .WEBM format. See https://core.telegram.org/stickers for technical requirements.
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#uploadstickerfile
+ */
+ uploadStickerFile(
+ user_id: number,
+ sticker_format: "static" | "animated" | "video",
+ sticker: InputFile,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.uploadStickerFile(
+ { user_id, sticker_format, sticker },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to create a new sticker set owned by a user. The bot will be able to edit the sticker set thus created. Returns True on success.
+ *
+ * @param user_id User identifier of created sticker set owner
+ * @param name Short name of sticker set, to be used in t.me/addstickers/ URLs (e.g., animals). Can contain only English letters, digits and underscores. Must begin with a letter, can't contain consecutive underscores and must end in `_by_`. `` is case insensitive. 1-64 characters.
+ * @param title Sticker set title, 1-64 characters
+ * @param stickers A list of 1-50 initial stickers to be added to the sticker set
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#createnewstickerset
+ */
+ createNewStickerSet(
+ user_id: number,
+ name: string,
+ title: string,
+ stickers: InputSticker[],
+ other?: Other<
+ R,
+ "createNewStickerSet",
+ | "user_id"
+ | "name"
+ | "title"
+ | "sticker_format"
+ | "stickers"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.createNewStickerSet(
+ { user_id, name, title, stickers, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to add a new sticker to a set created by the bot. The format of the added sticker must match the format of the other stickers in the set. Emoji sticker sets can have up to 200 stickers. Animated and video sticker sets can have up to 50 stickers. Static sticker sets can have up to 120 stickers. Returns True on success.
+ *
+ * @param user_id User identifier of sticker set owner
+ * @param name Sticker set name
+ * @param sticker An object with information about the added sticker. If exactly the same sticker had already been added to the set, then the set isn't changed.
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#addstickertoset
+ */
+ addStickerToSet(
+ user_id: number,
+ name: string,
+ sticker: InputSticker,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.addStickerToSet(
+ { user_id, name, sticker },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to move a sticker in a set created by the bot to a specific position. Returns True on success.
+ *
+ * @param sticker File identifier of the sticker
+ * @param position New sticker position in the set, zero-based
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setstickerpositioninset
+ */
+ setStickerPositionInSet(
+ sticker: string,
+ position: number,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setStickerPositionInSet({ sticker, position }, signal);
+ }
+
+ /**
+ * Use this method to delete a sticker from a set created by the bot. Returns True on success.
+ *
+ * @param sticker File identifier of the sticker
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#deletestickerfromset
+ */
+ deleteStickerFromSet(sticker: string, signal?: AbortSignal) {
+ return this.raw.deleteStickerFromSet({ sticker }, signal);
+ }
+
+ /**
+ * Use this method to replace an existing sticker in a sticker set with a new one. The method is equivalent to calling deleteStickerFromSet, then addStickerToSet, then setStickerPositionInSet. Returns True on success.
+ *
+ * @param user_id User identifier of the sticker set owner
+ * @param name Sticker set name
+ * @param old_sticker File identifier of the replaced sticker
+ * @param sticker An object with information about the added sticker. If exactly the same sticker had already been added to the set, then the set remains unchanged.:x
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#replacestickerinset
+ */
+ replaceStickerInSet(
+ user_id: number,
+ name: string,
+ old_sticker: string,
+ sticker: InputSticker,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.replaceStickerInSet(
+ { user_id, name, old_sticker, sticker },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to change the list of emoji assigned to a regular or custom emoji sticker. The sticker must belong to a sticker set created by the bot. Returns True on success.
+ *
+ * @param sticker File identifier of the sticker
+ * @param emoji_list A list of 1-20 emoji associated with the sticker
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setstickeremojilist
+ */
+ setStickerEmojiList(
+ sticker: string,
+ emoji_list: string[],
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setStickerEmojiList({ sticker, emoji_list }, signal);
+ }
+
+ /**
+ * Use this method to change search keywords assigned to a regular or custom emoji sticker. The sticker must belong to a sticker set created by the bot. Returns True on success.
+ *
+ * @param sticker File identifier of the sticker
+ * @param keywords A list of 0-20 search keywords for the sticker with total length of up to 64 characters
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setstickerkeywords
+ */
+ setStickerKeywords(
+ sticker: string,
+ keywords: string[],
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setStickerKeywords({ sticker, keywords }, signal);
+ }
+
+ /**
+ * Use this method to change the mask position of a mask sticker. The sticker must belong to a sticker set that was created by the bot. Returns True on success.
+ *
+ * @param sticker File identifier of the sticker
+ * @param mask_position An object with the position where the mask should be placed on faces. Omit the parameter to remove the mask position.
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setstickermaskposition
+ */
+ setStickerMaskPosition(
+ sticker: string,
+ mask_position?: MaskPosition,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setStickerMaskPosition(
+ { sticker, mask_position },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to set the title of a created sticker set. Returns True on success.
+ *
+ * @param name Sticker set name
+ * @param title Sticker set title, 1-64 characters
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setstickersettitle
+ */
+ setStickerSetTitle(name: string, title: string, signal?: AbortSignal) {
+ return this.raw.setStickerSetTitle({ name, title }, signal);
+ }
+
+ /**
+ * Use this method to delete a sticker set that was created by the bot. Returns True on success.
+ *
+ * @param name Sticker set name
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#deletestickerset
+ */
+ deleteStickerSet(name: string, signal?: AbortSignal) {
+ return this.raw.deleteStickerSet({ name }, signal);
+ }
+
+ /**
+ * Use this method to set the thumbnail of a regular or mask sticker set. The format of the thumbnail file must match the format of the stickers in the set. Returns True on success.
+ *
+ * @param name Sticker set name
+ * @param user_id User identifier of the sticker set owner
+ * @param thumbnail A .WEBP or .PNG image with the thumbnail, must be up to 128 kilobytes in size and have a width and height of exactly 100px, or a .TGS animation with a thumbnail up to 32 kilobytes in size (see https://core.telegram.org/stickers#animated-sticker-requirements for animated sticker technical requirements), or a WEBM video with the thumbnail up to 32 kilobytes in size; see https://core.telegram.org/stickers#video-sticker-requirements for video sticker technical requirements. Pass a file_id as a String to send a file that already exists on the Telegram servers, pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data. More information on Sending Files Β». Animated and video sticker set thumbnails can't be uploaded via HTTP URL. If omitted, then the thumbnail is dropped and the first sticker is used as the thumbnail.
+ * @param format Format of the thumbnail, must be one of βstaticβ for a .WEBP or .PNG image, βanimatedβ for a .TGS animation, or βvideoβ for a WEBM video
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setstickersetthumbnail
+ */
+ setStickerSetThumbnail(
+ name: string,
+ user_id: number,
+ thumbnail: InputFile | string | undefined,
+ format: "static" | "animated" | "video",
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setStickerSetThumbnail(
+ { name, user_id, thumbnail, format },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to set the thumbnail of a custom emoji sticker set. Returns True on success.
+ *
+ * @param name Sticker set name
+ * @param custom_emoji_id Custom emoji identifier of a sticker from the sticker set; pass an empty string to drop the thumbnail and use the first sticker as the thumbnail.
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setcustomemojistickersetthumbnail
+ */
+ setCustomEmojiStickerSetThumbnail(
+ name: string,
+ custom_emoji_id: string,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setCustomEmojiStickerSetThumbnail({
+ name,
+ custom_emoji_id,
+ }, signal);
+ }
+
+ /**
+ * Returns the list of gifts that can be sent by the bot to users and channel chats. Requires no parameters. Returns a Gifts object.
+ *
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getavailablegifts
+ */
+ getAvailableGifts(signal?: AbortSignal) {
+ return this.raw.getAvailableGifts(signal);
+ }
+
+ /**
+ * Sends a gift to the given user. The gift can't be converted to Telegram Stars by the receiver. Returns True on success.
+ *
+ * @param user_id Unique identifier for the chat or username of the channel (in the format `@username`) that will receive the gift.
+ * @param gift_id Identifier of the gift
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendgift
+ */
+ sendGift(
+ user_id: number,
+ gift_id: string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendGift({ user_id, gift_id, ...other }, signal);
+ }
+
+ /**
+ * Gifts a Telegram Premium subscription to the given user. Returns True on success.
+ *
+ * @param user_id Unique identifier of the target user who will receive a Telegram Premium subscription
+ * @param month_count Number of months the Telegram Premium subscription will be active for the user; must be one of 3, 6, or 12
+ * @param star_count Number of Telegram Stars to pay for the Telegram Premium subscription; must be 1000 for 3 months, 1500 for 6 months, and 2500 for 12 months
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#giftpremiumsubscription
+ */
+ giftPremiumSubscription(
+ user_id: number,
+ month_count: 3 | 6 | 12,
+ star_count: 1000 | 1500 | 2500,
+ other?: Other<
+ R,
+ "giftPremiumSubscription",
+ "user_id" | "month_count" | "star_count"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.giftPremiumSubscription(
+ { user_id, month_count, star_count, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Sends a gift to the given channel chat. The gift can't be converted to Telegram Stars by the receiver. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the chat or username of the channel (in the format @channelusername) that will receive the gift
+ * @param gift_id Identifier of the gift
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendgift
+ */
+ sendGiftToChannel(
+ chat_id: number | string,
+ gift_id: string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendGift({ chat_id, gift_id, ...other }, signal);
+ }
+
+ /**
+ * Use this method to send answers to an inline query. On success, True is returned.
+ * No more than 50 results per query are allowed.
+ *
+ * Example: An inline bot that sends YouTube videos can ask the user to connect the bot to their YouTube account to adapt search results accordingly. To do this, it displays a 'Connect your YouTube account' button above the results, or even before showing any. The user presses the button, switches to a private chat with the bot and, in doing so, passes a start parameter that instructs the bot to return an OAuth link. Once done, the bot can offer a switch_inline button so that the user can easily return to the chat where they wanted to use the bot's inline capabilities.
+ *
+ * @param inline_query_id Unique identifier for the answered query
+ * @param results An Array of results for the inline query
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#answerinlinequery
+ */
+ answerInlineQuery(
+ inline_query_id: string,
+ results: readonly InlineQueryResult[],
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.answerInlineQuery(
+ { inline_query_id, results, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to set the result of an interaction with a Web App and send a corresponding message on behalf of the user to the chat from which the query originated. On success, a SentWebAppMessage object is returned.
+ *
+ * @param web_app_query_id Unique identifier for the query to be answered
+ * @param result An object describing the message to be sent
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#answerwebappquery
+ */
+ answerWebAppQuery(
+ web_app_query_id: string,
+ result: InlineQueryResult,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.answerWebAppQuery({ web_app_query_id, result }, signal);
+ }
+
+ /**
+ * Stores a message that can be sent by a user of a Mini App. Returns a PreparedInlineMessage object.
+ *
+ * @param user_id Unique identifier of the target user that can use the prepared message
+ * @param result An object describing the message to be sent
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#savepreparedinlinemessage
+ */
+ savePreparedInlineMessage(
+ user_id: number,
+ result: InlineQueryResult,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.savePreparedInlineMessage(
+ { user_id, result, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Stores a keyboard button that can be used by a user within a Mini App. Returns a PreparedKeyboardButton object.
+ *
+ * @param user_id Unique identifier of the target user that can use the button
+ * @param button An object describing the button to be saved. The button must be of the type request_users, request_chat, or request_managed_bot
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#savepreparedkeyboardbutton
+ */
+ savePreparedKeyboardButton(
+ user_id: number,
+ button:
+ | KeyboardButton.RequestUsersButton
+ | KeyboardButton.RequestChatButton
+ | KeyboardButton.RequestManagedBotButton,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.savePreparedKeyboardButton({ user_id, button }, signal);
+ }
+
+ /**
+ * Use this method to send invoices. On success, the sent Message is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param title Product name, 1-32 characters
+ * @param description Product description, 1-255 characters
+ * @param payload Bot-defined invoice payload, 1-128 bytes. This will not be displayed to the user, use for your internal processes.
+ * @param currency Three-letter ISO 4217 currency code, see more on currencies
+ * @param prices Price breakdown, a list of components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.)
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendinvoice
+ */
+ sendInvoice(
+ chat_id: number | string,
+ title: string,
+ description: string,
+ payload: string,
+ currency: string,
+ prices: readonly LabeledPrice[],
+ other?: Other<
+ R,
+ "sendInvoice",
+ | "chat_id"
+ | "title"
+ | "description"
+ | "payload"
+ | "currency"
+ | "prices"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendInvoice({
+ chat_id,
+ title,
+ description,
+ payload,
+ currency,
+ prices,
+ ...other,
+ }, signal);
+ }
+
+ /**
+ * Use this method to create a link for an invoice. Returns the created invoice link as String on success.
+ *
+ * @param title Product name, 1-32 characters
+ * @param description Product description, 1-255 characters
+ * @param payload Bot-defined invoice payload, 1-128 bytes. This will not be displayed to the user, use for your internal processes.
+ * @param provider_token Payment provider token, obtained via BotFather
+ * @param currency Three-letter ISO 4217 currency code, see more on currencies
+ * @param prices Price breakdown, a list of components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.)
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#createinvoicelink
+ */
+ createInvoiceLink(
+ title: string,
+ description: string,
+ payload: string,
+ provider_token: string,
+ currency: string,
+ prices: LabeledPrice[],
+ other?: Other<
+ R,
+ "createInvoiceLink",
+ | "title"
+ | "description"
+ | "payload"
+ | "provider_token"
+ | "currency"
+ | "prices"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.createInvoiceLink({
+ title,
+ description,
+ payload,
+ provider_token,
+ currency,
+ prices,
+ ...other,
+ }, signal);
+ }
+
+ /**
+ * If you sent an invoice requesting a shipping address and the parameter is_flexible was specified, the Bot API will send an Update with a shipping_query field to the bot. Use this method to reply to shipping queries. On success, True is returned.
+ *
+ * @param shipping_query_id Unique identifier for the query to be answered
+ * @param ok Pass True if delivery to the specified address is possible and False if there are any problems (for example, if delivery to the specified address is not possible)
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#answershippingquery
+ */
+ answerShippingQuery(
+ shipping_query_id: string,
+ ok: boolean,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.answerShippingQuery(
+ { shipping_query_id, ok, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Once the user has confirmed their payment and shipping details, the Bot API sends the final confirmation in the form of an Update with the field pre_checkout_query. Use this method to respond to such pre-checkout queries. On success, True is returned. Note: The Bot API must receive an answer within 10 seconds after the pre-checkout query was sent.
+ *
+ * @param pre_checkout_query_id Unique identifier for the query to be answered
+ * @param ok Specify True if everything is alright (goods are available, etc.) and the bot is ready to proceed with the order. Use False if there are any problems.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#answerprecheckoutquery
+ */
+ answerPreCheckoutQuery(
+ pre_checkout_query_id: string,
+ ok: boolean,
+ other?: Other<
+ R,
+ "answerPreCheckoutQuery",
+ "pre_checkout_query_id" | "ok"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.answerPreCheckoutQuery(
+ { pre_checkout_query_id, ok, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Returns the bot's Telegram Star transactions in chronological order. On success, returns a StarTransactions object.
+ *
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getstartransactions
+ */
+ getStarTransactions(
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.getStarTransactions({ ...other }, signal);
+ }
+
+ /**
+ * Refunds a successful payment in Telegram Stars.
+ *
+ * @param user_id Identifier of the user whose payment will be refunded
+ * @param telegram_payment_charge_id Telegram payment identifier
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#refundstarpayment
+ */
+ refundStarPayment(
+ user_id: number,
+ telegram_payment_charge_id: string,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.refundStarPayment(
+ { user_id, telegram_payment_charge_id },
+ signal,
+ );
+ }
+
+ /**
+ * Allows the bot to cancel or re-enable extension of a subscription paid in Telegram Stars. Returns True on success.
+ *
+ * @param user_id Identifier of the user whose subscription will be edited
+ * @param telegram_payment_charge_id Telegram payment identifier for the subscription
+ * @param is_canceled Pass True to cancel extension of the user subscription; the subscription must be active up to the end of the current subscription period. Pass False to allow the user to re-enable a subscription that was previously canceled by the bot.
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#edituserstarsubscription
+ */
+ editUserStarSubscription(
+ user_id: number,
+ telegram_payment_charge_id: string,
+ is_canceled: boolean,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.editUserStarSubscription(
+ { user_id, telegram_payment_charge_id, is_canceled },
+ signal,
+ );
+ }
+
+ /**
+ * Verifies a user on behalf of the organization which is represented by the bot. Returns True on success.
+ *
+ * @param user_id Unique identifier of the target user
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#verifyuser
+ */
+ verifyUser(
+ user_id: number,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.verifyUser({ user_id, ...other }, signal);
+ }
+
+ /**
+ * Verifies a chat on behalf of the organization which is represented by the bot. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot, supergroup or channel in the format `@username`
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#verifychat
+ */
+ verifyChat(
+ chat_id: number | string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.verifyChat({ chat_id, ...other }, signal);
+ }
+
+ /**
+ * Removes verification from a user who is currently verified on behalf of the organization represented by the bot. Returns True on success.
+ *
+ * @param user_id Unique identifier of the target user
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#removeuserverification
+ */
+ removeUserVerification(user_id: number, signal?: AbortSignal) {
+ return this.raw.removeUserVerification({ user_id }, signal);
+ }
+
+ /**
+ * Removes verification from a chat that is currently verified on behalf of the organization represented by the bot. Returns True on success.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot or channel in the format `@username`
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#removechatverification
+ */
+ removeChatVerification(
+ chat_id: number | string,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.removeChatVerification({ chat_id }, signal);
+ }
+
+ /**
+ * Marks incoming message as read on behalf of a business account. Requires the can_read_messages business bot right. Returns True on success.
+ *
+ * @param business_connection_id Unique identifier of the business connection on behalf of which to read the message
+ * @param chat_id Unique identifier of the chat in which the message was received. The chat must have been active in the last 24 hours.
+ * @param message_id Unique identifier of the message to mark as read
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#readbusinessmessage
+ */
+ readBusinessMessage(
+ business_connection_id: string,
+ chat_id: number,
+ message_id: number,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.readBusinessMessage(
+ { business_connection_id, chat_id, message_id },
+ signal,
+ );
+ }
+
+ /**
+ * Informs a user that some of the Telegram Passport elements they provided contains errors. The user will not be able to re-submit their Passport to you until the errors are fixed (the contents of the field for which you returned the error must change). Returns True on success.
+ *
+ * Use this if the data submitted by the user doesn't satisfy the standards your service requires for any reason. For example, if a birthday date seems invalid, a submitted document is blurry, a scan shows evidence of tampering, etc. Supply some details in the error message to make sure the user knows how to correct the issues.
+ *
+ * @param user_id User identifier
+ * @param errors An Array describing the errors
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setpassportdataerrors
+ */
+ setPassportDataErrors(
+ user_id: number,
+ errors: readonly PassportElementError[],
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setPassportDataErrors({ user_id, errors }, signal);
+ }
+
+ /**
+ * Use this method to send a game. On success, the sent Message is returned.
+ *
+ * @param chat_id Unique identifier for the target chat or username of the target bot in the format `@username`. Games can't be sent to channel direct messages chats and channel chats.
+ * @param game_short_name Short name of the game, serves as the unique identifier for the game. Set up your games via BotFather.
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#sendgame
+ */
+ sendGame(
+ chat_id: number | string,
+ game_short_name: string,
+ other?: Other,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.sendGame(
+ { chat_id, game_short_name, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to set the score of the specified user in a game message. On success, if the message is not an inline message, the Message is returned, otherwise True is returned. Returns an error, if the new score is not greater than the user's current score in the chat and force is False.
+ *
+ * @param chat_id Unique identifier for the target chat
+ * @param message_id Identifier of the sent message
+ * @param user_id User identifier
+ * @param score New score, must be non-negative
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setgamescore
+ */
+ setGameScore(
+ chat_id: number,
+ message_id: number,
+ user_id: number,
+ score: number,
+ other?: Other<
+ R,
+ "setGameScore",
+ "chat_id" | "message_id" | "inline_message_id" | "user_id" | "score"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setGameScore(
+ { chat_id, message_id, user_id, score, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to set the score of the specified user in a game message. On success, if the message is not an inline message, the Message is returned, otherwise True is returned. Returns an error, if the new score is not greater than the user's current score in the chat and force is False.
+ *
+ * @param inline_message_id Identifier of the inline message
+ * @param user_id User identifier
+ * @param score New score, must be non-negative
+ * @param other Optional remaining parameters, confer the official reference below
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#setgamescore
+ */
+ setGameScoreInline(
+ inline_message_id: string,
+ user_id: number,
+ score: number,
+ other?: Other<
+ R,
+ "setGameScore",
+ "chat_id" | "message_id" | "inline_message_id" | "user_id" | "score"
+ >,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.setGameScore(
+ { inline_message_id, user_id, score, ...other },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to get data for high score tables. Will return the score of the specified user and several of their neighbors in a game. Returns an Array of GameHighScore objects.
+ *
+ * This method will currently return scores for the target user, plus two of their closest neighbors on each side. Will also return the top three users if the user and his neighbors are not among them. Please note that this behavior is subject to change.
+ *
+ * @param chat_id Unique identifier for the target chat
+ * @param message_id Identifier of the sent message
+ * @param user_id Target user id
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getgamehighscores
+ */
+ getGameHighScores(
+ chat_id: number,
+ message_id: number,
+ user_id: number,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.getGameHighScores(
+ { chat_id, message_id, user_id },
+ signal,
+ );
+ }
+
+ /**
+ * Use this method to get data for high score tables. Will return the score of the specified user and several of their neighbors in an inline game. On success, returns an Array of GameHighScore objects.
+ *
+ * This method will currently return scores for the target user, plus two of their closest neighbors on each side. Will also return the top three users if the user and his neighbors are not among them. Please note that this behavior is subject to change.
+ *
+ * @param inline_message_id Identifier of the inline message
+ * @param user_id Target user id
+ * @param signal Optional `AbortSignal` to cancel the request
+ *
+ * **Official reference:** https://core.telegram.org/bots/api#getgamehighscores
+ */
+ getGameHighScoresInline(
+ inline_message_id: string,
+ user_id: number,
+ signal?: AbortSignal,
+ ) {
+ return this.raw.getGameHighScores(
+ { inline_message_id, user_id },
+ signal,
+ );
+ }
+}
diff --git a/src/bot.ts b/src/bot.ts
new file mode 100644
index 0000000..1a648a8
--- /dev/null
+++ b/src/bot.ts
@@ -0,0 +1,760 @@
+// deno-lint-ignore-file camelcase
+import {
+ BotError,
+ Composer,
+ type Middleware,
+ type ReactionMiddleware,
+ run,
+} from "./composer.ts";
+import { Context, type MaybeArray, type ReactionContext } from "./context.ts";
+import { Api } from "./core/api.ts";
+import {
+ type ApiClientOptions,
+ type WebhookReplyEnvelope,
+} from "./core/client.ts";
+import { GrammyError, HttpError } from "./core/error.ts";
+import { type Filter, type FilterQuery, parse, preprocess } from "./filter.ts";
+import { debug as d } from "./platform.deno.ts";
+import {
+ type ReactionType,
+ type ReactionTypeEmoji,
+ type Update,
+ type UserFromGetMe,
+} from "./types.ts";
+const debug = d("grammy:bot");
+const debugWarn = d("grammy:warn");
+const debugErr = d("grammy:error");
+
+export const DEFAULT_UPDATE_TYPES = [
+ "message",
+ "edited_message",
+ "channel_post",
+ "edited_channel_post",
+ "business_connection",
+ "business_message",
+ "edited_business_message",
+ "deleted_business_messages",
+ "guest_message",
+ "inline_query",
+ "chosen_inline_result",
+ "callback_query",
+ "shipping_query",
+ "pre_checkout_query",
+ "purchased_paid_media",
+ "poll",
+ "poll_answer",
+ "my_chat_member",
+ "managed_bot",
+ "chat_join_request",
+ "chat_boost",
+ "removed_chat_boost",
+ "subscription",
+] as const satisfies ReadonlyArray>;
+
+/**
+ * Options that can be specified when running the bot via simple long polling.
+ */
+export interface PollingOptions {
+ /**
+ * Limits the number of updates to be retrieved per `getUpdates` call.
+ * Values between 1-100 are accepted. Defaults to 100.
+ */
+ limit?: number;
+ /**
+ * Timeout in seconds for long polling. grammY uses 30 seconds as a default
+ * value.
+ */
+ timeout?: number;
+ /**
+ * A list of the update types you want your bot to receive. For example,
+ * specify ["message", "edited_channel_post", "callback_query"] to only
+ * receive updates of these types. See Update for a complete list of
+ * available update types. Specify an empty list to receive all update types
+ * except chat_member, message_reaction, and message_reaction_count
+ * (default). If not specified, the previous setting will be used.
+ *
+ * Please note that this parameter doesn't affect updates created before the
+ * call to the getUpdates, so unwanted updates may be received for a short
+ * period of time.
+ */
+ allowed_updates?: ReadonlyArray>;
+ /**
+ * Pass True to drop all pending updates before starting the long polling.
+ */
+ drop_pending_updates?: boolean;
+ /**
+ * A callback function that is useful for logging (or setting up middleware
+ * if you did not do this before). It will be executed after the setup of
+ * the bot has completed, and immediately before the first updates are being
+ * fetched. The bot information `bot.botInfo` will be available when the
+ * function is run. For convenience, the callback function receives the
+ * value of `bot.botInfo` as an argument.
+ *
+ * When this function is invoked, the bot already signals that it is
+ * running. In other words, `bot.isRunning()` already returns true.
+ */
+ onStart?: (botInfo: UserFromGetMe) => void | Promise;
+}
+
+export { BotError };
+/**
+ * Error handler that can be installed on a bot to catch error thrown by
+ * middleware.
+ */
+export type ErrorHandler = (
+ error: BotError,
+) => unknown;
+
+/**
+ * Options to pass to the bot when creating it.
+ */
+export interface BotConfig {
+ /**
+ * You can specify a number of advanced options under the `client` property.
+ * The options will be passed to the grammY clientβthis is the part of
+ * grammY that actually connects to the Telegram Bot API server in the end
+ * when making HTTP requests.
+ */
+ client?: ApiClientOptions;
+ /**
+ * grammY automatically calls `getMe` when starting up to make sure that
+ * your bot has access to the bot's own information. If you restart your bot
+ * often, for example because it is running in a serverless environment,
+ * then you may want to skip this initial API call.
+ *
+ * Set this property of the options to pre-initialize the bot with cached
+ * values. If you use this option, grammY will not attempt to make a `getMe`
+ * call but use the provided data instead.
+ */
+ botInfo?: UserFromGetMe;
+ /**
+ * Pass the constructor of a custom context object that will be used when
+ * creating the context for each incoming update.
+ */
+ ContextConstructor?: new (
+ ...args: ConstructorParameters
+ ) => C;
+}
+
+/**
+ * This is the single most important class of grammY. It represents your bot.
+ *
+ * First, you must create a bot by talking to @BotFather, check out
+ * https://t.me/BotFather. Once it is ready, you obtain a secret token for your
+ * bot. grammY will use that token to identify as your bot when talking to the
+ * Telegram servers. Got the token? You are now ready to write some code and run
+ * your bot!
+ *
+ * You should do three things to run your bot:
+ * ```ts
+ * // 1. Create a bot instance
+ * const bot = new Bot('')
+ * // 2. Listen for updates
+ * bot.on('message:text', ctx => ctx.reply('You wrote: ' + ctx.message.text))
+ * // 3. Launch it!
+ * bot.start()
+ * ```
+ */
+export class Bot<
+ C extends Context = Context,
+ A extends Api = Api,
+> extends Composer {
+ private pollingRunning = false;
+ private pollingAbortController: AbortController | undefined;
+ private lastTriedUpdateId = 0;
+
+ /**
+ * Gives you full access to the Telegram Bot API.
+ * ```ts
+ * // This is how to call the Bot API methods:
+ * bot.api.sendMessage(chat_id, 'Hello, grammY!')
+ * ```
+ *
+ * Use this only outside of your middleware. If you have access to `ctx`,
+ * then using `ctx.api` instead of `bot.api` is preferred.
+ */
+ public readonly api: A;
+
+ private me: UserFromGetMe | undefined;
+ private mePromise: Promise | undefined;
+ private readonly clientConfig: ApiClientOptions | undefined;
+
+ private readonly ContextConstructor: new (
+ ...args: ConstructorParameters
+ ) => C;
+
+ /** Used to log a warning if some update types are not in allowed_updates */
+ private observedUpdateTypes = new Set();
+
+ /**
+ * Holds the bot's error handler that is invoked whenever middleware throws
+ * (rejects). If you set your own error handler via `bot.catch`, all that
+ * happens is that this variable is assigned.
+ */
+ public errorHandler: ErrorHandler = async (err) => {
+ console.error(
+ "Error in middleware while handling update",
+ err.ctx?.update?.update_id,
+ err.error,
+ );
+ console.error("No error handler was set!");
+ console.error("Set your own error handler with `bot.catch = ...`");
+ if (this.pollingRunning) {
+ console.error("Stopping bot");
+ await this.stop();
+ }
+ throw err;
+ };
+
+ /**
+ * Creates a new Bot with the given token.
+ *
+ * Remember that you can listen for messages by calling
+ * ```ts
+ * bot.on('message', ctx => { ... })
+ * ```
+ * or similar methods.
+ *
+ * The simplest way to start your bot is via simple long polling:
+ * ```ts
+ * bot.start()
+ * ```
+ *
+ * @param token The bot's token as acquired from https://t.me/BotFather
+ * @param config Optional configuration properties for the bot
+ */
+ constructor(public readonly token: string, config?: BotConfig) {
+ super();
+ if (!token) throw new Error("Empty token!");
+ this.me = config?.botInfo;
+ this.clientConfig = config?.client;
+ this.ContextConstructor = config?.ContextConstructor ??
+ (Context as unknown as new (
+ ...args: ConstructorParameters
+ ) => C);
+ this.api = new Api(token, this.clientConfig) as A;
+ }
+
+ /**
+ * Information about the bot itself as retrieved from `api.getMe()`. Only
+ * available after the bot has been initialized via `await bot.init()`, or
+ * after the value has been set manually.
+ *
+ * Starting the bot will always perform the initialization automatically,
+ * unless a manual value is already set.
+ *
+ * Note that the recommended way to set a custom bot information object is
+ * to pass it to the configuration object of the `new Bot()` instantiation,
+ * rather than assigning this property.
+ */
+ public set botInfo(botInfo: UserFromGetMe) {
+ this.me = botInfo;
+ }
+ public get botInfo(): UserFromGetMe {
+ if (this.me === undefined) {
+ throw new Error(
+ "Bot information unavailable! Make sure to call `await bot.init()` before accessing `bot.botInfo`!",
+ );
+ }
+ return this.me;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ override on(
+ filter: Q | Q[],
+ ...middleware: Array>>
+ ): Composer> {
+ for (const [u] of parse(filter).flatMap(preprocess)) {
+ this.observedUpdateTypes.add(u);
+ }
+ return super.on(filter, ...middleware);
+ }
+ /**
+ * @inheritdoc
+ */
+ override reaction(
+ reaction: MaybeArray,
+ ...middleware: Array>
+ ): Composer> {
+ this.observedUpdateTypes.add("message_reaction");
+ return super.reaction(reaction, ...middleware);
+ }
+
+ /**
+ * Checks if the bot has been initialized. A bot is initialized if the bot
+ * information is set. The bot information can either be set automatically
+ * by calling `bot.init`, or manually through the bot constructor. Note that
+ * usually, initialization is done automatically and you do not have to care
+ * about this method.
+ *
+ * @returns true if the bot is initialized, and false otherwise
+ */
+ isInited() {
+ return this.me !== undefined;
+ }
+
+ /**
+ * Initializes the bot, i.e. fetches information about the bot itself. This
+ * method is called automatically, you usually don't have to call it
+ * manually.
+ *
+ * @param signal Optional `AbortSignal` to cancel the initialization
+ */
+ async init(signal?: AbortSignal) {
+ if (!this.isInited()) {
+ debug("Initializing bot");
+ this.mePromise ??= withRetries(
+ () => this.api.getMe(signal),
+ signal,
+ );
+ let me: UserFromGetMe;
+ try {
+ me = await this.mePromise;
+ } finally {
+ this.mePromise = undefined;
+ }
+ if (this.me === undefined) this.me = me;
+ else debug("Bot info was set by now, will not overwrite");
+ }
+ debug(`I am ${this.me!.username}!`);
+ }
+
+ /**
+ * Internal. Do not call. Handles an update batch sequentially by supplying
+ * it one-by-one to the middleware. Handles middleware errors and stores the
+ * last update identifier that was being tried to handle.
+ *
+ * @param updates An array of updates to handle
+ */
+ private async handleUpdates(updates: Update[]) {
+ // handle updates sequentially (!)
+ for (const update of updates) {
+ this.lastTriedUpdateId = update.update_id;
+ try {
+ await this.handleUpdate(update);
+ } catch (err) {
+ // should always be true
+ if (err instanceof BotError) {
+ await this.errorHandler(err);
+ } else {
+ console.error("FATAL: grammY unable to handle:", err);
+ throw err;
+ }
+ }
+ }
+ }
+
+ /**
+ * This is an internal method that you probably will not ever need to call.
+ * It is used whenever a new update arrives from the Telegram servers that
+ * your bot will handle.
+ *
+ * If you're writing a library on top of grammY, check out the
+ * [documentation](https://grammy.dev/plugins/runner) of the runner
+ * plugin for an example that uses this method.
+ *
+ * @param update An update from the Telegram Bot API
+ * @param webhookReplyEnvelope An optional webhook reply envelope
+ */
+ async handleUpdate(
+ update: Update,
+ webhookReplyEnvelope?: WebhookReplyEnvelope,
+ ) {
+ if (this.me === undefined) {
+ throw new Error(
+ "Bot not initialized! Either call `await bot.init()`, \
+or directly set the `botInfo` option in the `Bot` constructor to specify \
+a known bot info object.",
+ );
+ }
+ debug(`Processing update ${update.update_id}`);
+ // create API object
+ const api = new Api(
+ this.token,
+ this.clientConfig,
+ webhookReplyEnvelope,
+ );
+ // configure it with the same transformers as bot.api
+ const t = this.api.config.installedTransformers();
+ if (t.length > 0) api.config.use(...t);
+ // create context object
+ const ctx = new this.ContextConstructor(update, api, this.me);
+ try {
+ // run middleware stack
+ await run(this.middleware(), ctx);
+ } catch (err) {
+ debugErr(`Error in middleware for update ${update.update_id}`);
+ throw new BotError(err, ctx);
+ }
+ }
+
+ /**
+ * Starts your bot using long polling.
+ *
+ * > This method returns a `Promise` that will never resolve except if your
+ * > bot is stopped. **You don't need to `await` the call to `bot.start`**,
+ * > but remember to catch potential errors by calling `bot.catch`.
+ * > Otherwise your bot will crash (and stop) if something goes wrong in
+ * > your code.
+ *
+ * This method effectively enters a loop that will repeatedly call
+ * `getUpdates` and run your middleware for every received update, allowing
+ * your bot to respond to messages.
+ *
+ * If your bot is already running, this method does nothing.
+ *
+ * **Note that this starts your bot using a very simple long polling
+ * implementation.** `bot.start` should only be used for small bots. While
+ * the rest of grammY was built to perform well even under extreme loads,
+ * simple long polling is not capable of scaling up in a similar fashion.
+ * You should switch over to using `@grammyjs/runner` if you are running a
+ * bot with high load.
+ *
+ * What exactly _high load_ means differs from bot to bot, but as a rule of
+ * thumb, simple long polling should not be processing more than ~5K
+ * messages every hour. Also, if your bot has long-running operations such
+ * as large file transfers that block the middleware from completing, this
+ * will impact the responsiveness negatively, so it makes sense to use the
+ * `@grammyjs/runner` package even if you receive much fewer messages. If
+ * you worry about how much load your bot can handle, check out the grammY
+ * [documentation](https://grammy.dev/advanced/scaling) about scaling
+ * up.
+ *
+ * @param options Options to use for simple long polling
+ */
+ async start(options?: PollingOptions) {
+ // Perform setup
+ const setup: Promise[] = [];
+ if (!this.isInited()) {
+ setup.push(this.init(this.pollingAbortController?.signal));
+ }
+ if (this.pollingRunning) {
+ await Promise.all(setup);
+ debug("Simple long polling already running!");
+ return;
+ }
+
+ this.pollingRunning = true;
+ this.pollingAbortController = new AbortController();
+
+ setup.push(withRetries(async () => {
+ await this.api.deleteWebhook({
+ drop_pending_updates: options?.drop_pending_updates,
+ }, this.pollingAbortController?.signal);
+ }, this.pollingAbortController?.signal));
+
+ try {
+ await Promise.all(setup);
+ // All async ops of setup complete, run callback
+ await options?.onStart?.(this.botInfo);
+ } catch (err) {
+ this.pollingRunning = false;
+ this.pollingAbortController = undefined;
+ throw err;
+ }
+
+ // Bot was stopped during `onStart`
+ if (!this.pollingRunning) return;
+
+ // Prevent common misuse that leads to missing updates
+ validateAllowedUpdates(
+ this.observedUpdateTypes,
+ options?.allowed_updates,
+ );
+ // Prevent common misuse that causes memory leak
+ this.use = noUseFunction;
+
+ // Start polling
+ debug("Starting simple long polling");
+ await this.loop(options);
+ debug("Middleware is done running");
+ }
+
+ /**
+ * Stops the bot from long polling.
+ *
+ * All middleware that is currently being executed may complete, but no
+ * further `getUpdates` calls will be performed. The current `getUpdates`
+ * request will be cancelled.
+ *
+ * In addition, this method will _confirm_ the last received update to the
+ * Telegram servers by calling `getUpdates` one last time with the latest
+ * offset value. If any updates are received in this call, they are
+ * discarded and will be fetched again when the bot starts up the next time.
+ * Confer the official documentation on confirming updates if you want to
+ * know more: https://core.telegram.org/bots/api#getupdates
+ *
+ * > Note that this method will not wait for the middleware stack to finish.
+ * > If you need to run code after all middleware is done, consider waiting
+ * > for the promise returned by `bot.start()` to resolve.
+ */
+ async stop() {
+ if (this.pollingRunning) {
+ debug("Stopping bot, saving update offset");
+ this.pollingRunning = false;
+ this.pollingAbortController?.abort();
+ const offset = this.lastTriedUpdateId + 1;
+ await this.api.getUpdates({ offset, limit: 1 })
+ .finally(() => this.pollingAbortController = undefined);
+ } else {
+ debug("Bot is not running!");
+ }
+ }
+
+ /**
+ * Returns true if the bot is currently running via built-in long polling,
+ * and false otherwise.
+ *
+ * If this method returns true, it means that `bot.start()` has been called,
+ * and that the bot has neither crashed nor was it stopped via a call to
+ * `bot.stop()`. This also means that you cannot use this method to check if
+ * a webhook server is running, or if grammY runner was started.
+ *
+ * Note that this method will already begin to return true even before the
+ * call to `bot.start()` has completed its initialization phase (and hence
+ * before `bot.isInited()` returns true). By extension, this method
+ * returns true before `onStart` callback of `bot.start()` is invoked.
+ */
+ isRunning() {
+ return this.pollingRunning;
+ }
+
+ /**
+ * Sets the bots error handler that is used during long polling.
+ *
+ * You should call this method to set an error handler if you are using long
+ * polling, no matter whether you use `bot.start` or the `@grammyjs/runner`
+ * package to run your bot.
+ *
+ * Calling `bot.catch` when using other means of running your bot (or
+ * webhooks) has no effect.
+ *
+ * @param errorHandler A function that handles potential middleware errors
+ */
+ catch(errorHandler: ErrorHandler) {
+ this.errorHandler = errorHandler;
+ }
+
+ /**
+ * Internal. Do not call. Enters a loop that will perform long polling until
+ * the bot is stopped.
+ */
+ private async loop(options?: PollingOptions) {
+ const limit = options?.limit;
+ const timeout = options?.timeout ?? 30; // seconds
+ let allowed_updates: PollingOptions["allowed_updates"] =
+ options?.allowed_updates ?? []; // reset to default if unspecified
+
+ try {
+ while (this.pollingRunning) {
+ // fetch updates
+ const updates = await this.fetchUpdates(
+ { limit, timeout, allowed_updates },
+ );
+ // check if polling stopped
+ if (updates === undefined) break;
+ // handle updates
+ await this.handleUpdates(updates);
+ // Telegram uses the last setting if `allowed_updates` is omitted so
+ // we can save some traffic by only sending it in the first request
+ allowed_updates = undefined;
+ }
+ } finally {
+ this.pollingRunning = false;
+ }
+ }
+
+ /**
+ * Internal. Do not call. Reliably fetches an update batch via `getUpdates`.
+ * Handles all known errors. Returns `undefined` if the bot is stopped and
+ * the call gets cancelled.
+ *
+ * @param options Polling options
+ * @returns An array of updates, or `undefined` if the bot is stopped.
+ */
+ private async fetchUpdates(
+ { limit, timeout, allowed_updates }: PollingOptions,
+ ) {
+ const offset = this.lastTriedUpdateId + 1;
+ let updates: Update[] | undefined = undefined;
+ do {
+ try {
+ updates = await this.api.getUpdates(
+ { offset, limit, timeout, allowed_updates },
+ this.pollingAbortController?.signal,
+ );
+ } catch (error) {
+ await this.handlePollingError(error);
+ }
+ } while (updates === undefined && this.pollingRunning);
+ return updates;
+ }
+
+ /**
+ * Internal. Do not call. Handles an error that occurred during long
+ * polling.
+ */
+ private async handlePollingError(error: unknown) {
+ if (!this.pollingRunning) {
+ debug("Pending getUpdates request cancelled");
+ return;
+ }
+ let sleepSeconds = 3;
+ if (error instanceof GrammyError) {
+ debugErr(error.message);
+ // rethrow upon unauthorized or conflict
+ if (error.error_code === 401 || error.error_code === 409) {
+ throw error;
+ } else if (error.error_code === 429) {
+ debugErr("Bot API server is closing.");
+ sleepSeconds = error.parameters.retry_after ?? sleepSeconds;
+ }
+ } else debugErr(error);
+ debugErr(
+ `Call to getUpdates failed, retrying in ${sleepSeconds} seconds ...`,
+ );
+ await sleep(sleepSeconds);
+ }
+}
+
+/**
+ * Performs a network call task, retrying upon known errors until success.
+ *
+ * If the task errors and a retry_after value can be used, a subsequent retry
+ * will be delayed by the specified period of time.
+ *
+ * Otherwise, if the first attempt at running the task fails, the task is
+ * retried immediately. If second attempt fails, too, waits for 100 ms, and then
+ * doubles this delay for every subsequent attempt. Never waits longer than 1
+ * hour before retrying.
+ *
+ * @param task Async task to perform
+ * @param signal Optional `AbortSignal` to prevent further retries
+ */
+async function withRetries(
+ task: () => Promise,
+ signal?: AbortSignal,
+): Promise {
+ // Set up delays between retries
+ const INITIAL_DELAY = 50; // ms
+ let lastDelay = INITIAL_DELAY;
+
+ // Define error handler
+ /**
+ * Determines the error handling strategy based on various error types.
+ * Sleeps if necessary, and returns whether to retry or rethrow an error.
+ */
+ async function handleError(error: unknown) {
+ let delay = false;
+ let strategy: "retry" | "rethrow" = "rethrow";
+
+ if (error instanceof HttpError) {
+ delay = true;
+ strategy = "retry";
+ } else if (error instanceof GrammyError) {
+ if (error.error_code >= 500) {
+ delay = true;
+ strategy = "retry";
+ } else if (error.error_code === 429) {
+ const retryAfter = error.parameters.retry_after;
+ if (typeof retryAfter === "number") {
+ // ignore the backoff for sleep, then reset it
+ await sleep(retryAfter, signal);
+ lastDelay = INITIAL_DELAY;
+ } else {
+ delay = true;
+ }
+ strategy = "retry";
+ }
+ }
+
+ if (delay) {
+ // Do not sleep for the first retry
+ if (lastDelay !== INITIAL_DELAY) {
+ await sleep(lastDelay, signal);
+ }
+ const TWENTY_MINUTES = 20 * 60 * 1000; // ms
+ lastDelay = Math.min(TWENTY_MINUTES, 2 * lastDelay);
+ }
+
+ return strategy;
+ }
+
+ // Perform the actual task with retries
+ let result: { ok: false } | { ok: true; value: T } = { ok: false };
+ while (!result.ok) {
+ try {
+ result = { ok: true, value: await task() };
+ } catch (error) {
+ debugErr(error);
+ const strategy = await handleError(error);
+ switch (strategy) {
+ case "retry":
+ continue;
+ case "rethrow":
+ throw error;
+ }
+ }
+ }
+ return result.value;
+}
+
+/**
+ * Returns a new promise that resolves after the specified number of seconds, or
+ * rejects as soon as the given signal is aborted.
+ */
+async function sleep(seconds: number, signal?: AbortSignal) {
+ let handle: Parameters[0];
+ let reject: ((err: Error) => void) | undefined;
+ function abort() {
+ reject?.(new Error("Aborted delay"));
+ if (handle !== undefined) clearTimeout(handle);
+ }
+ try {
+ await new Promise((res, rej) => {
+ reject = rej;
+ if (signal?.aborted) {
+ abort();
+ return;
+ }
+ signal?.addEventListener("abort", abort);
+ handle = setTimeout(res, 1000 * seconds);
+ });
+ } finally {
+ signal?.removeEventListener("abort", abort);
+ }
+}
+
+/**
+ * Takes a set of observed update types and a list of allowed updates and logs a
+ * warning in debug mode if some update types were observed that have not been
+ * allowed.
+ */
+function validateAllowedUpdates(
+ updates: Set,
+ allowed: readonly string[] = DEFAULT_UPDATE_TYPES,
+) {
+ const impossible = Array.from(updates).filter((u) => !allowed.includes(u));
+ if (impossible.length > 0) {
+ debugWarn(
+ `You registered listeners for the following update types, \
+but you did not specify them in \`allowed_updates\` \
+so they may not be received: ${impossible.map((u) => `'${u}'`).join(", ")}`,
+ );
+ }
+}
+function noUseFunction(): never {
+ throw new Error(`It looks like you are registering more listeners \
+on your bot from within other listeners! This means that every time your bot \
+handles a message like this one, new listeners will be added. This list grows until \
+your machine crashes, so grammY throws this error to tell you that you should \
+probably do things a bit differently. If you're unsure how to resolve this problem, \
+you can ask in the group chat: https://telegram.me/grammyjs
+
+On the other hand, if you actually know what you're doing and you do need to install \
+further middleware while your bot is running, consider installing a composer \
+instance on your bot, and in turn augment the composer after the fact. This way, \
+you can circumvent this protection against memory leaks.`);
+}
diff --git a/src/client.ts b/src/client.ts
new file mode 100644
index 0000000..d2fb4ef
--- /dev/null
+++ b/src/client.ts
@@ -0,0 +1,525 @@
+import { baseFetchConfig, debug as d } from "../platform.deno.ts";
+import {
+ type ApiMethods as Telegram,
+ type ApiResponse,
+ type Opts,
+} from "../types.ts";
+import { toGrammyError, toHttpError } from "./error.ts";
+import {
+ createFormDataPayload,
+ createJsonPayload,
+ requiresFormDataUpload,
+} from "./payload.ts";
+const debug = d("grammy:core");
+
+export type Methods = string & keyof R;
+
+// Available under `bot.api.raw`
+/**
+ * Represents the raw Telegram Bot API with all methods specified 1:1 as
+ * documented on the website (https://core.telegram.org/bots/api).
+ *
+ * Every method takes an optional `AbortSignal` object that allows to cancel the
+ * API call if desired.
+ */
+export type RawApi = {
+ [M in keyof Telegram]: Parameters[0] extends undefined
+ ? (signal?: AbortSignal) => Promise>
+ : (
+ args: Opts,
+ signal?: AbortSignal,
+ ) => Promise>;
+};
+
+export type Payload, R extends RawApi> = M extends unknown
+ ? R[M] extends (signal?: AbortSignal) => unknown // deno-lint-ignore ban-types
+ ? {} // deno-lint-ignore no-explicit-any
+ : R[M] extends (args: any, signal?: AbortSignal) => unknown
+ ? Parameters[0]
+ : never
+ : never;
+
+/**
+ * Small utility interface that abstracts from webhook reply calls of different
+ * web frameworks.
+ */
+export interface WebhookReplyEnvelope {
+ send?: (payload: string) => void | Promise;
+}
+
+/**
+ * Type of a function that can perform an API call. Used for Transformers.
+ */
+export type ApiCallFn = >(
+ method: M,
+ payload: Payload,
+ signal?: AbortSignal,
+) => Promise>>;
+
+type ApiCallResult, R extends RawApi> = R[M] extends
+ (...args: unknown[]) => unknown ? Awaited> : never;
+
+/**
+ * API call transformers are functions that can access and modify the method and
+ * payload of an API call on the fly. This can be useful if you want to
+ * implement rate limiting or other things against the Telegram Bot API.
+ *
+ * Confer the grammY
+ * [documentation](https://grammy.dev/advanced/transformers) to read more
+ * about how to use transformers.
+ */
+export type Transformer = >(
+ prev: ApiCallFn,
+ method: M,
+ payload: Payload,
+ signal?: AbortSignal,
+) => Promise>>;
+export type TransformerConsumer = TransformableApi<
+ R
+>["use"];
+/**
+ * A transformable API enhances the `RawApi` type by transformers.
+ */
+export interface TransformableApi {
+ /**
+ * Access to the raw API that the transformers will be installed on.
+ */
+ raw: R;
+ /**
+ * Can be used to register any number of transformers on the API.
+ */
+ use: (...transformers: Transformer[]) => this;
+ /**
+ * Returns a readonly list or the currently installed transformers. The list
+ * is sorted by time of installation where index 0 represents the
+ * transformer that was installed first.
+ */
+ installedTransformers: Transformer[];
+}
+
+// Transformer base functions
+function concatTransformer(
+ prev: ApiCallFn,
+ trans: Transformer,
+): ApiCallFn {
+ return (method, payload, signal) => trans(prev, method, payload, signal);
+}
+
+/**
+ * Options to pass to the API client that eventually connects to the Telegram
+ * Bot API server and makes the HTTP requests.
+ */
+export interface ApiClientOptions {
+ /**
+ * Root URL of the Telegram Bot API server. Default:
+ * https://api.telegram.org
+ */
+ apiRoot?: string;
+ /**
+ * Specifies whether to use the [test
+ * environment](https://core.telegram.org/bots/webapps#using-bots-in-the-test-environment).
+ * Can be either `"prod"` (default) or `"test"`.
+ *
+ * The testing infrastructure is separate from the regular production
+ * infrastructure. No chats, accounts, or other data is shared between them.
+ * If you set this option to `"test"`, you will need to make your Telegram
+ * client connect to the testing data centers of Telegram, register your
+ * phone number again, open a new chat with @BotFather, and create a
+ * separate bot.
+ */
+ environment?: "prod" | "test";
+ /**
+ * URL builder function for API calls. Can be used to modify which API
+ * server should be called.
+ *
+ * @param root The URL that was passed in `apiRoot`, or its default value
+ * @param token The bot's token that was passed when creating the bot
+ * @param method The API method to be called, e.g. `getMe`
+ * @param env The value that was passed in `environment`, or its default value
+ * @returns The URL that will be fetched during the API call
+ */
+ buildUrl?: (
+ root: string,
+ token: string,
+ method: string,
+ env: "prod" | "test",
+ ) => string | URL;
+ /**
+ * Maximum number of seconds that a request to the Bot API server may take.
+ * If a request has not completed before this time has elapsed, grammY
+ * aborts the request and errors. Without such a timeout, networking issues
+ * may cause your bot to leave open a connection indefinitely, which may
+ * effectively make your bot freeze.
+ *
+ * You probably do not have to care about this option. In rare cases, you
+ * may want to adjust it if you are transferring large files via slow
+ * connections to your own Bot API server.
+ *
+ * The default number of seconds is `500`, which corresponds to 8 minutes
+ * and 20 seconds. Note that this is also the value that is hard-coded in
+ * the official Bot API server, so you cannot perform any successful
+ * requests that exceed this time frame (even if you would allow it in
+ * grammY). Setting this option to higher than the default only makes sense
+ * with a custom Bot API server.
+ */
+ timeoutSeconds?: number;
+ /**
+ * If the bot is running on webhooks, as soon as the bot receives an update
+ * from Telegram, it is possible to make up to one API call in the response
+ * to the webhook request. As a benefit, this saves your bot from making up
+ * to one HTTP request per update. However, there are a number of drawbacks
+ * to using this:
+ * 1) You will not be able to handle potential errors of the respective API
+ * call. This includes rate limiting errors, so sent messages can be
+ * swallowed by the Bot API server and there is no way to detect if a
+ * message was actually sent or not.
+ * 2) More importantly, you also won't have access to the response object,
+ * so e.g. calling `sendMessage` will not give you access to the message
+ * you sent.
+ * 3) Furthermore, it is not possible to cancel the request. The
+ * `AbortSignal` will be disregarded.
+ * 4) Note also that the types in grammY do not reflect the consequences of
+ * a performed webhook callback! For instance, they indicate that you
+ * always receive a response object, so it is your own responsibility to
+ * make sure you're not screwing up while using this minor performance
+ * optimization.
+ *
+ * With this warning out of the way, here is what you can do with the
+ * `canUseWebhookReply` option: it can be used to pass a function that
+ * determines whether to use webhook reply for the given method. It will
+ * only be invoked if the payload can be sent as JSON. It will not be
+ * invoked again for a given update after it returned `true`, indicating
+ * that the API call should be performed as a webhook send. In other words,
+ * subsequent API calls (during the same update) will always perform their
+ * own HTTP requests.
+ *
+ * @param method The method to call
+ */
+ canUseWebhookReply?: (method: string) => boolean;
+ /**
+ * Base configuration for `fetch` calls. Specify any additional parameters
+ * to use when fetching a method of the Telegram Bot API. Default: `{
+ * compress: true, duplex: "half" }` (Node), `{ duplex: "half" }` (Deno, Web)
+ */
+ baseFetchConfig?: Omit<
+ NonNullable[1]>,
+ "method" | "headers" | "body"
+ >;
+
+ /**
+ * `fetch` function to use for making HTTP requests. Default: `node-fetch` in Node.js, `fetch` in Deno.
+ */
+ fetch?: typeof fetch;
+
+ /**
+ * When the network connection is unreliable and some API requests fail
+ * because of that, grammY will throw errors that tell you exactly which
+ * requests failed. However, the error messages do not disclose the fetched
+ * URL as it contains your bot's token. Logging it may lead to token leaks.
+ *
+ * If you are sure that no logs are ever posted in Telegram chats, GitHub
+ * issues, or otherwise shared, you can set this option to `true` in order
+ * to obtain more detailed logs that may help you debug your bot. The
+ * default value is `false`, meaning that the bot token is not logged.
+ */
+ sensitiveLogs?: boolean;
+}
+
+class ApiClient {
+ private readonly options: Required;
+
+ private readonly fetch: typeof fetch;
+
+ private hasUsedWebhookReply = false;
+
+ readonly installedTransformers: Transformer[] = [];
+
+ constructor(
+ private readonly token: string,
+ options: ApiClientOptions = {},
+ private readonly webhookReplyEnvelope: WebhookReplyEnvelope = {},
+ ) {
+ const apiRoot = options.apiRoot ?? "https://api.telegram.org";
+ const environment = options.environment ?? "prod";
+
+ // In an ideal world, `fetch` is independent of the context being called,
+ // but in a Cloudflare worker, any context other than global throws an error.
+ // That is why we need to call custom fetch or fetch without context.
+ const { fetch: customFetch } = options;
+ const fetchFn = customFetch ?? fetch;
+
+ this.options = {
+ apiRoot,
+ environment,
+ buildUrl: options.buildUrl ?? defaultBuildUrl,
+ timeoutSeconds: options.timeoutSeconds ?? 500,
+ baseFetchConfig: {
+ ...baseFetchConfig(apiRoot),
+ ...options.baseFetchConfig,
+ },
+ canUseWebhookReply: options.canUseWebhookReply ?? (() => false),
+ sensitiveLogs: options.sensitiveLogs ?? false,
+ fetch:
+ ((...args: Parameters) =>
+ fetchFn(...args)) as typeof fetch,
+ };
+ this.fetch = this.options.fetch;
+ if (this.options.apiRoot.endsWith("/")) {
+ throw new Error(
+ `Remove the trailing '/' from the 'apiRoot' option (use '${
+ this.options.apiRoot.substring(
+ 0,
+ this.options.apiRoot.length - 1,
+ )
+ }' instead of '${this.options.apiRoot}')`,
+ );
+ }
+ }
+
+ private call: ApiCallFn = async >(
+ method: M,
+ p: Payload,
+ signal?: AbortSignal,
+ ) => {
+ const payload = p ?? {};
+ debug(`Calling ${method}`);
+ if (signal !== undefined) validateSignal(method, payload, signal);
+ // General config
+ const opts = this.options;
+ const formDataRequired = requiresFormDataUpload(payload);
+ // Short-circuit on webhook reply
+ if (
+ this.webhookReplyEnvelope.send !== undefined &&
+ !this.hasUsedWebhookReply &&
+ !formDataRequired &&
+ opts.canUseWebhookReply(method)
+ ) {
+ this.hasUsedWebhookReply = true;
+ const config = createJsonPayload({ ...payload, method });
+ await this.webhookReplyEnvelope.send(config.body);
+ return { ok: true, result: true as ApiCallResult };
+ }
+ // Handle timeouts and errors in the underlying form-data stream
+ const { controller, unregisterSignal } =
+ createAbortControllerFromSignal(signal);
+ const timeout = createTimeout(controller, opts.timeoutSeconds, method);
+ const streamErr = createStreamError(controller);
+ // Build request URL and config
+ const url = opts.buildUrl(
+ opts.apiRoot,
+ this.token,
+ method,
+ opts.environment,
+ );
+ const config = formDataRequired
+ ? createFormDataPayload(payload, (err) => streamErr.catch(err))
+ : createJsonPayload(payload);
+ const sig = controller.signal;
+ const options = { ...opts.baseFetchConfig, signal: sig, ...config };
+ // Perform fetch call
+ const successPromise = this.fetch(url, options)
+ .then((res) => res.json());
+ // Those are the three possible outcomes of the fetch call:
+ const operations = [successPromise, streamErr.promise, timeout.promise];
+ // Wait for result
+ try {
+ return await Promise.race(operations);
+ } catch (error) {
+ throw toHttpError(method, opts.sensitiveLogs, error);
+ } finally {
+ if (timeout.handle !== undefined) clearTimeout(timeout.handle);
+ unregisterSignal?.();
+ }
+ };
+
+ use(...transformers: Transformer[]) {
+ this.call = transformers.reduce(concatTransformer, this.call);
+ this.installedTransformers.push(...transformers);
+ return this;
+ }
+
+ async callApi>(
+ method: M,
+ payload: Payload,
+ signal?: AbortSignal,
+ ) {
+ const data = await this.call(method, payload, signal);
+ if (data.ok) return data.result;
+ else throw toGrammyError(data, method, payload);
+ }
+}
+
+/**
+ * Creates a new transformable API, i.e. an object that lets you perform raw API
+ * calls to the Telegram Bot API server but pass the calls through a stack of
+ * transformers before. This will create a new API client instance under the
+ * hood that will be used to connect to the Telegram servers. You therefore need
+ * to pass the bot token. In addition, you may pass API client options as well
+ * as a webhook reply envelope that allows the client to perform up to one HTTP
+ * request in response to a webhook call if this is desired.
+ *
+ * @param token The bot's token
+ * @param options A number of options to pass to the created API client
+ * @param webhookReplyEnvelope The webhook reply envelope that will be used
+ */
+export function createRawApi(
+ token: string,
+ options?: ApiClientOptions,
+ webhookReplyEnvelope?: WebhookReplyEnvelope,
+): TransformableApi {
+ const client = new ApiClient(token, options, webhookReplyEnvelope);
+
+ const proxyHandler: ProxyHandler = {
+ get(_, m: Methods | "toJSON") {
+ return m === "toJSON"
+ ? "__internal"
+ // Methods with zero parameters are called without any payload,
+ // so we have to manually inject an empty payload.
+ : m === "getMe" ||
+ m === "getWebhookInfo" ||
+ m === "getForumTopicIconStickers" ||
+ m === "getAvailableGifts" ||
+ m === "logOut" ||
+ m === "close" ||
+ m === "getMyStarBalance" ||
+ m === "removeMyProfilePhoto"
+ ? client.callApi.bind(client, m, {} as Payload)
+ : client.callApi.bind(client, m);
+ },
+ ...proxyMethods,
+ };
+ const raw = new Proxy({} as R, proxyHandler);
+ const installedTransformers = client.installedTransformers;
+ const api: TransformableApi = {
+ raw,
+ installedTransformers,
+ use: (...t) => {
+ client.use(...t);
+ return api;
+ },
+ };
+
+ return api;
+}
+
+const defaultBuildUrl: NonNullable = (
+ root,
+ token,
+ method,
+ env,
+) => {
+ const prefix = env === "test" ? "test/" : "";
+ return `${root}/bot${token}/${prefix}${method}`;
+};
+
+const proxyMethods = {
+ set() {
+ return false;
+ },
+ defineProperty() {
+ return false;
+ },
+ deleteProperty() {
+ return false;
+ },
+ ownKeys() {
+ return [];
+ },
+};
+
+/** A container for a rejecting promise */
+interface AsyncError {
+ promise: Promise;
+}
+/** An async error caused by a timeout */
+interface Timeout extends AsyncError {
+ handle: ReturnType | undefined;
+}
+/** An async error caused by an error in an underlying resource stream */
+interface StreamError extends AsyncError {
+ catch: (err: unknown) => void;
+}
+
+/** Creates a timeout error which aborts a given controller */
+function createTimeout(
+ controller: AbortController,
+ seconds: number,
+ method: string,
+): Timeout {
+ let handle: Timeout["handle"] = undefined;
+ const promise = new Promise((_, reject) => {
+ handle = setTimeout(() => {
+ const msg =
+ `Request to '${method}' timed out after ${seconds} seconds`;
+ reject(new Error(msg));
+ controller.abort();
+ }, 1000 * seconds);
+ });
+ return { promise, handle };
+}
+/** Creates a stream error which abort a given controller */
+function createStreamError(abortController: AbortController): StreamError {
+ let onError: StreamError["catch"] = (err) => {
+ // Re-throw by default, but will be overwritten immediately
+ throw err;
+ };
+ const promise = new Promise((_, reject) => {
+ onError = (err: unknown) => {
+ reject(err);
+ abortController.abort();
+ };
+ });
+ return { promise, catch: onError };
+}
+
+function createAbortControllerFromSignal(signal?: AbortSignal) {
+ const controller = new AbortController();
+ if (signal === undefined) {
+ return { controller, unregisterSignal: undefined };
+ }
+ const sig = signal;
+ function abort() {
+ controller.abort();
+ unregisterSignal();
+ }
+ function unregisterSignal() {
+ sig.removeEventListener("abort", abort);
+ }
+ if (sig.aborted) abort();
+ else sig.addEventListener("abort", abort);
+ return {
+ controller: { abort, signal: controller.signal },
+ unregisterSignal,
+ };
+}
+
+function validateSignal(
+ method: string,
+ payload: Record,
+ signal: AbortSignal,
+) {
+ // We use a very simple heuristic to check for AbortSignal instances
+ // in order to avoid doing a runtime-specific version of `instanceof`.
+ if (typeof signal?.addEventListener === "function") {
+ return;
+ }
+
+ let payload0 = JSON.stringify(payload);
+ if (payload0.length > 20) {
+ payload0 = payload0.substring(0, 16) + " ...";
+ }
+ let payload1 = JSON.stringify(signal);
+ if (payload1.length > 20) {
+ payload1 = payload1.substring(0, 16) + " ...";
+ }
+ throw new Error(
+ `Incorrect abort signal instance found! \
+You passed two payloads to '${method}' but you should merge \
+the second one containing '${payload1}' into the first one \
+containing '${payload0}'! If you are using context shortcuts, \
+you may want to use a method on 'ctx.api' instead.
+
+If you want to prevent such mistakes in the future, \
+consider using TypeScript. https://www.typescriptlang.org/`,
+ );
+}
diff --git a/src/composer.ts b/src/composer.ts
new file mode 100644
index 0000000..2096b4f
--- /dev/null
+++ b/src/composer.ts
@@ -0,0 +1,1038 @@
+import {
+ type CallbackQueryContext,
+ type ChatTypeContext,
+ type ChosenInlineResultContext,
+ type CommandContext,
+ Context,
+ type GameQueryContext,
+ type HearsContext,
+ type InlineQueryContext,
+ type MaybeArray,
+ type PreCheckoutQueryContext,
+ type ReactionContext,
+ type ShippingQueryContext,
+ type StringWithCommandSuggestions,
+} from "./context.ts";
+import { type Filter, type FilterQuery } from "./filter.ts";
+import {
+ type Chat,
+ type ReactionType,
+ type ReactionTypeEmoji,
+} from "./types.ts";
+
+type MaybePromise = T | Promise;
+
+// === Middleware types
+/**
+ * A function of this type is passed as the second parameter to all middleware.
+ * Invoke it to call the downstream middleware and pass on the control flow.
+ *
+ * In other words, if your middleware is done handling the context object, and
+ * other middleware should take over, this function should be called and
+ * `await`ed.
+ *
+ * Once the `Promise` returned by this function resolves, the downstream
+ * middleware is done executing, hence returning the control.
+ */
+export type NextFunction = () => Promise;
+
+/**
+ * Middleware in the form of a function.
+ */
+export type MiddlewareFn = (
+ ctx: C,
+ next: NextFunction,
+) => MaybePromise;
+/**
+ * Middleware in the form of a container for a function.
+ */
+export interface MiddlewareObj {
+ /**
+ * Returns the contained middleware.
+ */
+ middleware: () => MiddlewareFn;
+}
+/**
+ * Middleware for grammY, either as a function or as a container for a function.
+ *
+ * Simply put, middleware is just a fancy term for a _listener_. You can
+ * register middleware on a bot to listen for updates. Example:
+ *
+ * ```ts
+ * bot.on('message', ctx => ctx.reply('I got your message!'))
+ * // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * // ^
+ * // |
+ * // This is middleware!
+ * ```
+ *
+ * Middleware receives one object that we call the _context object_. This is
+ * another fancy term for a simple object that holds information about the
+ * update you're processing. For instance, the context object gives you access
+ * to the message that was sent to your bot (`ctx.message`), including the text
+ * (or photo or whatever message the user has sent). The context object is
+ * commonly named `ctx`.
+ *
+ * It also provides you with the `ctx.api` object that you also find on
+ * `bot.api`. As a result, you can call `ctx.api.sendMessage` instead of
+ * `bot.api.sendMessage`. This prevents you from having to pass around your
+ * `bot` instance all over your code.
+ *
+ * Most importantly, the context object gives you a handful of really useful
+ * shortcuts, such as a `reply` method (see above). This method is nothing else
+ * than a wrapper around `ctx.api.sendMessage`βbut with some arguments
+ * pre-filled for you. As you can see above, you no longer have to specify a
+ * `chat_id` or anything; the context object knows which chat it belongs to, so
+ * when you call `reply`, the context will call `sendMessage` with the correct
+ * `chat_id`, namely the one for the same chat that the incoming message
+ * originates from. This makes it very convenient to reply to a message.
+ *
+ * Middleware is an extremely powerful concept and this short explanation only
+ * scratched the surface of what is possible with grammY. If you want to know
+ * more advanced things about middleware, check out the
+ * [documentation](https://grammy.dev/guide/middleware) on the website.
+ */
+export type Middleware =
+ | MiddlewareFn
+ | MiddlewareObj;
+
+// === Middleware errors
+/**
+ * This error is thrown when middleware throws. It simply wraps the original
+ * error (accessible via the `error` property), but also provides access to the
+ * respective context object that was processed while the error occurred.
+ */
+export class BotError extends Error {
+ constructor(public readonly error: unknown, public readonly ctx: C) {
+ super(generateBotErrorMessage(error));
+ this.name = "BotError";
+ if (error instanceof Error) this.stack = error.stack;
+ }
+}
+function generateBotErrorMessage(error: unknown) {
+ let msg: string;
+ if (error instanceof Error) {
+ msg = `${error.name} in middleware: ${error.message}`;
+ } else {
+ const type = typeof error;
+ msg = `Non-error value of type ${type} thrown in middleware`;
+ switch (type) {
+ case "bigint":
+ case "boolean":
+ case "number":
+ case "symbol":
+ msg += `: ${error}`;
+ break;
+ case "string":
+ msg += `: ${String(error).substring(0, 50)}`;
+ break;
+ default:
+ msg += "!";
+ break;
+ }
+ }
+ return msg;
+}
+
+// === Middleware base functions
+function flatten(mw: Middleware): MiddlewareFn {
+ return typeof mw === "function"
+ ? mw
+ : (ctx, next) => mw.middleware()(ctx, next);
+}
+function concat(
+ first: MiddlewareFn,
+ andThen: MiddlewareFn,
+): MiddlewareFn {
+ return async (ctx, next) => {
+ let nextCalled = false;
+ await first(ctx, async () => {
+ if (nextCalled) throw new Error("`next` already called before!");
+ else nextCalled = true;
+ await andThen(ctx, next);
+ });
+ };
+}
+function pass(_ctx: C, next: NextFunction) {
+ return next();
+}
+
+const leaf: NextFunction = () => Promise.resolve();
+/**
+ * Runs some given middleware function with a given context object.
+ *
+ * @param middleware The middleware to run
+ * @param ctx The context to use
+ */
+export async function run(
+ middleware: MiddlewareFn,
+ ctx: C,
+) {
+ await middleware(ctx, leaf);
+}
+
+// === Composer
+/**
+ * The composer is the heart of the middleware system in grammY. It is also the
+ * superclass of `Bot`. Whenever you call `use` or `on` or some of the other
+ * methods on your bot, you are in fact using the underlying composer instance
+ * to register your middleware.
+ *
+ * If you're just getting started, you do not need to worry about what
+ * middleware is, or about how to use a composer.
+ *
+ * On the other hand, if you want to dig deeper into how grammY implements
+ * middleware, check out the
+ * [documentation](https://grammy.dev/advanced/middleware) on the website.
+ */
+export class Composer implements MiddlewareObj {
+ private handler: MiddlewareFn;
+
+ /**
+ * Constructs a new composer based on the provided middleware. If no
+ * middleware is given, the composer instance will simply make all context
+ * objects pass through without touching them.
+ *
+ * @param middleware The middleware to compose
+ */
+ constructor(...middleware: Array>) {
+ this.handler = middleware.length === 0
+ ? pass
+ : middleware.map(flatten).reduce(concat);
+ }
+
+ middleware() {
+ return this.handler;
+ }
+
+ /**
+ * Registers some middleware that receives all updates. It is installed by
+ * concatenating it to the end of all previously installed middleware.
+ *
+ * Often, this method is used to install middleware that behaves like a
+ * plugin, for example session middleware.
+ * ```ts
+ * bot.use(session())
+ * ```
+ *
+ * This method returns a new instance of composer. The returned instance can
+ * be further extended, and all changes will be regarded here. Confer the
+ * [documentation](https://grammy.dev/advanced/middleware) on the
+ * website if you want to know more about how the middleware system in
+ * grammY works, especially when it comes to chaining the method calls
+ * (`use( ... ).use( ... ).use( ... )`).
+ *
+ * @param middleware The middleware to register
+ */
+ use(...middleware: Array>) {
+ const composer = new Composer(...middleware);
+ this.handler = concat(this.handler, flatten(composer));
+ return composer;
+ }
+
+ /**
+ * Registers some middleware that will only be executed for some specific
+ * updates, namely those matching the provided filter query. Filter queries
+ * are a concise way to specify which updates you are interested in.
+ *
+ * Here are some examples of valid filter queries:
+ * ```ts
+ * // All kinds of message updates
+ * bot.on('message', ctx => { ... })
+ *
+ * // Only text messages
+ * bot.on('message:text', ctx => { ... })
+ *
+ * // Only text messages with URL
+ * bot.on('message:entities:url', ctx => { ... })
+ *
+ * // Text messages and text channel posts
+ * bot.on(':text', ctx => { ... })
+ *
+ * // Messages with URL in text or caption (i.e. entities or caption entities)
+ * bot.on('message::url', ctx => { ... })
+ *
+ * // Messages or channel posts with URL in text or caption
+ * bot.on('::url', ctx => { ... })
+ * ```
+ *
+ * You can use autocomplete in VS Code to see all available filter queries.
+ * Check out the
+ * [documentation](https://grammy.dev/guide/filter-queries) on the
+ * website to learn more about filter queries in grammY.
+ *
+ * It is possible to pass multiple filter queries in an array, i.e.
+ * ```ts
+ * // Matches all text messages and edited text messages that contain a URL
+ * bot.on(['message:entities:url', 'edited_message:entities:url'], ctx => { ... })
+ * ```
+ *
+ * Your middleware will be executed if _any of the provided filter queries_
+ * matches (logical OR).
+ *
+ * If you instead want to match _all of the provided filter queries_
+ * (logical AND), you can chain the `.on` calls:
+ * ```ts
+ * // Matches all messages and channel posts that both a) contain a URL and b) are forwards
+ * bot.on('::url').on(':forward_origin', ctx => { ... })
+ * ```
+ *
+ * @param filter The filter query to use, may also be an array of queries
+ * @param middleware The middleware to register behind the given filter
+ */
+ on(
+ filter: Q | Q[],
+ ...middleware: Array>>
+ ): Composer> {
+ return this.filter(Context.has.filterQuery(filter), ...middleware);
+ }
+
+ /**
+ * Registers some middleware that will only be executed when the message
+ * contains some text. Is it possible to pass a regular expression to match:
+ * ```ts
+ * // Match some text (exact match)
+ * bot.hears('I love grammY', ctx => ctx.reply('And grammY loves you! <3'))
+ * // Match a regular expression
+ * bot.hears(/\/echo (.+)/, ctx => ctx.reply(ctx.match[1]))
+ * ```
+ * Note how `ctx.match` will contain the result of the regular expression.
+ * Here it is a `RegExpMatchArray` object, so `ctx.match[1]` refers to the
+ * part of the regex that was matched by `(.+)`, i.e. the text that comes
+ * after β/echoβ.
+ *
+ * You can pass an array of triggers. Your middleware will be executed if at
+ * least one of them matches.
+ *
+ * Both text and captions of the received messages will be scanned. For
+ * example, when a photo is sent to the chat and its caption matches the
+ * trigger, your middleware will be executed.
+ *
+ * If you only want to match text messages and not captions, you can do
+ * this:
+ * ```ts
+ * // Only matches text messages (and channel posts) for the regex
+ * bot.on(':text').hears(/\/echo (.+)/, ctx => { ... })
+ * ```
+ *
+ * @param trigger The text to look for
+ * @param middleware The middleware to register
+ */
+ hears(
+ trigger: MaybeArray,
+ ...middleware: Array>
+ ): Composer> {
+ return this.filter(Context.has.text(trigger), ...middleware);
+ }
+
+ /**
+ * Registers some middleware that will only be executed when a certain
+ * command is found.
+ * ```ts
+ * // Reacts to /start commands
+ * bot.command('start', ctx => { ... })
+ * // Reacts to /help commands
+ * bot.command('help', ctx => { ... })
+ * ```
+ *
+ * The rest of the message (excluding the command, and trimmed) is provided
+ * via `ctx.match`.
+ *
+ * > **Did you know?** You can use deep linking
+ * > (https://core.telegram.org/bots/features#deep-linking) to let users
+ * > start your bot with a custom payload. As an example, send someone the
+ * > link https://t.me/name-of-your-bot?start=custom-payload and register a
+ * > start command handler on your bot with grammY. As soon as the user
+ * > starts your bot, you will receive `custom-payload` in the `ctx.match`
+ * > property!
+ * > ```ts
+ * > bot.command('start', ctx => {
+ * > const payload = ctx.match // will be 'custom-payload'
+ * > })
+ * > ```
+ *
+ * Note that commands are not matched in captions or in the middle of the
+ * text.
+ * ```ts
+ * bot.command('start', ctx => { ... })
+ * // ... does not match:
+ * // A message saying: βsome text /start some more textβ
+ * // A photo message with the caption β/startβ
+ * ```
+ *
+ * By default, commands are detected in channel posts, too. This means that
+ * `ctx.message` is potentially `undefined`, so you should use `ctx.msg`
+ * instead to grab both messages and channel posts. Alternatively, if you
+ * want to limit your bot to finding commands only in private and group
+ * chats, you can use `bot.on('message').command('start', ctx => { ... })`,
+ * or even store a message-only version of your bot in a variable like so:
+ * ```ts
+ * const m = bot.on('message')
+ *
+ * m.command('start', ctx => { ... })
+ * m.command('help', ctx => { ... })
+ * // etc
+ * ```
+ *
+ * If you need more freedom matching your commands, check out the `commands`
+ * plugin.
+ *
+ * @param command The command to look for
+ * @param middleware The middleware to register
+ */
+ command(
+ command: MaybeArray,
+ ...middleware: Array>
+ ): Composer> {
+ return this.filter(Context.has.command(command), ...middleware);
+ }
+
+ /**
+ * Registers some middleware that will only be added when a new reaction of
+ * the given type is added to a message.
+ * ```ts
+ * // Reacts to new 'π' reactions
+ * bot.reaction('π', ctx => { ... })
+ * // Reacts to new 'π' or 'π' reactions
+ * bot.reaction(['π', 'π'], ctx => { ... })
+ * ```
+ *
+ * > Note that you have to enable `message_reaction` updates in
+ * `allowed_updates` if you want your bot to receive updates about message
+ * reactions.
+ *
+ * `bot.reaction` will trigger if:
+ * - a new emoji reaction is added to a message
+ * - a new custom emoji reaction is added a message
+ *
+ * `bot.reaction` will not trigger if:
+ * - a reaction is removed
+ * - an anonymous reaction count is updated, such as on channel posts
+ * - `message_reaction` updates are not enabled for your bot
+ *
+ * @param reaction The reaction to look for
+ * @param middleware The middleware to register
+ */
+ reaction(
+ reaction: MaybeArray,
+ ...middleware: Array>
+ ): Composer> {
+ return this.filter(Context.has.reaction(reaction), ...middleware);
+ }
+
+ /**
+ * Registers some middleware for certain chat types only. For example, you
+ * can use this method to only receive updates from private chats. The four
+ * chat types are `"channel"`, `"supergroup"`, `"group"`, and `"private"`.
+ * This is especially useful when combined with other filtering logic. For
+ * example, this is how can you respond to `/start` commands only from
+ * private chats:
+ * ```ts
+ * bot.chatType("private").command("start", ctx => { ... })
+ * ```
+ *
+ * Naturally, you can also use this method on its own.
+ * ```ts
+ * // Private chats only
+ * bot.chatType("private", ctx => { ... });
+ * // Channels only
+ * bot.chatType("channel", ctx => { ... });
+ * ```
+ *
+ * You can pass an array of chat types if you want your middleware to run
+ * for any of several provided chat types.
+ * ```ts
+ * // Groups and supergroups only
+ * bot.chatType(["group", "supergroup"], ctx => { ... });
+ * ```
+ * [Remember](https://grammy.dev/guide/context#shortcuts) also that you
+ * can access the chat type via `ctx.chat.type`.
+ *
+ * @param chatType The chat type
+ * @param middleware The middleware to register
+ */
+ chatType(
+ chatType: MaybeArray,
+ ...middleware: Array>>
+ ): Composer> {
+ return this.filter(Context.has.chatType(chatType), ...middleware);
+ }
+
+ /**
+ * Registers some middleware for callback queries, i.e. the updates that
+ * Telegram delivers to your bot when a user clicks an inline button (that
+ * is a button under a message).
+ *
+ * This method is essentially the same as calling
+ * ```ts
+ * bot.on('callback_query:data', ctx => { ... })
+ * ```
+ * but it also allows you to match the query data against a given text or
+ * regular expression.
+ *
+ * ```ts
+ * // Create an inline keyboard
+ * const keyboard = new InlineKeyboard().text('Go!', 'button-payload')
+ * // Send a message with the keyboard
+ * await bot.api.sendMessage(chat_id, 'Press a button!', {
+ * reply_markup: keyboard
+ * })
+ * // Listen to users pressing buttons with that specific payload
+ * bot.callbackQuery('button-payload', ctx => { ... })
+ *
+ * // Listen to users pressing any button your bot ever sent
+ * bot.on('callback_query:data', ctx => { ... })
+ * ```
+ *
+ * Always remember to call `answerCallbackQuery`βeven if you don't perform
+ * any action: https://core.telegram.org/bots/api#answercallbackquery
+ * ```ts
+ * bot.on('callback_query:data', async ctx => {
+ * await ctx.answerCallbackQuery()
+ * })
+ * ```
+ *
+ * You can pass an array of triggers. Your middleware will be executed if at
+ * least one of them matches.
+ *
+ * @param trigger The string to look for in the payload
+ * @param middleware The middleware to register
+ */
+ callbackQuery(
+ trigger: MaybeArray,
+ ...middleware: Array>
+ ): Composer> {
+ return this.filter(Context.has.callbackQuery(trigger), ...middleware);
+ }
+
+ /**
+ * Registers some middleware for game queries, i.e. the updates that
+ * Telegram delivers to your bot when a user clicks an inline button for the
+ * HTML5 games platform on Telegram.
+ *
+ * This method is essentially the same as calling
+ * ```ts
+ * bot.on('callback_query:game_short_name', ctx => { ... })
+ * ```
+ * but it also allows you to match the query data against a given text or
+ * regular expression.
+ *
+ * You can pass an array of triggers. Your middleware will be executed if at
+ * least one of them matches.
+ *
+ * @param trigger The string to look for in the payload
+ * @param middleware The middleware to register
+ */
+ gameQuery(
+ trigger: MaybeArray,
+ ...middleware: Array>
+ ): Composer> {
+ return this.filter(Context.has.gameQuery(trigger), ...middleware);
+ }
+
+ /**
+ * Registers middleware for inline queries. Telegram sends an inline query
+ * to your bot whenever a user types β@your_bot_name ...β into a text field
+ * in Telegram. You bot will then receive the entered search query and can
+ * respond with a number of results (text, images, etc) that the user can
+ * pick from to send a message _via_ your bot to the respective chat. Check
+ * out https://core.telegram.org/bots/inline to read more about inline bots.
+ *
+ * > Note that you have to enable inline mode for you bot by contacting
+ * > @BotFather first.
+ *
+ * ```ts
+ * // Listen for users typing β@your_bot_name queryβ
+ * bot.inlineQuery('query', async ctx => {
+ * // Answer the inline query, confer https://core.telegram.org/bots/api#answerinlinequery
+ * await ctx.answerInlineQuery( ... )
+ * })
+ * ```
+ *
+ * @param trigger The inline query text to match
+ * @param middleware The middleware to register
+ */
+ inlineQuery(
+ trigger: MaybeArray,
+ ...middleware: Array>
+ ): Composer> {
+ return this.filter(Context.has.inlineQuery(trigger), ...middleware);
+ }
+
+ /**
+ * Registers middleware for the ChosenInlineResult by the given id or ids.
+ * ChosenInlineResult represents a result of an inline query that was chosen
+ * by the user and sent to their chat partner. Check out
+ * https://core.telegram.org/bots/api#choseninlineresult to read more about
+ * chosen inline results.
+ *
+ * ```ts
+ * bot.chosenInlineResult('id', async ctx => {
+ * const id = ctx.result_id;
+ * // Your code
+ * })
+ * ```
+ *
+ * @param resultId An id or array of ids
+ * @param middleware The middleware to register
+ */
+ chosenInlineResult(
+ resultId: MaybeArray,
+ ...middleware: Array>
+ ): Composer> {
+ return this.filter(
+ Context.has.chosenInlineResult(resultId),
+ ...middleware,
+ );
+ }
+
+ /**
+ * Registers middleware for pre-checkout queries. Telegram sends a
+ * pre-checkout query to your bot whenever a user has confirmed their
+ * payment and shipping details. You bot will then receive all information
+ * about the order and has to respond within 10 seconds with a confirmation
+ * of whether everything is alright (goods are available, etc.) and the bot
+ * is ready to proceed with the order. Check out
+ * https://core.telegram.org/bots/api#precheckoutquery to read more about
+ * pre-checkout queries.
+ *
+ * ```ts
+ * bot.preCheckoutQuery('invoice_payload', async ctx => {
+ * // Answer the pre-checkout query, confer https://core.telegram.org/bots/api#answerprecheckoutquery
+ * await ctx.answerPreCheckoutQuery( ... )
+ * })
+ * ```
+ *
+ * @param trigger The string to look for in the invoice payload
+ * @param middleware The middleware to register
+ */
+ preCheckoutQuery(
+ trigger: MaybeArray,
+ ...middleware: Array>
+ ): Composer> {
+ return this.filter(
+ Context.has.preCheckoutQuery(trigger),
+ ...middleware,
+ );
+ }
+
+ /**
+ * Registers middleware for shipping queries. If you sent an invoice
+ * requesting a shipping address and the parameter _is_flexible_ was
+ * specified, Telegram will send a shipping query to your bot whenever a
+ * user has confirmed their shipping details. You bot will then receive the
+ * shipping information and can respond with a confirmation of whether
+ * delivery to the specified address is possible. Check out
+ * https://core.telegram.org/bots/api#shippingquery to read more about
+ * shipping queries.
+ *
+ * ```ts
+ * bot.shippingQuery('invoice_payload', async ctx => {
+ * // Answer the shipping query, confer https://core.telegram.org/bots/api#answershippingquery
+ * await ctx.answerShippingQuery( ... )
+ * })
+ * ```
+ *
+ * @param trigger The string to look for in the invoice payload
+ * @param middleware The middleware to register
+ */
+ shippingQuery(
+ trigger: MaybeArray,
+ ...middleware: Array>
+ ): Composer> {
+ return this.filter(Context.has.shippingQuery(trigger), ...middleware);
+ }
+
+ /**
+ * > This is an advanced method of grammY.
+ *
+ * Registers middleware behind a custom filter function that operates on the
+ * context object and decides whether or not to execute the middleware. In
+ * other words, the middleware will only be executed if the given predicate
+ * returns `true` for the given context object. Otherwise, it will be
+ * skipped and the next middleware will be executed.
+ *
+ * This method has two signatures. The first one is straightforward, it is
+ * the one described above. Note that the predicate may be asynchronous,
+ * i.e. it can return a Promise of a boolean.
+ *
+ * Alternatively, you can pass a function that has a type predicate as
+ * return type. This will allow you to narrow down the context object. The
+ * installed middleware is then able to operate on this constrained context
+ * object.
+ * ```ts
+ * // NORMAL USAGE
+ * // Only process every second update
+ * bot.filter(ctx => ctx.update.update_id % 2 === 0, ctx => { ... })
+ *
+ * // TYPE PREDICATE USAGE
+ * function predicate(ctx): ctx is Context & { message: undefined } {
+ * return ctx.message === undefined
+ * }
+ * // Only process updates where `message` is `undefined`
+ * bot.filter(predicate, ctx => {
+ * const m = ctx.message // inferred as always undefined!
+ * const m2 = ctx.update.message // also inferred as always undefined!
+ * })
+ * ```
+ *
+ * @param predicate The predicate to check
+ * @param middleware The middleware to register
+ */
+ filter(
+ predicate: (ctx: C) => ctx is D,
+ ...middleware: Array>
+ ): Composer;
+ filter(
+ predicate: (ctx: C) => MaybePromise,
+ ...middleware: Array>
+ ): Composer;
+ filter(
+ predicate: (ctx: C) => MaybePromise,
+ ...middleware: Array>
+ ) {
+ const composer = new Composer(...middleware);
+ this.branch(predicate, composer, pass);
+ return composer;
+ }
+
+ /**
+ * > This is an advanced method of grammY.
+ *
+ * Registers middleware behind a custom filter function that operates on the
+ * context object and decides whether or not to execute the middleware. In
+ * other words, the middleware will only be executed if the given predicate
+ * returns `false` for the given context object. Otherwise, it will be
+ * skipped and the next middleware will be executed. Note that the predicate
+ * may be asynchronous, i.e. it can return a Promise of a boolean.
+ *
+ * This method is the same using `filter` (normal usage) with a negated
+ * predicate.
+ *
+ * @param predicate The predicate to check
+ * @param middleware The middleware to register
+ */
+ drop(
+ predicate: (ctx: C) => MaybePromise,
+ ...middleware: Array>
+ ) {
+ return this.filter(
+ async (ctx: C) => !(await predicate(ctx)),
+ ...middleware,
+ );
+ }
+
+ /**
+ * > This is an advanced method of grammY.
+ *
+ * Registers some middleware that runs concurrently to the executing
+ * middleware stack.
+ * ```ts
+ * bot.use( ... ) // will run first
+ * bot.fork( ... ) // will be started second, but run concurrently
+ * bot.use( ... ) // will also be run second
+ * ```
+ * In the first middleware, as soon as `next`'s Promise resolves, both forks
+ * have completed.
+ *
+ * Both the fork and the downstream middleware are awaited with
+ * `Promise.all`, so you will only be able to catch at most one error (the
+ * one that is thrown first).
+ *
+ * In contrast to the other middleware methods on composer, `fork` does not
+ * simply return the composer connected to the main middleware stack.
+ * Instead, it returns the created composer _of the fork_ connected to the
+ * middleware stack. This allows for the following pattern.
+ * ```ts
+ * // Middleware will be run concurrently!
+ * bot.fork().on('message', ctx => { ... })
+ * ```
+ *
+ * @param middleware The middleware to run concurrently
+ */
+ fork(...middleware: Array>) {
+ const composer = new Composer(...middleware);
+ const fork = flatten(composer);
+ this.use((ctx, next) => Promise.all([next(), run(fork, ctx)]));
+ return composer;
+ }
+
+ /**
+ * > This is an advanced method of grammY.
+ *
+ * Executes some middleware that can be generated on the fly for each
+ * context. Pass a factory function that creates some middleware (or a
+ * middleware array even). The factory function will be called once per
+ * context, and its result will be executed with the context object.
+ * ```ts
+ * // The middleware returned by `createMyMiddleware` will be used only once
+ * bot.lazy(ctx => createMyMiddleware(ctx))
+ * ```
+ *
+ * You may generate this middleware in an `async` fashion.
+ *
+ * You can decide to return an empty array (`[]`) if you don't want to run
+ * any middleware for a given context object. This is equivalent to
+ * returning an empty instance of `Composer`.
+ *
+ * @param middlewareFactory The factory function creating the middleware
+ */
+ lazy(
+ middlewareFactory: (ctx: C) => MaybePromise>>,
+ ): Composer {
+ return this.use(async (ctx, next) => {
+ const middleware = await middlewareFactory(ctx);
+ const arr = Array.isArray(middleware) ? middleware : [middleware];
+ await flatten(new Composer(...arr))(ctx, next);
+ });
+ }
+
+ /**
+ * > This is an advanced method of grammY.
+ *
+ * _Not to be confused with the `router` plugin._
+ *
+ * This method is an alternative to the `router` plugin. It allows you to
+ * branch between different middleware per context object. You can pass two
+ * things to it:
+ * 1. A routing function
+ * 2. Different middleware identified by key
+ *
+ * The routing function decides based on the context object which middleware
+ * to run. Each middleware is identified by a key, so the routing function
+ * simply returns the key of that middleware.
+ * ```ts
+ * // Define different route handlers
+ * const routeHandlers = {
+ * evenUpdates: (ctx: Context) => { ... }
+ * oddUpdates: (ctx: Context) => { ... }
+ * }
+ * // Decide for a context object which one to pick
+ * const router = (ctx: Context) => ctx.update.update_id % 2 === 0
+ * ? 'evenUpdates'
+ * : 'oddUpdates'
+ * // Route it!
+ * bot.route(router, routeHandlers)
+ * ```
+ *
+ * Optionally, you can pass a third option that is used as fallback
+ * middleware if your route function returns `undefined`, or if the key
+ * returned by your router has no middleware associated with it.
+ *
+ * This method may need less setup than first instantiating a `Router`, but
+ * for more complex setups, having a `Router` may be more readable.
+ *
+ * @param router The routing function to use
+ * @param routeHandlers Handlers for every route
+ * @param fallback Optional fallback middleware if no route matches
+ */
+ route>>(
+ router: (ctx: C) => MaybePromise,
+ routeHandlers: R,
+ fallback: Middleware = pass,
+ ): Composer {
+ return this.lazy(async (ctx) => {
+ const route = await router(ctx);
+ return (route === undefined || !routeHandlers[route]
+ ? fallback
+ : routeHandlers[route]) ?? [];
+ });
+ }
+
+ /**
+ * > This is an advanced method of grammY.
+ *
+ * Allows you to branch between two cases for a given context object.
+ *
+ * This method takes a predicate function that is tested once per context
+ * object. If it returns `true`, the first supplied middleware is executed.
+ * If it returns `false`, the second supplied middleware is executed. Note
+ * that the predicate may be asynchronous, i.e. it can return a Promise of a
+ * boolean.
+ *
+ * @param predicate The predicate to check
+ * @param trueMiddleware The middleware for the `true` case
+ * @param falseMiddleware The middleware for the `false` case
+ */
+ branch(
+ predicate: (ctx: C) => MaybePromise,
+ trueMiddleware: MaybeArray>,
+ falseMiddleware: MaybeArray>,
+ ) {
+ return this.lazy(async (ctx) =>
+ (await predicate(ctx)) ? trueMiddleware : falseMiddleware
+ );
+ }
+
+ /**
+ * > This is an advanced function of grammY.
+ *
+ * Installs an error boundary that catches errors that happen only inside
+ * the given middleware. This allows you to install custom error handlers
+ * that protect some parts of your bot. Errors will not be able to bubble
+ * out of this part of your middleware system, unless the supplied error
+ * handler rethrows them, in which case the next surrounding error boundary
+ * will catch the error.
+ *
+ * Example usage:
+ * ```ts
+ * function errHandler(err: BotError) {
+ * console.error('Error boundary caught error!', err)
+ * }
+ *
+ * const safe =
+ * // All passed middleware will be protected by the error boundary.
+ * bot.errorBoundary(errHandler, middleware0, middleware1, middleware2)
+ *
+ * // Those will also be protected!
+ * safe.on('message', middleware3)
+ *
+ * // No error from `middleware4` will reach the `errHandler` from above,
+ * // as errors are suppressed.
+ *
+ * // do nothing on error (suppress error), and run outside middleware
+ * const suppress = (_err: BotError, next: NextFunction) => { return next() }
+ * safe.errorBoundary(suppress).on('edited_message', middleware4)
+ * ```
+ *
+ * Check out the
+ * [documentation](https://grammy.dev/guide/errors#error-boundaries) on
+ * the website to learn more about error boundaries.
+ *
+ * @param errorHandler The error handler to use
+ * @param middleware The middleware to protect
+ */
+ errorBoundary(
+ errorHandler: (
+ error: BotError,
+ next: NextFunction,
+ ) => MaybePromise,
+ ...middleware: Array>
+ ) {
+ const composer = new Composer(...middleware);
+ const bound = flatten(composer);
+ this.use(async (ctx, next) => {
+ let nextCalled = false;
+ const cont = () => ((nextCalled = true), Promise.resolve());
+ try {
+ await bound(ctx, cont);
+ } catch (err) {
+ nextCalled = false;
+ await errorHandler(new BotError(err, ctx), cont);
+ }
+ if (nextCalled) await next();
+ });
+ return composer;
+ }
+}
+
+// === Filtered context middleware types
+/**
+ * Type of the middleware that can be passed to `bot.hears`.
+ *
+ * This helper type can be used to annotate middleware functions that are
+ * defined in one place, so that they have the correct type when passed to
+ * `bot.hears` in a different place. For instance, this allows for more modular
+ * code where handlers are defined in separate files.
+ */
+export type HearsMiddleware