teh-bot 1.0.0

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.
Files changed (5) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +560 -0
  3. package/index.d.ts +566 -0
  4. package/index.js +962 -0
  5. package/package.json +36 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Teh Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,560 @@
1
+ # teh-bot - Lightweight Telegram Bot API
2
+
3
+ [![npm version](https://img.shields.io/npm/v/teh.svg)](https://www.npmjs.com/package/teh-bot)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ A lightweight, high-performance Telegram Bot API module with **zero dependencies**. Built for speed, stability, and simplicity.
7
+
8
+ ## Features
9
+
10
+ - **Zero Dependencies** - Only native Node.js modules
11
+ - **High Performance** - Optimized HTTP requests with connection pooling
12
+ - **Full API Coverage** - Complete Telegram Bot API implementation
13
+ - **Event-Driven** - Built on Node.js EventEmitter
14
+ - **Middleware Support** - Express-style middleware system
15
+ - **Smart Rate Limiting** - Automatic request queuing and retry logic
16
+ - **Both Polling & Webhooks** - Choose your preferred update method
17
+ - **TypeScript Support** - Full TypeScript definitions included
18
+ - **Small Bundle Size** - Minimal footprint for fast deployments
19
+ - **Clean API** - Intuitive, chainable methods
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install teh-bot
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ```javascript
30
+ const TelegramBot = require('teh-bot');
31
+
32
+ const bot = new TelegramBot('YOUR_BOT_TOKEN', {
33
+ polling: true
34
+ });
35
+
36
+ bot.command('start', async (ctx) => {
37
+ await ctx.reply('Hello! Welcome to my bot!');
38
+ });
39
+
40
+ bot.on('text', async (message, ctx) => {
41
+ await ctx.reply(`You said: ${message.text}`);
42
+ });
43
+ ```
44
+
45
+ ## Table of Contents
46
+
47
+ - [Basic Usage](#basic-usage)
48
+ - [Polling vs Webhooks](#polling-vs-webhooks)
49
+ - [Sending Messages](#sending-messages)
50
+ - [Keyboards](#keyboards)
51
+ - [Commands](#commands)
52
+ - [Middleware](#middleware)
53
+ - [Events](#events)
54
+ - [File Handling](#file-handling)
55
+ - [Error Handling](#error-handling)
56
+ - [API Reference](#api-reference)
57
+
58
+ ## Basic Usage
59
+
60
+ ### Initializing the Bot
61
+
62
+ ```javascript
63
+ const TelegramBot = require('teh-bot');
64
+
65
+ const bot = new TelegramBot('YOUR_BOT_TOKEN', {
66
+ polling: true,
67
+ pollingInterval: 1000,
68
+ pollingTimeout: 30
69
+ });
70
+ ```
71
+
72
+ ### Options
73
+
74
+ - `polling` (boolean) - Enable long polling (default: false)
75
+ - `pollingInterval` (number) - Polling interval in ms (default: 1000)
76
+ - `pollingTimeout` (number) - Long polling timeout in seconds (default: 30)
77
+ - `webhook` (boolean) - Enable webhook mode (default: false)
78
+ - `webhookPort` (number) - Webhook server port (default: 3000)
79
+ - `webhookPath` (string) - Webhook URL path (default: '/webhook')
80
+ - `requestTimeout` (number) - HTTP request timeout in ms (default: 30000)
81
+ - `allowedUpdates` (array) - List of update types to receive
82
+
83
+ ## Polling vs Webhooks
84
+
85
+ ### Polling Mode
86
+
87
+ ```javascript
88
+ const bot = new TelegramBot(token, { polling: true });
89
+
90
+ bot.startPolling();
91
+
92
+ bot.on('polling_error', (error) => {
93
+ console.error('Polling error:', error);
94
+ });
95
+ ```
96
+
97
+ ### Webhook Mode
98
+
99
+ ```javascript
100
+ const bot = new TelegramBot(token, {
101
+ webhook: true,
102
+ webhookPort: 8443,
103
+ webhookPath: '/bot-webhook'
104
+ });
105
+
106
+ await bot.setWebhook('https://yourdomain.com/bot-webhook');
107
+
108
+ bot.on('webhook_start', (port) => {
109
+ console.log(`Webhook server started on port ${port}`);
110
+ });
111
+ ```
112
+
113
+ ## Sending Messages
114
+
115
+ ### Text Messages
116
+
117
+ ```javascript
118
+ await bot.sendMessage(chatId, 'Hello World!');
119
+
120
+ await bot.sendMessage(chatId, '*Bold* and _italic_ text', {
121
+ parse_mode: 'Markdown'
122
+ });
123
+
124
+ await bot.sendMessage(chatId, '<b>Bold</b> and <i>italic</i> text', {
125
+ parse_mode: 'HTML'
126
+ });
127
+ ```
128
+
129
+ ### Photos
130
+
131
+ ```javascript
132
+ await bot.sendPhoto(chatId, 'https://example.com/image.jpg');
133
+
134
+ await bot.sendPhoto(chatId, '/path/to/local/image.jpg');
135
+
136
+ await bot.sendPhoto(chatId, 'file_id_from_telegram');
137
+
138
+ await bot.sendPhoto(chatId, photoBuffer);
139
+ ```
140
+
141
+ ### Documents
142
+
143
+ ```javascript
144
+ await bot.sendDocument(chatId, '/path/to/document.pdf', {
145
+ caption: 'Here is your document'
146
+ });
147
+ ```
148
+
149
+ ### Other Media Types
150
+
151
+ ```javascript
152
+ await bot.sendVideo(chatId, videoPath);
153
+ await bot.sendAudio(chatId, audioPath);
154
+ await bot.sendVoice(chatId, voicePath);
155
+ await bot.sendSticker(chatId, stickerId);
156
+ await bot.sendAnimation(chatId, gifPath);
157
+ ```
158
+
159
+ ### Location
160
+
161
+ ```javascript
162
+ await bot.sendLocation(chatId, latitude, longitude);
163
+ ```
164
+
165
+ ### Contact
166
+
167
+ ```javascript
168
+ await bot.sendContact(chatId, '+1234567890', 'John Doe');
169
+ ```
170
+
171
+ ### Poll
172
+
173
+ ```javascript
174
+ await bot.sendPoll(chatId, 'What is your favorite color?', [
175
+ 'Red',
176
+ 'Blue',
177
+ 'Green',
178
+ 'Yellow'
179
+ ]);
180
+ ```
181
+
182
+ ## Keyboards
183
+
184
+ ### Inline Keyboards
185
+
186
+ ```javascript
187
+ const keyboard = TelegramBot.InlineKeyboard()
188
+ .text('Button 1', 'callback_data_1')
189
+ .text('Button 2', 'callback_data_2')
190
+ .row()
191
+ .url('Visit Website', 'https://example.com')
192
+ .build();
193
+
194
+ await bot.sendMessage(chatId, 'Choose an option:', {
195
+ reply_markup: keyboard
196
+ });
197
+
198
+ bot.on('callback_query', async (query, ctx) => {
199
+ if (query.data === 'callback_data_1') {
200
+ await ctx.answerCallbackQuery({ text: 'You clicked Button 1!' });
201
+ await ctx.editMessageText('You selected Button 1');
202
+ }
203
+ });
204
+ ```
205
+
206
+ ### Reply Keyboards
207
+
208
+ ```javascript
209
+ const keyboard = TelegramBot.ReplyKeyboard()
210
+ .text('Option 1')
211
+ .text('Option 2')
212
+ .row()
213
+ .text('Option 3')
214
+ .resize()
215
+ .oneTime()
216
+ .build();
217
+
218
+ await bot.sendMessage(chatId, 'Select an option:', {
219
+ reply_markup: keyboard
220
+ });
221
+ ```
222
+
223
+ ### Remove Keyboard
224
+
225
+ ```javascript
226
+ await bot.sendMessage(chatId, 'Keyboard removed', {
227
+ reply_markup: TelegramBot.RemoveKeyboard()
228
+ });
229
+ ```
230
+
231
+ ### Request Contact/Location
232
+
233
+ ```javascript
234
+ const keyboard = TelegramBot.ReplyKeyboard()
235
+ .requestContact('Share Contact')
236
+ .row()
237
+ .requestLocation('Share Location')
238
+ .resize()
239
+ .build();
240
+
241
+ await bot.sendMessage(chatId, 'Please share your info:', {
242
+ reply_markup: keyboard
243
+ });
244
+ ```
245
+
246
+ ## Commands
247
+
248
+ ### Basic Commands
249
+
250
+ ```javascript
251
+ bot.command('start', async (ctx) => {
252
+ await ctx.reply('Welcome! Use /help to see available commands.');
253
+ });
254
+
255
+ bot.command('help', async (ctx) => {
256
+ await ctx.reply('Available commands:\n/start - Start the bot\n/help - Show this message');
257
+ });
258
+ ```
259
+
260
+ ### Multiple Command Aliases
261
+
262
+ ```javascript
263
+ bot.command(['info', 'about'], async (ctx) => {
264
+ await ctx.reply('Bot information...');
265
+ });
266
+ ```
267
+
268
+ ### Command with Arguments
269
+
270
+ ```javascript
271
+ bot.on('text', async (message, ctx) => {
272
+ if (message.text.startsWith('/greet')) {
273
+ const args = message.text.split(' ').slice(1);
274
+ const name = args.join(' ') || 'stranger';
275
+ await ctx.reply(`Hello, ${name}!`);
276
+ }
277
+ });
278
+ ```
279
+
280
+ ## Middleware
281
+
282
+ ### Basic Middleware
283
+
284
+ ```javascript
285
+ bot.use(async (ctx, next) => {
286
+ console.log('Received update:', ctx.update.update_id);
287
+ await next();
288
+ });
289
+
290
+ bot.use(async (ctx, next) => {
291
+ ctx.startTime = Date.now();
292
+ await next();
293
+ const duration = Date.now() - ctx.startTime;
294
+ console.log(`Request took ${duration}ms`);
295
+ });
296
+ ```
297
+
298
+ ### Authentication Middleware
299
+
300
+ ```javascript
301
+ const AUTHORIZED_USERS = [123456789, 987654321];
302
+
303
+ bot.use(async (ctx, next) => {
304
+ if (ctx.from && AUTHORIZED_USERS.includes(ctx.from.id)) {
305
+ await next();
306
+ } else {
307
+ await ctx.reply('You are not authorized to use this bot.');
308
+ }
309
+ });
310
+ ```
311
+
312
+ ### Logging Middleware
313
+
314
+ ```javascript
315
+ bot.use(async (ctx, next) => {
316
+ const user = ctx.from?.username || ctx.from?.id || 'unknown';
317
+ const message = ctx.message?.text || 'no text';
318
+ console.log(`[${new Date().toISOString()}] ${user}: ${message}`);
319
+ await next();
320
+ });
321
+ ```
322
+
323
+ ## Events
324
+
325
+ ### Message Events
326
+
327
+ ```javascript
328
+ bot.on('message', (message, ctx) => {
329
+ console.log('New message:', message);
330
+ });
331
+
332
+ bot.on('text', async (message, ctx) => {
333
+ console.log('Text message:', message.text);
334
+ });
335
+
336
+ bot.on('photo', async (message, ctx) => {
337
+ console.log('Photo received:', message.photo);
338
+ });
339
+
340
+ bot.on('document', async (message, ctx) => {
341
+ console.log('Document received:', message.document);
342
+ });
343
+
344
+ bot.on('video', async (message, ctx) => {
345
+ console.log('Video received:', message.video);
346
+ });
347
+
348
+ bot.on('sticker', async (message, ctx) => {
349
+ await ctx.reply('Nice sticker!');
350
+ });
351
+
352
+ bot.on('location', async (message, ctx) => {
353
+ const { latitude, longitude } = message.location;
354
+ await ctx.reply(`You are at: ${latitude}, ${longitude}`);
355
+ });
356
+
357
+ bot.on('contact', async (message, ctx) => {
358
+ await ctx.reply(`Contact received: ${message.contact.first_name}`);
359
+ });
360
+ ```
361
+
362
+ ### Update Events
363
+
364
+ ```javascript
365
+ bot.on('edited_message', (message, ctx) => {
366
+ console.log('Message edited');
367
+ });
368
+
369
+ bot.on('callback_query', async (query, ctx) => {
370
+ await ctx.answerCallbackQuery();
371
+ });
372
+
373
+ bot.on('inline_query', async (query, ctx) => {
374
+ console.log('Inline query:', query.query);
375
+ });
376
+ ```
377
+
378
+ ### Error Events
379
+
380
+ ```javascript
381
+ bot.on('error', (error) => {
382
+ console.error('Bot error:', error);
383
+ });
384
+
385
+ bot.on('polling_error', (error) => {
386
+ console.error('Polling error:', error);
387
+ });
388
+
389
+ bot.on('webhook_error', (error) => {
390
+ console.error('Webhook error:', error);
391
+ });
392
+ ```
393
+
394
+ ## File Handling
395
+
396
+ ### Download Files
397
+
398
+ ```javascript
399
+ bot.on('document', async (message, ctx) => {
400
+ const fileId = message.document.file_id;
401
+
402
+ try {
403
+ await bot.downloadFile(fileId, './downloads/document.pdf');
404
+ await ctx.reply('File downloaded successfully!');
405
+ } catch (error) {
406
+ await ctx.reply('Failed to download file.');
407
+ }
408
+ });
409
+ ```
410
+
411
+ ### Get File Info
412
+
413
+ ```javascript
414
+ const file = await bot.getFile(fileId);
415
+ console.log('File path:', file.file_path);
416
+ console.log('File size:', file.file_size);
417
+ ```
418
+
419
+ ## Error Handling
420
+
421
+ ### Try-Catch Pattern
422
+
423
+ ```javascript
424
+ bot.command('start', async (ctx) => {
425
+ try {
426
+ await ctx.reply('Welcome!');
427
+ } catch (error) {
428
+ console.error('Failed to send message:', error);
429
+ }
430
+ });
431
+ ```
432
+
433
+ ### Global Error Handler
434
+
435
+ ```javascript
436
+ bot.on('error', (error) => {
437
+ if (error.code === 403) {
438
+ console.error('Bot was blocked by user');
439
+ } else if (error.code === 429) {
440
+ console.error('Rate limit exceeded');
441
+ } else {
442
+ console.error('Unexpected error:', error);
443
+ }
444
+ });
445
+ ```
446
+
447
+ ## API Reference
448
+
449
+ ### Bot Methods
450
+
451
+ #### Message Methods
452
+ - `sendMessage(chatId, text, options)` - Send text message
453
+ - `sendPhoto(chatId, photo, options)` - Send photo
454
+ - `sendAudio(chatId, audio, options)` - Send audio
455
+ - `sendDocument(chatId, document, options)` - Send document
456
+ - `sendVideo(chatId, video, options)` - Send video
457
+ - `sendAnimation(chatId, animation, options)` - Send animation/GIF
458
+ - `sendVoice(chatId, voice, options)` - Send voice message
459
+ - `sendVideoNote(chatId, videoNote, options)` - Send video note
460
+ - `sendSticker(chatId, sticker, options)` - Send sticker
461
+ - `sendLocation(chatId, latitude, longitude, options)` - Send location
462
+ - `sendVenue(chatId, latitude, longitude, title, address, options)` - Send venue
463
+ - `sendContact(chatId, phoneNumber, firstName, options)` - Send contact
464
+ - `sendPoll(chatId, question, options, params)` - Send poll
465
+ - `sendDice(chatId, options)` - Send dice
466
+ - `sendChatAction(chatId, action)` - Send chat action
467
+
468
+ #### Edit Methods
469
+ - `editMessageText(text, options)` - Edit message text
470
+ - `editMessageCaption(options)` - Edit message caption
471
+ - `editMessageReplyMarkup(options)` - Edit reply markup
472
+ - `deleteMessage(chatId, messageId)` - Delete message
473
+
474
+ #### Forward Methods
475
+ - `forwardMessage(chatId, fromChatId, messageId, options)` - Forward message
476
+ - `copyMessage(chatId, fromChatId, messageId, options)` - Copy message
477
+
478
+ #### Chat Methods
479
+ - `getChat(chatId)` - Get chat info
480
+ - `getChatAdministrators(chatId)` - Get chat administrators
481
+ - `getChatMemberCount(chatId)` - Get member count
482
+ - `getChatMember(chatId, userId)` - Get chat member
483
+ - `setChatTitle(chatId, title)` - Set chat title
484
+ - `setChatDescription(chatId, description)` - Set chat description
485
+ - `pinChatMessage(chatId, messageId, options)` - Pin message
486
+ - `unpinChatMessage(chatId, options)` - Unpin message
487
+ - `unpinAllChatMessages(chatId)` - Unpin all messages
488
+ - `leaveChat(chatId)` - Leave chat
489
+ - `banChatMember(chatId, userId, options)` - Ban member
490
+ - `unbanChatMember(chatId, userId, options)` - Unban member
491
+ - `restrictChatMember(chatId, userId, permissions, options)` - Restrict member
492
+ - `promoteChatMember(chatId, userId, options)` - Promote member
493
+
494
+ #### File Methods
495
+ - `getFile(fileId)` - Get file info
496
+ - `downloadFile(fileId, destination)` - Download file
497
+
498
+ #### Other Methods
499
+ - `getMe()` - Get bot info
500
+ - `answerCallbackQuery(callbackQueryId, options)` - Answer callback query
501
+ - `answerInlineQuery(inlineQueryId, results, options)` - Answer inline query
502
+
503
+ ### Context Object
504
+
505
+ The context object (`ctx`) is passed to command handlers and middleware:
506
+
507
+ ```javascript
508
+ {
509
+ update, // Original update object
510
+ bot, // Bot instance
511
+ message, // Message object (if available)
512
+ callbackQuery, // Callback query (if available)
513
+ inlineQuery, // Inline query (if available)
514
+ chat, // Chat object
515
+ from, // User object
516
+ chatId, // Chat ID
517
+ reply, // Reply to current chat
518
+ replyWithPhoto, // Reply with photo
519
+ replyWithDocument, // Reply with document
520
+ editMessageText, // Edit message text
521
+ answerCallbackQuery, // Answer callback query
522
+ deleteMessage // Delete message
523
+ }
524
+ ```
525
+
526
+ ## Performance Tips
527
+
528
+ 1. **Use Rate Limiting**: The bot automatically handles rate limits with smart retry logic
529
+ 2. **Batch Requests**: When possible, batch multiple operations
530
+ 3. **Use Webhooks in Production**: Webhooks are more efficient than polling for production bots
531
+ 4. **Enable Compression**: Use reverse proxy (nginx) with gzip for webhook endpoints
532
+ 5. **Connection Pooling**: The module uses optimized HTTP connection handling
533
+
534
+ ## Best Practices
535
+
536
+ 1. **Always Handle Errors**: Use try-catch blocks and error event listeners
537
+ 2. **Validate User Input**: Always validate and sanitize user input
538
+ 3. **Use Middleware for Common Tasks**: Authentication, logging, etc.
539
+ 4. **Set Request Timeouts**: Adjust timeouts based on your needs
540
+ 5. **Implement Graceful Shutdown**: Clean up resources on exit
541
+
542
+ ```javascript
543
+ process.on('SIGINT', () => {
544
+ bot.stopPolling();
545
+ console.log('Bot stopped gracefully');
546
+ process.exit(0);
547
+ });
548
+ ```
549
+
550
+ ## License
551
+
552
+ MIT
553
+
554
+ ## Contributing
555
+
556
+ Contributions are welcome! Please feel free to submit a Pull Request.
557
+
558
+ ## Support
559
+
560
+ For issues and questions, please use the [GitHub Issues](https://github.com/kazedevid/teh/issues) page.