npm node-telegram-bot-api 2.3.0

4 hours ago

2.3.0 adds a durable S3 session store, makes bot.command() ignore commands addressed to other bots, makes ctx.reply() answer where the message came from (business connections, forum topics), and stops a graceful shutdown from redelivering the update that was being handled. This release rolls up 2.3.0-rc0 and 2.3.0-rc1; the notes below describe the final 2.3.0 behavior.

Session storage

  • New S3SessionStorage (exported from the core node-telegram-bot-api): a durable, cross-instance session backend for any S3-compatible object store (AWS S3, Cloudflare R2, MinIO, DigitalOcean Spaces). It speaks the S3 REST API directly over fetch with AWS Signature V4 signing, so it is runtime-agnostic (Node 19+, Bun, Deno, Workers, edge). fetch and crypto are injectable, so Node 18 can pass node:crypto's webcrypto. There is no per-object TTL - use a bucket lifecycle rule on the prefix.
import { createSession, S3SessionStorage } from "node-telegram-bot-api";

bot.use(createSession({
  store: new S3SessionStorage({
    bucket: "my-bot-sessions",
    region: "us-east-1",
    credentials: { accessKeyId: "...", secretAccessKey: "..." },
    prefix: "sessions/", // optional; `endpoint` targets R2 / MinIO / Spaces
  }),
  initial: () => ({ count: 0 }),
}));

Dispatch

  • bot.command(name, ...) now ignores commands addressed to another bot. In a group, /start@some_bot runs the handler only when @some_bot is this bot's username (compared case-insensitively); /start@other_bot falls through to downstream middleware, and a bare /start still always matches. The bot's identity is exposed as bot.botInfo and, in handlers, ctx.me.
  • ctx.reply() now answers where the incoming message came from instead of the bare chat (#1386, #1387):
    • business_connection_id for business_message, edited_business_message and deleted_business_messages - previously the bot replied as itself (403 if the customer never started it).
    • message_thread_id for forum-topic messages (only when is_topic_message is set) - previously the reply landed in General. A plain reply/comment thread is still not followed.
    • direct_messages_topic_id for channel direct-messages chats, where it is required.
    • For a callback query, these come from the message the button is attached to. Anything passed in other still wins; pass undefined for a key to opt out.
  • ctx.reply() now throws for guest_message updates, pointing to api.answerGuestQuery with the message's guest_query_id: a guest bot is not a member of the chat, so sendMessage there cannot reach it.

Polling

  • Stopping the bot (bot.stop(), or SIGINT/SIGTERM via run()) while a handler runs no longer leaves that update unconfirmed (#1385, #1388). The loop used to exit before the next getUpdates carried the new offset, so a deploy's SIGTERM during a slow handler made Telegram redeliver the update on restart and non-idempotent handlers ran twice. On stop, longPoll now sends one final best-effort getUpdates({ offset, limit: 1, timeout: 0 }), capped at 5s. Updates that were never handled (the rest of a batch) are still redelivered, and an update whose bot.catch() throws (fail-loud) is never confirmed.

Uploads

  • InputFile uploads no longer throw ReferenceError: crypto is not defined on Node 18: the multipart boundary no longer needs the global WebCrypto, so uploads work across the full supported Node 18.2+ range (#1378).

Upgrading from 2.2.0

  • bot.init() (run by startPolling(), run() and the first handleUpdate()) now calls getMe() once to learn the bot's identity. Tests that inject a fake fetch need to answer getMe.
  • Handlers that relied on ctx.reply() landing in the bare chat for business or forum-topic messages now reply in the business connection / topic; pass { business_connection_id: undefined } or { message_thread_id: undefined } to keep the old target.
  • ctx.reply() in a guest_message handler now throws; use api.answerGuestQuery.

Full changelog: v2.2.0...v2.3.0

Don't miss a new node-telegram-bot-api release

NewReleases is sending notifications on new releases.