Skip to content

Тестирование стало богаче, CallbackData — надёжнее, TypeScript API Reference запущен

18–22 февраля 2026

Насыщенная неделя по всей экосистеме GramIO. @gramio/test v0.3.0 — 9 новых методов: editMessage, forwardMessage, sendMediaGroup, pinMessage, clickByText, три новых медиа-метода, ChatObject.post() для ботов в каналах, а также хелперы env.clearApiCalls() и env.lastApiCall(). @gramio/callback-data v0.1.0 вводит safeUnpack() — типизированный распаковщик, который никогда не бросает исключений, — и делает добавление optional-полей в существующие схемы полностью обратно совместимым. Новый пакет @gramio/schema-parser заменяет Rust-крейт tg-bot-api в основе @gramio/types: теперь есть точные InputFile | string-юнионы, семантические маркеры типов, синтезированный enum Currencies с XTR, и ранее отсутствовавшие типы APIResponse*. Из неопубликованного: @gramio/composer получает filter-only .on() с автоопределением CompatibleEvents<TEventMap, Narrowing> и типизированный Patch-дженерик для use(); сам gramio — filter-only перегрузки .on() и полноценную библиотеку предикатов filters.* с сужением через forwardOrigin(type?) и senderChat(type?). Документационный рывок не меньше: полный TypeDoc API Reference по /api/, 200+ страниц методов Telegram Bot API по /telegram/, новый Cheat Sheet, страницы JSX и Split-плагинов, интерактивные визуализаторы middleware и рассылок, production-архитектурное руководство по Composer, расширенные docs по сессиям и антипаттернам форматирования, и глобальная кнопка копирования в Markdown на каждой странице.

@gramio/test v0.3.0 — больше акторов, больше действий

9 новых методов: правка, пересылка, закрепление, медиагруппа и clickByText

Библиотека для тестирования серьёзно выросла. Вот что появилось:

user.editMessage(msg, text) — отправляет событие edited_message. Тестируйте обработчики редактирования без лишнего кода:

ts
const msg = await user.sendMessage("Привет");
await user.editMessage(msg, "Привет, мир!");
expect(env.apiCalls[0].method).toBe("editMessageText");

user.forwardMessage(msg, toChat?) — отправляет событие message с заполненным forward_origin. Удобно для тестирования логики определения пересланных сообщений:

ts
const msg = await user.sendMessage("Оригинальное сообщение");
await user.forwardMessage(msg, group); // переслано в группу

user.sendMediaGroup(chat, payloads[]) — отправляет несколько событий message с одним media_group_id. Для тестирования обработки альбомов:

ts
await user.sendMediaGroup(group, [
    { photo: {} },
    { video: {} },
]);

user.pinMessage(msg, inChat?) — отправляет служебное сообщение с pinned_message. GramIO направляет такие сообщения в событие "pinned_message":

ts
const msg = await user.sendMessage("Важное объявление");
await user.pinMessage(msg);

user.on(msg).clickByText(buttonText) — ищет в inline_keyboard кнопку с нужным текстом и кликает на её callback_data. Выбрасывает исключение, если кнопка не найдена:

ts
// (бот ответил сообщением с кнопками "Да" и "Нет")
await user.on(botReply).clickByText("Да");

Три новых медиа-метода: sendAudio(), sendAnimation(), sendVideoNote() — с автогенерацией file_id и тем же API, что и у остальных медиа-методов:

ts
await user.sendAudio({ caption: "Отличный трек" });
await user.sendAnimation(group, { caption: "Смешная гифка" });
await user.sendVideoNote(); // кружочек

ChatObject.post(text) — отправляет событие channel_post (без поля from) для тестирования ботов в каналах:

ts
const channel = env.createChat({ type: "channel", title: "Мой канал" });
await channel.post("Новый пост из канала");

env.clearApiCalls() и env.lastApiCall()

Два новых хелпера для чистых проверок:

ts
// Сбросить лог вызовов между фазами теста
env.clearApiCalls();

// Получить последний вызов для конкретного метода
const lastSend = env.lastApiCall("sendMessage");
expect(lastSend?.params.text).toBe("Добро пожаловать!");

@gramio/callback-data v0.1.0 — safeUnpack() и обратно-совместимые схемы

safeUnpack() — больше не падаем на устаревших кнопках

Кнопки инлайн-клавиатуры живут в истории чата днями и неделями. Если схема изменилась, unpack() падает на старых данных. Новый safeUnpack() никогда не бросает исключение — вместо этого возвращает дискриминированный union.

