@elcrm/tb 0.0.1

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 ADDED
@@ -0,0 +1,523 @@
1
+ # @elcrm/tb - Telegram Bot библиотека
2
+
3
+ Библиотека для работы с Telegram Bot API на основе Bun runtime. Предоставляет простой и удобный интерфейс для создания Telegram ботов без использования классов.
4
+
5
+ ## Особенности
6
+
7
+ - 🚀 Простое использование без создания экземпляров
8
+ - 🔧 Автоматическое использование токена из переменных окружения
9
+ - 📦 Типизированный API с полной поддержкой TypeScript
10
+ - ⚡ Ленивая инициализация - экземпляр создается при первом использовании
11
+ - 🎯 Поддержка webhook для получения обновлений
12
+ - 🔐 Валидация данных Telegram WebApp
13
+ - ⏱️ Автоматическое ограничение скорости - максимум 30 запросов в секунду
14
+ - 📋 Очередь запросов - все запросы автоматически ставятся в очередь и обрабатываются последовательно
15
+
16
+ ## Установка
17
+
18
+ ```bash
19
+ npm install @elcrm/tb
20
+ # или
21
+ bun add @elcrm/tb
22
+ ```
23
+
24
+ ## Быстрый старт
25
+
26
+ ```typescript
27
+ import { tb } from "@elcrm/tb";
28
+
29
+ // Использование напрямую без создания экземпляра
30
+ // Токен автоматически берется из process.env.TELEGRAM
31
+
32
+ // Регистрация обработчика сообщений
33
+ tb.onMessage(async (update) => {
34
+ if (update.message?.text) {
35
+ const chatId = update.message.from!.id;
36
+ await tb.sendMessage(chatId, `Вы написали: ${update.message.text}`);
37
+ }
38
+ });
39
+
40
+ // Использование webhook
41
+ const routes = tb.webhook("telegram-webhook");
42
+ ```
43
+
44
+ ## API Документация
45
+
46
+ ### `tb` - Объект Telegram Bot
47
+
48
+ Глобальный объект для работы с Telegram Bot API. Токен автоматически берется из переменной окружения `process.env.TELEGRAM`.
49
+
50
+ **Использование:**
51
+
52
+ ```typescript
53
+ import { tb } from "@elcrm/tb";
54
+
55
+ // Использование напрямую без создания экземпляра
56
+ tb.onMessage(async (update) => {
57
+ // обработка сообщений
58
+ });
59
+
60
+ tb.sendMessage(123456789, "Привет!");
61
+ ```
62
+
63
+ **Примечание:** Если нужно создать несколько экземпляров с разными токенами, используйте функцию `createTelegramBot(token)`:
64
+
65
+ ```typescript
66
+ import { createTelegramBot } from "@elcrm/tb";
67
+
68
+ const bot1 = createTelegramBot("TOKEN_1");
69
+ const bot2 = createTelegramBot("TOKEN_2");
70
+ ```
71
+
72
+ ---
73
+
74
+ ### Методы TelegramBot
75
+
76
+ #### `onMessage(callback: (update: TelegramUpdate) => void | Promise<void>): void`
77
+
78
+ Регистрирует обработчик для всех входящих сообщений.
79
+
80
+ **Параметры:**
81
+
82
+ - `callback` - Функция-обработчик, которая вызывается при получении сообщения
83
+
84
+ **Пример:**
85
+
86
+ ```typescript
87
+ tb.onMessage(async (update) => {
88
+ if (update.message?.text === "/start") {
89
+ const chatId = update.message.from!.id;
90
+ await tb.sendMessage(chatId, "Добро пожаловать!");
91
+ }
92
+ });
93
+ ```
94
+
95
+ ---
96
+
97
+ #### `onCallbackQuery(name: string, callback: (data: CallbackQueryData) => void | Promise<void>): void`
98
+
99
+ Регистрирует обработчик для callback query (нажатие на inline-кнопки).
100
+
101
+ **Параметры:**
102
+
103
+ - `name` (string) - Имя обработчика, должно совпадать с `data` кнопки
104
+ - `callback` - Функция-обработчик, вызываемая при нажатии на кнопку
105
+
106
+ **Пример:**
107
+
108
+ ```typescript
109
+ // Регистрация обработчика
110
+ tb.onCallbackQuery("button_click", async (data) => {
111
+ const chatId = data.from.id;
112
+ await tb.sendMessage(chatId, "Кнопка нажата!");
113
+ });
114
+
115
+ // Отправка сообщения с inline-кнопкой
116
+ await tb.sendMessage(chatId, "Нажмите кнопку", {
117
+ inline_keyboard: [[{ text: "Нажми меня", callback_data: "button_click" }]],
118
+ });
119
+ ```
120
+
121
+ ---
122
+
123
+ #### `sendMessage(chat_id: number, text: string, reply_markup?: ReplyMarkup): Promise<any>`
124
+
125
+ Отправляет текстовое сообщение пользователю.
126
+
127
+ **Параметры:**
128
+
129
+ - `chat_id` (number) - ID чата или пользователя
130
+ - `text` (string) - Текст сообщения (поддерживает HTML)
131
+ - `reply_markup` (ReplyMarkup, опционально) - Клавиатура или inline-кнопки
132
+
133
+ **Пример:**
134
+
135
+ ```typescript
136
+ // Простое сообщение
137
+ await tb.sendMessage(123456789, "Привет!");
138
+
139
+ // Сообщение с inline-кнопками
140
+ await tb.sendMessage(123456789, "Выберите действие:", {
141
+ inline_keyboard: [
142
+ [{ text: "Кнопка 1", callback_data: "action1" }],
143
+ [{ text: "Кнопка 2", callback_data: "action2" }],
144
+ ],
145
+ });
146
+
147
+ // Сообщение с обычной клавиатурой
148
+ await tb.sendMessage(123456789, "Нажмите кнопку:", {
149
+ keyboard: [[{ text: "Отправить контакт", request_contact: true }]],
150
+ resize_keyboard: true,
151
+ });
152
+ ```
153
+
154
+ ---
155
+
156
+ #### `sendPhoto(chat_id: number, photo: string, caption?: string, reply_markup?: ReplyMarkup): Promise<any>`
157
+
158
+ Отправляет фотографию пользователю.
159
+
160
+ **Параметры:**
161
+
162
+ - `chat_id` (number) - ID чата или пользователя
163
+ - `photo` (string) - URL или file_id фотографии
164
+ - `caption` (string, опционально) - Подпись к фотографии
165
+ - `reply_markup` (ReplyMarkup, опционально) - Клавиатура или inline-кнопки
166
+
167
+ **Пример:**
168
+
169
+ ```typescript
170
+ await tb.sendPhoto(
171
+ 123456789,
172
+ "https://example.com/image.jpg",
173
+ "Описание фотографии",
174
+ {
175
+ inline_keyboard: [[{ text: "Подробнее", callback_data: "photo_info" }]],
176
+ }
177
+ );
178
+ ```
179
+
180
+ ---
181
+
182
+ #### `editMessageText(chatId: number, messageId: number, text: string, replyMarkup?: ReplyMarkup): Promise<any>`
183
+
184
+ Редактирует текст существующего сообщения.
185
+
186
+ **Параметры:**
187
+
188
+ - `chatId` (number) - ID чата
189
+ - `messageId` (number) - ID сообщения для редактирования
190
+ - `text` (string) - Новый текст сообщения
191
+ - `replyMarkup` (ReplyMarkup, опционально) - Новая клавиатура или inline-кнопки
192
+
193
+ **Пример:**
194
+
195
+ ```typescript
196
+ tb.onCallbackQuery("edit_message", async (data) => {
197
+ await tb.editMessageText(
198
+ data.message.chat.id,
199
+ data.message.message_id,
200
+ "Сообщение обновлено!"
201
+ );
202
+ });
203
+ ```
204
+
205
+ ---
206
+
207
+ #### `answerCallbackQuery(callbackId: string, text?: string): Promise<any>`
208
+
209
+ Отвечает на callback query. Вызывается автоматически при обработке callback_query, но можно вызвать вручную.
210
+
211
+ **Параметры:**
212
+
213
+ - `callbackId` (string) - ID callback query
214
+ - `text` (string, опционально) - Текст уведомления (если указан, показывается alert)
215
+
216
+ **Пример:**
217
+
218
+ ```typescript
219
+ tb.onCallbackQuery("show_alert", async (data) => {
220
+ await tb.answerCallbackQuery(data.id, "Это уведомление!");
221
+ });
222
+ ```
223
+
224
+ ---
225
+
226
+ #### `setWebhook(url: string): Promise<any>`
227
+
228
+ Устанавливает webhook URL для получения обновлений от Telegram.
229
+
230
+ **Параметры:**
231
+
232
+ - `url` (string) - HTTPS URL для получения обновлений
233
+
234
+ **Пример:**
235
+
236
+ ```typescript
237
+ const result = await tb.setWebhook("https://example.com/webhook");
238
+ console.log(result);
239
+ ```
240
+
241
+ ---
242
+
243
+ #### `webhook(router: string): Record<string, (req: Request) => Promise<Response>>`
244
+
245
+ Создает роутер для обработки webhook запросов от Telegram.
246
+
247
+ **Параметры:**
248
+
249
+ - `router` (string) - Путь для webhook (например, 'telegram-webhook')
250
+
251
+ **Возвращает:** Объект с методом для обработки запросов
252
+
253
+ **Пример использования с Bun:**
254
+
255
+ ```typescript
256
+ // Регистрация обработчиков
257
+ tb.onMessage(async (update) => {
258
+ // Обработка сообщений
259
+ });
260
+
261
+ tb.onCallbackQuery("action", async (data) => {
262
+ // Обработка callback query
263
+ });
264
+
265
+ // Создание роутера
266
+ const routes = tb.webhook("telegram-webhook");
267
+
268
+ // Использование в Bun server
269
+ Bun.serve({
270
+ port: 3000,
271
+ fetch(req) {
272
+ const url = new URL(req.url);
273
+ const handler = routes[url.pathname];
274
+ if (handler) {
275
+ return handler(req);
276
+ }
277
+ return new Response("Not found", { status: 404 });
278
+ },
279
+ });
280
+ ```
281
+
282
+ **Примечание:**
283
+
284
+ - GET запросы автоматически устанавливают webhook на URL запроса
285
+ - POST запросы обрабатывают обновления от Telegram
286
+
287
+ ---
288
+
289
+ #### `validatingData(body: string | URLSearchParams): boolean`
290
+
291
+ Валидирует данные от Telegram WebApp.
292
+
293
+ **Параметры:**
294
+
295
+ - `body` (string | URLSearchParams) - Данные от Telegram WebApp
296
+
297
+ **Возвращает:** `true` если данные валидны, иначе `false`
298
+
299
+ **Пример:**
300
+
301
+ ```typescript
302
+ // В обработчике запроса от WebApp
303
+ const isValid = tb.validatingData(requestBody);
304
+ if (isValid) {
305
+ // Данные валидны, можно использовать
306
+ } else {
307
+ // Данные невалидны
308
+ }
309
+ ```
310
+
311
+ ---
312
+
313
+ #### `handleUpdate(update: TelegramUpdate): Promise<void>`
314
+
315
+ Обрабатывает обновление от Telegram. Обычно вызывается автоматически через webhook, но можно вызвать вручную.
316
+
317
+ **Параметры:**
318
+
319
+ - `update` (TelegramUpdate) - Объект обновления от Telegram API
320
+
321
+ **Пример:**
322
+
323
+ ```typescript
324
+ // Ручная обработка обновления
325
+ const update = await fetch("...").then((r) => r.json());
326
+ await tb.handleUpdate(update);
327
+ ```
328
+
329
+ ---
330
+
331
+ ## Типы
332
+
333
+ ### `TelegramUpdate`
334
+
335
+ Интерфейс для обновления от Telegram API.
336
+
337
+ ```typescript
338
+ interface TelegramUpdate {
339
+ message?: {
340
+ from?: {
341
+ id: number;
342
+ [key: string]: any;
343
+ };
344
+ contact?: {
345
+ phone_number: string;
346
+ user_id: number;
347
+ [key: string]: any;
348
+ };
349
+ text?: string;
350
+ [key: string]: any;
351
+ };
352
+ callback_query?: {
353
+ id: string;
354
+ data: string;
355
+ from: any;
356
+ message: any;
357
+ };
358
+ [key: string]: any;
359
+ }
360
+ ```
361
+
362
+ ### `CallbackQueryData`
363
+
364
+ Данные callback query.
365
+
366
+ ```typescript
367
+ interface CallbackQueryData {
368
+ id: string;
369
+ data: string;
370
+ from: any;
371
+ message: any;
372
+ }
373
+ ```
374
+
375
+ ### `ReplyMarkup`
376
+
377
+ Клавиатура или inline-кнопки.
378
+
379
+ ```typescript
380
+ interface ReplyMarkup {
381
+ inline_keyboard?: any[][];
382
+ keyboard?: any[][];
383
+ [key: string]: any;
384
+ }
385
+ ```
386
+
387
+ ### `TelegramBot`
388
+
389
+ Интерфейс объекта бота со всеми методами.
390
+
391
+ ---
392
+
393
+ ## Полный пример
394
+
395
+ ```typescript
396
+ import { tb } from "@elcrm/tb";
397
+
398
+ // Использование напрямую (токен берется из process.env.TELEGRAM)
399
+
400
+ // Обработчик сообщений
401
+ tb.onMessage(async (update) => {
402
+ if (!update.message?.text || !update.message.from) return;
403
+
404
+ const chatId = update.message.from.id;
405
+ 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
+ }
418
+ });
419
+
420
+ // Обработчик callback query
421
+ tb.onCallbackQuery("start_action", async (data) => {
422
+ const chatId = data.from.id;
423
+ await tb.sendMessage(chatId, "Действие выполнено!");
424
+ await tb.answerCallbackQuery(data.id, "Готово!");
425
+ });
426
+
427
+ // Создание webhook роутера
428
+ const routes = tb.webhook("telegram-webhook");
429
+
430
+ // Запуск сервера (Bun)
431
+ Bun.serve({
432
+ port: 3000,
433
+ fetch(req) {
434
+ const url = new URL(req.url);
435
+ const handler = routes[url.pathname];
436
+ if (handler) {
437
+ return handler(req);
438
+ }
439
+ return new Response("Not found", { status: 404 });
440
+ },
441
+ });
442
+ ```
443
+
444
+ ---
445
+
446
+ ## Экспорты
447
+
448
+ Библиотека экспортирует следующие элементы:
449
+
450
+ - `tb` - Основной объект для работы с Telegram Bot API (синглтон)
451
+ - `createTelegramBot(token: string)` - Функция для создания дополнительных экземпляров бота
452
+ - `TelegramBot` - Интерфейс объекта бота
453
+ - `TelegramUpdate` - Интерфейс для обновлений от Telegram
454
+ - `CallbackQueryData` - Интерфейс для данных callback query
455
+ - `ReplyMarkup` - Интерфейс для клавиатур и кнопок
456
+ - `TelegramWebAppData` - Интерфейс для данных Telegram WebApp
457
+
458
+ **Пример импорта типов:**
459
+
460
+ ```typescript
461
+ import {
462
+ tb,
463
+ createTelegramBot,
464
+ type TelegramUpdate,
465
+ type CallbackQueryData,
466
+ } from "@elcrm/tb";
467
+ ```
468
+
469
+ ---
470
+
471
+ ## Требования
472
+
473
+ - Bun runtime (для работы с `Bun.CryptoHasher` в методе `validatingData`)
474
+ - Node.js/Bun для выполнения
475
+
476
+ ## Переменные окружения
477
+
478
+ Библиотека использует переменную окружения `TELEGRAM` для получения токена бота:
479
+
480
+ ```bash
481
+ export TELEGRAM="123456789:ABCdefGHIjklMNOpqrsTUVwxyz"
482
+ ```
483
+
484
+ Или создайте файл `.env`:
485
+
486
+ ```
487
+ TELEGRAM=123456789:ABCdefGHIjklMNOpqrsTUVwxyz
488
+ ```
489
+
490
+ **Важно:** Если переменная `TELEGRAM` не установлена, при первом использовании `tb` будет выброшена ошибка. В этом случае используйте функцию `createTelegramBot(token)` для создания экземпляра с явным токеном.
491
+
492
+ ---
493
+
494
+ ## Ограничение скорости запросов
495
+
496
+ Библиотека автоматически ограничивает скорость запросов к Telegram API до **30 запросов в секунду** (лимит Telegram Bot API). Все запросы автоматически ставятся в очередь и обрабатываются последовательно с необходимой задержкой.
497
+
498
+ ### Как это работает:
499
+
500
+ - Все запросы к API (кроме `setWebhook`) попадают в очередь перед выполнением
501
+ - Запросы обрабатываются последовательно с минимальной задержкой ~33.33 мс между ними
502
+ - Если запрос выполняется дольше задержки, дополнительная задержка не добавляется
503
+ - Ограничение применяется автоматически ко всем методам: `sendMessage`, `sendPhoto`, `editMessageText`, `answerCallbackQuery`
504
+
505
+ **Пример:**
506
+
507
+ ```typescript
508
+ // Все эти запросы автоматически будут обработаны с правильной скоростью
509
+ for (let i = 0; i < 100; i++) {
510
+ await tb.sendMessage(chatId, `Сообщение ${i}`);
511
+ // Запросы будут обработаны последовательно, не превышая лимит 30 запросов/сек
512
+ }
513
+ ```
514
+
515
+ ---
516
+
517
+ ## Лицензия
518
+
519
+ MIT
520
+
521
+ ## Автор
522
+
523
+ MaSkal <dev@elcrm.online>
@@ -0,0 +1,74 @@
1
+ export interface TelegramWebAppData {
2
+ hash: string;
3
+ user: Record<string, any>;
4
+ [key: string]: any;
5
+ }
6
+ export interface TelegramUpdate {
7
+ message?: {
8
+ from?: {
9
+ id: number;
10
+ [key: string]: any;
11
+ };
12
+ contact?: {
13
+ phone_number: string;
14
+ user_id: number;
15
+ [key: string]: any;
16
+ };
17
+ text?: string;
18
+ [key: string]: any;
19
+ };
20
+ callback_query?: {
21
+ id: string;
22
+ data: string;
23
+ from: any;
24
+ message: any;
25
+ };
26
+ [key: string]: any;
27
+ }
28
+ export interface CallbackQueryData {
29
+ id: string;
30
+ data: string;
31
+ from: any;
32
+ message: any;
33
+ }
34
+ export interface ReplyMarkup {
35
+ inline_keyboard?: any[][];
36
+ keyboard?: any[][];
37
+ [key: string]: any;
38
+ }
39
+ export interface TelegramBot {
40
+ validatingData: (body: string | URLSearchParams) => boolean;
41
+ setWebhook: (url: string) => Promise<any>;
42
+ handleUpdate: (update: TelegramUpdate) => Promise<void>;
43
+ webhook: (
44
+ router: string
45
+ ) => Record<string, (req: Request) => Promise<Response>>;
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;
53
+ answerCallbackQuery: (callbackId: string, text?: string) => Promise<any>;
54
+ editMessageText: (
55
+ chatId: number,
56
+ messageId: number,
57
+ text: string,
58
+ replyMarkup?: ReplyMarkup
59
+ ) => Promise<any>;
60
+ sendMessage: (
61
+ chat_id: number,
62
+ text: string,
63
+ reply_markup?: ReplyMarkup
64
+ ) => Promise<any>;
65
+ sendPhoto: (
66
+ chat_id: number,
67
+ photo: string,
68
+ caption?: string,
69
+ reply_markup?: ReplyMarkup
70
+ ) => Promise<any>;
71
+ }
72
+ declare function createTelegramBot(token: string): TelegramBot;
73
+ export declare const tb: TelegramBot;
74
+ export { createTelegramBot };
@@ -0,0 +1,180 @@
1
+ function e(e) {
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 };
@@ -0,0 +1,203 @@
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
+ });
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@elcrm/tb",
3
+ "version": "0.0.1",
4
+ "description": "plugin for elCRM",
5
+ "type": "module",
6
+ "author": "MaSkal <dev@elcrm.online>",
7
+ "license": "MIT",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "keywords": [
12
+ "elcrm",
13
+ "tb",
14
+ "bun"
15
+ ],
16
+ "main": "./dist/index.umd.js",
17
+ "module": "./dist/index.es.js",
18
+ "types": "./dist/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "import": "./dist/index.es.js",
23
+ "require": "./dist/index.umd.js"
24
+ }
25
+ }
26
+ }