@vvlad1973/telegram-bot-client
v2.0.4
Published
This package provides Telegram Bot API client
Maintainers
Readme
@vvlad1973/telegram-bot-client
Мощная и типобезопасная библиотека для создания Telegram ботов на TypeScript с поддержкой нескольких токенов, системой событий и расширенной фильтрацией.
Основные возможности
- Полная типизация TypeScript - автоматически сгенерированные типы из OpenAPI спецификации Telegram Bot API 9.2.0
- Event-driven архитектура - гибкая система событий для обработки обновлений
- Middleware система - цепочка обработчиков для pre-processing обновлений
- Расширенная фильтрация - мощная система фильтров с поддержкой RegExp
- Поддержка нескольких токенов - управление несколькими ботами одновременно
- Long Polling Manager - встроенный менеджер с worker threads и автоматическими перезапусками
- Обертки (Wrappers) - удобные методы для работы с сообщениями и callback query
- Построители (Builders) - fluent API для создания клавиатур и команд
- Обработка ошибок - иерархия специализированных классов ошибок
- Интеграция с логированием - поддержка LoggerTree и SimpleLogger
- Native Fetch API - использует встроенный fetch без внешних зависимостей
Установка
npm install @vvlad1973/telegram-bot-clientБыстрый старт
Создание и инициализация бота
Библиотека поддерживает три режима работы с Telegram Bot API:
- Inactive - неактивный режим (только для отправки запросов)
- LongPolling - получение обновлений через long polling
- Webhook - получение обновлений через webhook
Жизненный цикл маршрута (route)
Каждый бот проходит следующие этапы:
- Создание - конфигурация маршрута (route) с токеном и режимом
- Инициализация - вызов
getMeдля получения информации о боте - Активация - установка режима работы (webhook/polling)
- Работа - обработка обновлений
- Деактивация - остановка получения обновлений
- Завершение - закрытие всех ресурсов
Режим 1: Inactive (только отправка)
Используйте этот режим, когда нужно только отправлять сообщения без получения обновлений:
import { TelegramBotClient, RouteMode } from '@vvlad1973/telegram-bot-client';
// Создание клиента
const bot = new TelegramBotClient({
routes: {
token: 'YOUR_BOT_TOKEN',
mode: RouteMode.Inactive
}
});
// Инициализация (получает информацию о боте через getMe)
await bot.init();
// Отправка сообщения без получения обновлений
await bot.sendMessage({
chat_id: 123456789,
text: 'Привет! Это одностороннее сообщение.'
});
// Завершение работы
await bot.shutdown();Режим 2: Long Polling (получение обновлений)
Long polling - рекомендуемый режим для разработки и небольших ботов:
import { TelegramBotClient, RouteMode } from '@vvlad1973/telegram-bot-client';
// Шаг 1: Создание клиента с конфигурацией
const bot = new TelegramBotClient({
routes: {
token: 'YOUR_BOT_TOKEN',
mode: RouteMode.LongPolling,
longPolling: {
timeout: 30, // Таймаут long polling запроса (сек)
limit: 100, // Максимальное количество обновлений
allowedUpdates: [ // Типы обновлений (опционально)
'message',
'callback_query'
]
}
}
});
// Шаг 2: Установка обработчиков событий (до инициализации)
bot.on('/start', (params, wrapper) => {
wrapper.replyMessage('Добро пожаловать! Я бот в режиме Long Polling.');
});
bot.on('message.text', (wrapper) => {
wrapper.replyMessage(`Эхо: ${wrapper.text}`);
});
bot.on('callback_query', (wrapper) => {
wrapper.answer('Кнопка нажата!');
});
// Шаг 3: Инициализация (вызывает getMe, сохраняет информацию о боте)
await bot.init();
// Шаг 4: Запуск long polling (начинает получать обновления)
await bot.startPolling();
console.log('Бот запущен в режиме Long Polling');
// Шаг 5: Graceful shutdown
process.on('SIGINT', async () => {
console.log('Остановка бота...');
await bot.stopPolling();
await bot.shutdown();
process.exit(0);
});Режим 3: Webhook (для продакшена)
Webhook режим рекомендуется для продакшен-окружения:
import { TelegramBotClient, RouteMode } from '@vvlad1973/telegram-bot-client';
import express from 'express';
// Шаг 1: Создание клиента с webhook конфигурацией
const bot = new TelegramBotClient({
routes: {
token: 'YOUR_BOT_TOKEN',
mode: RouteMode.Webhook,
webhook: {
path: '/webhook/bot', // Путь для webhook
secretToken: 'your-secret-123', // Секретный токен для защиты
maxConnections: 100, // Макс. одновременных соединений
allowedUpdates: [ // Типы обновлений
'message',
'callback_query'
]
}
},
webhookBaseUrl: 'https://your-domain.com' // Базовый URL (обязательно HTTPS!)
});
// Шаг 2: Установка обработчиков
bot.on('/start', (params, wrapper) => {
wrapper.replyMessage('Привет! Я бот в режиме Webhook.');
});
bot.on('message.text', (wrapper) => {
wrapper.replyMessage(`Получено: ${wrapper.text}`);
});
// Шаг 3: Инициализация
await bot.init();
// Шаг 4: Активация (устанавливает webhook через setWebhook)
await bot.activate();
// Шаг 5: Настройка Express для обработки webhook
const app = express();
app.use(express.json());
app.post('/webhook/bot', async (req, res) => {
// Проверка секретного токена (опционально)
const secretToken = req.headers['x-telegram-bot-api-secret-token'];
if (secretToken !== 'your-secret-123') {
return res.status(403).send('Forbidden');
}
// Обработка обновления
try {
await bot.processUpdate(req.body);
res.status(200).send('OK');
} catch (error) {
console.error('Error processing update:', error);
res.status(500).send('Error');
}
});
// Шаг 6: Запуск сервера
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Webhook сервер запущен на порту ${PORT}`);
});
// Graceful shutdown
process.on('SIGINT', async () => {
console.log('Остановка сервера...');
await bot.deactivate(); // Удаляет webhook через deleteWebhook
await bot.shutdown();
process.exit(0);
});Режим 4: Переключение между режимами
Вы можете создать бота в одном режиме и переключить его в другой:
import { TelegramBotClient, RouteMode } from '@vvlad1973/telegram-bot-client';
// Создание в неактивном режиме
const bot = new TelegramBotClient({
routes: {
token: 'YOUR_BOT_TOKEN',
mode: RouteMode.Inactive
}
});
// Инициализация
await bot.init();
// Переключение на Long Polling
await bot.activate(undefined, RouteMode.LongPolling);
await bot.startPolling();
// Работа в режиме Long Polling...
console.log('Работаем в Long Polling...');
await new Promise(resolve => setTimeout(resolve, 10000));
// Остановка polling и переключение на Webhook
await bot.stopPolling();
await bot.deactivate();
// Обновление конфигурации маршрута
bot.setRoute('default', {
token: 'YOUR_BOT_TOKEN',
mode: RouteMode.Webhook,
webhook: { path: '/webhook' }
});
// Активация в режиме Webhook
await bot.activate(undefined, RouteMode.Webhook);
// Теперь бот работает через webhookРежим 5: Автоматическая активация
Для упрощения можно использовать автоматическую активацию:
import { TelegramBotClient, RouteMode } from '@vvlad1973/telegram-bot-client';
const bot = new TelegramBotClient({
routes: {
token: 'YOUR_BOT_TOKEN',
mode: RouteMode.LongPolling,
autoActivate: true // Автоматическая активация при инициализации
}
});
// Обработчики
bot.on('message.text', (wrapper) => {
wrapper.replyMessage(`Эхо: ${wrapper.text}`);
});
// Только инициализация - активация произойдет автоматически
await bot.init();
// Для Long Polling все равно нужно запустить polling
await bot.startPolling();Работа с клавиатурами
import { InlineKeyboardBuilder } from '@vvlad1973/telegram-bot-client';
// Создание inline клавиатуры
const keyboard = new InlineKeyboardBuilder()
.appendRows(2)
.appendTextButton('Помощь', 'help', 0)
.appendTextButton('Настройки', 'settings', 0)
.appendUrlButton('Наш сайт', 'https://example.com', 1)
.build();
bot.on('/menu', (params, wrapper) => {
wrapper.replyMessage('Выберите действие:', {
reply_markup: keyboard
});
});
// Обработка callback
bot.on('callback_query', (wrapper) => {
if (wrapper.data === 'help') {
wrapper.editMessageText('Справка по боту...');
wrapper.answer();
}
});Фильтрация обновлений
// Фильтр по приватным чатам
bot.onFilter({
type: 'message.text',
chat: 'private'
}, (wrapper) => {
wrapper.replyMessage('Это приватный чат');
});
// Фильтр с RegExp
bot.onFilter({
type: 'message.text',
contents: /^\/admin/,
user: /^(111111|222222)$/ // Только определенные пользователи
}, (wrapper) => {
wrapper.replyMessage('Админ-команда');
});
// Фильтр по типу чата
bot.onFilter({
type: 'message.text',
chat_type: 'group'
}, (wrapper) => {
console.log('Сообщение из группы');
});Middleware
// Логирование всех обновлений
bot.use((update, next, client) => {
console.log('Update ID:', update.update_id);
next();
});
// Аутентификация
bot.use((update, next, client) => {
const userId = update.message?.from?.id;
if (isAuthorized(userId)) {
next(); // Продолжить обработку
}
// Если не вызвать next(), обработка остановится
});
// Обработка ошибок
bot.use(async (update, next, client) => {
try {
next();
} catch (error) {
console.error('Error processing update:', error);
}
});Документация
- Быстрый старт - подробное руководство для начинающих
- Migration Guide v2.0 - миграция с v1.x на v2.0
- Справочник классов - полное описание всех классов
- API Reference - TypeDoc документация (запустите
npm run docsдля генерации)
Архитектура
TelegramBotClient (клиентский слой)
↓ наследует
BaseTelegramApi (сгенерированные методы API)
↓ использует
TelegramTransport (транспортный слой)
↓ использует
TelegramHttpClient (HTTP-клиент)
↓ использует
Native Fetch APIОсновные компоненты
- TelegramBotClient - основной клиент с системой событий и фильтрацией
- TelegramTransport - транспортный слой для HTTP-запросов
- TelegramHttpClient - HTTP-клиент с автоматическими повторами
- TokensManager - управление несколькими токенами ботов
- LongPollingManager - менеджер long polling с worker threads
- MessageWrapper - обертка для удобной работы с сообщениями
- CallbackQueryWrapper - обертка для callback query
- InlineKeyboardBuilder - построитель inline-клавиатур
- ReplyKeyboardBuilder - построитель обычных клавиатур
Примеры использования
Несколько токенов
import { TelegramBotClient, RouteMode } from '@vvlad1973/telegram-bot-client';
// Создание клиента с несколькими маршрутами
const bot = new TelegramBotClient({
routes: [
{
token: 'TOKEN_1',
mode: RouteMode.LongPolling
},
{
token: 'TOKEN_2',
mode: RouteMode.Webhook,
webhook: { path: '/webhook/support' }
}
],
defaultRouteId: 'default',
webhookBaseUrl: 'https://example.com'
});
// Инициализация всех маршрутов
await bot.init();
// Активация конкретного маршрута
await bot.managers.lifecycle.activateRoute('default', RouteMode.LongPolling);
// Отправка от конкретного бота
await bot.sendMessage(
{ chat_id: 123, text: 'Hello from main bot!' },
{ routeId: 'default' }
);
await bot.sendMessage(
{ chat_id: 456, text: 'Hello from support!' },
{ routeId: 'route_1' }
);
// Запуск polling для всех маршрутов в режиме LongPolling
await bot.startPolling();Работа с менеджерами (Advanced)
TelegramBotClient использует три менеджера для управления маршрутами:
1. RouteConfigManager - управление конфигурацией
// Доступ к менеджеру
const configManager = bot.managers.config;
// Получение списка всех маршрутов
const routeIds = configManager.getRouteIds();
console.log('Доступные маршруты:', routeIds);
// Получение конфигурации маршрута
const config = configManager.getRoute('default');
console.log('Режим:', config.mode);
console.log('Токен:', config.token);
// Установка/обновление конфигурации маршрута
bot.setRoute('bot2', {
token: 'NEW_TOKEN',
mode: RouteMode.LongPolling,
longPolling: {
timeout: 30,
limit: 100
}
});
// Получение ID маршрута по умолчанию
const defaultRouteId = configManager.getDefaultRouteId();
// Проверка существования маршрута
if (configManager.hasRoute('bot2')) {
console.log('Маршрут bot2 существует');
}2. RouteLifecycleManager - управление жизненным циклом
// Доступ к менеджеру
const lifecycleManager = bot.managers.lifecycle;
// Инициализация конкретного маршрута (вызывает getMe)
await lifecycleManager.initRoute('bot1');
// Активация маршрута в указанном режиме
await lifecycleManager.activateRoute('bot1', RouteMode.LongPolling);
// Деактивация маршрута (удаляет webhook, останавливает polling)
await lifecycleManager.deactivateRoute('bot1');
// Получение информации о боте (после init)
const botInfo = lifecycleManager.getBotInfo('bot1');
console.log('Имя бота:', botInfo.username);
console.log('ID бота:', botInfo.id);
// Получение статуса маршрута
const status = lifecycleManager.getRouteStatus('bot1');
console.log('Статус:', status.state); // 'initialized', 'active', 'inactive'
console.log('Режим:', status.mode); // RouteMode
console.log('Последняя ошибка:', status.lastError);
// Переключение режима (деактивирует текущий и активирует новый)
await lifecycleManager.switchMode('bot1', RouteMode.Webhook);
// Горячая перезагрузка конфигурации (применяет новые настройки)
await lifecycleManager.hotReload('bot1');3. PollingIntegrationManager - управление polling
// Доступ к менеджеру
const pollingManager = bot.managers.polling;
// Запуск polling для конкретного маршрута
await pollingManager.startPolling();
// Остановка polling
await pollingManager.stopPolling();
// Проверка активности polling для маршрута
const isActive = pollingManager.isPollingActive('bot1');
console.log('Polling активен:', isActive);
// Получение текущего offset для маршрута
const offset = pollingManager.getOffset('bot1');
console.log('Текущий offset:', offset);
// Получение статистики polling для маршрута
const stats = pollingManager.getStats('bot1');
console.log('Всего получено обновлений:', stats.totalUpdates);
console.log('Последнее обновление:', stats.lastUpdate);
console.log('Статус worker:', stats.workerStatus);Полный пример с менеджерами
import { TelegramBotClient, RouteMode } from '@vvlad1973/telegram-bot-client';
// Создание клиента с несколькими маршрутами
const bot = new TelegramBotClient({
routes: new Map([
['main', {
token: 'MAIN_BOT_TOKEN',
mode: RouteMode.Inactive
}],
['support', {
token: 'SUPPORT_BOT_TOKEN',
mode: RouteMode.Inactive
}]
]),
defaultRouteId: 'main'
});
// 1. Инициализация обоих ботов
console.log('Инициализация ботов...');
await bot.managers.lifecycle.initRoute('main');
await bot.managers.lifecycle.initRoute('support');
// Проверка информации о ботах
const mainInfo = bot.managers.lifecycle.getBotInfo('main');
const supportInfo = bot.managers.lifecycle.getBotInfo('support');
console.log('Основной бот:', mainInfo.username);
console.log('Бот поддержки:', supportInfo.username);
// 2. Активация основного бота в Long Polling
console.log('Активация основного бота...');
await bot.managers.lifecycle.activateRoute('main', RouteMode.LongPolling);
await bot.startPolling();
// 3. Активация бота поддержки в Webhook
console.log('Активация бота поддержки...');
bot.setRoute('support', {
token: 'SUPPORT_BOT_TOKEN',
mode: RouteMode.Webhook,
webhook: { path: '/webhook/support' }
});
await bot.managers.lifecycle.activateRoute('support', RouteMode.Webhook);
// 4. Мониторинг состояния
setInterval(() => {
// Статус маршрутов
const mainStatus = bot.managers.lifecycle.getRouteStatus('main');
const supportStatus = bot.managers.lifecycle.getRouteStatus('support');
console.log('Основной бот - состояние:', mainStatus.state, 'режим:', mainStatus.mode);
console.log('Бот поддержки - состояние:', supportStatus.state, 'режим:', supportStatus.mode);
// Статистика polling для основного бота
if (bot.managers.polling.isPollingActive('main')) {
const stats = bot.managers.polling.getStats('main');
console.log('Получено обновлений:', stats.totalUpdates);
}
}, 30000);
// 5. Переключение режима основного бота (с Long Polling на Webhook)
setTimeout(async () => {
console.log('Переключение основного бота на Webhook...');
await bot.stopPolling();
bot.setRoute('main', {
token: 'MAIN_BOT_TOKEN',
mode: RouteMode.Webhook,
webhook: { path: '/webhook/main' }
});
await bot.managers.lifecycle.switchMode('main', RouteMode.Webhook);
}, 60000);
// Graceful shutdown
process.on('SIGINT', async () => {
console.log('Остановка всех ботов...');
// Деактивация всех маршрутов
for (const routeId of bot.managers.config.getRouteIds()) {
await bot.managers.lifecycle.deactivateRoute(routeId);
}
await bot.shutdown();
process.exit(0);
});Обработка ошибок
import { TelegramRateLimitError, TelegramBadRequestError } from '@vvlad1973/telegram-bot-client';
try {
await bot.sendMessage({
chat_id: chatId,
text: 'Hello!'
});
} catch (error) {
if (error instanceof TelegramRateLimitError) {
console.log(`Rate limited. Retry after ${error.retryAfter} seconds`);
// Автоматическая задержка
await new Promise(resolve => setTimeout(resolve, error.getRetryDelay()));
} else if (error instanceof TelegramBadRequestError) {
console.error('Bad request:', error.description);
}
}Логирование
import { SimpleLogger } from '@vvlad1973/simple-logger';
const logger = new SimpleLogger({
level: 'info',
prettyPrint: true
});
const transport = new TelegramTransport({
tokens: { default: token },
logger
});
const bot = new TelegramBotClient({
transport,
logger
});
// Логи автоматически выводятся на всех уровняхMessageWrapper методы
bot.on('message.text', async (wrapper) => {
// Ответ на сообщение
await wrapper.replyMessage('Hello!');
// Отправка в тот же чат
await wrapper.answerMessage('Message sent!');
// Редактирование
await wrapper.editText('Updated text');
// Удаление
await wrapper.delete();
// Пересылка
await wrapper.forward(otherChatId);
// Закрепление
await wrapper.pin();
// Chat action
await wrapper.answerChatAction('typing');
// Отправка фото
await wrapper.replyPhoto('file_id_or_url', {
caption: 'Photo caption'
});
});ReplyKeyboardBuilder
import { ReplyKeyboardBuilder } from '@vvlad1973/telegram-bot-client';
const keyboard = new ReplyKeyboardBuilder()
.appendRows(3)
.appendTextButton('Начать', 0)
.appendTextButton('Помощь', 0)
.appendRequestContactButton('Отправить контакт', 1)
.appendRequestLocationButton('Отправить локацию', 2)
.setResizeKeyboard(true)
.setOneTimeKeyboard(true)
.build();
await bot.sendMessage({
chat_id: chatId,
text: 'Выберите действие:',
reply_markup: keyboard
});Требования
- Node.js >= 18.0.0
- npm >= 9.0.0
- TypeScript >= 5.0 (для разработки)
Зависимости
Основные зависимости:
@vvlad1973/base-api- базовый API класс@vvlad1973/data-validator- валидация данных@vvlad1973/logger-tree- система логирования@vvlad1973/simple-logger- простой логгер@vvlad1973/utils- утилитыajv- JSON Schema валидация
Скрипты
# Сборка проекта
npm run build
# Тестирование
npm test
npm run test:coverage
# Линтинг
npm run lint
npm run lint:fix
npm run lint:md
npm run lint:md:fix
# Генерация документации
npm run docs
# Обновление API
npm run fetch-api # Скачать спецификацию Telegram Bot API
npm run generate-api # Сгенерировать типы и методы
npm run update-api # Скачать и сгенерироватьРазработка
Генерация API
Типы и методы автоматически генерируются из OpenAPI спецификации:
# Скачать актуальную спецификацию
npm run fetch-api
# Сгенерировать классы и типы
npm run generate-api
# Или всё вместе
npm run update-apiСтруктура проекта
telegram-bot-client/
├── src/
│ ├── api/ # Сгенерированные API классы
│ │ ├── BaseTelegramApi.generated.ts
│ │ └── types/ # Сгенерированные типы
│ ├── client/ # TelegramBotClient
│ ├── transport/ # Транспортный слой
│ ├── builders/ # Построители клавиатур
│ ├── wrappers/ # Обертки для Message и CallbackQuery
│ ├── agents/ # Long Polling Manager
│ ├── errors/ # Классы ошибок
│ ├── helpers/ # Вспомогательные функции
│ └── types/ # Общие типы
├── scripts/ # Скрипты генерации
├── docs/ # Документация
├── examples/ # Примеры
└── models/ # OpenAPI спецификацияПримеры
Все примеры использования представлены в разделах выше с подробными комментариями и пояснениями.
Changelog
См. CHANGELOG.md для полной истории изменений.
Лицензия
MIT with Commercial Use License
Автор
Vladislav Vnukovskiy [email protected]
Ссылки
Поддержка
Если у вас возникли проблемы или вопросы:
- Проверьте документацию
- Посмотрите примеры
- Создайте issue на GitHub
Благодарности
- Telegram Team за отличный Bot API
- Сообщество разработчиков Telegram ботов
