telegix 1.1.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/LICENSE +21 -0
- package/README.md +1534 -0
- package/index.d.ts +539 -0
- package/index.js +38 -0
- package/lib/album.js +57 -0
- package/lib/api.js +1840 -0
- package/lib/chataction.js +40 -0
- package/lib/cluster.js +68 -0
- package/lib/composer.js +419 -0
- package/lib/context.js +970 -0
- package/lib/errors.js +67 -0
- package/lib/format.js +115 -0
- package/lib/i18n.js +158 -0
- package/lib/inline-debounce.js +49 -0
- package/lib/inline.js +79 -0
- package/lib/markdownv2.js +29 -0
- package/lib/markup.js +321 -0
- package/lib/payment.js +91 -0
- package/lib/polling.js +101 -0
- package/lib/prompt.js +62 -0
- package/lib/ratelimit.js +59 -0
- package/lib/rich.js +609 -0
- package/lib/scenes.js +206 -0
- package/lib/serialize.js +141 -0
- package/lib/session.js +145 -0
- package/lib/telegix.js +176 -0
- package/lib/webapp.js +65 -0
- package/lib/webhook.js +86 -0
- package/package.json +42 -0
package/README.md
ADDED
|
@@ -0,0 +1,1534 @@
|
|
|
1
|
+
# โก Telegix
|
|
2
|
+
|
|
3
|
+
> **lightweight Telegram Bot API framework for Node.js, Bun, Deno, and modern JavaScript runtimes.**
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/telegix)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://nodejs.org)
|
|
8
|
+
[](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
|
|
9
|
+
[](https://core.telegram.org/bots/api)
|
|
10
|
+
|
|
11
|
+
Telegix is a high-performance, developer-friendly Telegram Bot API library built with **100% Pure JavaScript and zero runtime dependencies** beyond native platform APIs (`fetch`, `FormData`, `Blob`). It provides full, first-class support for the latest [Telegram Bot API Specification](https://core.telegram.org/bots/api), including **Bot API 10.3**.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## ๐ Table of Contents
|
|
16
|
+
|
|
17
|
+
- [๐ Key Highlights](#-key-highlights)
|
|
18
|
+
- [๐ฆ Installation](#-installation)
|
|
19
|
+
- [๐ Quick Start Guide](#-quick-start-guide)
|
|
20
|
+
- [ECMAScript Modules (ESM)](#ecmascript-modules-esm)
|
|
21
|
+
- [CommonJS (CJS)](#commonjs-cjs)
|
|
22
|
+
- [๐๏ธ Bot Core & Lifecycle](#๏ธ-bot-core--lifecycle)
|
|
23
|
+
- [Initialization & Configuration Options](#initialization--configuration-options)
|
|
24
|
+
- [Fetching Bot Info with getMe()](#fetching-bot-info-with-getme)
|
|
25
|
+
- [Long-Polling Mode](#long-polling-mode)
|
|
26
|
+
- [Webhook Mode (Node.js HTTP, Express, Fastify, Serverless)](#webhook-mode-nodejs-http-express-fastify-serverless)
|
|
27
|
+
- [Multi-Core Cluster Mode](#multi-core-cluster-mode)
|
|
28
|
+
- [Error Handling & bot.catch()](#error-handling--botcatch)
|
|
29
|
+
- [๐ ๏ธ Context (`ctx`) Reference & Functions](#๏ธ-context-ctx-reference--functions)
|
|
30
|
+
- [Context Properties & Getters](#context-properties--getters)
|
|
31
|
+
- [Text & HTML / Markdown Replies](#text--html--markdown-replies)
|
|
32
|
+
- [Media Sending Functions (Photos, Audio, Videos, Documents, Albums)](#media-sending-functions-photos-audio-videos-documents-albums)
|
|
33
|
+
- [Interactive Messages (Polls, Locations, Venues, Contacts, Dice, Stickers, Games)](#interactive-messages-polls-locations-venues-contacts-dice-stickers-games)
|
|
34
|
+
- [Message Reactions & Chat Actions](#message-reactions--chat-actions)
|
|
35
|
+
- [Message Editing, Deleting, Forwarding, Copying, & Pinning](#message-editing-deleting-forwarding-copying--pinning)
|
|
36
|
+
- [Chat Administration & Member Moderation](#chat-administration--member-moderation)
|
|
37
|
+
- [Forum Supergroups & Topics Management](#forum-supergroups--topics-management)
|
|
38
|
+
- [Bot API 10.3 Methods (Rich Messages, Drafts, Ephemeral Messages, Managed Access)](#bot-api-103-methods-rich-messages-drafts-ephemeral-messages-managed-access)
|
|
39
|
+
- [๐จ Rich Message & Layout Builder Suite (`RichMessage`)](#-rich-message--layout-builder-suite-richmessage)
|
|
40
|
+
- [Fluent Block Builder API](#fluent-block-builder-api)
|
|
41
|
+
- [Static Factory Methods](#static-factory-methods)
|
|
42
|
+
- [Complete Interactive Rich Card Example](#complete-interactive-rich-card-example)
|
|
43
|
+
- [๐ฆ Composer & Router Engine](#-composer--router-engine)
|
|
44
|
+
- [Event Filtering (`bot.on`)](#event-filtering-boton)
|
|
45
|
+
- [Slash Commands (`bot.command`)](#slash-commands-botcommand)
|
|
46
|
+
- [Text Pattern Matching (`bot.hears`)](#text-pattern-matching-bothears)
|
|
47
|
+
- [Button Callbacks (`bot.action`)](#button-callbacks-botaction)
|
|
48
|
+
- [Specialized Filters (Chat Types, Reactions, Boosts, Business, Forum)](#specialized-filters-chat-types-reactions-boosts-business-forum)
|
|
49
|
+
- [Control Flow (`filter`, `drop`, `branch`)](#control-flow-filter-drop-branch)
|
|
50
|
+
- [๐๏ธ Fluent Keyboard & Markup Builder (`Markup`)](#๏ธ-fluent-keyboard--markup-builder-markup)
|
|
51
|
+
- [Custom Reply Keyboards](#custom-reply-keyboards)
|
|
52
|
+
- [Inline Keyboards](#inline-keyboards)
|
|
53
|
+
- [Complete Button Builder Reference](#complete-button-builder-reference)
|
|
54
|
+
- [Removing Keyboards & Force Reply](#removing-keyboards--force-reply)
|
|
55
|
+
- [๐ฌ Asynchronous Conversations & Wizard Scenes](#-asynchronous-conversations--wizard-scenes)
|
|
56
|
+
- [Interactive Inline Prompts (`await ctx.prompt`)](#interactive-inline-prompts-await-ctxprompt)
|
|
57
|
+
- [Multi-Step Wizard Scenes (`WizardScene` & `Stage`)](#multi-step-wizard-scenes-wizardscene--stage)
|
|
58
|
+
- [๐พ Session & State Persistence](#-session--state-persistence)
|
|
59
|
+
- [Memory Session Store](#memory-session-store)
|
|
60
|
+
- [File Session Store](#file-session-store)
|
|
61
|
+
- [Custom Store Integration (Redis, MongoDB, PostgreSQL)](#custom-store-integration-redis-mongodb-postgresql)
|
|
62
|
+
- [๐ Internationalization & Localization (`I18n`)](#-internationalization--localization-i18n)
|
|
63
|
+
- [โ๏ธ Message Formatting (`fmt`, `html`, `mdv2`)](#๏ธ-message-formatting-fmt-html-mdv2)
|
|
64
|
+
- [XSS-Safe HTML Builder (`fmt` & `html`)](#xss-safe-html-builder-fmt--html)
|
|
65
|
+
- [MarkdownV2 Escaping Helpers (`mdv2`)](#markdownv2-escaping-helpers-mdv2)
|
|
66
|
+
- [๐ณ Payments, Invoices & Telegram Stars (`InvoiceBuilder`)](#-payments-invoices--telegram-stars-invoicebuilder)
|
|
67
|
+
- [๐ฑ Telegram Mini Apps / WebApps (`validateWebAppInitData`)](#-telegram-mini-apps--webapps-validatewebappinitdata)
|
|
68
|
+
- [๐ค Multi-Bot Process Manager (`TelegixManager`)](#-multi-bot-process-manager-telegixmanager)
|
|
69
|
+
- [โก Advanced Built-in Middlewares](#-advanced-built-in-middlewares)
|
|
70
|
+
- [Rate Limiter Middleware (`rateLimit`)](#rate-limiter-middleware-ratelimit)
|
|
71
|
+
- [Media Group / Album Batching (`albumMiddleware`)](#media-group--album-batching-albummiddleware)
|
|
72
|
+
- [Inline Query Debounce & Cache (`inlineDebounceMiddleware`)](#inline-query-debounce--cache-inlinedebouncemiddleware)
|
|
73
|
+
- [Automatic Chat Action (`chatActionMiddleware`)](#automatic-chat-action-chatactionmiddleware)
|
|
74
|
+
- [Inline Query Pagination (`paginateInlineQuery`)](#inline-query-pagination-paginateinlinequery)
|
|
75
|
+
- [๐ Complete Telegram API Client Method Reference (`bot.telegram` / `bot.api`)](#-complete-telegram-api-client-method-reference-bottelegram--botapi)
|
|
76
|
+
- [๐ฆ TypeScript Support](#-typescript-support)
|
|
77
|
+
- [๐งช Running Tests](#-running-tests)
|
|
78
|
+
- [๐ License](#-license)
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## ๐ Key Highlights
|
|
83
|
+
|
|
84
|
+
- **Pure JavaScript & Zero Runtime Dependencies**: Built entirely on native Web standards (`fetch`, `FormData`, `Blob`) with zero binary compilation and zero third-party packages.
|
|
85
|
+
- **Dual Module Architecture**: Full, native compatibility with modern **ESM (`import`)** and **CommonJS (`require`)**.
|
|
86
|
+
- **Complete Telegram Bot API 10.3 Compliance**: Built-in support for message drafts (`sendMessageDraft`, `sendRichMessageDraft`), ephemeral messages (`sendEphemeralMessage`), managed bot access settings (`getManagedBotAccessSettings`, `setManagedBotAccessSettings`), disabled buttons (`Markup.button.disabled`), and Telegram Stars (`XTR`).
|
|
87
|
+
- **Rich Message Builder Suite**: Fluent `RichMessage` API with structured blocks, headers, badges, quotes, code blocks, and automatic HTML fallback compilation.
|
|
88
|
+
- **Seamless Keyboard Normalization**: Pass `Markup.keyboard()` or `Markup.inlineKeyboard()` directly as the 2nd argument to `ctx.reply()` without manual JSON wrapping or extra payloads.
|
|
89
|
+
- **Asynchronous Inline Prompts**: Await user answers step-by-step with `const answer = await ctx.prompt('What is your name?')`.
|
|
90
|
+
- **Multi-Step Wizard Scenes**: Structured conversation flows with `WizardScene` and `Stage` for complex interactive state machines.
|
|
91
|
+
- **Pluggable Session Storage**: Includes `MemorySessionStore`, `FileSessionStore`, and custom adapter support for Redis, MongoDB, or SQL databases.
|
|
92
|
+
- **XSS-Safe Dynamic Formatting**: Tagged template literals with `fmt` and `html` prevent Telegram HTML parsing exceptions and script injection.
|
|
93
|
+
- **Multi-Bot Manager**: Run and orchestrate hundreds of bot tokens simultaneously inside a single Node.js process using `TelegixManager`.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## ๐ฆ Installation
|
|
98
|
+
|
|
99
|
+
Install Telegix using your preferred package manager:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# Using npm
|
|
103
|
+
npm install telegix
|
|
104
|
+
|
|
105
|
+
# Using pnpm
|
|
106
|
+
pnpm add telegix
|
|
107
|
+
|
|
108
|
+
# Using yarn
|
|
109
|
+
yarn add telegix
|
|
110
|
+
|
|
111
|
+
# Using bun
|
|
112
|
+
bun add telegix
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## ๐ Quick Start Guide
|
|
118
|
+
|
|
119
|
+
### ECMAScript Modules (ESM)
|
|
120
|
+
|
|
121
|
+
Create a file named `bot.mjs` (or set `"type": "module"` in your `package.json`):
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
import { Telegix, Markup, RichMessage, fmt, html } from 'telegix';
|
|
125
|
+
|
|
126
|
+
const bot = new Telegix(process.env.BOT_TOKEN || 'YOUR_TELEGRAM_BOT_TOKEN');
|
|
127
|
+
|
|
128
|
+
// 1. Slash Command: /start
|
|
129
|
+
bot.command('start', async (ctx) => {
|
|
130
|
+
const name = ctx.from?.first_name || 'there';
|
|
131
|
+
await ctx.reply(
|
|
132
|
+
fmt`Hello, <b>${name}</b>! Welcome to <b>Telegix</b> โก`,
|
|
133
|
+
{ parse_mode: 'HTML' }
|
|
134
|
+
);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// 2. Custom Reply Keyboard: /menu
|
|
138
|
+
bot.command('menu', async (ctx) => {
|
|
139
|
+
const replyKeyboard = Markup.keyboard([
|
|
140
|
+
['โ Coffee', '๐ Pizza'],
|
|
141
|
+
['๐ Status', 'โ๏ธ Settings'],
|
|
142
|
+
]).resize();
|
|
143
|
+
|
|
144
|
+
await ctx.reply('Please choose an option from the keyboard below:', replyKeyboard);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// 3. Inline Keyboard & Disabled Button (Bot API 10.3)
|
|
148
|
+
bot.command('order', async (ctx) => {
|
|
149
|
+
const inlineMenu = Markup.inlineKeyboard([
|
|
150
|
+
[
|
|
151
|
+
Markup.button.callback('Margherita ($10)', 'pizza_margherita'),
|
|
152
|
+
Markup.button.callback('Pepperoni ($12)', 'pizza_pepperoni'),
|
|
153
|
+
],
|
|
154
|
+
[
|
|
155
|
+
Markup.button.url('๐ View Full Menu', 'https://example.com/menu'),
|
|
156
|
+
Markup.button.disabled('๐ Truffle (Sold Out)'),
|
|
157
|
+
],
|
|
158
|
+
]);
|
|
159
|
+
|
|
160
|
+
await ctx.reply('Select your pizza:', inlineMenu);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// 4. Handle Inline Button Callbacks
|
|
164
|
+
bot.action(/^pizza_(.+)$/, async (ctx) => {
|
|
165
|
+
const selectedPizza = ctx.match[1];
|
|
166
|
+
await ctx.answerCallbackQuery(`Added ${selectedPizza} to your cart!`);
|
|
167
|
+
await ctx.editMessageText(
|
|
168
|
+
`โ
You selected: <b>${selectedPizza.toUpperCase()}</b>\nThank you for ordering!`,
|
|
169
|
+
{ parse_mode: 'HTML' }
|
|
170
|
+
);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// 5. Catch-All Text Messages with Reactions
|
|
174
|
+
bot.on('message:text', async (ctx) => {
|
|
175
|
+
await ctx.react('๐');
|
|
176
|
+
await ctx.reply(`You said: "${ctx.text}"`);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Launch the bot with Long-Polling
|
|
180
|
+
bot.launch().then(() => {
|
|
181
|
+
console.log('๐ค Bot is online and listening for updates!');
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### CommonJS (CJS)
|
|
186
|
+
|
|
187
|
+
Create a file named `bot.js`:
|
|
188
|
+
|
|
189
|
+
```javascript
|
|
190
|
+
const { Telegix, Markup } = require('telegix');
|
|
191
|
+
|
|
192
|
+
const bot = new Telegix(process.env.BOT_TOKEN || 'YOUR_TELEGRAM_BOT_TOKEN');
|
|
193
|
+
|
|
194
|
+
bot.command('start', (ctx) => ctx.reply('Hello from Telegix CommonJS!'));
|
|
195
|
+
|
|
196
|
+
bot.launch().then(() => {
|
|
197
|
+
console.log('๐ค Bot is online!');
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## ๐๏ธ Bot Core & Lifecycle
|
|
204
|
+
|
|
205
|
+
### Initialization & Configuration Options
|
|
206
|
+
|
|
207
|
+
The `Telegix` constructor accepts the bot token as its first parameter and an optional configuration object:
|
|
208
|
+
|
|
209
|
+
```javascript
|
|
210
|
+
import { Telegix } from 'telegix';
|
|
211
|
+
|
|
212
|
+
const bot = new Telegix('123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11', {
|
|
213
|
+
apiRoot: 'https://api.telegram.org', // Custom Bot API server URL (e.g. self-hosted server)
|
|
214
|
+
testEnv: false, // Connect to Telegram test environment
|
|
215
|
+
timeout: 60000, // Network HTTP request timeout in ms (default: 60000)
|
|
216
|
+
autoRetry: true, // Automatically retry after 429 Too Many Requests (default: true)
|
|
217
|
+
handlerTimeout: 90000, // Timeout in ms for update middleware execution
|
|
218
|
+
polling: {
|
|
219
|
+
timeout: 30, // Long-polling timeout in seconds (default: 30)
|
|
220
|
+
limit: 100, // Maximum updates to retrieve per polling request (default: 100)
|
|
221
|
+
allowedUpdates: [ // List of update types to receive
|
|
222
|
+
'message',
|
|
223
|
+
'edited_message',
|
|
224
|
+
'channel_post',
|
|
225
|
+
'edited_channel_post',
|
|
226
|
+
'business_connection',
|
|
227
|
+
'business_message',
|
|
228
|
+
'edited_business_message',
|
|
229
|
+
'deleted_business_messages',
|
|
230
|
+
'message_reaction',
|
|
231
|
+
'message_reaction_count',
|
|
232
|
+
'inline_query',
|
|
233
|
+
'chosen_inline_result',
|
|
234
|
+
'callback_query',
|
|
235
|
+
'shipping_query',
|
|
236
|
+
'pre_checkout_query',
|
|
237
|
+
'poll',
|
|
238
|
+
'poll_answer',
|
|
239
|
+
'my_chat_member',
|
|
240
|
+
'chat_member',
|
|
241
|
+
'chat_join_request',
|
|
242
|
+
'chat_boost',
|
|
243
|
+
'removed_chat_boost',
|
|
244
|
+
],
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Fetching Bot Info with `getMe()`
|
|
250
|
+
|
|
251
|
+
`getMe()` retrieves basic information about the bot in the form of a Telegram `User` object. You can call it directly on `bot.telegram` or through the `ctx` context inside any update:
|
|
252
|
+
|
|
253
|
+
```javascript
|
|
254
|
+
// 1. Direct fetch before or outside update handling:
|
|
255
|
+
const botInfo = await bot.telegram.getMe();
|
|
256
|
+
console.log(`Bot Account: @${botInfo.username} (ID: ${botInfo.id})`);
|
|
257
|
+
console.log(`Can join groups: ${botInfo.can_join_groups}`);
|
|
258
|
+
console.log(`Can read all group messages: ${botInfo.can_read_all_group_messages}`);
|
|
259
|
+
console.log(`Supports inline queries: ${botInfo.supports_inline_queries}`);
|
|
260
|
+
|
|
261
|
+
// 2. Fetch inside any middleware or command handler:
|
|
262
|
+
bot.command('whoami', async (ctx) => {
|
|
263
|
+
const me = await ctx.getMe();
|
|
264
|
+
await ctx.reply(
|
|
265
|
+
`๐ค <b>Bot Details:</b>\n` +
|
|
266
|
+
`โข Name: ${me.first_name}\n` +
|
|
267
|
+
`โข Username: @${me.username}\n` +
|
|
268
|
+
`โข Bot ID: <code>${me.id}</code>`,
|
|
269
|
+
{ parse_mode: 'HTML' }
|
|
270
|
+
);
|
|
271
|
+
});
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Long-Polling Mode
|
|
275
|
+
|
|
276
|
+
Start, monitor, and stop the long-polling lifecycle:
|
|
277
|
+
|
|
278
|
+
```javascript
|
|
279
|
+
// Launch long-polling
|
|
280
|
+
await bot.launch({
|
|
281
|
+
dropPendingUpdates: true, // Drop updates accumulated while bot was offline
|
|
282
|
+
allowedUpdates: ['message', 'callback_query'],
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
// Manual polling controls
|
|
286
|
+
await bot.startPolling({ timeout: 30 });
|
|
287
|
+
|
|
288
|
+
// Gracefully stop the bot on process termination
|
|
289
|
+
process.once('SIGINT', () => bot.stop('SIGINT'));
|
|
290
|
+
process.once('SIGTERM', () => bot.stop('SIGTERM'));
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Webhook Mode (Node.js HTTP, Express, Fastify, Serverless)
|
|
294
|
+
|
|
295
|
+
Use `createWebhookCallback()` to create a request handler compatible with all standard Node.js server frameworks:
|
|
296
|
+
|
|
297
|
+
#### Native Node.js `http` / `https`
|
|
298
|
+
```javascript
|
|
299
|
+
import http from 'node:http';
|
|
300
|
+
import { Telegix, createWebhookCallback } from 'telegix';
|
|
301
|
+
|
|
302
|
+
const bot = new Telegix(process.env.BOT_TOKEN);
|
|
303
|
+
const secretToken = 'my_super_secret_webhook_token';
|
|
304
|
+
|
|
305
|
+
// Set the webhook with Telegram
|
|
306
|
+
await bot.telegram.setWebhook('https://my-domain.com/webhook', {
|
|
307
|
+
secret_token: secretToken,
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
const server = http.createServer(
|
|
311
|
+
createWebhookCallback(bot, {
|
|
312
|
+
path: '/webhook',
|
|
313
|
+
secretToken: secretToken,
|
|
314
|
+
})
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
server.listen(3000, () => {
|
|
318
|
+
console.log('Webhook server running on port 3000');
|
|
319
|
+
});
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
#### Express.js
|
|
323
|
+
```javascript
|
|
324
|
+
import express from 'express';
|
|
325
|
+
import { Telegix, createWebhookCallback } from 'telegix';
|
|
326
|
+
|
|
327
|
+
const app = express();
|
|
328
|
+
const bot = new Telegix(process.env.BOT_TOKEN);
|
|
329
|
+
|
|
330
|
+
app.use(express.json());
|
|
331
|
+
app.post('/webhook', createWebhookCallback(bot, { secretToken: process.env.WEBHOOK_SECRET }));
|
|
332
|
+
|
|
333
|
+
app.listen(3000);
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Multi-Core Cluster Mode
|
|
337
|
+
|
|
338
|
+
Scale your bot horizontally across all CPU cores on a multi-core server:
|
|
339
|
+
|
|
340
|
+
```javascript
|
|
341
|
+
import { Telegix } from 'telegix';
|
|
342
|
+
|
|
343
|
+
const bot = new Telegix(process.env.BOT_TOKEN);
|
|
344
|
+
|
|
345
|
+
// Spawn a worker for each CPU core automatically
|
|
346
|
+
if (bot.cluster()) {
|
|
347
|
+
// Primary process manages child worker lifecycles
|
|
348
|
+
} else {
|
|
349
|
+
// Worker process handles bot updates
|
|
350
|
+
bot.command('ping', (ctx) => ctx.reply(`Pong from worker ${process.pid}!`));
|
|
351
|
+
bot.launch();
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Error Handling & `bot.catch()`
|
|
356
|
+
|
|
357
|
+
Catch and handle uncaught errors gracefully across all middlewares:
|
|
358
|
+
|
|
359
|
+
```javascript
|
|
360
|
+
import { TelegramError } from 'telegix';
|
|
361
|
+
|
|
362
|
+
bot.catch((err, ctx) => {
|
|
363
|
+
console.error(`Error occurred while handling update ${ctx.update.update_id}:`, err);
|
|
364
|
+
|
|
365
|
+
if (err instanceof TelegramError) {
|
|
366
|
+
console.error(`Telegram API Error [${err.errorCode}]: ${err.description}`);
|
|
367
|
+
if (err.parameters?.retry_after) {
|
|
368
|
+
console.warn(`Rate limit retry after: ${err.parameters.retry_after}s`);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Attempt to notify user if possible
|
|
373
|
+
ctx.reply('โ ๏ธ An unexpected error occurred while processing your request.').catch(() => {});
|
|
374
|
+
});
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## ๐ ๏ธ Context (`ctx`) Reference & Functions
|
|
380
|
+
|
|
381
|
+
Every middleware, command, and event handler receives a `Context` instance (`ctx`) encapsulating the current update and providing dozens of helper methods.
|
|
382
|
+
|
|
383
|
+
### Context Properties & Getters
|
|
384
|
+
|
|
385
|
+
| Property / Getter | Type | Description |
|
|
386
|
+
|---|---|---|
|
|
387
|
+
| `ctx.update` | `object` | The raw Telegram Update object received from Telegram Bot API. |
|
|
388
|
+
| `ctx.updateType` | `string` | The primary update type (e.g., `'message'`, `'callback_query'`, `'chat_boost'`). |
|
|
389
|
+
| `ctx.updateSubtypes` | `string[]` | Subtype classifications (e.g., `['text']`, `['photo']`, `['pinned_message']`). |
|
|
390
|
+
| `ctx.botInfo` | `object` | The cached `User` object of this bot. |
|
|
391
|
+
| `ctx.telegram` / `ctx.api` | `Telegram` | The low-level Telegram API client instance. |
|
|
392
|
+
| `ctx.state` | `object` | Clean per-update state dictionary to share data between middlewares. |
|
|
393
|
+
| `ctx.session` | `object` | Persistent session object (when `session()` middleware is enabled). |
|
|
394
|
+
| `ctx.message` / `ctx.msg` | `object\|null` | Shortcut to incoming Message (or edited message, channel post, business message). |
|
|
395
|
+
| `ctx.chat` | `object\|null` | The `Chat` object associated with the current update. |
|
|
396
|
+
| `ctx.chatId` | `number\|string` | ID of the current chat. |
|
|
397
|
+
| `ctx.from` | `object\|null` | The `User` object of the sender. |
|
|
398
|
+
| `ctx.userId` | `number` | ID of the sender user. |
|
|
399
|
+
| `ctx.text` | `string\|null` | Text content of the current message. |
|
|
400
|
+
| `ctx.callbackQuery` | `object\|null` | CallbackQuery object if this update is a button callback. |
|
|
401
|
+
| `ctx.inlineQuery` | `object\|null` | InlineQuery object if this update is an inline query. |
|
|
402
|
+
| `ctx.match` | `RegExpMatchArray` | Regex match results when triggered via `bot.hears()` or `bot.action()`. |
|
|
403
|
+
| `ctx.payload` | `string` | Command arguments payload after a slash command (e.g. `/ban 123` -> `'123'`). |
|
|
404
|
+
| `ctx.isForum` | `boolean` | `true` if the current chat is a forum supergroup. |
|
|
405
|
+
| `ctx.topicId` | `number\|null` | Forum thread ID / Message Thread ID if inside a forum topic. |
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
### Text & HTML / Markdown Replies
|
|
410
|
+
|
|
411
|
+
```javascript
|
|
412
|
+
// Plain text reply
|
|
413
|
+
await ctx.reply('Hello, World!');
|
|
414
|
+
|
|
415
|
+
// HTML formatted reply
|
|
416
|
+
await ctx.replyWithHTML('<b>Bold</b>, <i>Italic</i>, <code>Code</code>, <a href="https://telegix.dev">Link</a>');
|
|
417
|
+
|
|
418
|
+
// Markdown formatted reply
|
|
419
|
+
await ctx.replyWithMarkdown('*Bold text*, _Italic text_, `Code`');
|
|
420
|
+
|
|
421
|
+
// MarkdownV2 formatted reply
|
|
422
|
+
await ctx.replyWithMarkdownV2('*Bold* and _Italic_ and ||Spoiler||');
|
|
423
|
+
|
|
424
|
+
// Reply with additional options and keyboard
|
|
425
|
+
await ctx.reply('Choose an option:', {
|
|
426
|
+
parse_mode: 'HTML',
|
|
427
|
+
reply_to_message_id: ctx.message?.message_id,
|
|
428
|
+
reply_markup: Markup.inlineKeyboard([
|
|
429
|
+
[Markup.button.callback('Option 1', 'opt_1')],
|
|
430
|
+
]),
|
|
431
|
+
});
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
### Media Sending Functions (Photos, Audio, Videos, Documents, Albums)
|
|
437
|
+
|
|
438
|
+
```javascript
|
|
439
|
+
// 1. Send Photo (by URL, File ID, Blob, or Buffer)
|
|
440
|
+
await ctx.replyWithPhoto('https://example.com/image.jpg', {
|
|
441
|
+
caption: '๐
Beautiful sunset in HTML: <b>Nature</b>',
|
|
442
|
+
parse_mode: 'HTML',
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
// 2. Send Audio File
|
|
446
|
+
await ctx.replyWithAudio('https://example.com/song.mp3', {
|
|
447
|
+
title: 'Track Title',
|
|
448
|
+
performer: 'Artist Name',
|
|
449
|
+
caption: '๐ต Enjoy the music!',
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
// 3. Send Document / File
|
|
453
|
+
await ctx.replyWithDocument('https://example.com/manual.pdf', {
|
|
454
|
+
caption: '๐ User Manual PDF',
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
// 4. Send Video
|
|
458
|
+
await ctx.replyWithVideo('https://example.com/clip.mp4', {
|
|
459
|
+
caption: '๐ฌ Video Showcase',
|
|
460
|
+
supports_streaming: true,
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
// 5. Send Animation / GIF
|
|
464
|
+
await ctx.replyWithAnimation('https://example.com/cheers.gif');
|
|
465
|
+
|
|
466
|
+
// 6. Send Voice Note (.ogg audio)
|
|
467
|
+
await ctx.replyWithVoice('https://example.com/voice.ogg');
|
|
468
|
+
|
|
469
|
+
// 7. Send Video Note (Round video message)
|
|
470
|
+
await ctx.replyWithVideoNote('https://example.com/round_video.mp4');
|
|
471
|
+
|
|
472
|
+
// 8. Send Media Group / Photo Album
|
|
473
|
+
await ctx.replyWithMediaGroup([
|
|
474
|
+
{ type: 'photo', media: 'https://example.com/photo1.jpg', caption: 'Photo 1' },
|
|
475
|
+
{ type: 'photo', media: 'https://example.com/photo2.jpg' },
|
|
476
|
+
{ type: 'video', media: 'https://example.com/video1.mp4' },
|
|
477
|
+
]);
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
---
|
|
481
|
+
|
|
482
|
+
### Interactive Messages (Polls, Locations, Venues, Contacts, Dice, Stickers, Games)
|
|
483
|
+
|
|
484
|
+
```javascript
|
|
485
|
+
// 1. Send Location (Latitude, Longitude)
|
|
486
|
+
await ctx.replyWithLocation(37.7749, -122.4194);
|
|
487
|
+
|
|
488
|
+
// 2. Send Venue
|
|
489
|
+
await ctx.replyWithVenue(37.7749, -122.4194, 'San Francisco City Hall', '1 Dr Carlton B Goodlett Pl');
|
|
490
|
+
|
|
491
|
+
// 3. Send Contact Card
|
|
492
|
+
await ctx.replyWithContact('+1234567890', 'John', { last_name: 'Doe' });
|
|
493
|
+
|
|
494
|
+
// 4. Send Poll or Quiz
|
|
495
|
+
await ctx.replyWithPoll(
|
|
496
|
+
'Which database do you prefer?',
|
|
497
|
+
['PostgreSQL', 'Redis', 'MongoDB', 'SQLite'],
|
|
498
|
+
{
|
|
499
|
+
is_anonymous: false,
|
|
500
|
+
allows_multiple_answers: true,
|
|
501
|
+
}
|
|
502
|
+
);
|
|
503
|
+
|
|
504
|
+
// 5. Send Animated Dice (๐ฒ, ๐ฏ, ๐, โฝ, ๐ฐ, ๐ณ)
|
|
505
|
+
await ctx.replyWithDice({ emoji: '๐ฏ' });
|
|
506
|
+
|
|
507
|
+
// 6. Send Sticker
|
|
508
|
+
await ctx.replyWithSticker('CAACAgIAAxkBAAE...');
|
|
509
|
+
|
|
510
|
+
// 7. Send Telegram Game
|
|
511
|
+
await ctx.replyWithGame('my_telegix_game');
|
|
512
|
+
|
|
513
|
+
// 8. Send Paid Media (Telegram Stars)
|
|
514
|
+
await ctx.replyWithPaidMedia(25, [
|
|
515
|
+
{ type: 'photo', media: 'https://example.com/exclusive_art.jpg' }
|
|
516
|
+
]);
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
---
|
|
520
|
+
|
|
521
|
+
### Message Reactions & Chat Actions
|
|
522
|
+
|
|
523
|
+
```javascript
|
|
524
|
+
// Add an emoji reaction to the current message
|
|
525
|
+
await ctx.react('โค๏ธ');
|
|
526
|
+
await ctx.react('๐ฅ');
|
|
527
|
+
|
|
528
|
+
// Send chat action indicators ('typing', 'upload_photo', 'record_video', 'upload_document', etc.)
|
|
529
|
+
await ctx.replyWithChatAction('typing');
|
|
530
|
+
await ctx.replyWithChatAction('upload_document');
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
---
|
|
534
|
+
|
|
535
|
+
### Message Editing, Deleting, Forwarding, Copying, & Pinning
|
|
536
|
+
|
|
537
|
+
```javascript
|
|
538
|
+
// 1. Edit current message text
|
|
539
|
+
await ctx.editMessageText('Updated text content', { parse_mode: 'HTML' });
|
|
540
|
+
|
|
541
|
+
// 2. Edit current message caption
|
|
542
|
+
await ctx.editMessageCaption('Updated media caption');
|
|
543
|
+
|
|
544
|
+
// 3. Edit current message reply markup
|
|
545
|
+
await ctx.editMessageReplyMarkup(
|
|
546
|
+
Markup.inlineKeyboard([[Markup.button.callback('New Option', 'opt_new')]])
|
|
547
|
+
);
|
|
548
|
+
|
|
549
|
+
// 4. Delete messages
|
|
550
|
+
await ctx.deleteMessage(); // Deletes current incoming message
|
|
551
|
+
await ctx.deleteMessage(targetMessageId);
|
|
552
|
+
await ctx.deleteMessages([msgId1, msgId2, msgId3]);
|
|
553
|
+
|
|
554
|
+
// 5. Forward or Copy messages to another chat
|
|
555
|
+
await ctx.forwardMessage(targetChatId);
|
|
556
|
+
await ctx.copyMessage(targetChatId);
|
|
557
|
+
|
|
558
|
+
// 6. Pin / Unpin messages
|
|
559
|
+
await ctx.pinChatMessage();
|
|
560
|
+
await ctx.unpinChatMessage();
|
|
561
|
+
await ctx.unpinAllChatMessages();
|
|
562
|
+
|
|
563
|
+
// 7. Answer Callback Query
|
|
564
|
+
await ctx.answerCallbackQuery('Action confirmed!', { show_alert: false });
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
---
|
|
568
|
+
|
|
569
|
+
### Chat Administration & Member Moderation
|
|
570
|
+
|
|
571
|
+
```javascript
|
|
572
|
+
// Get Chat Details & Administrators
|
|
573
|
+
const chat = await ctx.getChat();
|
|
574
|
+
const admins = await ctx.getChatAdministrators();
|
|
575
|
+
|
|
576
|
+
// Get Member Info & Total Member Count
|
|
577
|
+
const member = await ctx.getChatMember(targetUserId);
|
|
578
|
+
const count = await ctx.getChatMembersCount();
|
|
579
|
+
|
|
580
|
+
// Ban / Kick Member
|
|
581
|
+
await ctx.banChatMember(targetUserId, {
|
|
582
|
+
until_date: Math.floor(Date.now() / 1000) + 86400, // 24 hours ban
|
|
583
|
+
revoke_messages: true,
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
// Unban Member
|
|
587
|
+
await ctx.unbanChatMember(targetUserId, { only_if_banned: true });
|
|
588
|
+
|
|
589
|
+
// Restrict Permissions
|
|
590
|
+
await ctx.restrictChatMember(targetUserId, {
|
|
591
|
+
can_send_messages: false,
|
|
592
|
+
can_send_media_messages: false,
|
|
593
|
+
can_send_other_messages: false,
|
|
594
|
+
can_add_web_page_previews: false,
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
// Promote Member to Administrator
|
|
598
|
+
await ctx.promoteChatMember(targetUserId, {
|
|
599
|
+
can_change_info: true,
|
|
600
|
+
can_delete_messages: true,
|
|
601
|
+
can_invite_users: true,
|
|
602
|
+
can_pin_messages: true,
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
// Manage Chat Info
|
|
606
|
+
await ctx.setChatTitle('New Group Title');
|
|
607
|
+
await ctx.setChatDescription('Updated group description.');
|
|
608
|
+
await ctx.leaveChat();
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
---
|
|
612
|
+
|
|
613
|
+
### Forum Supergroups & Topics Management
|
|
614
|
+
|
|
615
|
+
```javascript
|
|
616
|
+
// Check if the current chat is a forum supergroup
|
|
617
|
+
if (ctx.isForum) {
|
|
618
|
+
console.log('Current forum thread ID:', ctx.topicId);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// Create a new topic in a forum supergroup
|
|
622
|
+
const topic = await ctx.createForumTopic('๐ Development Updates', {
|
|
623
|
+
icon_color: 0x6FB9F0,
|
|
624
|
+
icon_custom_emoji_id: '5312345678901234567',
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
// Edit, Close, Reopen, or Delete Topics
|
|
628
|
+
await ctx.editForumTopic(ctx.topicId, { name: '๐ Archived Updates' });
|
|
629
|
+
await ctx.closeForumTopic(ctx.topicId);
|
|
630
|
+
await ctx.reopenForumTopic(ctx.topicId);
|
|
631
|
+
await ctx.deleteForumTopic(ctx.topicId);
|
|
632
|
+
await ctx.unpinAllForumTopicMessages(ctx.topicId);
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
---
|
|
636
|
+
|
|
637
|
+
### Bot API 10.3 Methods (Rich Messages, Drafts, Ephemeral Messages, Managed Access)
|
|
638
|
+
|
|
639
|
+
```javascript
|
|
640
|
+
import { RichMessage, Markup } from 'telegix';
|
|
641
|
+
|
|
642
|
+
// 1. Send Rich Message (structured layout blocks with automatic fallback)
|
|
643
|
+
const card = RichMessage.card('โก Server Health Check', 'All systems operational.')
|
|
644
|
+
.header('Cluster Status', '๐ข')
|
|
645
|
+
.badge('CPU Load', '14%')
|
|
646
|
+
.badge('Memory', '1.2 GB / 8.0 GB')
|
|
647
|
+
.list(['Node 1: Online', 'Node 2: Online', 'Node 3: Standby'])
|
|
648
|
+
.expandableQuote('Rich messages provide structured block layouts.')
|
|
649
|
+
.row(
|
|
650
|
+
Markup.button.callback('๐ Refresh', 'refresh_stats'),
|
|
651
|
+
Markup.button.disabled('๐ Advanced Tuning')
|
|
652
|
+
);
|
|
653
|
+
|
|
654
|
+
await ctx.replyWithRichMessage(card);
|
|
655
|
+
|
|
656
|
+
// 2. Edit existing message with Rich Message
|
|
657
|
+
await ctx.editRichMessageText(card);
|
|
658
|
+
|
|
659
|
+
// 3. Send Rich Message Draft
|
|
660
|
+
await ctx.sendRichMessageDraft(card);
|
|
661
|
+
|
|
662
|
+
// 4. Send Message Draft (Real-time draft displayed directly in user client)
|
|
663
|
+
await ctx.sendMessageDraft('Bot is currently preparing your report...');
|
|
664
|
+
|
|
665
|
+
// 5. Send Ephemeral Message (Message with automated lifetime)
|
|
666
|
+
await ctx.sendEphemeralMessage('This message will automatically vanish in 15 seconds.', 15);
|
|
667
|
+
|
|
668
|
+
// 6. Managed Bot Access Settings (Bot API 10.3)
|
|
669
|
+
const accessSettings = await ctx.getManagedBotAccessSettings(adminUserId);
|
|
670
|
+
await ctx.setManagedBotAccessSettings({ allow_admin_override: true }, adminUserId);
|
|
671
|
+
|
|
672
|
+
// 7. Get User Personal Chat Messages
|
|
673
|
+
const messages = await ctx.getUserPersonalChatMessages(targetUserId);
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
---
|
|
677
|
+
|
|
678
|
+
## ๐จ Rich Message & Layout Builder Suite (`RichMessage`)
|
|
679
|
+
|
|
680
|
+
The `RichMessage` class allows you to construct modern, structured card layouts, dashboards, and rich messages using a fluent chaining syntax.
|
|
681
|
+
|
|
682
|
+
### Fluent Block Builder API
|
|
683
|
+
|
|
684
|
+
| Builder Method | Description |
|
|
685
|
+
|---|---|
|
|
686
|
+
| `.header(text, emoji?)` | Adds a prominent header block with an optional leading emoji. |
|
|
687
|
+
| `.paragraph(text)` | Adds a body paragraph block. |
|
|
688
|
+
| `.bold(text)` / `.italic(text)` | Adds bold or italic styled text blocks. |
|
|
689
|
+
| `.underline(text)` / `.strikethrough(text)` | Adds underlined or struck-through text blocks. |
|
|
690
|
+
| `.code(codeText, language?)` | Adds inline or syntax-highlighted multiline code blocks. |
|
|
691
|
+
| `.quote(text, expandable?)` | Adds a standard or expandable Telegram blockquote. |
|
|
692
|
+
| `.expandableQuote(text)` | Shortcut to add an expandable blockquote. |
|
|
693
|
+
| `.spoiler(text)` | Adds tap-to-reveal spoiler formatted text. |
|
|
694
|
+
| `.link(text, url)` | Adds a formatted hyperlink. |
|
|
695
|
+
| `.mention(text, userId)` | Adds an inline mention link for a Telegram user ID. |
|
|
696
|
+
| `.list(items, bullet?)` | Formats an array of strings into a bulleted list. |
|
|
697
|
+
| `.numberedList(items)` | Formats an array of strings into a numbered list (1., 2., 3.). |
|
|
698
|
+
| `.badge(label, value, icon?)` | Adds a key-value metric badge item. |
|
|
699
|
+
| `.divider()` | Inserts a clean visual separator line. |
|
|
700
|
+
| `.row(...buttons)` | Appends a row of inline keyboard buttons. |
|
|
701
|
+
| `.callback(text, data)` | Appends an inline callback query button. |
|
|
702
|
+
| `.url(text, url)` | Appends an external URL link button. |
|
|
703
|
+
| `.disabled(text)` | Appends a non-clickable disabled button (Bot API 10.3). |
|
|
704
|
+
| `.ephemeral(seconds)` | Sets message lifetime parameter for auto-expiration. |
|
|
705
|
+
| `.draftId(id?)` / `.asDraft()` | Configures the rich message as a real-time message draft. |
|
|
706
|
+
| `.compile()` / `.build()` | Compiles all blocks into a Telegram-ready payload object. |
|
|
707
|
+
| `.send(ctx)` | Sends the rich message using the active context. |
|
|
708
|
+
| `.edit(ctx)` | Edits an existing message with this rich message. |
|
|
709
|
+
|
|
710
|
+
### Static Factory Methods
|
|
711
|
+
|
|
712
|
+
```javascript
|
|
713
|
+
import { RichMessage } from 'telegix';
|
|
714
|
+
|
|
715
|
+
// Create a blank builder
|
|
716
|
+
const msg = RichMessage.create('Optional initial text');
|
|
717
|
+
|
|
718
|
+
// Create a pre-structured Card
|
|
719
|
+
const card = RichMessage.card('Card Title', 'Card Description', [
|
|
720
|
+
Markup.button.callback('Click Me', 'btn_1'),
|
|
721
|
+
]);
|
|
722
|
+
|
|
723
|
+
// Create a Draft Message
|
|
724
|
+
const draft = RichMessage.draft('Drafting text...', 12345);
|
|
725
|
+
|
|
726
|
+
// Create an Ephemeral Message
|
|
727
|
+
const expiring = RichMessage.ephemeral('Expiring note', 30);
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
### Complete Interactive Rich Card Example
|
|
731
|
+
|
|
732
|
+
```javascript
|
|
733
|
+
import { Telegix, Markup, RichMessage } from 'telegix';
|
|
734
|
+
|
|
735
|
+
const bot = new Telegix(process.env.BOT_TOKEN);
|
|
736
|
+
|
|
737
|
+
bot.command('dashboard', async (ctx) => {
|
|
738
|
+
const dashboard = RichMessage.card('โก Infrastructure Dashboard', 'Live metrics from production cluster:')
|
|
739
|
+
.header('Cluster Status', '๐ข')
|
|
740
|
+
.badge('CPU Utilization', '28.4%', '๐ป')
|
|
741
|
+
.badge('RAM Usage', '3.8 GB / 16.0 GB', '๐ง ')
|
|
742
|
+
.badge('Active Connections', '1,420', '๐')
|
|
743
|
+
.badge('Error Rate', '0.002%', '๐ก๏ธ')
|
|
744
|
+
.divider()
|
|
745
|
+
.header('Active Worker Nodes', '๐ฅ๏ธ')
|
|
746
|
+
.list([
|
|
747
|
+
'worker-ap-southeast-1a: Healthy (0.12 load)',
|
|
748
|
+
'worker-ap-southeast-1b: Healthy (0.15 load)',
|
|
749
|
+
'worker-ap-southeast-1c: Standby',
|
|
750
|
+
])
|
|
751
|
+
.divider()
|
|
752
|
+
.expandableQuote('Auto-scaling policy is currently enabled. Additional instances will spawn if CPU exceeds 75%.')
|
|
753
|
+
.code('curl -s https://api.cluster.internal/v1/health | jq', 'bash')
|
|
754
|
+
.row(
|
|
755
|
+
Markup.button.callback('๐ Refresh Data', 'refresh_metrics'),
|
|
756
|
+
Markup.button.url('๐ Grafana', 'https://grafana.example.com')
|
|
757
|
+
)
|
|
758
|
+
.row(
|
|
759
|
+
Markup.button.disabled('๐ Deploy Patch (Admin Only)')
|
|
760
|
+
);
|
|
761
|
+
|
|
762
|
+
await ctx.replyWithRichMessage(dashboard);
|
|
763
|
+
});
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
---
|
|
767
|
+
|
|
768
|
+
## ๐ฆ Composer & Router Engine
|
|
769
|
+
|
|
770
|
+
`Composer` powers the routing and middleware pipeline in Telegix.
|
|
771
|
+
|
|
772
|
+
### Event Filtering (`bot.on`)
|
|
773
|
+
|
|
774
|
+
Filter and intercept incoming updates by type and subtype:
|
|
775
|
+
|
|
776
|
+
```javascript
|
|
777
|
+
// Text messages
|
|
778
|
+
bot.on('message:text', async (ctx) => { ... });
|
|
779
|
+
|
|
780
|
+
// Photos, Audios, Documents, Videos
|
|
781
|
+
bot.on('message:photo', async (ctx) => { ... });
|
|
782
|
+
bot.on('message:audio', async (ctx) => { ... });
|
|
783
|
+
bot.on('message:document', async (ctx) => { ... });
|
|
784
|
+
bot.on('message:video', async (ctx) => { ... });
|
|
785
|
+
|
|
786
|
+
// Service messages
|
|
787
|
+
bot.on('message:new_chat_members', async (ctx) => { ... });
|
|
788
|
+
bot.on('message:left_chat_member', async (ctx) => { ... });
|
|
789
|
+
bot.on('message:pinned_message', async (ctx) => { ... });
|
|
790
|
+
|
|
791
|
+
// Channel Posts
|
|
792
|
+
bot.on('channel_post:text', async (ctx) => { ... });
|
|
793
|
+
|
|
794
|
+
// Inline Queries & Results
|
|
795
|
+
bot.on('inline_query', async (ctx) => { ... });
|
|
796
|
+
bot.on('chosen_inline_result', async (ctx) => { ... });
|
|
797
|
+
|
|
798
|
+
// Reactions & Boosts
|
|
799
|
+
bot.on('message_reaction', async (ctx) => { ... });
|
|
800
|
+
bot.on('chat_boost', async (ctx) => { ... });
|
|
801
|
+
|
|
802
|
+
// Listen to multiple event types at once
|
|
803
|
+
bot.on(['message:voice', 'message:video_note'], async (ctx) => { ... });
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
---
|
|
807
|
+
|
|
808
|
+
### Slash Commands (`bot.command`)
|
|
809
|
+
|
|
810
|
+
Handles slash commands and parses command arguments into `ctx.payload`:
|
|
811
|
+
|
|
812
|
+
```javascript
|
|
813
|
+
// Matches /start
|
|
814
|
+
bot.command('start', async (ctx) => {
|
|
815
|
+
await ctx.reply('Welcome!');
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
// Matches /ban <userId> <reason>
|
|
819
|
+
bot.command('ban', async (ctx) => {
|
|
820
|
+
const [targetId, ...reasonParts] = ctx.payload.split(' ');
|
|
821
|
+
const reason = reasonParts.join(' ');
|
|
822
|
+
await ctx.reply(`Banning user ${targetId} for reason: ${reason}`);
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
// Matches multiple commands simultaneously
|
|
826
|
+
bot.command(['help', 'info', 'guide'], async (ctx) => {
|
|
827
|
+
await ctx.reply('Help documentation...');
|
|
828
|
+
});
|
|
829
|
+
```
|
|
830
|
+
|
|
831
|
+
---
|
|
832
|
+
|
|
833
|
+
### Text Pattern Matching (`bot.hears`)
|
|
834
|
+
|
|
835
|
+
Match message text or captions against static strings or Regular Expressions:
|
|
836
|
+
|
|
837
|
+
```javascript
|
|
838
|
+
// Static string matching
|
|
839
|
+
bot.hears('hi', async (ctx) => ctx.reply('Hello there!'));
|
|
840
|
+
|
|
841
|
+
// Regular expression matching with capture groups
|
|
842
|
+
bot.hears(/^echo (.+)$/i, async (ctx) => {
|
|
843
|
+
const capturedText = ctx.match[1];
|
|
844
|
+
await ctx.reply(`Echo: ${capturedText}`);
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
// Match multiple phrases
|
|
848
|
+
bot.hears(['help', 'support', 'contact'], async (ctx) => {
|
|
849
|
+
await ctx.reply('Please email support@example.com for assistance.');
|
|
850
|
+
});
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
---
|
|
854
|
+
|
|
855
|
+
### Button Callbacks (`bot.action`)
|
|
856
|
+
|
|
857
|
+
Handle inline button callback queries with exact strings or regex matching:
|
|
858
|
+
|
|
859
|
+
```javascript
|
|
860
|
+
// Exact match
|
|
861
|
+
bot.action('confirm_delete', async (ctx) => {
|
|
862
|
+
await ctx.answerCallbackQuery('Item deleted!');
|
|
863
|
+
await ctx.deleteMessage();
|
|
864
|
+
});
|
|
865
|
+
|
|
866
|
+
// Regex match with parameter extraction
|
|
867
|
+
bot.action(/^user:(\d+):action:(ban|kick|warn)$/, async (ctx) => {
|
|
868
|
+
const userId = ctx.match[1];
|
|
869
|
+
const action = ctx.match[2];
|
|
870
|
+
await ctx.answerCallbackQuery(`Executed ${action} on user ${userId}`);
|
|
871
|
+
});
|
|
872
|
+
```
|
|
873
|
+
|
|
874
|
+
---
|
|
875
|
+
|
|
876
|
+
### Specialized Filters (Chat Types, Reactions, Boosts, Business, Forum)
|
|
877
|
+
|
|
878
|
+
```javascript
|
|
879
|
+
import { Composer } from 'telegix';
|
|
880
|
+
|
|
881
|
+
// Filter by Chat Type: 'private', 'group', 'supergroup', 'channel'
|
|
882
|
+
bot.use(Composer.chatType('private', async (ctx, next) => {
|
|
883
|
+
console.log('Update came from a private DM!');
|
|
884
|
+
return next();
|
|
885
|
+
}));
|
|
886
|
+
|
|
887
|
+
// Filter by Message Reactions
|
|
888
|
+
bot.use(Composer.reaction(async (ctx, next) => {
|
|
889
|
+
console.log('User reacted with:', ctx.messageReaction.new_reaction);
|
|
890
|
+
return next();
|
|
891
|
+
}));
|
|
892
|
+
|
|
893
|
+
// Filter by Telegram Business Connection
|
|
894
|
+
bot.use(Composer.business(async (ctx, next) => {
|
|
895
|
+
console.log('Business message received');
|
|
896
|
+
return next();
|
|
897
|
+
}));
|
|
898
|
+
|
|
899
|
+
// Filter Forum Supergroups
|
|
900
|
+
bot.use(Composer.forum(async (ctx, next) => {
|
|
901
|
+
console.log('Forum topic message received');
|
|
902
|
+
return next();
|
|
903
|
+
}));
|
|
904
|
+
```
|
|
905
|
+
|
|
906
|
+
---
|
|
907
|
+
|
|
908
|
+
## ๐๏ธ Fluent Keyboard & Markup Builder (`Markup`)
|
|
909
|
+
|
|
910
|
+
Construct reply and inline keyboards cleanly with `Markup`.
|
|
911
|
+
|
|
912
|
+
### Custom Reply Keyboards
|
|
913
|
+
|
|
914
|
+
```javascript
|
|
915
|
+
import { Markup } from 'telegix';
|
|
916
|
+
|
|
917
|
+
// Create a customized reply keyboard
|
|
918
|
+
const keyboard = Markup.keyboard([
|
|
919
|
+
['๐ Shop', '๐ฆ Orders'],
|
|
920
|
+
['๐ Support', 'โ๏ธ Settings'],
|
|
921
|
+
])
|
|
922
|
+
.resize() // Compact button sizes
|
|
923
|
+
.oneTime() // Hide keyboard after first selection
|
|
924
|
+
.placeholder('Select an option...')
|
|
925
|
+
.selective(); // Show only to specific mentioned users
|
|
926
|
+
|
|
927
|
+
await ctx.reply('Main Menu:', keyboard);
|
|
928
|
+
```
|
|
929
|
+
|
|
930
|
+
---
|
|
931
|
+
|
|
932
|
+
### Inline Keyboards
|
|
933
|
+
|
|
934
|
+
```javascript
|
|
935
|
+
const inline = Markup.inlineKeyboard([
|
|
936
|
+
[
|
|
937
|
+
Markup.button.callback('๐ Like', 'action_like'),
|
|
938
|
+
Markup.button.callback('๐ Dislike', 'action_dislike'),
|
|
939
|
+
],
|
|
940
|
+
[
|
|
941
|
+
Markup.button.url('๐ Visit Website', 'https://telegix.dev'),
|
|
942
|
+
Markup.button.copyText('๐ Copy Code', 'TELE-2026'),
|
|
943
|
+
],
|
|
944
|
+
[
|
|
945
|
+
Markup.button.webApp('๐ Launch Mini App', 'https://miniapp.example.com'),
|
|
946
|
+
],
|
|
947
|
+
]);
|
|
948
|
+
|
|
949
|
+
await ctx.reply('Interactive Post:', inline);
|
|
950
|
+
```
|
|
951
|
+
|
|
952
|
+
---
|
|
953
|
+
|
|
954
|
+
### Complete Button Builder Reference
|
|
955
|
+
|
|
956
|
+
| Button Builder Method | Description |
|
|
957
|
+
|---|---|
|
|
958
|
+
| `Markup.button.text(text)` | Standard reply keyboard text button. |
|
|
959
|
+
| `Markup.button.callback(text, data)` | Inline button triggering a callback query with `data`. |
|
|
960
|
+
| `Markup.button.url(text, url)` | Inline button opening an external URL. |
|
|
961
|
+
| `Markup.button.webApp(text, url)` | Button launching a Telegram Mini App. |
|
|
962
|
+
| `Markup.button.copyText(text, textToCopy)` | Inline button that copies `textToCopy` to the clipboard. |
|
|
963
|
+
| `Markup.button.disabled(text)` | Disabled, non-clickable button (**Bot API 10.3**). |
|
|
964
|
+
| `Markup.button.login(text, url, options?)` | Telegram Login URL authorization button. |
|
|
965
|
+
| `Markup.button.switchToChat(text, query)` | Inline button switching to chat with inline query. |
|
|
966
|
+
| `Markup.button.switchToCurrentChat(text, query)` | Inline button opening current chat with inline query. |
|
|
967
|
+
| `Markup.button.pay(text)` | Payment invoice button. |
|
|
968
|
+
| `Markup.button.contactRequest(text)` | Reply button requesting the user's phone number. |
|
|
969
|
+
| `Markup.button.locationRequest(text)` | Reply button requesting the user's GPS location. |
|
|
970
|
+
| `Markup.button.pollRequest(text, type?)` | Reply button requesting user to create a poll or quiz. |
|
|
971
|
+
| `Markup.button.userRequest(text, reqId, options?)` | Reply button requesting user selection. |
|
|
972
|
+
| `Markup.button.botRequest(text, reqId, options?)` | Reply button requesting bot selection. |
|
|
973
|
+
| `Markup.button.groupRequest(text, reqId, options?)` | Reply button requesting group chat selection. |
|
|
974
|
+
| `Markup.button.channelRequest(text, reqId, options?)` | Reply button requesting channel selection. |
|
|
975
|
+
|
|
976
|
+
---
|
|
977
|
+
|
|
978
|
+
### Removing Keyboards & Force Reply
|
|
979
|
+
|
|
980
|
+
```javascript
|
|
981
|
+
// Remove custom reply keyboard
|
|
982
|
+
await ctx.reply('Keyboard removed.', Markup.removeKeyboard());
|
|
983
|
+
|
|
984
|
+
// Force user to reply to this message
|
|
985
|
+
await ctx.reply('Please enter your email address:', Markup.forceReply());
|
|
986
|
+
```
|
|
987
|
+
|
|
988
|
+
---
|
|
989
|
+
|
|
990
|
+
## ๐ฌ Asynchronous Conversations & Wizard Scenes
|
|
991
|
+
|
|
992
|
+
### Interactive Inline Prompts (`await ctx.prompt`)
|
|
993
|
+
|
|
994
|
+
Ask sequential questions and await answers asynchronously directly inside your code:
|
|
995
|
+
|
|
996
|
+
```javascript
|
|
997
|
+
import { Telegix, promptMiddleware } from 'telegix';
|
|
998
|
+
|
|
999
|
+
const bot = new Telegix(process.env.BOT_TOKEN);
|
|
1000
|
+
bot.use(promptMiddleware());
|
|
1001
|
+
|
|
1002
|
+
bot.command('register', async (ctx) => {
|
|
1003
|
+
// Step 1: Ask Name
|
|
1004
|
+
const name = await ctx.prompt('What is your full name?');
|
|
1005
|
+
|
|
1006
|
+
// Step 2: Ask Age
|
|
1007
|
+
const age = await ctx.prompt(`Nice to meet you, ${name}! How old are you?`, {
|
|
1008
|
+
timeoutMs: 30000, // 30 seconds timeout
|
|
1009
|
+
});
|
|
1010
|
+
|
|
1011
|
+
// Step 3: Confirmation
|
|
1012
|
+
await ctx.reply(`๐ Registration complete!\nName: ${name}\nAge: ${age}`);
|
|
1013
|
+
});
|
|
1014
|
+
```
|
|
1015
|
+
|
|
1016
|
+
---
|
|
1017
|
+
|
|
1018
|
+
### Multi-Step Wizard Scenes (`WizardScene` & `Stage`)
|
|
1019
|
+
|
|
1020
|
+
Build complex, multi-step conversation wizards with state tracking:
|
|
1021
|
+
|
|
1022
|
+
```javascript
|
|
1023
|
+
import { Telegix, WizardScene, Stage, session, Markup } from 'telegix';
|
|
1024
|
+
|
|
1025
|
+
// 1. Define Wizard Scene
|
|
1026
|
+
const orderWizard = new WizardScene(
|
|
1027
|
+
'pizza_order_wizard',
|
|
1028
|
+
// Step 1: Select Flavor
|
|
1029
|
+
async (ctx) => {
|
|
1030
|
+
await ctx.reply(
|
|
1031
|
+
'๐ Step 1: Choose your pizza flavor:',
|
|
1032
|
+
Markup.keyboard([['Margherita', 'Pepperoni'], ['Hawaiian', 'BBQ Chicken']]).resize()
|
|
1033
|
+
);
|
|
1034
|
+
return ctx.wizard.next();
|
|
1035
|
+
},
|
|
1036
|
+
// Step 2: Select Size
|
|
1037
|
+
async (ctx) => {
|
|
1038
|
+
ctx.wizard.state.flavor = ctx.message.text;
|
|
1039
|
+
await ctx.reply(
|
|
1040
|
+
`Selected: ${ctx.wizard.state.flavor}\nStep 2: Choose size:`,
|
|
1041
|
+
Markup.keyboard([['Small', 'Medium', 'Large']]).resize()
|
|
1042
|
+
);
|
|
1043
|
+
return ctx.wizard.next();
|
|
1044
|
+
},
|
|
1045
|
+
// Step 3: Confirm & Finish
|
|
1046
|
+
async (ctx) => {
|
|
1047
|
+
ctx.wizard.state.size = ctx.message.text;
|
|
1048
|
+
await ctx.reply(
|
|
1049
|
+
`โ
Order Summary:\nโข Flavor: ${ctx.wizard.state.flavor}\nโข Size: ${ctx.wizard.state.size}\nThank you!`,
|
|
1050
|
+
Markup.removeKeyboard()
|
|
1051
|
+
);
|
|
1052
|
+
return ctx.scene.leave();
|
|
1053
|
+
}
|
|
1054
|
+
);
|
|
1055
|
+
|
|
1056
|
+
// 2. Setup Stage
|
|
1057
|
+
const stage = new Stage([orderWizard]);
|
|
1058
|
+
|
|
1059
|
+
const bot = new Telegix(process.env.BOT_TOKEN);
|
|
1060
|
+
bot.use(session());
|
|
1061
|
+
bot.use(stage.middleware());
|
|
1062
|
+
|
|
1063
|
+
bot.command('order', (ctx) => ctx.scene.enter('pizza_order_wizard'));
|
|
1064
|
+
```
|
|
1065
|
+
|
|
1066
|
+
---
|
|
1067
|
+
|
|
1068
|
+
## ๐พ Session & State Persistence
|
|
1069
|
+
|
|
1070
|
+
Store per-user or per-chat state that survives across multiple messages.
|
|
1071
|
+
|
|
1072
|
+
### Memory Session Store
|
|
1073
|
+
|
|
1074
|
+
```javascript
|
|
1075
|
+
import { Telegix, session, MemorySessionStore } from 'telegix';
|
|
1076
|
+
|
|
1077
|
+
const bot = new Telegix(process.env.BOT_TOKEN);
|
|
1078
|
+
|
|
1079
|
+
bot.use(session({
|
|
1080
|
+
store: new MemorySessionStore({ ttlMs: 86400000 }), // 24 hours TTL
|
|
1081
|
+
initial: () => ({ count: 0 }),
|
|
1082
|
+
}));
|
|
1083
|
+
|
|
1084
|
+
bot.command('counter', async (ctx) => {
|
|
1085
|
+
ctx.session.count += 1;
|
|
1086
|
+
await ctx.reply(`You have invoked this command ${ctx.session.count} times!`);
|
|
1087
|
+
});
|
|
1088
|
+
```
|
|
1089
|
+
|
|
1090
|
+
---
|
|
1091
|
+
|
|
1092
|
+
### File Session Store
|
|
1093
|
+
|
|
1094
|
+
Persist user states to local disk JSON automatically:
|
|
1095
|
+
|
|
1096
|
+
```javascript
|
|
1097
|
+
import { Telegix, session, FileSessionStore } from 'telegix';
|
|
1098
|
+
|
|
1099
|
+
bot.use(session({
|
|
1100
|
+
store: new FileSessionStore({ filePath: './data/sessions.json' }),
|
|
1101
|
+
initial: () => ({ favorites: [] }),
|
|
1102
|
+
}));
|
|
1103
|
+
```
|
|
1104
|
+
|
|
1105
|
+
---
|
|
1106
|
+
|
|
1107
|
+
### Custom Store Integration (Redis, MongoDB, PostgreSQL)
|
|
1108
|
+
|
|
1109
|
+
Provide your own storage engine with `get`, `set`, and `delete` methods:
|
|
1110
|
+
|
|
1111
|
+
```javascript
|
|
1112
|
+
import { session } from 'telegix';
|
|
1113
|
+
import Redis from 'ioredis';
|
|
1114
|
+
|
|
1115
|
+
const redis = new Redis();
|
|
1116
|
+
|
|
1117
|
+
const redisStore = {
|
|
1118
|
+
async get(key) {
|
|
1119
|
+
const data = await redis.get(`session:${key}`);
|
|
1120
|
+
return data ? JSON.parse(data) : undefined;
|
|
1121
|
+
},
|
|
1122
|
+
async set(key, value, ttlMs) {
|
|
1123
|
+
if (ttlMs) {
|
|
1124
|
+
await redis.set(`session:${key}`, JSON.stringify(value), 'PX', ttlMs);
|
|
1125
|
+
} else {
|
|
1126
|
+
await redis.set(`session:${key}`, JSON.stringify(value));
|
|
1127
|
+
}
|
|
1128
|
+
},
|
|
1129
|
+
async delete(key) {
|
|
1130
|
+
await redis.del(`session:${key}`);
|
|
1131
|
+
},
|
|
1132
|
+
};
|
|
1133
|
+
|
|
1134
|
+
bot.use(session({ store: redisStore }));
|
|
1135
|
+
```
|
|
1136
|
+
|
|
1137
|
+
---
|
|
1138
|
+
|
|
1139
|
+
## ๐ Internationalization & Localization (`I18n`)
|
|
1140
|
+
|
|
1141
|
+
Built-in internationalization supporting variable interpolation (`{{name}}`), nested paths (`menu.profile`), and pluralization rules:
|
|
1142
|
+
|
|
1143
|
+
```javascript
|
|
1144
|
+
import { Telegix, I18n, session } from 'telegix';
|
|
1145
|
+
|
|
1146
|
+
const i18n = new I18n({
|
|
1147
|
+
defaultLocale: 'en',
|
|
1148
|
+
locales: {
|
|
1149
|
+
en: {
|
|
1150
|
+
welcome: 'Welcome, {{name}}!',
|
|
1151
|
+
menu: { profile: 'User Profile', settings: 'Settings' },
|
|
1152
|
+
items: {
|
|
1153
|
+
one: '1 item in cart',
|
|
1154
|
+
other: '{{count}} items in cart',
|
|
1155
|
+
},
|
|
1156
|
+
},
|
|
1157
|
+
es: {
|
|
1158
|
+
welcome: 'ยกBienvenido, {{name}}!',
|
|
1159
|
+
menu: { profile: 'Perfil de Usuario', settings: 'Ajustes' },
|
|
1160
|
+
items: {
|
|
1161
|
+
one: '1 artรญculo en el carrito',
|
|
1162
|
+
other: '{{count}} artรญculos en el carrito',
|
|
1163
|
+
},
|
|
1164
|
+
},
|
|
1165
|
+
},
|
|
1166
|
+
});
|
|
1167
|
+
|
|
1168
|
+
const bot = new Telegix(process.env.BOT_TOKEN);
|
|
1169
|
+
bot.use(session());
|
|
1170
|
+
bot.use(i18n.middleware());
|
|
1171
|
+
|
|
1172
|
+
bot.command('start', async (ctx) => {
|
|
1173
|
+
await ctx.reply(ctx.t('welcome', { name: ctx.from?.first_name }));
|
|
1174
|
+
await ctx.reply(ctx.t('menu.profile'));
|
|
1175
|
+
await ctx.reply(ctx.t('items', { count: 3 }));
|
|
1176
|
+
});
|
|
1177
|
+
|
|
1178
|
+
bot.command('set_spanish', async (ctx) => {
|
|
1179
|
+
ctx.i18n.setLocale('es');
|
|
1180
|
+
await ctx.reply(ctx.t('welcome', { name: ctx.from?.first_name }));
|
|
1181
|
+
});
|
|
1182
|
+
```
|
|
1183
|
+
|
|
1184
|
+
---
|
|
1185
|
+
|
|
1186
|
+
## โ๏ธ Message Formatting (`fmt`, `html`, `mdv2`)
|
|
1187
|
+
|
|
1188
|
+
### XSS-Safe HTML Builder (`fmt` & `html`)
|
|
1189
|
+
|
|
1190
|
+
Safely interpolate untrusted user input into HTML messages without escaping errors:
|
|
1191
|
+
|
|
1192
|
+
```javascript
|
|
1193
|
+
import { fmt, html } from 'telegix';
|
|
1194
|
+
|
|
1195
|
+
bot.command('profile', async (ctx) => {
|
|
1196
|
+
const untrustedBio = '<script>alert("xss")</script> & <b>test</b>';
|
|
1197
|
+
|
|
1198
|
+
const message = fmt`
|
|
1199
|
+
<b>๐ค User Profile</b>
|
|
1200
|
+
โข Name: ${ctx.from?.first_name}
|
|
1201
|
+
โข Bio: ${untrustedBio}
|
|
1202
|
+
โข Status: ${html`<i>Verified Member</i>`}
|
|
1203
|
+
โข Points: ${1500}
|
|
1204
|
+
${fmt.link('Open Dashboard', 'https://example.com')}
|
|
1205
|
+
`;
|
|
1206
|
+
|
|
1207
|
+
await ctx.reply(message, { parse_mode: 'HTML' });
|
|
1208
|
+
});
|
|
1209
|
+
```
|
|
1210
|
+
|
|
1211
|
+
---
|
|
1212
|
+
|
|
1213
|
+
### MarkdownV2 Escaping Helpers (`mdv2`)
|
|
1214
|
+
|
|
1215
|
+
```javascript
|
|
1216
|
+
import { mdv2 } from 'telegix';
|
|
1217
|
+
|
|
1218
|
+
bot.command('md', async (ctx) => {
|
|
1219
|
+
const rawText = 'Price: $99.99 (Special Offer! *Limited*)';
|
|
1220
|
+
const boldEscaped = mdv2.bold(rawText);
|
|
1221
|
+
|
|
1222
|
+
await ctx.reply(boldEscaped, { parse_mode: 'MarkdownV2' });
|
|
1223
|
+
});
|
|
1224
|
+
```
|
|
1225
|
+
|
|
1226
|
+
---
|
|
1227
|
+
|
|
1228
|
+
## ๐ณ Payments, Invoices & Telegram Stars (`InvoiceBuilder`)
|
|
1229
|
+
|
|
1230
|
+
Create and dispatch invoices for fiat currencies or **Telegram Stars (`XTR`)**:
|
|
1231
|
+
|
|
1232
|
+
```javascript
|
|
1233
|
+
import { InvoiceBuilder, answerPreCheckoutQuery } from 'telegix';
|
|
1234
|
+
|
|
1235
|
+
bot.command('buy_stars', async (ctx) => {
|
|
1236
|
+
const invoice = new InvoiceBuilder(
|
|
1237
|
+
'โญ 100 Telegram Stars Pass',
|
|
1238
|
+
'Unlock 30 days of premium bot capabilities',
|
|
1239
|
+
'order_stars_100',
|
|
1240
|
+
'XTR' // Telegram Stars currency
|
|
1241
|
+
)
|
|
1242
|
+
.addPrice('Stars Membership', 100)
|
|
1243
|
+
.photo('https://example.com/stars_banner.png')
|
|
1244
|
+
.build();
|
|
1245
|
+
|
|
1246
|
+
await ctx.replyWithInvoice(
|
|
1247
|
+
invoice.title,
|
|
1248
|
+
invoice.description,
|
|
1249
|
+
invoice.payload,
|
|
1250
|
+
invoice.currency,
|
|
1251
|
+
invoice.prices,
|
|
1252
|
+
invoice
|
|
1253
|
+
);
|
|
1254
|
+
});
|
|
1255
|
+
|
|
1256
|
+
// Pre-checkout query validation
|
|
1257
|
+
bot.on('pre_checkout_query', async (ctx) => {
|
|
1258
|
+
await answerPreCheckoutQuery(ctx, true);
|
|
1259
|
+
});
|
|
1260
|
+
|
|
1261
|
+
// Successful payment notification
|
|
1262
|
+
bot.on('successful_payment', async (ctx) => {
|
|
1263
|
+
const payment = ctx.message.successful_payment;
|
|
1264
|
+
await ctx.reply(`๐ Payment confirmed! Received ${payment.total_amount} ${payment.currency}.`);
|
|
1265
|
+
});
|
|
1266
|
+
```
|
|
1267
|
+
|
|
1268
|
+
---
|
|
1269
|
+
|
|
1270
|
+
## ๐ฑ Telegram Mini Apps / WebApps (`validateWebAppInitData`)
|
|
1271
|
+
|
|
1272
|
+
Cryptographically verify Mini App authentication payloads using HMAC-SHA256:
|
|
1273
|
+
|
|
1274
|
+
```javascript
|
|
1275
|
+
import { validateWebAppInitData, parseWebAppInitData } from 'telegix';
|
|
1276
|
+
|
|
1277
|
+
// Inside your backend API route (e.g. Express / Fastify)
|
|
1278
|
+
app.post('/api/auth/validate', (req, res) => {
|
|
1279
|
+
const { initData } = req.body;
|
|
1280
|
+
const isValid = validateWebAppInitData(initData, process.env.BOT_TOKEN, 86400); // 24h expiration
|
|
1281
|
+
|
|
1282
|
+
if (!isValid) {
|
|
1283
|
+
return res.status(401).json({ error: 'Invalid Telegram WebApp session' });
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
const parsed = parseWebAppInitData(initData);
|
|
1287
|
+
return res.json({ success: true, user: parsed.user });
|
|
1288
|
+
});
|
|
1289
|
+
```
|
|
1290
|
+
|
|
1291
|
+
---
|
|
1292
|
+
|
|
1293
|
+
## ๐ค Multi-Bot Process Manager (`TelegixManager`)
|
|
1294
|
+
|
|
1295
|
+
Run, coordinate, and supervise multiple Telegram bots within a single Node.js process:
|
|
1296
|
+
|
|
1297
|
+
```javascript
|
|
1298
|
+
import { TelegixManager } from 'telegix';
|
|
1299
|
+
|
|
1300
|
+
const manager = new TelegixManager();
|
|
1301
|
+
|
|
1302
|
+
// Register Bot 1
|
|
1303
|
+
const supportBot = manager.add('support_bot', process.env.SUPPORT_BOT_TOKEN);
|
|
1304
|
+
supportBot.command('start', (ctx) => ctx.reply('Support bot online!'));
|
|
1305
|
+
|
|
1306
|
+
// Register Bot 2
|
|
1307
|
+
const alertBot = manager.add('alerts_bot', process.env.ALERTS_BOT_TOKEN);
|
|
1308
|
+
alertBot.command('start', (ctx) => ctx.reply('Alerts bot online!'));
|
|
1309
|
+
|
|
1310
|
+
// Launch all registered bots concurrently
|
|
1311
|
+
await manager.launchAll();
|
|
1312
|
+
console.log(`Running ${manager.size} bots concurrently!`);
|
|
1313
|
+
```
|
|
1314
|
+
|
|
1315
|
+
---
|
|
1316
|
+
|
|
1317
|
+
## โก Advanced Built-in Middlewares
|
|
1318
|
+
|
|
1319
|
+
### Rate Limiter Middleware (`rateLimit`)
|
|
1320
|
+
|
|
1321
|
+
```javascript
|
|
1322
|
+
import { rateLimit } from 'telegix';
|
|
1323
|
+
|
|
1324
|
+
bot.use(
|
|
1325
|
+
rateLimit({
|
|
1326
|
+
windowMs: 5000, // 5 second rolling window
|
|
1327
|
+
limit: 3, // Max 3 messages per window
|
|
1328
|
+
handler: async (ctx) => {
|
|
1329
|
+
await ctx.reply('โ ๏ธ Rate limit exceeded! Please wait a moment before sending more messages.');
|
|
1330
|
+
},
|
|
1331
|
+
})
|
|
1332
|
+
);
|
|
1333
|
+
```
|
|
1334
|
+
|
|
1335
|
+
### Media Group / Album Batching (`albumMiddleware`)
|
|
1336
|
+
|
|
1337
|
+
Batches photos and documents sent together into a single `ctx.album` array:
|
|
1338
|
+
|
|
1339
|
+
```javascript
|
|
1340
|
+
import { albumMiddleware } from 'telegix';
|
|
1341
|
+
|
|
1342
|
+
bot.use(albumMiddleware({ windowMs: 500 }));
|
|
1343
|
+
|
|
1344
|
+
bot.on('message:photo', async (ctx) => {
|
|
1345
|
+
if (ctx.album) {
|
|
1346
|
+
console.log(`Received photo album containing ${ctx.album.count} photos!`);
|
|
1347
|
+
for (const msg of ctx.album.messages) {
|
|
1348
|
+
console.log('File ID:', msg.photo[msg.photo.length - 1].file_id);
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
});
|
|
1352
|
+
```
|
|
1353
|
+
|
|
1354
|
+
### Inline Query Debounce & Cache (`inlineDebounceMiddleware`)
|
|
1355
|
+
|
|
1356
|
+
```javascript
|
|
1357
|
+
import { inlineDebounceMiddleware } from 'telegix';
|
|
1358
|
+
|
|
1359
|
+
bot.use(inlineDebounceMiddleware({ windowMs: 300, cacheTtlMs: 60000 }));
|
|
1360
|
+
```
|
|
1361
|
+
|
|
1362
|
+
### Automatic Chat Action (`chatActionMiddleware`)
|
|
1363
|
+
|
|
1364
|
+
Keeps the "typing" action active continuously during long asynchronous computations or AI streaming:
|
|
1365
|
+
|
|
1366
|
+
```javascript
|
|
1367
|
+
import { chatActionMiddleware } from 'telegix';
|
|
1368
|
+
|
|
1369
|
+
bot.command('ai_summary', chatActionMiddleware('typing'), async (ctx) => {
|
|
1370
|
+
const result = await generateAiSummary(ctx.payload);
|
|
1371
|
+
await ctx.reply(result);
|
|
1372
|
+
});
|
|
1373
|
+
```
|
|
1374
|
+
|
|
1375
|
+
### Inline Query Pagination (`paginateInlineQuery`)
|
|
1376
|
+
|
|
1377
|
+
```javascript
|
|
1378
|
+
import { InlineQueryResultBuilder, paginateInlineQuery } from 'telegix';
|
|
1379
|
+
|
|
1380
|
+
const inventory = [
|
|
1381
|
+
{ id: '1', name: 'MacBook Pro', price: '$1999' },
|
|
1382
|
+
{ id: '2', name: 'iPhone 16 Pro', price: '$999' },
|
|
1383
|
+
{ id: '3', name: 'iPad Pro', price: '$799' },
|
|
1384
|
+
];
|
|
1385
|
+
|
|
1386
|
+
bot.on('inline_query', async (ctx) => {
|
|
1387
|
+
await paginateInlineQuery(
|
|
1388
|
+
ctx,
|
|
1389
|
+
inventory,
|
|
1390
|
+
(item) =>
|
|
1391
|
+
InlineQueryResultBuilder.article(
|
|
1392
|
+
item.id,
|
|
1393
|
+
item.name,
|
|
1394
|
+
`<b>${item.name}</b>: ${item.price}`,
|
|
1395
|
+
{ description: `Order ${item.name}` }
|
|
1396
|
+
),
|
|
1397
|
+
{ limit: 10 }
|
|
1398
|
+
);
|
|
1399
|
+
});
|
|
1400
|
+
```
|
|
1401
|
+
|
|
1402
|
+
---
|
|
1403
|
+
|
|
1404
|
+
## ๐ Complete Telegram API Client Method Reference (`bot.telegram` / `bot.api`)
|
|
1405
|
+
|
|
1406
|
+
The `Telegram` client exposes every official method of the Telegram Bot API:
|
|
1407
|
+
|
|
1408
|
+
### Account & Identity
|
|
1409
|
+
- `getMe()` โ Retrieve bot identity information.
|
|
1410
|
+
- `logOut()` / `close()` โ Log out from the cloud Bot API or close the local bot instance.
|
|
1411
|
+
- `getMyName(extra)` / `setMyName(name, extra)` โ Get or set bot name.
|
|
1412
|
+
- `getMyDescription(extra)` / `setMyDescription(description, extra)` โ Get or set bot description.
|
|
1413
|
+
- `getMyShortDescription(extra)` / `setMyShortDescription(shortDescription, extra)` โ Get or set short description.
|
|
1414
|
+
- `getMyCommands(extra)` / `setMyCommands(commands, extra)` / `deleteMyCommands(extra)` โ Manage bot command menu list.
|
|
1415
|
+
- `getMyDefaultAdministratorRights(extra)` / `setMyDefaultAdministratorRights(rights, extra)` โ Manage administrator rights.
|
|
1416
|
+
- `getChatMenuButton(extra)` / `setChatMenuButton(extra)` โ Manage the chat menu button.
|
|
1417
|
+
|
|
1418
|
+
### Messages & Media Sending
|
|
1419
|
+
- `sendMessage(chatId, text, extra)`
|
|
1420
|
+
- `forwardMessage(chatId, fromChatId, messageId, extra)` / `forwardMessages(chatId, fromChatId, messageIds, extra)`
|
|
1421
|
+
- `copyMessage(chatId, fromChatId, messageId, extra)` / `copyMessages(chatId, fromChatId, messageIds, extra)`
|
|
1422
|
+
- `sendPhoto(chatId, photo, extra)`
|
|
1423
|
+
- `sendAudio(chatId, audio, extra)`
|
|
1424
|
+
- `sendDocument(chatId, document, extra)`
|
|
1425
|
+
- `sendVideo(chatId, video, extra)`
|
|
1426
|
+
- `sendAnimation(chatId, animation, extra)`
|
|
1427
|
+
- `sendVoice(chatId, voice, extra)`
|
|
1428
|
+
- `sendVideoNote(chatId, videoNote, extra)`
|
|
1429
|
+
- `sendPaidMedia(chatId, starCount, media, extra)`
|
|
1430
|
+
- `sendMediaGroup(chatId, media, extra)`
|
|
1431
|
+
- `sendLocation(chatId, latitude, longitude, extra)`
|
|
1432
|
+
- `sendVenue(chatId, latitude, longitude, title, address, extra)`
|
|
1433
|
+
- `sendContact(chatId, phoneNumber, firstName, extra)`
|
|
1434
|
+
- `sendPoll(chatId, question, options, extra)`
|
|
1435
|
+
- `sendDice(chatId, extra)`
|
|
1436
|
+
- `sendChatAction(chatId, action, extra)`
|
|
1437
|
+
- `setMessageReaction(chatId, messageId, reaction, extra)`
|
|
1438
|
+
- `sendSticker(chatId, sticker, extra)`
|
|
1439
|
+
- `sendGame(chatId, gameShortName, extra)`
|
|
1440
|
+
- `sendInvoice(chatId, title, description, payload, currency, prices, extra)`
|
|
1441
|
+
- `sendGift(userId, giftId, extra)`
|
|
1442
|
+
- `sendEphemeralMessage(chatId, text, ephemeralParameters, extra)`
|
|
1443
|
+
- `sendMessageDraft(chatId, text, extra)`
|
|
1444
|
+
- `sendRichMessage(chatId, richMessage, extra)`
|
|
1445
|
+
- `sendRichMessageDraft(chatId, draft, extra)`
|
|
1446
|
+
|
|
1447
|
+
### Messages Editing & Deletion
|
|
1448
|
+
- `editMessageText(chatId, messageId, inlineMessageId, text, extra)`
|
|
1449
|
+
- `editMessageCaption(chatId, messageId, inlineMessageId, caption, extra)`
|
|
1450
|
+
- `editMessageMedia(chatId, messageId, inlineMessageId, media, extra)`
|
|
1451
|
+
- `editMessageReplyMarkup(chatId, messageId, inlineMessageId, replyMarkup, extra)`
|
|
1452
|
+
- `editRichMessageText(chatId, messageId, richMessage, extra)`
|
|
1453
|
+
- `editRichMessageCaption(chatId, messageId, caption, extra)`
|
|
1454
|
+
- `deleteMessage(chatId, messageId)`
|
|
1455
|
+
- `deleteMessages(chatId, messageIds)`
|
|
1456
|
+
- `editMessageLiveLocation(latitude, longitude, extra)` / `stopMessageLiveLocation(extra)`
|
|
1457
|
+
- `stopPoll(chatId, messageId, extra)`
|
|
1458
|
+
|
|
1459
|
+
### Chat Moderation & Administration
|
|
1460
|
+
- `getChat(chatId)`
|
|
1461
|
+
- `getChatAdministrators(chatId)`
|
|
1462
|
+
- `getChatMemberCount(chatId)` / `getChatMembersCount(chatId)`
|
|
1463
|
+
- `getChatMember(chatId, userId)`
|
|
1464
|
+
- `banChatMember(chatId, userId, extra)`
|
|
1465
|
+
- `unbanChatMember(chatId, userId, extra)`
|
|
1466
|
+
- `restrictChatMember(chatId, userId, permissions, extra)`
|
|
1467
|
+
- `promoteChatMember(chatId, userId, rights)`
|
|
1468
|
+
- `setChatAdministratorCustomTitle(chatId, userId, customTitle)`
|
|
1469
|
+
- `setChatPermissions(chatId, permissions, extra)`
|
|
1470
|
+
- `setChatTitle(chatId, title)`
|
|
1471
|
+
- `setChatDescription(chatId, description)`
|
|
1472
|
+
- `setChatPhoto(chatId, photo)` / `deleteChatPhoto(chatId)`
|
|
1473
|
+
- `pinChatMessage(chatId, messageId, extra)` / `unpinChatMessage(chatId, messageId)` / `unpinAllChatMessages(chatId)`
|
|
1474
|
+
- `leaveChat(chatId)`
|
|
1475
|
+
- `exportChatInviteLink(chatId)`
|
|
1476
|
+
- `createChatInviteLink(chatId, extra)`
|
|
1477
|
+
- `editChatInviteLink(chatId, inviteLink, extra)`
|
|
1478
|
+
- `revokeChatInviteLink(chatId, inviteLink)`
|
|
1479
|
+
- `approveChatJoinRequest(chatId, userId)`
|
|
1480
|
+
- `declineChatJoinRequest(chatId, userId)`
|
|
1481
|
+
- `verifyUser(userId, customDescription)`
|
|
1482
|
+
- `verifyChat(chatId, customDescription)`
|
|
1483
|
+
- `removeUserVerification(userId)`
|
|
1484
|
+
- `removeChatVerification(chatId)`
|
|
1485
|
+
- `getUserChatBoosts(chatId, userId)`
|
|
1486
|
+
- `getBusinessConnection(businessConnectionId)`
|
|
1487
|
+
|
|
1488
|
+
### Forum Topics Management
|
|
1489
|
+
- `createForumTopic(chatId, name, extra)`
|
|
1490
|
+
- `editForumTopic(chatId, messageThreadId, extra)`
|
|
1491
|
+
- `closeForumTopic(chatId, messageThreadId)`
|
|
1492
|
+
- `reopenForumTopic(chatId, messageThreadId)`
|
|
1493
|
+
- `deleteForumTopic(chatId, messageThreadId)`
|
|
1494
|
+
- `unpinAllForumTopicMessages(chatId, messageThreadId)`
|
|
1495
|
+
- `editGeneralForumTopic(chatId, name)`
|
|
1496
|
+
- `closeGeneralForumTopic(chatId)`
|
|
1497
|
+
- `reopenGeneralForumTopic(chatId)`
|
|
1498
|
+
- `hideGeneralForumTopic(chatId)`
|
|
1499
|
+
- `unhideGeneralForumTopic(chatId)`
|
|
1500
|
+
|
|
1501
|
+
### Managed Bot Access Settings (Bot API 10.3)
|
|
1502
|
+
- `getManagedBotAccessSettings(userId, extra)`
|
|
1503
|
+
- `setManagedBotAccessSettings(userId, settings, extra)`
|
|
1504
|
+
- `getUserPersonalChatMessages(userId, extra)`
|
|
1505
|
+
|
|
1506
|
+
---
|
|
1507
|
+
|
|
1508
|
+
## ๐ฆ TypeScript Support
|
|
1509
|
+
|
|
1510
|
+
Telegix comes with zero-config TypeScript type declarations included in `index.d.ts`:
|
|
1511
|
+
|
|
1512
|
+
```typescript
|
|
1513
|
+
import { Telegix, Context } from 'telegix';
|
|
1514
|
+
|
|
1515
|
+
interface SessionData {
|
|
1516
|
+
counter: number;
|
|
1517
|
+
selectedCity?: string;
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
interface CustomContext extends Context {
|
|
1521
|
+
session: SessionData;
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
const bot = new Telegix<CustomContext>(process.env.BOT_TOKEN!);
|
|
1525
|
+
|
|
1526
|
+
bot.command('count', async (ctx) => {
|
|
1527
|
+
ctx.session.counter = (ctx.session.counter || 0) + 1;
|
|
1528
|
+
await ctx.reply(`Count: ${ctx.session.counter}`);
|
|
1529
|
+
});
|
|
1530
|
+
```
|
|
1531
|
+
|
|
1532
|
+
---
|
|
1533
|
+
|
|
1534
|
+
---
|