Важно: Если вы используете bot.callbackQuery(schema, handler), распаковка происходит автоматически — в ctx.queryData уже есть типизированные данные, safeUnpack не нужен. Метод полезен при обработке callback_query через bot.on() или когда нужно поддерживать несколько версий схемы в одном обработчике.

ts
const data = new CallbackData("action").number("id").string("type");

// Нужен только вне bot.callbackQuery() — например, в общем catch-all обработчике
bot.on("callback_query", (ctx) => {
    const result = data.safeUnpack(ctx.data ?? "");
    if (!result.success) {
        // кнопка из старой версии схемы
        return ctx.answerCallbackQuery({ text: "Эта кнопка устарела!" });
    }

    ctx.answerCallbackQuery({ text: `ID: ${result.data.id}` }); // типизировано
});

Тип SafeUnpackResult<T> экспортируется для использования в собственных type guard-ах.

Добавление optional-полей теперь обратно совместимо

Раньше любое добавление поля в схему — даже optional — ломало уже упакованные строки. Теперь, если данные упакованы без битмаски, все optional-поля считаются отсутствующими (значение undefined или дефолтное). Добавление optional-полей в конец схемы стало безопасной операцией:

ts
// v1 схема (строки уже есть в истории чата)
const v1 = new CallbackData("page").number("id");

// v2 схема — добавление optional-поля безопасно!
const v2 = new CallbackData("page")
    .number("id")
    .string("tab", { optional: true }); // новое поле

// Старые v1-строки нормально распаковываются в v2
const result = v2.safeUnpack(v1PackedString);
// result.success === true, result.data.tab === undefined

Опасные операции (добавление required-поля, смена порядка, переименование nameId) по-прежнему остаются breaking change-ами.


@gramio/schema-parser v1.0.1 — новый движок схем

Новый TypeScript-пакет для парсинга HTML-документации Telegram Bot API в структурированную типизированную схему. Питает @gramio/types — заменяя прежнюю зависимость от Rust-крейта tg-bot-api.

Схема поддерживает:

  • Семантические маркерыsemanticType: "formattable" для текстовых полей, "markup" для объектов клавиатур, "updateType" для типов контекста
  • Определение загрузки файлов — string-поля, принимающие файлы, становятся InputFile | string-юнионами
  • Enum валют — синтезируется из currencies.json Telegram с XTR (Telegram Stars)
  • Правильные const-значения — булевые литералы true/false вместо строк
  • Поддержка oneOf — union-типы с ссылками и описаниями

@gramio/types v9.4.2 — нативная схема, улучшенная семантика

Пакет переехал с tg-bot-api (Rust-крейт) на @gramio/schema-parser (TypeScript). Генерируемый вывод теперь содержит:

  • Более точные InputFile | string-юнионы для параметров загрузки файлов
  • Formattable-поля правильно типизированы через семантические маркеры
  • Enum Currencies со всеми поддерживаемыми валютами, включая XTR для Stars
  • Типы APIResponse, APIResponseOk, APIResponseError (раньше отсутствовали)

@gramio/composer — Filter-Only .on() и CompatibleEvents (в разработке)

Новые возможности приземлились в ветке main репозитория composer вместе с работой над системой фильтров gramio:

Filter-only .on() в Composer

Composer теперь поддерживает вызов .on(filter, handler) без имени события. Утилитарный тип CompatibleEvents<TEventMap, Narrowing> автоматически определяет, какие события содержат все ключи, до которых сужает предикат:

ts
// Type-narrowing предикат — Composer сам находит совместимые события
app.on(
    (ctx): ctx is { text: string } => typeof ctx.text === "string",
    (ctx) => {
        ctx.text; // string — сужено, обработчик срабатывает только на событиях с .text
    }
);

Patch-дженерик в use()

use<Patch extends object>(handler) теперь принимает type parameter для локального расширения контекста без изменения TOut для downstream middleware:

ts
app.use<{ requestId: string }>((ctx, next) => {
    ctx.requestId = crypto.randomUUID();
    return next();
});

gramio — новая система фильтров (в разработке)

В релиз ещё не попало, но на main уже приземлилось:

Перегрузки filter-only .on()

.on() теперь принимает просто предикат — без указания имени события. GramIO сам определяет совместимые события из type-narrowing предиката:

ts
// Type-narrowing предикат — сужает тип контекста в обработчике
bot.on((ctx): ctx is { text: string } => typeof ctx.text === "string", (ctx) => {
    ctx.text; // string (не string | undefined)
});

Новые фильтры по свойствам сообщения

Standalone-предикаты для сужения типов в обработчиках:

ts
import { filters } from "gramio";

