@elcrm/tb 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +286 -70
- package/dist/index.d.ts +16 -30
- package/dist/index.es.js +1 -180
- package/dist/index.umd.js +1 -203
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
## Особенности
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
7
|
+
- 🚀 Простое использование без создания экземпляров
|
|
8
|
+
- 🔧 Автоматическое использование токена из переменных окружения
|
|
9
|
+
- 📦 Типизированный API с полной поддержкой TypeScript
|
|
10
|
+
- 🎯 Поддержка webhook для получения обновлений
|
|
11
|
+
- 🔐 Валидация данных Telegram WebApp
|
|
12
|
+
- ⏱️ Автоматическое ограничение скорости - максимум 30 запросов в секунду
|
|
13
|
+
- 📋 Очередь запросов - все запросы автоматически ставятся в очередь и обрабатываются последовательно
|
|
14
|
+
- 🎨 Поддержка обработки команд, цепочек сообщений и фильтрации по пользователям
|
|
15
15
|
|
|
16
16
|
## Установка
|
|
17
17
|
|
|
@@ -60,14 +60,7 @@ tb.onMessage(async (update) => {
|
|
|
60
60
|
tb.sendMessage(123456789, "Привет!");
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
```typescript
|
|
66
|
-
import { createTelegramBot } from "@elcrm/tb";
|
|
67
|
-
|
|
68
|
-
const bot1 = createTelegramBot("TOKEN_1");
|
|
69
|
-
const bot2 = createTelegramBot("TOKEN_2");
|
|
70
|
-
```
|
|
63
|
+
**Важно:** Токен должен быть установлен в переменной окружения `TELEGRAM`. Если токен не установлен, при использовании методов будет выброшена ошибка.
|
|
71
64
|
|
|
72
65
|
---
|
|
73
66
|
|
|
@@ -79,7 +72,7 @@ const bot2 = createTelegramBot("TOKEN_2");
|
|
|
79
72
|
|
|
80
73
|
**Параметры:**
|
|
81
74
|
|
|
82
|
-
-
|
|
75
|
+
- `callback` - Функция-обработчик, которая вызывается при получении сообщения
|
|
83
76
|
|
|
84
77
|
**Пример:**
|
|
85
78
|
|
|
@@ -100,18 +93,25 @@ tb.onMessage(async (update) => {
|
|
|
100
93
|
|
|
101
94
|
**Параметры:**
|
|
102
95
|
|
|
103
|
-
-
|
|
104
|
-
-
|
|
96
|
+
- `name` (string) - Имя обработчика, должно совпадать с `data` кнопки. Если имя заканчивается на `%`, используется поиск по префиксу
|
|
97
|
+
- `callback` - Функция-обработчик, вызываемая при нажатии на кнопку
|
|
105
98
|
|
|
106
99
|
**Пример:**
|
|
107
100
|
|
|
108
101
|
```typescript
|
|
109
|
-
// Регистрация обработчика
|
|
102
|
+
// Регистрация обработчика для точного совпадения
|
|
110
103
|
tb.onCallbackQuery("button_click", async (data) => {
|
|
111
104
|
const chatId = data.from.id;
|
|
112
105
|
await tb.sendMessage(chatId, "Кнопка нажата!");
|
|
113
106
|
});
|
|
114
107
|
|
|
108
|
+
// Регистрация обработчика по префиксу (если data начинается с "action_")
|
|
109
|
+
tb.onCallbackQuery("action_%", async (data) => {
|
|
110
|
+
// Обработает все callback_data вида "action_1", "action_2", "action_delete" и т.д.
|
|
111
|
+
const chatId = data.from.id;
|
|
112
|
+
await tb.sendMessage(chatId, `Выполнено действие: ${data.data}`);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
115
|
// Отправка сообщения с inline-кнопкой
|
|
116
116
|
await tb.sendMessage(chatId, "Нажмите кнопку", {
|
|
117
117
|
inline_keyboard: [[{ text: "Нажми меня", callback_data: "button_click" }]],
|
|
@@ -126,9 +126,9 @@ await tb.sendMessage(chatId, "Нажмите кнопку", {
|
|
|
126
126
|
|
|
127
127
|
**Параметры:**
|
|
128
128
|
|
|
129
|
-
-
|
|
130
|
-
-
|
|
131
|
-
-
|
|
129
|
+
- `chat_id` (number) - ID чата или пользователя
|
|
130
|
+
- `text` (string) - Текст сообщения (поддерживает HTML)
|
|
131
|
+
- `reply_markup` (ReplyMarkup, опционально) - Клавиатура или inline-кнопки
|
|
132
132
|
|
|
133
133
|
**Пример:**
|
|
134
134
|
|
|
@@ -159,10 +159,10 @@ await tb.sendMessage(123456789, "Нажмите кнопку:", {
|
|
|
159
159
|
|
|
160
160
|
**Параметры:**
|
|
161
161
|
|
|
162
|
-
-
|
|
163
|
-
-
|
|
164
|
-
-
|
|
165
|
-
-
|
|
162
|
+
- `chat_id` (number) - ID чата или пользователя
|
|
163
|
+
- `photo` (string) - URL или file_id фотографии
|
|
164
|
+
- `caption` (string, опционально) - Подпись к фотографии
|
|
165
|
+
- `reply_markup` (ReplyMarkup, опционально) - Клавиатура или inline-кнопки
|
|
166
166
|
|
|
167
167
|
**Пример:**
|
|
168
168
|
|
|
@@ -173,7 +173,7 @@ await tb.sendPhoto(
|
|
|
173
173
|
"Описание фотографии",
|
|
174
174
|
{
|
|
175
175
|
inline_keyboard: [[{ text: "Подробнее", callback_data: "photo_info" }]],
|
|
176
|
-
}
|
|
176
|
+
},
|
|
177
177
|
);
|
|
178
178
|
```
|
|
179
179
|
|
|
@@ -185,10 +185,10 @@ await tb.sendPhoto(
|
|
|
185
185
|
|
|
186
186
|
**Параметры:**
|
|
187
187
|
|
|
188
|
-
-
|
|
189
|
-
-
|
|
190
|
-
-
|
|
191
|
-
-
|
|
188
|
+
- `chatId` (number) - ID чата
|
|
189
|
+
- `messageId` (number) - ID сообщения для редактирования
|
|
190
|
+
- `text` (string) - Новый текст сообщения
|
|
191
|
+
- `replyMarkup` (ReplyMarkup, опционально) - Новая клавиатура или inline-кнопки
|
|
192
192
|
|
|
193
193
|
**Пример:**
|
|
194
194
|
|
|
@@ -197,7 +197,7 @@ tb.onCallbackQuery("edit_message", async (data) => {
|
|
|
197
197
|
await tb.editMessageText(
|
|
198
198
|
data.message.chat.id,
|
|
199
199
|
data.message.message_id,
|
|
200
|
-
"Сообщение обновлено!"
|
|
200
|
+
"Сообщение обновлено!",
|
|
201
201
|
);
|
|
202
202
|
});
|
|
203
203
|
```
|
|
@@ -210,8 +210,8 @@ tb.onCallbackQuery("edit_message", async (data) => {
|
|
|
210
210
|
|
|
211
211
|
**Параметры:**
|
|
212
212
|
|
|
213
|
-
-
|
|
214
|
-
-
|
|
213
|
+
- `callbackId` (string) - ID callback query
|
|
214
|
+
- `text` (string, опционально) - Текст уведомления (если указан, показывается alert)
|
|
215
215
|
|
|
216
216
|
**Пример:**
|
|
217
217
|
|
|
@@ -229,7 +229,7 @@ tb.onCallbackQuery("show_alert", async (data) => {
|
|
|
229
229
|
|
|
230
230
|
**Параметры:**
|
|
231
231
|
|
|
232
|
-
-
|
|
232
|
+
- `url` (string) - HTTPS URL для получения обновлений
|
|
233
233
|
|
|
234
234
|
**Пример:**
|
|
235
235
|
|
|
@@ -246,7 +246,7 @@ console.log(result);
|
|
|
246
246
|
|
|
247
247
|
**Параметры:**
|
|
248
248
|
|
|
249
|
-
-
|
|
249
|
+
- `router` (string) - Путь для webhook (например, 'telegram-webhook')
|
|
250
250
|
|
|
251
251
|
**Возвращает:** Объект с методом для обработки запросов
|
|
252
252
|
|
|
@@ -281,8 +281,8 @@ Bun.serve({
|
|
|
281
281
|
|
|
282
282
|
**Примечание:**
|
|
283
283
|
|
|
284
|
-
-
|
|
285
|
-
-
|
|
284
|
+
- GET запросы автоматически устанавливают webhook на URL запроса
|
|
285
|
+
- POST запросы обрабатывают обновления от Telegram
|
|
286
286
|
|
|
287
287
|
---
|
|
288
288
|
|
|
@@ -292,7 +292,7 @@ Bun.serve({
|
|
|
292
292
|
|
|
293
293
|
**Параметры:**
|
|
294
294
|
|
|
295
|
-
-
|
|
295
|
+
- `body` (string | URLSearchParams) - Данные от Telegram WebApp
|
|
296
296
|
|
|
297
297
|
**Возвращает:** `true` если данные валидны, иначе `false`
|
|
298
298
|
|
|
@@ -316,7 +316,7 @@ if (isValid) {
|
|
|
316
316
|
|
|
317
317
|
**Параметры:**
|
|
318
318
|
|
|
319
|
-
-
|
|
319
|
+
- `update` (TelegramUpdate) - Объект обновления от Telegram API
|
|
320
320
|
|
|
321
321
|
**Пример:**
|
|
322
322
|
|
|
@@ -328,6 +328,210 @@ await tb.handleUpdate(update);
|
|
|
328
328
|
|
|
329
329
|
---
|
|
330
330
|
|
|
331
|
+
#### `command_message(name: string, callback: (data: any) => void | Promise<void>): void`
|
|
332
|
+
|
|
333
|
+
Регистрирует обработчик для команд (сообщений с типом `bot_command`).
|
|
334
|
+
|
|
335
|
+
**Параметры:**
|
|
336
|
+
|
|
337
|
+
- `name` (string) - Имя команды (например, '/start', '/help')
|
|
338
|
+
- `callback` - Функция-обработчик, вызываемая при получении команды
|
|
339
|
+
|
|
340
|
+
**Пример:**
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
tb.command_message("/start", async (message) => {
|
|
344
|
+
const chatId = message.from.id;
|
|
345
|
+
await tb.sendMessage(chatId, "Добро пожаловать!");
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
tb.command_message("/help", async (message) => {
|
|
349
|
+
const chatId = message.from.id;
|
|
350
|
+
await tb.sendMessage(chatId, "Это справочное сообщение");
|
|
351
|
+
});
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
#### `getChatMember(userId: number, chatId: number | string): Promise<any>`
|
|
357
|
+
|
|
358
|
+
Получает информацию о члене чата.
|
|
359
|
+
|
|
360
|
+
**Параметры:**
|
|
361
|
+
|
|
362
|
+
- `userId` (number) - ID пользователя
|
|
363
|
+
- `chatId` (number | string) - ID чата (может быть числом или строкой)
|
|
364
|
+
|
|
365
|
+
**Возвращает:** Объект с информацией о статусе пользователя:
|
|
366
|
+
|
|
367
|
+
- `status` - Статус пользователя ('creator', 'administrator', 'member', 'restricted', 'left', 'kicked')
|
|
368
|
+
- `isAdmin` - `true` если пользователь является создателем или администратором
|
|
369
|
+
- `isMember` - `true` если пользователь является членом чата
|
|
370
|
+
- `raw` - Полный объект данных о пользователе от Telegram API
|
|
371
|
+
|
|
372
|
+
**Пример:**
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
const memberInfo = await tb.getChatMember(userId, chatId);
|
|
376
|
+
if (memberInfo.isAdmin) {
|
|
377
|
+
await tb.sendMessage(chatId, "Вы администратор!");
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
#### `editMessageCaption(chatId: number, messageId: number, caption: string, replyMarkup?: ReplyMarkup): Promise<any>`
|
|
384
|
+
|
|
385
|
+
Редактирует подпись существующего сообщения с медиа.
|
|
386
|
+
|
|
387
|
+
**Параметры:**
|
|
388
|
+
|
|
389
|
+
- `chatId` (number) - ID чата
|
|
390
|
+
- `messageId` (number) - ID сообщения для редактирования
|
|
391
|
+
- `caption` (string) - Новая подпись сообщения
|
|
392
|
+
- `replyMarkup` (ReplyMarkup, опционально) - Новая клавиатура или inline-кнопки
|
|
393
|
+
|
|
394
|
+
**Пример:**
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
tb.onCallbackQuery("edit_caption", async (data) => {
|
|
398
|
+
await tb.editMessageCaption(
|
|
399
|
+
data.message.chat.id,
|
|
400
|
+
data.message.message_id,
|
|
401
|
+
"Новая подпись к фотографии",
|
|
402
|
+
);
|
|
403
|
+
});
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
#### `editMessageMedia(chatId: number, messageId: number, media: any, replyMarkup?: ReplyMarkup): Promise<any>`
|
|
409
|
+
|
|
410
|
+
Редактирует медиа существующего сообщения.
|
|
411
|
+
|
|
412
|
+
**Параметры:**
|
|
413
|
+
|
|
414
|
+
- `chatId` (number) - ID чата
|
|
415
|
+
- `messageId` (number) - ID сообщения для редактирования
|
|
416
|
+
- `media` (any) - Новое медиа (объект с типом и медиа, например `{ type: 'photo', media: 'https://...' }`)
|
|
417
|
+
- `replyMarkup` (ReplyMarkup, опционально) - Новая клавиатура или inline-кнопки
|
|
418
|
+
|
|
419
|
+
**Пример:**
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
tb.onCallbackQuery("change_photo", async (data) => {
|
|
423
|
+
await tb.editMessageMedia(data.message.chat.id, data.message.message_id, {
|
|
424
|
+
type: "photo",
|
|
425
|
+
media: "https://example.com/new-photo.jpg",
|
|
426
|
+
});
|
|
427
|
+
});
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
#### `getFile(file_id: string, savePath?: string): Promise<any>`
|
|
433
|
+
|
|
434
|
+
Получает информацию о файле по file_id. Если указан `savePath`, файл автоматически скачивается и сохраняется.
|
|
435
|
+
|
|
436
|
+
**Параметры:**
|
|
437
|
+
|
|
438
|
+
- `file_id` (string) - ID файла в Telegram
|
|
439
|
+
- `savePath` (string, опционально) - Путь для сохранения файла
|
|
440
|
+
|
|
441
|
+
**Возвращает:** Информацию о файле от Telegram API или `true`/`false` если указан `savePath`
|
|
442
|
+
|
|
443
|
+
**Пример:**
|
|
444
|
+
|
|
445
|
+
```typescript
|
|
446
|
+
// Получение информации о файле
|
|
447
|
+
const fileInfo = await tb.getFile(fileId);
|
|
448
|
+
console.log(fileInfo.result.file_path);
|
|
449
|
+
|
|
450
|
+
// Получение и сохранение файла
|
|
451
|
+
const saved = await tb.getFile(fileId, "./downloads/file.jpg");
|
|
452
|
+
if (saved) {
|
|
453
|
+
console.log("Файл успешно сохранен");
|
|
454
|
+
}
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
---
|
|
458
|
+
|
|
459
|
+
#### `downloadFile(file_path: string, savePath: string): Promise<boolean>`
|
|
460
|
+
|
|
461
|
+
Скачивает файл с Telegram серверов и сохраняет на локальный сервер.
|
|
462
|
+
|
|
463
|
+
**Параметры:**
|
|
464
|
+
|
|
465
|
+
- `file_path` (string) - Путь к файлу на серверах Telegram (получается из `getFile`)
|
|
466
|
+
- `savePath` (string) - Путь для сохранения файла на локальном сервере
|
|
467
|
+
|
|
468
|
+
**Возвращает:** `true` если файл успешно скачан, иначе `false`
|
|
469
|
+
|
|
470
|
+
**Пример:**
|
|
471
|
+
|
|
472
|
+
```typescript
|
|
473
|
+
const fileInfo = await tb.getFile(fileId);
|
|
474
|
+
if (fileInfo.ok) {
|
|
475
|
+
const downloaded = await tb.downloadFile(
|
|
476
|
+
fileInfo.result.file_path,
|
|
477
|
+
"./downloads/file.jpg",
|
|
478
|
+
);
|
|
479
|
+
if (downloaded) {
|
|
480
|
+
console.log("Файл скачан");
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
---
|
|
486
|
+
|
|
487
|
+
#### `from_id(from_id: number, callback: (data: any) => void | Promise<void>): void`
|
|
488
|
+
|
|
489
|
+
Регистрирует обработчик сообщений от конкретного пользователя.
|
|
490
|
+
|
|
491
|
+
**Параметры:**
|
|
492
|
+
|
|
493
|
+
- `from_id` (number) - ID пользователя
|
|
494
|
+
- `callback` - Функция-обработчик, вызываемая при получении сообщения от указанного пользователя
|
|
495
|
+
|
|
496
|
+
**Пример:**
|
|
497
|
+
|
|
498
|
+
```typescript
|
|
499
|
+
// Обработка сообщений только от конкретного пользователя
|
|
500
|
+
tb.from_id(123456789, async (message) => {
|
|
501
|
+
const chatId = message.chat.id;
|
|
502
|
+
await tb.sendMessage(chatId, "Ваше сообщение получено!");
|
|
503
|
+
});
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
---
|
|
507
|
+
|
|
508
|
+
#### `chaining(chaining: string[], callback: (data: any) => void | Promise<void>): void`
|
|
509
|
+
|
|
510
|
+
Регистрирует обработчик цепочки сообщений по комбинации ключей сообщения.
|
|
511
|
+
|
|
512
|
+
**Параметры:**
|
|
513
|
+
|
|
514
|
+
- `chaining` (string[]) - Массив ключей сообщения для отслеживания (например, `['photo', 'caption']`)
|
|
515
|
+
- `callback` - Функция-обработчик, вызываемая при получении сообщения с указанными ключами
|
|
516
|
+
|
|
517
|
+
**Пример:**
|
|
518
|
+
|
|
519
|
+
```typescript
|
|
520
|
+
// Обработка сообщений с фотографией и подписью
|
|
521
|
+
tb.chaining(["photo", "caption"], async (message) => {
|
|
522
|
+
const chatId = message.chat.id;
|
|
523
|
+
await tb.sendMessage(chatId, "Получена фотография с подписью!");
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
// Обработка сообщений только с фотографией
|
|
527
|
+
tb.chaining(["photo"], async (message) => {
|
|
528
|
+
const chatId = message.chat.id;
|
|
529
|
+
await tb.sendMessage(chatId, "Получена фотография без подписи!");
|
|
530
|
+
});
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
---
|
|
534
|
+
|
|
331
535
|
## Типы
|
|
332
536
|
|
|
333
537
|
### `TelegramUpdate`
|
|
@@ -397,24 +601,25 @@ import { tb } from "@elcrm/tb";
|
|
|
397
601
|
|
|
398
602
|
// Использование напрямую (токен берется из process.env.TELEGRAM)
|
|
399
603
|
|
|
400
|
-
// Обработчик
|
|
604
|
+
// Обработчик команд
|
|
605
|
+
tb.command_message("/start", async (message) => {
|
|
606
|
+
const chatId = message.from.id;
|
|
607
|
+
await tb.sendMessage(chatId, "Добро пожаловать!", {
|
|
608
|
+
inline_keyboard: [[{ text: "Начать", callback_data: "start_action" }]],
|
|
609
|
+
});
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
tb.command_message("/help", async (message) => {
|
|
613
|
+
const chatId = message.from.id;
|
|
614
|
+
await tb.sendMessage(chatId, "Это справочное сообщение");
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
// Обработчик всех сообщений
|
|
401
618
|
tb.onMessage(async (update) => {
|
|
402
619
|
if (!update.message?.text || !update.message.from) return;
|
|
403
|
-
|
|
404
620
|
const chatId = update.message.from.id;
|
|
405
621
|
const text = update.message.text;
|
|
406
|
-
|
|
407
|
-
if (text === "/start") {
|
|
408
|
-
await tb.sendMessage(chatId, "Добро пожаловать!", {
|
|
409
|
-
inline_keyboard: [
|
|
410
|
-
[{ text: "Начать", callback_data: "start_action" }],
|
|
411
|
-
],
|
|
412
|
-
});
|
|
413
|
-
} else if (text === "/help") {
|
|
414
|
-
await tb.sendMessage(chatId, "Это справочное сообщение");
|
|
415
|
-
} else {
|
|
416
|
-
await tb.sendMessage(chatId, `Вы написали: ${text}`);
|
|
417
|
-
}
|
|
622
|
+
await tb.sendMessage(chatId, `Вы написали: ${text}`);
|
|
418
623
|
});
|
|
419
624
|
|
|
420
625
|
// Обработчик callback query
|
|
@@ -424,6 +629,18 @@ tb.onCallbackQuery("start_action", async (data) => {
|
|
|
424
629
|
await tb.answerCallbackQuery(data.id, "Готово!");
|
|
425
630
|
});
|
|
426
631
|
|
|
632
|
+
// Обработчик callback query по префиксу
|
|
633
|
+
tb.onCallbackQuery("action_%", async (data) => {
|
|
634
|
+
const chatId = data.from.id;
|
|
635
|
+
await tb.sendMessage(chatId, `Выполнено действие: ${data.data}`);
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
// Обработчик сообщений с фотографией и подписью
|
|
639
|
+
tb.chaining(["photo", "caption"], async (message) => {
|
|
640
|
+
const chatId = message.chat.id;
|
|
641
|
+
await tb.sendMessage(chatId, "Получена фотография с подписью!");
|
|
642
|
+
});
|
|
643
|
+
|
|
427
644
|
// Создание webhook роутера
|
|
428
645
|
const routes = tb.webhook("telegram-webhook");
|
|
429
646
|
|
|
@@ -447,22 +664,21 @@ Bun.serve({
|
|
|
447
664
|
|
|
448
665
|
Библиотека экспортирует следующие элементы:
|
|
449
666
|
|
|
450
|
-
-
|
|
451
|
-
-
|
|
452
|
-
-
|
|
453
|
-
-
|
|
454
|
-
-
|
|
455
|
-
-
|
|
456
|
-
- `TelegramWebAppData` - Интерфейс для данных Telegram WebApp
|
|
667
|
+
- `tb` - Основной объект для работы с Telegram Bot API
|
|
668
|
+
- `TelegramBot` - Интерфейс объекта бота
|
|
669
|
+
- `TelegramUpdate` - Интерфейс для обновлений от Telegram
|
|
670
|
+
- `CallbackQueryData` - Интерфейс для данных callback query
|
|
671
|
+
- `ReplyMarkup` - Интерфейс для клавиатур и кнопок
|
|
672
|
+
- `TelegramWebAppData` - Интерфейс для данных Telegram WebApp
|
|
457
673
|
|
|
458
674
|
**Пример импорта типов:**
|
|
459
675
|
|
|
460
676
|
```typescript
|
|
461
677
|
import {
|
|
462
678
|
tb,
|
|
463
|
-
createTelegramBot,
|
|
464
679
|
type TelegramUpdate,
|
|
465
680
|
type CallbackQueryData,
|
|
681
|
+
type TelegramBot,
|
|
466
682
|
} from "@elcrm/tb";
|
|
467
683
|
```
|
|
468
684
|
|
|
@@ -470,8 +686,8 @@ import {
|
|
|
470
686
|
|
|
471
687
|
## Требования
|
|
472
688
|
|
|
473
|
-
-
|
|
474
|
-
-
|
|
689
|
+
- Bun runtime (для работы с `Bun.CryptoHasher` в методе `validatingData`)
|
|
690
|
+
- Node.js/Bun для выполнения
|
|
475
691
|
|
|
476
692
|
## Переменные окружения
|
|
477
693
|
|
|
@@ -487,7 +703,7 @@ export TELEGRAM="123456789:ABCdefGHIjklMNOpqrsTUVwxyz"
|
|
|
487
703
|
TELEGRAM=123456789:ABCdefGHIjklMNOpqrsTUVwxyz
|
|
488
704
|
```
|
|
489
705
|
|
|
490
|
-
**Важно:** Если переменная `TELEGRAM` не установлена, при
|
|
706
|
+
**Важно:** Если переменная `TELEGRAM` не установлена, при использовании методов `tb` будет выброшена ошибка `"TELEGRAM token not found"`.
|
|
491
707
|
|
|
492
708
|
---
|
|
493
709
|
|
|
@@ -497,10 +713,10 @@ TELEGRAM=123456789:ABCdefGHIjklMNOpqrsTUVwxyz
|
|
|
497
713
|
|
|
498
714
|
### Как это работает:
|
|
499
715
|
|
|
500
|
-
-
|
|
501
|
-
-
|
|
502
|
-
-
|
|
503
|
-
-
|
|
716
|
+
- Все запросы к API (кроме `setWebhook`) попадают в очередь перед выполнением
|
|
717
|
+
- Запросы обрабатываются последовательно с минимальной задержкой ~33.33 мс между ними
|
|
718
|
+
- Если запрос выполняется дольше задержки, дополнительная задержка не добавляется
|
|
719
|
+
- Ограничение применяется автоматически ко всем методам: `sendMessage`, `sendPhoto`, `editMessageText`, `answerCallbackQuery`
|
|
504
720
|
|
|
505
721
|
**Пример:**
|
|
506
722
|
|
package/dist/index.d.ts
CHANGED
|
@@ -40,35 +40,21 @@ export interface TelegramBot {
|
|
|
40
40
|
validatingData: (body: string | URLSearchParams) => boolean;
|
|
41
41
|
setWebhook: (url: string) => Promise<any>;
|
|
42
42
|
handleUpdate: (update: TelegramUpdate) => Promise<void>;
|
|
43
|
-
webhook: (
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
onCallbackQuery: (
|
|
47
|
-
name: string,
|
|
48
|
-
callback: (data: CallbackQueryData) => void | Promise<void>
|
|
49
|
-
) => void;
|
|
50
|
-
onMessage: (
|
|
51
|
-
callback: (update: TelegramUpdate) => void | Promise<void>
|
|
52
|
-
) => void;
|
|
43
|
+
webhook: (router: string) => Record<string, (req: Request) => Promise<Response>>;
|
|
44
|
+
onCallbackQuery: (name: string, callback: (data: CallbackQueryData) => void | Promise<void>) => void;
|
|
45
|
+
onMessage: (callback: (update: TelegramUpdate) => void | Promise<void>) => void;
|
|
53
46
|
answerCallbackQuery: (callbackId: string, text?: string) => Promise<any>;
|
|
54
|
-
editMessageText: (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
) => Promise<any>;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
) => Promise<
|
|
65
|
-
sendPhoto: (
|
|
66
|
-
chat_id: number,
|
|
67
|
-
photo: string,
|
|
68
|
-
caption?: string,
|
|
69
|
-
reply_markup?: ReplyMarkup
|
|
70
|
-
) => Promise<any>;
|
|
47
|
+
editMessageText: (chatId: number, messageId: number, text: string, replyMarkup?: ReplyMarkup) => Promise<any>;
|
|
48
|
+
sendMessage: (chat_id: number, text: string, reply_markup?: ReplyMarkup) => Promise<any>;
|
|
49
|
+
sendPhoto: (chat_id: number, photo: string, caption?: string, reply_markup?: ReplyMarkup) => Promise<any>;
|
|
50
|
+
command_message: (name: string, callback: (data: any) => void | Promise<void>) => void;
|
|
51
|
+
getChatMember: (userId: number, chatId: number | string) => Promise<any>;
|
|
52
|
+
editMessageCaption: (chatId: number, messageId: number, caption: string, replyMarkup?: ReplyMarkup) => Promise<any>;
|
|
53
|
+
editMessageMedia: (chatId: number, messageId: number, media: any, replyMarkup?: ReplyMarkup) => Promise<any>;
|
|
54
|
+
getFile: (file_id: string, savePath?: string) => Promise<any>;
|
|
55
|
+
downloadFile: (file_path: string, savePath: string) => Promise<boolean>;
|
|
56
|
+
from_id: (from_id: number, callback: (data: any) => void | Promise<void>) => void;
|
|
57
|
+
chaining: (chaining: string[], callback: (data: any) => void | Promise<void>) => void;
|
|
71
58
|
}
|
|
72
|
-
declare
|
|
73
|
-
export
|
|
74
|
-
export { createTelegramBot };
|
|
59
|
+
declare const tb: TelegramBot;
|
|
60
|
+
export { tb };
|
package/dist/index.es.js
CHANGED
|
@@ -1,180 +1 @@
|
|
|
1
|
-
|
|
2
|
-
if (!e) throw new Error("Telegram bot token is required");
|
|
3
|
-
const a = e,
|
|
4
|
-
t = { callback_query: {} },
|
|
5
|
-
s = [];
|
|
6
|
-
let n = !1;
|
|
7
|
-
const r = 1e3 / 30,
|
|
8
|
-
o = async (e, t) =>
|
|
9
|
-
new Promise((o, c) => {
|
|
10
|
-
s.push({ method: e, body: t, resolve: o, reject: c }),
|
|
11
|
-
(async () => {
|
|
12
|
-
if (!n && 0 !== s.length) {
|
|
13
|
-
for (n = !0; s.length > 0; ) {
|
|
14
|
-
const t = s.shift();
|
|
15
|
-
if (!t) break;
|
|
16
|
-
try {
|
|
17
|
-
const e = Date.now(),
|
|
18
|
-
s = await fetch(
|
|
19
|
-
`https://api.telegram.org/bot${a}/${t.method}`,
|
|
20
|
-
{
|
|
21
|
-
method: "POST",
|
|
22
|
-
headers: {
|
|
23
|
-
"Content-Type":
|
|
24
|
-
"application/json",
|
|
25
|
-
},
|
|
26
|
-
body: JSON.stringify(t.body),
|
|
27
|
-
}
|
|
28
|
-
),
|
|
29
|
-
n = await s.json();
|
|
30
|
-
t.resolve(n);
|
|
31
|
-
const o = Date.now() - e,
|
|
32
|
-
c = Math.max(0, r - o);
|
|
33
|
-
c > 0 &&
|
|
34
|
-
(await new Promise((e) =>
|
|
35
|
-
setTimeout(e, c)
|
|
36
|
-
));
|
|
37
|
-
} catch (e) {
|
|
38
|
-
console.error(
|
|
39
|
-
`Error calling Telegram API (${t.method}):`,
|
|
40
|
-
e
|
|
41
|
-
),
|
|
42
|
-
t.reject(e);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
n = !1;
|
|
46
|
-
}
|
|
47
|
-
})();
|
|
48
|
-
}),
|
|
49
|
-
c = {
|
|
50
|
-
setWebhook: async (e) => {
|
|
51
|
-
const t = e.replace("http://", "https://"),
|
|
52
|
-
s = await fetch(
|
|
53
|
-
`https://api.telegram.org/bot${a}/setWebhook?url=${t}`
|
|
54
|
-
);
|
|
55
|
-
return await s.json();
|
|
56
|
-
},
|
|
57
|
-
webhook: (e) => ({
|
|
58
|
-
[`/${e}`]: async (e) => {
|
|
59
|
-
try {
|
|
60
|
-
const a = e.method,
|
|
61
|
-
t = new URL(e.url);
|
|
62
|
-
if ("GET" === a) {
|
|
63
|
-
const e = await c.setWebhook(t.href);
|
|
64
|
-
return new Response(JSON.stringify(e), {
|
|
65
|
-
headers: { "Content-Type": "application/json" },
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
if ("POST" === a) {
|
|
69
|
-
const a = await e.json();
|
|
70
|
-
return await c.handleUpdate(a), new Response("OK");
|
|
71
|
-
}
|
|
72
|
-
return new Response("Method not allowed", {
|
|
73
|
-
status: 405,
|
|
74
|
-
});
|
|
75
|
-
} catch (a) {
|
|
76
|
-
return (
|
|
77
|
-
console.error("Error handling webhook:", a),
|
|
78
|
-
new Response("Internal Server Error", {
|
|
79
|
-
status: 500,
|
|
80
|
-
})
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
}),
|
|
85
|
-
handleUpdate: async (e) => {
|
|
86
|
-
if (
|
|
87
|
-
(e.message && t.message && (await t.message(e)),
|
|
88
|
-
e.callback_query)
|
|
89
|
-
) {
|
|
90
|
-
const {
|
|
91
|
-
id: a,
|
|
92
|
-
data: s,
|
|
93
|
-
from: n,
|
|
94
|
-
message: r,
|
|
95
|
-
} = e.callback_query;
|
|
96
|
-
await c.answerCallbackQuery(a),
|
|
97
|
-
t.callback_query[s] &&
|
|
98
|
-
(await t.callback_query[s]({
|
|
99
|
-
id: a,
|
|
100
|
-
data: s,
|
|
101
|
-
from: n,
|
|
102
|
-
message: r,
|
|
103
|
-
}));
|
|
104
|
-
}
|
|
105
|
-
},
|
|
106
|
-
sendMessage: async (e, a, t) => {
|
|
107
|
-
const s = { chat_id: e, text: a, parse_mode: "HTML" };
|
|
108
|
-
return t && (s.reply_markup = t), o("sendMessage", s);
|
|
109
|
-
},
|
|
110
|
-
sendPhoto: async (e, a, t, s) => {
|
|
111
|
-
const n = { chat_id: e, photo: a };
|
|
112
|
-
return (
|
|
113
|
-
t && (n.caption = t),
|
|
114
|
-
s && (n.reply_markup = s),
|
|
115
|
-
o("sendPhoto", n)
|
|
116
|
-
);
|
|
117
|
-
},
|
|
118
|
-
answerCallbackQuery: async (e, a) => {
|
|
119
|
-
const t = { callback_query_id: e };
|
|
120
|
-
return (
|
|
121
|
-
a && ((t.text = a), (t.show_alert = !0)),
|
|
122
|
-
o("answerCallbackQuery", t)
|
|
123
|
-
);
|
|
124
|
-
},
|
|
125
|
-
validatingData: (e) => {
|
|
126
|
-
const t = "string" == typeof e ? new URLSearchParams(e) : e,
|
|
127
|
-
s = new URLSearchParams(t);
|
|
128
|
-
s.sort();
|
|
129
|
-
const n = s.get("hash");
|
|
130
|
-
s.delete("hash");
|
|
131
|
-
const r = [...s.entries()]
|
|
132
|
-
.map(([e, a]) => `${e}=${a}`)
|
|
133
|
-
.join("\n"),
|
|
134
|
-
o = new Bun.CryptoHasher("sha256", "WebAppData")
|
|
135
|
-
.update(a)
|
|
136
|
-
.digest();
|
|
137
|
-
return (
|
|
138
|
-
new Bun.CryptoHasher("sha256", o)
|
|
139
|
-
.update(r)
|
|
140
|
-
.digest("hex") === n
|
|
141
|
-
);
|
|
142
|
-
},
|
|
143
|
-
editMessageText: async (e, a, t, s) => {
|
|
144
|
-
const n = { chat_id: e, message_id: a, text: t };
|
|
145
|
-
return s && (n.reply_markup = s), o("editMessageText", n);
|
|
146
|
-
},
|
|
147
|
-
onCallbackQuery: (e, a) => {
|
|
148
|
-
t.callback_query[e] = a;
|
|
149
|
-
},
|
|
150
|
-
onMessage: (e) => {
|
|
151
|
-
t.message = e;
|
|
152
|
-
},
|
|
153
|
-
};
|
|
154
|
-
return c;
|
|
155
|
-
}
|
|
156
|
-
let a = null;
|
|
157
|
-
function t() {
|
|
158
|
-
if (!a) {
|
|
159
|
-
const t = process.env.TELEGRAM;
|
|
160
|
-
if (!t)
|
|
161
|
-
throw new Error(
|
|
162
|
-
"TELEGRAM environment variable is required. Set TELEGRAM environment variable or use createTelegramBot(token) function"
|
|
163
|
-
);
|
|
164
|
-
a = e(t);
|
|
165
|
-
}
|
|
166
|
-
return a;
|
|
167
|
-
}
|
|
168
|
-
const s = {
|
|
169
|
-
validatingData: (...e) => t().validatingData(...e),
|
|
170
|
-
setWebhook: (...e) => t().setWebhook(...e),
|
|
171
|
-
handleUpdate: (...e) => t().handleUpdate(...e),
|
|
172
|
-
webhook: (...e) => t().webhook(...e),
|
|
173
|
-
onCallbackQuery: (...e) => t().onCallbackQuery(...e),
|
|
174
|
-
onMessage: (...e) => t().onMessage(...e),
|
|
175
|
-
answerCallbackQuery: (...e) => t().answerCallbackQuery(...e),
|
|
176
|
-
editMessageText: (...e) => t().editMessageText(...e),
|
|
177
|
-
sendMessage: (...e) => t().sendMessage(...e),
|
|
178
|
-
sendPhoto: (...e) => t().sendPhoto(...e),
|
|
179
|
-
};
|
|
180
|
-
export { e as createTelegramBot, s as tb };
|
|
1
|
+
const e={callback_query:{},callback_query_search:{},command_message:{},from_id:{},chaining:{},message:void 0},t=[];let a=!1;const r=1e3/30,o=async(e,o)=>new Promise((s,n)=>{t.push({method:e,body:o,resolve:s,reject:n}),(async()=>{if(!a&&0!==t.length){for(a=!0;t.length>0;){const a=t.shift();if(!a)break;try{const e=Date.now();if(!process.env.TELEGRAM)throw new Error("TELEGRAM token not found");const t=await fetch(`https://api.telegram.org/bot${process.env.TELEGRAM}/${a.method}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a.body)}),o=await t.json();a.resolve(o);const s=Date.now()-e,n=Math.max(0,r-s);n>0&&await new Promise(e=>setTimeout(e,n))}catch(e){console.error(`Error calling Telegram API (${a.method}):`,e),a.reject(e)}}a=!1}})()}),s={setWebhook:async e=>{if(!process.env.TELEGRAM)throw new Error("TELEGRAM token not found");const t=await fetch(`https://api.telegram.org/bot${process.env.TELEGRAM}/setWebhook?url=${e.replace("http://","https://")}`);return await t.json()},webhook:e=>({[`/${e}`]:async e=>{try{const t=e.method,a=new URL(e.url);if("GET"===t){const e=await s.setWebhook(a.href);return new Response(JSON.stringify(e),{headers:{"Content-Type":"application/json"}})}if("POST"===t){const t=await e.json();return await s.handleUpdate(t),new Response("OK")}return new Response("Method not allowed",{status:405})}catch(t){return console.error("Error handling webhook:",t),new Response("Internal Server Error",{status:500})}}}),handleUpdate:async t=>{if(t.message){const a=t.message;if(a.entities&&"bot_command"===a.entities[0]?.type){const t=a.entities[0],r=(a.text??"").slice(t.offset,t.offset+t.length);if(e.command_message[r])return void(await e.command_message[r](a))}const r=Object.keys(a).filter(e=>"photo"===e||"caption"===e).sort().join("");if(e.chaining[r])return void(await e.chaining[r](a));if(a.from?.id&&e.from_id[a.from.id.toString()])return void(await e.from_id[a.from.id.toString()](a));e.message&&await e.message(t)}if(t.callback_query){const{id:a,data:r,from:o,message:n}=t.callback_query;if(await s.answerCallbackQuery(a),e.callback_query[r])await e.callback_query[r]({id:a,data:r,from:o,message:n});else{const t=r.split("_")[0];e.callback_query_search[t]&&await e.callback_query_search[t]({id:a,data:r,from:o,message:n})}}},sendMessage:async(e,t,a)=>{const r={chat_id:e,text:t,parse_mode:"HTML"};return a&&(r.reply_markup=a),o("sendMessage",r)},sendPhoto:async(e,t,a,r)=>{const s={chat_id:e,photo:t,parse_mode:"HTML"};return a&&(s.caption=a),r&&(s.reply_markup=r),o("sendPhoto",s)},answerCallbackQuery:async(e,t)=>{const a={callback_query_id:e};return t&&(a.text=t,a.show_alert=!0),o("answerCallbackQuery",a)},validatingData:e=>{if(!process.env.TELEGRAM)throw new Error("TELEGRAM token not found");const t="string"==typeof e?new URLSearchParams(e):e,a=new URLSearchParams(t);a.sort();const r=a.get("hash");a.delete("hash");const o=[...a.entries()].map(([e,t])=>`${e}=${t}`).join("\n"),s=new Bun.CryptoHasher("sha256","WebAppData").update(process.env.TELEGRAM).digest();return new Bun.CryptoHasher("sha256",s).update(o).digest("hex")===r},editMessageText:async(e,t,a,r)=>{const s={chat_id:e,message_id:t,text:a};return r&&(s.reply_markup=r),o("editMessageText",s)},onCallbackQuery:(t,a)=>{t.endsWith("%")?e.callback_query_search[t.slice(0,-1)]=a:e.callback_query[t]=a},onMessage:t=>{e.message=t},command_message:(t,a)=>{e.command_message[t]=a},getChatMember:async(e,t)=>{if(!process.env.TELEGRAM)throw new Error("TELEGRAM token not found");const a=`https://api.telegram.org/bot${process.env.TELEGRAM}/getChatMember?chat_id=`+encodeURIComponent(String(t))+"&user_id="+encodeURIComponent(String(e)),r=await fetch(a),o=await r.json().catch(()=>null);if(!r.ok||!o?.ok)return{status:!1};const s=o.result,n=s.status;return{status:n,isAdmin:"creator"===n||"administrator"===n,isMember:"creator"===n||"administrator"===n||"member"===n,raw:s}},editMessageCaption:async(e,t,a,r)=>{const s={chat_id:e,message_id:t,caption:a,parse_mode:"HTML"};return r&&(s.reply_markup=r),o("editMessageCaption",s)},editMessageMedia:async(e,t,a,r)=>{const s={chat_id:e,message_id:t,media:a};return r&&(s.reply_markup=r),o("editMessageMedia",s)},getFile:async(e,t)=>{if(!process.env.TELEGRAM)throw new Error("TELEGRAM token not found");try{const a=await fetch(`https://api.telegram.org/bot${process.env.TELEGRAM}/getFile?file_id=${e}`),r=await a.json();if(r&&r?.ok){const e=r.result.file_path;if(t){return!!(await s.downloadFile(e,t))}return r}return console.error("Не удалось получить информацию о файле"),r}catch(a){return console.error("Error getting file info:",a),null}},downloadFile:async(e,t)=>{if(!process.env.TELEGRAM)throw new Error("TELEGRAM token not found");try{const a=`https://api.telegram.org/file/bot${process.env.TELEGRAM}/${e}`,r=await fetch(a);if(!r.ok)throw new Error(`Failed to download file: ${r.statusText}`);const o=await r.arrayBuffer(),s=Buffer.from(o);return await Bun.write(t,s),!0}catch(a){return console.error("Error downloading file:",a),!1}},from_id:(t,a)=>{e.from_id[t.toString()]=a},chaining:(t,a)=>{e.chaining[t.sort().join("")]=a}};export{s as tb};
|
package/dist/index.umd.js
CHANGED
|
@@ -1,203 +1 @@
|
|
|
1
|
-
!(function (e, t) {
|
|
2
|
-
"object" == typeof exports && "undefined" != typeof module
|
|
3
|
-
? t(exports)
|
|
4
|
-
: "function" == typeof define && define.amd
|
|
5
|
-
? define(["exports"], t)
|
|
6
|
-
: t(
|
|
7
|
-
(((e =
|
|
8
|
-
"undefined" != typeof globalThis
|
|
9
|
-
? globalThis
|
|
10
|
-
: e || self).elcrm = e.elcrm || {}),
|
|
11
|
-
(e.elcrm.tb = {}))
|
|
12
|
-
);
|
|
13
|
-
})(this, function (e) {
|
|
14
|
-
"use strict";
|
|
15
|
-
function t(e) {
|
|
16
|
-
if (!e) throw new Error("Telegram bot token is required");
|
|
17
|
-
const t = e,
|
|
18
|
-
a = { callback_query: {} },
|
|
19
|
-
n = [];
|
|
20
|
-
let s = !1;
|
|
21
|
-
const o = 1e3 / 30,
|
|
22
|
-
r = async (e, a) =>
|
|
23
|
-
new Promise((r, c) => {
|
|
24
|
-
n.push({ method: e, body: a, resolve: r, reject: c }),
|
|
25
|
-
(async () => {
|
|
26
|
-
if (!s && 0 !== n.length) {
|
|
27
|
-
for (s = !0; n.length > 0; ) {
|
|
28
|
-
const a = n.shift();
|
|
29
|
-
if (!a) break;
|
|
30
|
-
try {
|
|
31
|
-
const e = Date.now(),
|
|
32
|
-
n = await fetch(
|
|
33
|
-
`https://api.telegram.org/bot${t}/${a.method}`,
|
|
34
|
-
{
|
|
35
|
-
method: "POST",
|
|
36
|
-
headers: {
|
|
37
|
-
"Content-Type":
|
|
38
|
-
"application/json",
|
|
39
|
-
},
|
|
40
|
-
body: JSON.stringify(
|
|
41
|
-
a.body
|
|
42
|
-
),
|
|
43
|
-
}
|
|
44
|
-
),
|
|
45
|
-
s = await n.json();
|
|
46
|
-
a.resolve(s);
|
|
47
|
-
const r = Date.now() - e,
|
|
48
|
-
c = Math.max(0, o - r);
|
|
49
|
-
c > 0 &&
|
|
50
|
-
(await new Promise((e) =>
|
|
51
|
-
setTimeout(e, c)
|
|
52
|
-
));
|
|
53
|
-
} catch (e) {
|
|
54
|
-
console.error(
|
|
55
|
-
`Error calling Telegram API (${a.method}):`,
|
|
56
|
-
e
|
|
57
|
-
),
|
|
58
|
-
a.reject(e);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
s = !1;
|
|
62
|
-
}
|
|
63
|
-
})();
|
|
64
|
-
}),
|
|
65
|
-
c = {
|
|
66
|
-
setWebhook: async (e) => {
|
|
67
|
-
const a = e.replace("http://", "https://"),
|
|
68
|
-
n = await fetch(
|
|
69
|
-
`https://api.telegram.org/bot${t}/setWebhook?url=${a}`
|
|
70
|
-
);
|
|
71
|
-
return await n.json();
|
|
72
|
-
},
|
|
73
|
-
webhook: (e) => ({
|
|
74
|
-
[`/${e}`]: async (e) => {
|
|
75
|
-
try {
|
|
76
|
-
const t = e.method,
|
|
77
|
-
a = new URL(e.url);
|
|
78
|
-
if ("GET" === t) {
|
|
79
|
-
const e = await c.setWebhook(a.href);
|
|
80
|
-
return new Response(JSON.stringify(e), {
|
|
81
|
-
headers: {
|
|
82
|
-
"Content-Type": "application/json",
|
|
83
|
-
},
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
if ("POST" === t) {
|
|
87
|
-
const t = await e.json();
|
|
88
|
-
return (
|
|
89
|
-
await c.handleUpdate(t), new Response("OK")
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
return new Response("Method not allowed", {
|
|
93
|
-
status: 405,
|
|
94
|
-
});
|
|
95
|
-
} catch (t) {
|
|
96
|
-
return (
|
|
97
|
-
console.error("Error handling webhook:", t),
|
|
98
|
-
new Response("Internal Server Error", {
|
|
99
|
-
status: 500,
|
|
100
|
-
})
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
},
|
|
104
|
-
}),
|
|
105
|
-
handleUpdate: async (e) => {
|
|
106
|
-
if (
|
|
107
|
-
(e.message && a.message && (await a.message(e)),
|
|
108
|
-
e.callback_query)
|
|
109
|
-
) {
|
|
110
|
-
const {
|
|
111
|
-
id: t,
|
|
112
|
-
data: n,
|
|
113
|
-
from: s,
|
|
114
|
-
message: o,
|
|
115
|
-
} = e.callback_query;
|
|
116
|
-
await c.answerCallbackQuery(t),
|
|
117
|
-
a.callback_query[n] &&
|
|
118
|
-
(await a.callback_query[n]({
|
|
119
|
-
id: t,
|
|
120
|
-
data: n,
|
|
121
|
-
from: s,
|
|
122
|
-
message: o,
|
|
123
|
-
}));
|
|
124
|
-
}
|
|
125
|
-
},
|
|
126
|
-
sendMessage: async (e, t, a) => {
|
|
127
|
-
const n = { chat_id: e, text: t, parse_mode: "HTML" };
|
|
128
|
-
return a && (n.reply_markup = a), r("sendMessage", n);
|
|
129
|
-
},
|
|
130
|
-
sendPhoto: async (e, t, a, n) => {
|
|
131
|
-
const s = { chat_id: e, photo: t };
|
|
132
|
-
return (
|
|
133
|
-
a && (s.caption = a),
|
|
134
|
-
n && (s.reply_markup = n),
|
|
135
|
-
r("sendPhoto", s)
|
|
136
|
-
);
|
|
137
|
-
},
|
|
138
|
-
answerCallbackQuery: async (e, t) => {
|
|
139
|
-
const a = { callback_query_id: e };
|
|
140
|
-
return (
|
|
141
|
-
t && ((a.text = t), (a.show_alert = !0)),
|
|
142
|
-
r("answerCallbackQuery", a)
|
|
143
|
-
);
|
|
144
|
-
},
|
|
145
|
-
validatingData: (e) => {
|
|
146
|
-
const a = "string" == typeof e ? new URLSearchParams(e) : e,
|
|
147
|
-
n = new URLSearchParams(a);
|
|
148
|
-
n.sort();
|
|
149
|
-
const s = n.get("hash");
|
|
150
|
-
n.delete("hash");
|
|
151
|
-
const o = [...n.entries()]
|
|
152
|
-
.map(([e, t]) => `${e}=${t}`)
|
|
153
|
-
.join("\n"),
|
|
154
|
-
r = new Bun.CryptoHasher("sha256", "WebAppData")
|
|
155
|
-
.update(t)
|
|
156
|
-
.digest();
|
|
157
|
-
return (
|
|
158
|
-
new Bun.CryptoHasher("sha256", r)
|
|
159
|
-
.update(o)
|
|
160
|
-
.digest("hex") === s
|
|
161
|
-
);
|
|
162
|
-
},
|
|
163
|
-
editMessageText: async (e, t, a, n) => {
|
|
164
|
-
const s = { chat_id: e, message_id: t, text: a };
|
|
165
|
-
return n && (s.reply_markup = n), r("editMessageText", s);
|
|
166
|
-
},
|
|
167
|
-
onCallbackQuery: (e, t) => {
|
|
168
|
-
a.callback_query[e] = t;
|
|
169
|
-
},
|
|
170
|
-
onMessage: (e) => {
|
|
171
|
-
a.message = e;
|
|
172
|
-
},
|
|
173
|
-
};
|
|
174
|
-
return c;
|
|
175
|
-
}
|
|
176
|
-
let a = null;
|
|
177
|
-
function n() {
|
|
178
|
-
if (!a) {
|
|
179
|
-
const e = process.env.TELEGRAM;
|
|
180
|
-
if (!e)
|
|
181
|
-
throw new Error(
|
|
182
|
-
"TELEGRAM environment variable is required. Set TELEGRAM environment variable or use createTelegramBot(token) function"
|
|
183
|
-
);
|
|
184
|
-
a = t(e);
|
|
185
|
-
}
|
|
186
|
-
return a;
|
|
187
|
-
}
|
|
188
|
-
const s = {
|
|
189
|
-
validatingData: (...e) => n().validatingData(...e),
|
|
190
|
-
setWebhook: (...e) => n().setWebhook(...e),
|
|
191
|
-
handleUpdate: (...e) => n().handleUpdate(...e),
|
|
192
|
-
webhook: (...e) => n().webhook(...e),
|
|
193
|
-
onCallbackQuery: (...e) => n().onCallbackQuery(...e),
|
|
194
|
-
onMessage: (...e) => n().onMessage(...e),
|
|
195
|
-
answerCallbackQuery: (...e) => n().answerCallbackQuery(...e),
|
|
196
|
-
editMessageText: (...e) => n().editMessageText(...e),
|
|
197
|
-
sendMessage: (...e) => n().sendMessage(...e),
|
|
198
|
-
sendPhoto: (...e) => n().sendPhoto(...e),
|
|
199
|
-
};
|
|
200
|
-
(e.createTelegramBot = t),
|
|
201
|
-
(e.tb = s),
|
|
202
|
-
Object.defineProperty(e, Symbol.toStringTag, { value: "Module" });
|
|
203
|
-
});
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(((e="undefined"!=typeof globalThis?globalThis:e||self).elcrm=e.elcrm||{},e.elcrm.tb={}))}(this,function(e){"use strict";const t={callback_query:{},callback_query_search:{},command_message:{},from_id:{},chaining:{},message:void 0},a=[];let r=!1;const o=1e3/30,n=async(e,t)=>new Promise((n,s)=>{a.push({method:e,body:t,resolve:n,reject:s}),(async()=>{if(!r&&0!==a.length){for(r=!0;a.length>0;){const t=a.shift();if(!t)break;try{const e=Date.now();if(!process.env.TELEGRAM)throw new Error("TELEGRAM token not found");const a=await fetch(`https://api.telegram.org/bot${process.env.TELEGRAM}/${t.method}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t.body)}),r=await a.json();t.resolve(r);const n=Date.now()-e,s=Math.max(0,o-n);s>0&&await new Promise(e=>setTimeout(e,s))}catch(e){console.error(`Error calling Telegram API (${t.method}):`,e),t.reject(e)}}r=!1}})()}),s={setWebhook:async e=>{if(!process.env.TELEGRAM)throw new Error("TELEGRAM token not found");const t=await fetch(`https://api.telegram.org/bot${process.env.TELEGRAM}/setWebhook?url=${e.replace("http://","https://")}`);return await t.json()},webhook:e=>({[`/${e}`]:async e=>{try{const t=e.method,a=new URL(e.url);if("GET"===t){const e=await s.setWebhook(a.href);return new Response(JSON.stringify(e),{headers:{"Content-Type":"application/json"}})}if("POST"===t){const t=await e.json();return await s.handleUpdate(t),new Response("OK")}return new Response("Method not allowed",{status:405})}catch(t){return console.error("Error handling webhook:",t),new Response("Internal Server Error",{status:500})}}}),handleUpdate:async e=>{if(e.message){const a=e.message;if(a.entities&&"bot_command"===a.entities[0]?.type){const e=a.entities[0],r=(a.text??"").slice(e.offset,e.offset+e.length);if(t.command_message[r])return void(await t.command_message[r](a))}const r=Object.keys(a).filter(e=>"photo"===e||"caption"===e).sort().join("");if(t.chaining[r])return void(await t.chaining[r](a));if(a.from?.id&&t.from_id[a.from.id.toString()])return void(await t.from_id[a.from.id.toString()](a));t.message&&await t.message(e)}if(e.callback_query){const{id:a,data:r,from:o,message:n}=e.callback_query;if(await s.answerCallbackQuery(a),t.callback_query[r])await t.callback_query[r]({id:a,data:r,from:o,message:n});else{const e=r.split("_")[0];t.callback_query_search[e]&&await t.callback_query_search[e]({id:a,data:r,from:o,message:n})}}},sendMessage:async(e,t,a)=>{const r={chat_id:e,text:t,parse_mode:"HTML"};return a&&(r.reply_markup=a),n("sendMessage",r)},sendPhoto:async(e,t,a,r)=>{const o={chat_id:e,photo:t,parse_mode:"HTML"};return a&&(o.caption=a),r&&(o.reply_markup=r),n("sendPhoto",o)},answerCallbackQuery:async(e,t)=>{const a={callback_query_id:e};return t&&(a.text=t,a.show_alert=!0),n("answerCallbackQuery",a)},validatingData:e=>{if(!process.env.TELEGRAM)throw new Error("TELEGRAM token not found");const t="string"==typeof e?new URLSearchParams(e):e,a=new URLSearchParams(t);a.sort();const r=a.get("hash");a.delete("hash");const o=[...a.entries()].map(([e,t])=>`${e}=${t}`).join("\n"),n=new Bun.CryptoHasher("sha256","WebAppData").update(process.env.TELEGRAM).digest();return new Bun.CryptoHasher("sha256",n).update(o).digest("hex")===r},editMessageText:async(e,t,a,r)=>{const o={chat_id:e,message_id:t,text:a};return r&&(o.reply_markup=r),n("editMessageText",o)},onCallbackQuery:(e,a)=>{e.endsWith("%")?t.callback_query_search[e.slice(0,-1)]=a:t.callback_query[e]=a},onMessage:e=>{t.message=e},command_message:(e,a)=>{t.command_message[e]=a},getChatMember:async(e,t)=>{if(!process.env.TELEGRAM)throw new Error("TELEGRAM token not found");const a=`https://api.telegram.org/bot${process.env.TELEGRAM}/getChatMember?chat_id=`+encodeURIComponent(String(t))+"&user_id="+encodeURIComponent(String(e)),r=await fetch(a),o=await r.json().catch(()=>null);if(!r.ok||!o?.ok)return{status:!1};const n=o.result,s=n.status;return{status:s,isAdmin:"creator"===s||"administrator"===s,isMember:"creator"===s||"administrator"===s||"member"===s,raw:n}},editMessageCaption:async(e,t,a,r)=>{const o={chat_id:e,message_id:t,caption:a,parse_mode:"HTML"};return r&&(o.reply_markup=r),n("editMessageCaption",o)},editMessageMedia:async(e,t,a,r)=>{const o={chat_id:e,message_id:t,media:a};return r&&(o.reply_markup=r),n("editMessageMedia",o)},getFile:async(e,t)=>{if(!process.env.TELEGRAM)throw new Error("TELEGRAM token not found");try{const a=await fetch(`https://api.telegram.org/bot${process.env.TELEGRAM}/getFile?file_id=${e}`),r=await a.json();if(r&&r?.ok){const e=r.result.file_path;if(t){return!!(await s.downloadFile(e,t))}return r}return console.error("Не удалось получить информацию о файле"),r}catch(a){return console.error("Error getting file info:",a),null}},downloadFile:async(e,t)=>{if(!process.env.TELEGRAM)throw new Error("TELEGRAM token not found");try{const a=`https://api.telegram.org/file/bot${process.env.TELEGRAM}/${e}`,r=await fetch(a);if(!r.ok)throw new Error(`Failed to download file: ${r.statusText}`);const o=await r.arrayBuffer(),n=Buffer.from(o);return await Bun.write(t,n),!0}catch(a){return console.error("Error downloading file:",a),!1}},from_id:(e,a)=>{t.from_id[e.toString()]=a},chaining:(e,a)=>{t.chaining[e.sort().join("")]=a}};e.tb=s,Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})});
|