bot.on("message", filters.reply, (ctx) => {
    ctx.replyToMessage; // гарантированно присутствует
});

bot.on("message", filters.entities, handler);  // есть entities
bot.on("message", filters.quote, handler);      // цитата
bot.on("message", filters.isBot, handler);      // отправитель — бот
bot.on("message", filters.isPremium, handler);  // есть Premium

forwardOrigin() и senderChat() как callable-перегрузки

Раньше были отдельными фильтрами, теперь — единая callable-перегрузка с опциональным сужением типа:

ts
// Сужает до сообщений, пересланных от пользователя
bot.on("message", filters.forwardOrigin("user"), (ctx) => {
    ctx.forwardOrigin; // MessageOriginUser — полностью типизировано
});

// Без аргумента — матчит любое пересланное сообщение
bot.on("message", filters.forwardOrigin(), handler);

Документация

Запущен TypeScript API Reference по адресу /api/

Полный TypeDoc-справочник доступен по адресу /api/. Охватывает все основные и плагиновые пакеты — gramio, @gramio/contexts, @gramio/types, @gramio/keyboards, @gramio/callback-data, @gramio/composer и дюжину плагинов. Сайдбар генерируется автоматически и выпрямляет пути внутренних модулей.

Справочник Telegram Bot API — 200+ методов по адресу /telegram/

Более 200 методов и типов Telegram Bot API теперь имеют отдельные страницы. На каждой — примеры использования с GramIO, таблицы параметров (с ограничениями, типами, значениями enum и пометками required/optional), таблицы ошибок и перекрёстные ссылки на связанные методы. Компонент ApiParam рендерит встроенные значки типов со ссылками на связанные типы Telegram. Кликабельные значки типов, курсивные литералы True/False, составные значки и аннотации docsLink для перекрёстных ссылок Files/Keyboards/Formattable добавлены в этом цикле (da3a4eb, 526b4db, b2167cc).

Страница Cheat Sheet

Быстрый справочник теперь доступен в навигации по адресу /cheat-sheet. Распространённые паттерны GramIO в одном месте — не нужно искать нужную сигнатуру по нескольким страницам руководств.

Документация JSX-плагина

Новая страница /plugins/official/jsx посвящена плагину @gramio/jsx — форматирование текста, построение inline- и reply-клавиатур через JSX, примеры использования на двух языках.

Расширена документация Split-плагина

Страница @gramio/split по адресу /plugins/official/split теперь включает полные шаги установки, детальный справочник API, объяснение механики разбиения entity, примеры кастомных лимитов и паттерны использования без привязки к конкретному фреймворку.

Интерактивный визуализатор middleware-пайплайна

В руководство по middleware добавлен интерактивный компонент UpdatePipelineVisualizer — выбирайте типы апдейтов, симулируйте debug-режим и наблюдайте, как контекст проходит по цепочке, в реальном времени.

Документация rate limits — BroadcastVisualizer и детальный разбор

Страница ограничений частоты запросов обновилась: добавлен компонент BroadcastVisualizer и детальный разбор механики HTTP 429, антипаттернов рассылки (наивный цикл for) и сравнение простого цикла vs @gramio/broadcast vs BullMQ — с диаграммами времени.

Руководство по production-архитектуре @gramio/composer

Справочник по composer теперь охватывает механику Named Composer deduplication, внутреннее устройство isolation group, паттерны scoped/global propagation и подводные камни dedup/shared-data. Включён пример production-архитектуры с withUser/router assembly (bcc0c8f).

Антипаттерны форматирования

В руководство по форматированию добавлены критические правила:

ts
// ❌ НЕПРАВИЛЬНО — никогда не используйте parse_mode вместе с @gramio/format
ctx.send({ text: format`${bold("привет")}`, parse_mode: "HTML" });

// ❌ НЕПРАВИЛЬНО — никогда не делайте .join() из массива Formattable (теряются offset)
[bold("а"), italic("б")].join(", ");

// ✅ ПРАВИЛЬНО — используйте хелпер join() из @gramio/format
import { join } from "gramio";
join([bold("а"), italic("б")], ", ");

Расширена документация плагина Session

Документация сессий теперь включает ленивую загрузку, $clear() для удаления сессии, функции кастомных ключей для разграничения по чату/пользователю и явную типизацию для обоих режимов — eager и lazy.

Кнопки «Скопировать / Скачать как Markdown» на каждой странице

Компонент CopyOrDownloadAsMarkdownButtons теперь зарегистрирован глобально — на каждой странице документации есть кнопка, чтобы одним кликом скопировать или скачать содержимое в виде чистого Markdown. Удобно для передачи документации в AI-ассистенты.