@xbibzlibrary/telebibz 0.1.2 → 0.1.3
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/CHANGELOG.md +16 -1
- package/README.id.md +158 -0
- package/README.md +53 -33
- package/README.zh-CN.md +158 -0
- package/RELEASE_AUTOMATION.md +66 -0
- package/RELEASE_POLICY.md +2 -2
- package/assets/readme-preview.html +75 -0
- package/assets/telebibz-readme-preview.png +0 -0
- package/dist/src/api/index.d.ts +1 -0
- package/dist/src/api/index.d.ts.map +1 -1
- package/dist/src/api/index.js +1 -0
- package/dist/src/api/index.js.map +1 -1
- package/dist/src/api/telegram-types/LICENSE +21 -0
- package/dist/src/api/telegram-types/api.d.ts +22 -0
- package/dist/src/api/telegram-types/checklist.d.ts +72 -0
- package/dist/src/api/telegram-types/inline.d.ts +692 -0
- package/dist/src/api/telegram-types/langs.d.ts +193 -0
- package/dist/src/api/telegram-types/manage.d.ts +1144 -0
- package/dist/src/api/telegram-types/markup.d.ts +268 -0
- package/dist/src/api/telegram-types/message.d.ts +1537 -0
- package/dist/src/api/telegram-types/methods.d.ts +2870 -0
- package/dist/src/api/telegram-types/mod.d.ts +14 -0
- package/dist/src/api/telegram-types/passport.d.ts +163 -0
- package/dist/src/api/telegram-types/payment.d.ts +570 -0
- package/dist/src/api/telegram-types/rich.d.ts +1010 -0
- package/dist/src/api/telegram-types/settings.d.ts +120 -0
- package/dist/src/api/telegram-types/story.d.ts +89 -0
- package/dist/src/api/telegram-types/update.d.ts +84 -0
- package/dist/src/api/telegram.d.ts +7 -0
- package/dist/src/api/telegram.d.ts.map +1 -0
- package/dist/src/api/telegram.js +2 -0
- package/dist/src/api/telegram.js.map +1 -0
- package/dist/src/approval/approval.d.ts +8 -0
- package/dist/src/approval/approval.d.ts.map +1 -1
- package/dist/src/approval/approval.js +9 -0
- package/dist/src/approval/approval.js.map +1 -1
- package/dist/src/cache/cache.d.ts +6 -5
- package/dist/src/cache/cache.d.ts.map +1 -1
- package/dist/src/cache/cache.js +7 -3
- package/dist/src/cache/cache.js.map +1 -1
- package/dist/src/context/context.d.ts.map +1 -1
- package/dist/src/context/context.js +26 -3
- package/dist/src/context/context.js.map +1 -1
- package/dist/src/core/bot.d.ts +6 -4
- package/dist/src/core/bot.d.ts.map +1 -1
- package/dist/src/core/bot.js +48 -7
- package/dist/src/core/bot.js.map +1 -1
- package/dist/src/core/events.d.ts +4 -0
- package/dist/src/core/events.d.ts.map +1 -1
- package/dist/src/core/events.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/queue/queue.d.ts +25 -0
- package/dist/src/queue/queue.d.ts.map +1 -1
- package/dist/src/queue/queue.js +175 -51
- package/dist/src/queue/queue.js.map +1 -1
- package/dist/src/router/router.d.ts +8 -1
- package/dist/src/router/router.d.ts.map +1 -1
- package/dist/src/router/router.js +75 -17
- package/dist/src/router/router.js.map +1 -1
- package/dist/src/state/conversation.d.ts +6 -0
- package/dist/src/state/conversation.d.ts.map +1 -1
- package/dist/src/state/conversation.js +79 -11
- package/dist/src/state/conversation.js.map +1 -1
- package/dist/src/state/menu.d.ts +53 -5
- package/dist/src/state/menu.d.ts.map +1 -1
- package/dist/src/state/menu.js +116 -17
- package/dist/src/state/menu.js.map +1 -1
- package/dist/src/storage/storage.d.ts +115 -12
- package/dist/src/storage/storage.d.ts.map +1 -1
- package/dist/src/storage/storage.js +130 -4
- package/dist/src/storage/storage.js.map +1 -1
- package/dist/src/telegram-features.d.ts +33 -0
- package/dist/src/telegram-features.d.ts.map +1 -0
- package/dist/src/telegram-features.js +69 -0
- package/dist/src/telegram-features.js.map +1 -0
- package/dist/src/testing.d.ts +1 -0
- package/dist/src/testing.d.ts.map +1 -1
- package/dist/src/testing.js +16 -0
- package/dist/src/testing.js.map +1 -1
- package/dist-cjs/src/api/index.js +1 -0
- package/dist-cjs/src/api/telegram-types/LICENSE +21 -0
- package/dist-cjs/src/api/telegram-types/api.d.ts +22 -0
- package/dist-cjs/src/api/telegram-types/checklist.d.ts +72 -0
- package/dist-cjs/src/api/telegram-types/inline.d.ts +692 -0
- package/dist-cjs/src/api/telegram-types/langs.d.ts +193 -0
- package/dist-cjs/src/api/telegram-types/manage.d.ts +1144 -0
- package/dist-cjs/src/api/telegram-types/markup.d.ts +268 -0
- package/dist-cjs/src/api/telegram-types/message.d.ts +1537 -0
- package/dist-cjs/src/api/telegram-types/methods.d.ts +2870 -0
- package/dist-cjs/src/api/telegram-types/mod.d.ts +14 -0
- package/dist-cjs/src/api/telegram-types/passport.d.ts +163 -0
- package/dist-cjs/src/api/telegram-types/payment.d.ts +570 -0
- package/dist-cjs/src/api/telegram-types/rich.d.ts +1010 -0
- package/dist-cjs/src/api/telegram-types/settings.d.ts +120 -0
- package/dist-cjs/src/api/telegram-types/story.d.ts +89 -0
- package/dist-cjs/src/api/telegram-types/update.d.ts +84 -0
- package/dist-cjs/src/api/telegram.js +2 -0
- package/dist-cjs/src/approval/approval.js +11 -1
- package/dist-cjs/src/cache/cache.js +7 -3
- package/dist-cjs/src/context/context.js +26 -3
- package/dist-cjs/src/core/bot.js +48 -7
- package/dist-cjs/src/index.js +1 -0
- package/dist-cjs/src/queue/queue.js +177 -51
- package/dist-cjs/src/router/router.js +75 -17
- package/dist-cjs/src/state/conversation.js +79 -11
- package/dist-cjs/src/state/menu.js +118 -18
- package/dist-cjs/src/storage/storage.js +135 -5
- package/dist-cjs/src/telegram-features.js +74 -0
- package/dist-cjs/src/testing.js +17 -0
- package/docs/API.id.md +1800 -0
- package/docs/API.md +1799 -0
- package/docs/API.zh-CN.md +1794 -0
- package/docs/README.md +26 -15
- package/package.json +13 -2
package/docs/API.md
ADDED
|
@@ -0,0 +1,1799 @@
|
|
|
1
|
+
# telebibz API Reference — English
|
|
2
|
+
[English](API.md) · [Bahasa Indonesia](API.id.md) · [简体中文](API.zh-CN.md)
|
|
3
|
+
|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
This document is the API reference for `@xbibzlibrary/telebibz@0.1.2`. All signatures and behaviors described here are mapped from the package's exported TypeScript source. If a Telegram type does not have a specific parameter/result mapping, the package still provides runtime access via a dynamic API, but the parameter types remain generic.
|
|
7
|
+
|
|
8
|
+
> **Implementation status.** This documentation describes the capabilities that are actually available in the current release. `MemoryStorage`, `MemoryCache`, `TaskQueue`, and `Scheduler` are in-memory primitives; distributed adapters, external persistence, and full schema typing for the entire Telegram Bot API are not included in this release.
|
|
9
|
+
|
|
10
|
+
## Installation and import
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @xbibzlibrary/telebibz
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
ESM:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import {
|
|
20
|
+
Bot,
|
|
21
|
+
InlineKeyboard,
|
|
22
|
+
compose,
|
|
23
|
+
escapeHtml,
|
|
24
|
+
type Context,
|
|
25
|
+
} from "@xbibzlibrary/telebibz";
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
CommonJS:
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
const { Bot, InlineKeyboard } = require("@xbibzlibrary/telebibz");
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The available subpath exports are as follows.
|
|
35
|
+
|
|
36
|
+
| Subpath | Content |
|
|
37
|
+
|---|---|
|
|
38
|
+
| `@xbibzlibrary/telebibz` | The entire main public API from `src/index.ts` |
|
|
39
|
+
| `@xbibzlibrary/telebibz/api` | Client, transport, errors, and all Telegram API types |
|
|
40
|
+
| `@xbibzlibrary/telebibz/keyboard` | `InlineKeyboard`, `ReplyKeyboard`, and keyboard helpers |
|
|
41
|
+
| `@xbibzlibrary/telebibz/testing` | `MockTransport` and test factories |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 1. Core Bot
|
|
46
|
+
|
|
47
|
+
### `BotStatus`
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
type BotStatus =
|
|
51
|
+
| "created"
|
|
52
|
+
| "initialized"
|
|
53
|
+
| "awaiting-approval"
|
|
54
|
+
| "starting"
|
|
55
|
+
| "running"
|
|
56
|
+
| "stopping"
|
|
57
|
+
| "stopped"
|
|
58
|
+
| "error";
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### `BotOptions<S>`
|
|
62
|
+
|
|
63
|
+
| Property | Type | Default | Description |
|
|
64
|
+
|---|---|---:|---|
|
|
65
|
+
| `token` | `string` | required | BotFather token in the format `<digits>:<token>`. |
|
|
66
|
+
| `apiBaseUrl` | `string` | `https://api.telegram.org` | Telegram API base URL. Trailing `/` is removed automatically. |
|
|
67
|
+
| `transport` | `Transport` | `FetchTransport` | Custom transport for mocks, proxies, or other implementations. |
|
|
68
|
+
| `transportOptions` | `Omit<FetchTransportOptions, "baseUrl">` | `{}` | Timeout, retry, backoff, jitter, headers, and fetch implementation. |
|
|
69
|
+
| `session` | `Storage<string, S>` | new storage | Session storage keyed by chat/user; any storage adapter may be used. |
|
|
70
|
+
| `services` | `Record<string, unknown>` | `{}` | Dependencies/services available via `ctx.services`. |
|
|
71
|
+
| `polling.timeout` | `number` | `30` | Long-poll timeout in seconds for `getUpdates`. |
|
|
72
|
+
| `polling.limit` | `number` | `100` | Maximum number of updates per polling request. |
|
|
73
|
+
| `polling.allowedUpdates` | `string[]` | `[]` | Telegram update filters. |
|
|
74
|
+
| `polling.retryDelayMs` | `number` | `500` | Initial delay when polling fails. |
|
|
75
|
+
| `polling.maxRetryDelayMs` | `number` | `30000` | Maximum reconnect delay. |
|
|
76
|
+
| `approval` | `ApprovalOptions` | disabled | Enable approval gate for the owner. |
|
|
77
|
+
|
|
78
|
+
### Constructor `Bot`
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
new Bot<S extends object = Record<string, unknown>>(
|
|
82
|
+
options: string | BotOptions<S>,
|
|
83
|
+
): Bot<S>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
If the argument is a string, it is treated as the token. The constructor creates `ApiClient`, router, event bus, plugin manager, session storage, and approval gate if configured. The constructor emits the `bot:created` event asynchronously.
|
|
87
|
+
|
|
88
|
+
The constructor throws `Error` if the token is empty or does not match the Telegram token pattern.
|
|
89
|
+
|
|
90
|
+
### Properties and getters `Bot`
|
|
91
|
+
|
|
92
|
+
| API | Type | Description |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| `api` | `ApiClient` | Telegram typed/dynamic client. |
|
|
95
|
+
| `router` | `Router<Context<S>>` | Bot's main router. |
|
|
96
|
+
| `events` | `EventBus<EventMap>` | Event bus for lifecycle, updates, API, webhook, and polling. |
|
|
97
|
+
| `plugins` | `PluginManager<Context<S>>` | Plugin lifecycle manager. |
|
|
98
|
+
| `session` | `Storage<string, S>` | Bot session; any persistent adapter may be used. |
|
|
99
|
+
| `services` | `Record<string, unknown>` | A copy of services provided to the constructor. |
|
|
100
|
+
| `approval` | `ApprovalGate \| undefined` | Approval gate if `approval` is configured. |
|
|
101
|
+
| `token` | `string` | Bot token used by the client. |
|
|
102
|
+
| `status` | `BotStatus` | Current lifecycle status. |
|
|
103
|
+
| `botInfo` | `User \| undefined` | Last stored result of `getMe()`. |
|
|
104
|
+
|
|
105
|
+
### `bot.use(...middleware)`
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
use(...middleware: Middleware<Context<S>>[]): this
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Adds global middleware. Middleware are executed before the router on every update, in registration order. Returns the bot instance for chaining.
|
|
112
|
+
|
|
113
|
+
### `bot.command(name, handler)`
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
command(name: string, handler: Middleware<Context<S>>): this
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Registers a Telegram command with or without the leading `/`. Matching takes the first token after `/` and ignores bot mentions after `@`. For example, `/start@my_bot` matches `"start"`.
|
|
120
|
+
|
|
121
|
+
### `bot.callback(pattern, handler)`
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
callback(pattern: string | RegExp, handler: Middleware<Context<S>>): this
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Shortcut for a callback query route. A string ending with `*` means prefix matching; other strings must match exactly.
|
|
128
|
+
|
|
129
|
+
### `bot.onText(text, handler)`
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
onText(text: string, handler: Middleware<Context<S>>): this
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Handles messages whose `message.text` is exactly equal to `text`.
|
|
136
|
+
|
|
137
|
+
### `bot.onRegex(expression, handler)`
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
onRegex(expression: RegExp, handler: Middleware<Context<S>>): this
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Handles message text using a `RegExp`. Route parameters are not automatically extracted into `ctx.params`; use a predicate or custom middleware if extraction is needed.
|
|
144
|
+
|
|
145
|
+
### `bot.usePlugin(plugin)`
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
usePlugin(plugin: Plugin<Context<S>>): this
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Registers a plugin. Plugin names must be unique.
|
|
152
|
+
|
|
153
|
+
### `bot.init()`
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
init(): Promise<this>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Calls `getMe()`, stores the bot information, processes the approval gate if active, then runs plugin lifecycle `setup()` and `start()`.
|
|
160
|
+
|
|
161
|
+
If approval has not been granted, the method sets the status to `"awaiting-approval"`, notifies the owner via the `ApprovalGate`, and returns the bot without marking it as `initialized`. Subsequent calls can be used after the owner grants approval.
|
|
162
|
+
|
|
163
|
+
`init()` is idempotent when the status is already `initialized` or `running`.
|
|
164
|
+
|
|
165
|
+
### `bot.start()`
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
start(): Promise<void>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Shortcut for `launch({ mode: "polling" })`. This method runs long polling and waits until polling is stopped or fails fatally.
|
|
172
|
+
|
|
173
|
+
### `bot.launch(options?)`
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
launch(options?: {
|
|
177
|
+
mode: "polling";
|
|
178
|
+
timeout?: number;
|
|
179
|
+
allowedUpdates?: string[];
|
|
180
|
+
}): Promise<void>
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Runs the bot in polling mode. On start, the lifecycle moves through `starting` to `running`, then the `getUpdates()` loop processes each update sequentially. Polling failures emit `polling:reconnect` and use exponential backoff.
|
|
184
|
+
|
|
185
|
+
Modes other than `"polling"` throw an error and suggest using `createWebhookHandler()` for webhooks.
|
|
186
|
+
|
|
187
|
+
### `bot.stop()`
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
stop(): Promise<void>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Stops polling via an `AbortController`, runs `plugins.dispose()`, sets the status to `stopped`, and emits stopping/stopped events. Calling it when the status is `created` or `stopped` does nothing.
|
|
194
|
+
|
|
195
|
+
### `bot.restart()`
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
restart(): Promise<void>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Runs `stop()` and then `start()`.
|
|
202
|
+
|
|
203
|
+
### `bot.health()`
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
health(): Promise<HealthStatus>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Calls `getMe()` to check API reachability. It does not throw on request failures; failures are returned as `apiReachable: false` with an error message.
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
interface HealthStatus {
|
|
213
|
+
status: BotStatus;
|
|
214
|
+
apiReachable: boolean;
|
|
215
|
+
bot?: User;
|
|
216
|
+
checkedAt: string; // ISO timestamp
|
|
217
|
+
error?: string;
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### `bot.getMe()`
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
getMe(): Promise<User>
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Fetches the bot data from Telegram and updates `botInfo`.
|
|
228
|
+
|
|
229
|
+
### `bot.setCommands(commands, scope?, languageCode?)`
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
setCommands(
|
|
233
|
+
commands: BotCommand[],
|
|
234
|
+
scope?: BotCommandScope,
|
|
235
|
+
languageCode?: string,
|
|
236
|
+
): Promise<true>
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Shortcut to `setMyCommands`. `languageCode` is mapped to Telegram's `language_code` field.
|
|
240
|
+
|
|
241
|
+
### `bot.deleteCommands(scope?, languageCode?)`
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
deleteCommands(
|
|
245
|
+
scope?: BotCommandScope,
|
|
246
|
+
languageCode?: string,
|
|
247
|
+
): Promise<true>
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Shortcut to `deleteMyCommands`.
|
|
251
|
+
|
|
252
|
+
### `bot.handleUpdate(update)`
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
handleUpdate(update: Update): Promise<void>
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Processes a single update manually. The method determines the session key from `chat.id` and `from.id`, creates a `Context`, emits `update` and `message` events, runs middleware then the router, and saves the session after the pipeline completes.
|
|
259
|
+
|
|
260
|
+
If approval is active and the bot has not been approved, normal updates are stopped. Approval callbacks are still forwarded to `ApprovalGate.handleCallback()`.
|
|
261
|
+
|
|
262
|
+
Pipeline errors set the bot status to `error`, emit `bot:error`, and then rethrow the error.
|
|
263
|
+
|
|
264
|
+
### Minimal bot example
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
import { Bot, InlineKeyboard } from "@xbibzlibrary/telebibz";
|
|
268
|
+
|
|
269
|
+
const bot = new Bot({
|
|
270
|
+
token: process.env.TELEGRAM_BOT_TOKEN!,
|
|
271
|
+
polling: { allowedUpdates: ["message", "callback_query"] },
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
bot.command("start", async (ctx) => {
|
|
275
|
+
await ctx.reply("Hello from telebibz", {
|
|
276
|
+
reply_markup: new InlineKeyboard()
|
|
277
|
+
.text("Status", "status")
|
|
278
|
+
.build(),
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
bot.callback("status", async (ctx) => {
|
|
283
|
+
await ctx.answerCallbackQuery("Bot is active");
|
|
284
|
+
await ctx.reply("Status: running");
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
await bot.start();
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## 2. Event bus
|
|
293
|
+
|
|
294
|
+
### `EventMap`
|
|
295
|
+
|
|
296
|
+
| Event | Payload |
|
|
297
|
+
|---|---|
|
|
298
|
+
| `bot:created` | `{ bot: unknown }` |
|
|
299
|
+
| `bot:initialized` | `{ bot: unknown }` |
|
|
300
|
+
| `bot:starting` | `{ bot: unknown }` |
|
|
301
|
+
| `bot:started` | `{ bot: unknown }` |
|
|
302
|
+
| `bot:stopping` | `{ bot: unknown }` |
|
|
303
|
+
| `bot:stopped` | `{ bot: unknown }` |
|
|
304
|
+
| `bot:error` | `{ bot: unknown; error: unknown }` |
|
|
305
|
+
| `update` | `{ update: unknown }` |
|
|
306
|
+
| `message` | `{ message: unknown }` |
|
|
307
|
+
| `command` | `{ name: string; update: unknown }` |
|
|
308
|
+
| `callback` | `{ data: string; update: unknown }` |
|
|
309
|
+
| `api:request` | `{ method: string; payload: unknown }` |
|
|
310
|
+
| `api:response` | `{ method: string; durationMs: number; response: unknown }` |
|
|
311
|
+
| `api:error` | `{ method: string; durationMs: number; error: unknown }` |
|
|
312
|
+
| `webhook:request` | `{ update: unknown }` |
|
|
313
|
+
| `polling:reconnect` | `{ error: unknown; attempt: number }` |
|
|
314
|
+
|
|
315
|
+
### `EventBus<Events>`
|
|
316
|
+
|
|
317
|
+
```ts
|
|
318
|
+
new EventBus<Events extends Record<string, unknown> = EventMap>()
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
| Method | Signature | Behavior |
|
|
322
|
+
|---|---|---|
|
|
323
|
+
| `on` | `on<K>(event: K, listener: (payload: Events[K]) => void \| Promise<void>): () => void` | Adds a listener and returns an unsubscribe function. |
|
|
324
|
+
| `once` | `once<K>(event: K, listener: ...): () => void` | Listener is called only once, then removed. |
|
|
325
|
+
| `off` | `off<K>(event: K, listener: ...): void` | Removes a specific listener. |
|
|
326
|
+
| `emit` | `emit<K>(event: K, payload: Events[K]): Promise<void>` | Calls listeners sequentially and awaits each. |
|
|
327
|
+
| `removeAllListeners` | `removeAllListeners(): void` | Removes all listeners. |
|
|
328
|
+
| `listenerCount` | `listenerCount<K>(event: K): number` | Returns the number of listeners for the event. |
|
|
329
|
+
|
|
330
|
+
```ts
|
|
331
|
+
const unsubscribe = bot.events.on("bot:error", ({ error }) => {
|
|
332
|
+
console.error(error);
|
|
333
|
+
});
|
|
334
|
+
unsubscribe();
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## 3. API client, transport, and errors
|
|
340
|
+
|
|
341
|
+
### Basic types
|
|
342
|
+
|
|
343
|
+
```ts
|
|
344
|
+
type ChatId = number | string;
|
|
345
|
+
type ParseMode = "Markdown" | "MarkdownV2" | "HTML";
|
|
346
|
+
type InputFile =
|
|
347
|
+
| string
|
|
348
|
+
| Uint8Array
|
|
349
|
+
| ArrayBuffer
|
|
350
|
+
| Blob
|
|
351
|
+
| NodeJS.ReadableStream
|
|
352
|
+
| { source: string | Uint8Array | ArrayBuffer | Blob | NodeJS.ReadableStream; filename?: string };
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
`InputFile` string can be a plain string or a file path when used as the `source` in an upload object. In Node.js, absolute paths, `./...`, and `../...` are read by `FetchTransport` and then sent as multipart files.
|
|
356
|
+
|
|
357
|
+
### `TelegramResponse<T>`
|
|
358
|
+
|
|
359
|
+
```ts
|
|
360
|
+
interface TelegramResponse<T> {
|
|
361
|
+
ok: boolean;
|
|
362
|
+
result?: T;
|
|
363
|
+
description?: string;
|
|
364
|
+
error_code?: number;
|
|
365
|
+
parameters?: ResponseParameters;
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### `TransportRequest`, `TransportResponse`, and `Transport`
|
|
370
|
+
|
|
371
|
+
```ts
|
|
372
|
+
interface TransportRequest {
|
|
373
|
+
method: string;
|
|
374
|
+
payload?: Record<string, unknown>;
|
|
375
|
+
signal?: AbortSignal;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
interface TransportResponse<T = unknown> {
|
|
379
|
+
status: number;
|
|
380
|
+
headers: Headers;
|
|
381
|
+
data: TelegramResponse<T>;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
interface Transport {
|
|
385
|
+
request<T>(request: TransportRequest): Promise<TransportResponse<T>>;
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### `FetchTransportOptions`
|
|
390
|
+
|
|
391
|
+
| Property | Default | Description |
|
|
392
|
+
|---|---:|---|
|
|
393
|
+
| `baseUrl` | `https://api.telegram.org` | URL prefix before `/<method>`. |
|
|
394
|
+
| `fetch` | `globalThis.fetch` | Custom fetch implementation. |
|
|
395
|
+
| `timeoutMs` | `30000` | Timeout per attempt. |
|
|
396
|
+
| `retries` | `2` | Number of retries for network errors after the initial attempt. |
|
|
397
|
+
| `backoffMs` | `250` | Initial exponential delay. |
|
|
398
|
+
| `maxBackoffMs` | `8000` | Transport delay cap. |
|
|
399
|
+
| `jitter` | `0.2` | Random variation ±20% of the exponential delay. |
|
|
400
|
+
| `headers` | `{}` | Additional headers. |
|
|
401
|
+
|
|
402
|
+
### `new FetchTransport(options?)`
|
|
403
|
+
|
|
404
|
+
```ts
|
|
405
|
+
new FetchTransport(options?: FetchTransportOptions): FetchTransport
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
Default transport based on `fetch`. Payloads without uploads are sent as JSON. Payloads that contain `Uint8Array`, `ArrayBuffer`, `Blob`, or nested uploads are sent as `multipart/form-data` using `FormData`.
|
|
409
|
+
|
|
410
|
+
### `fetchTransport.request(request)`
|
|
411
|
+
|
|
412
|
+
```ts
|
|
413
|
+
request<T>(request: TransportRequest): Promise<TransportResponse<T>>
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
Sends a POST to `${baseUrl}/${method}`. Methods with a leading `/` are normalized. External AbortSignals are forwarded to the internal controller. Network errors considered retryable are retried with exponential backoff and jitter; when retries are exhausted, the error is wrapped as a `TelegramNetworkError`.
|
|
417
|
+
|
|
418
|
+
### `ApiHookContext`, `ApiClientOptions`, and `ApiMethods`
|
|
419
|
+
|
|
420
|
+
```ts
|
|
421
|
+
interface ApiHookContext {
|
|
422
|
+
method: string;
|
|
423
|
+
payload: unknown;
|
|
424
|
+
startedAt: number;
|
|
425
|
+
durationMs?: number;
|
|
426
|
+
response?: TelegramResponse<unknown>;
|
|
427
|
+
error?: unknown;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
interface ApiClientOptions {
|
|
431
|
+
transport: Transport;
|
|
432
|
+
hooks?: {
|
|
433
|
+
onRequest?: (context: ApiHookContext) => void | Promise<void>;
|
|
434
|
+
onResponse?: (context: ApiHookContext) => void | Promise<void>;
|
|
435
|
+
onError?: (context: ApiHookContext) => void | Promise<void>;
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
`ApiMethods` is a mapped type of the 184 `TelegramMethodName`s:
|
|
441
|
+
|
|
442
|
+
```ts
|
|
443
|
+
type ApiMethods = {
|
|
444
|
+
[M in TelegramMethodName]:
|
|
445
|
+
(...args: ApiCallArgs<M>) => Promise<ApiResult<M>>;
|
|
446
|
+
};
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### `new ApiClient(options)`
|
|
450
|
+
|
|
451
|
+
```ts
|
|
452
|
+
new ApiClient(options: ApiClientOptions): ApiClient
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
Creates dynamic proxy methods on `client.methods`. The `onRequest` hook is called before the transport, `onResponse` after a response is received, and `onError` when a request fails or Telegram's response is `ok: false`.
|
|
456
|
+
|
|
457
|
+
### `api.methods.<method>(params?)`
|
|
458
|
+
|
|
459
|
+
Dynamic methods can be called directly. Methods that have empty parameters like `getMe()` are called without arguments; other methods accept a single parameter object.
|
|
460
|
+
|
|
461
|
+
```ts
|
|
462
|
+
const me = await bot.api.methods.getMe();
|
|
463
|
+
const chat = await bot.api.methods.getChat({ chat_id: "@channel" });
|
|
464
|
+
const message = await bot.api.methods.sendMessage({
|
|
465
|
+
chat_id: 123456789,
|
|
466
|
+
text: "Hello",
|
|
467
|
+
});
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### `api.call(method, ...args)`
|
|
471
|
+
|
|
472
|
+
```ts
|
|
473
|
+
call<M extends TelegramMethodName>(
|
|
474
|
+
method: M,
|
|
475
|
+
...args: ApiCallArgs<M>
|
|
476
|
+
): Promise<ApiResult<M>>
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
Typed form for calling a method based on a string literal.
|
|
480
|
+
|
|
481
|
+
### `api.request(method, payload?, signal?)`
|
|
482
|
+
|
|
483
|
+
```ts
|
|
484
|
+
request<M extends TelegramMethodName>(
|
|
485
|
+
method: M,
|
|
486
|
+
payload?: ApiParams<M>,
|
|
487
|
+
signal?: AbortSignal,
|
|
488
|
+
): Promise<ApiResult<M>>
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
Low-level request method that allows an explicit `AbortSignal`.
|
|
492
|
+
|
|
493
|
+
### `api.raw(method, payload?, signal?)`
|
|
494
|
+
|
|
495
|
+
```ts
|
|
496
|
+
raw(
|
|
497
|
+
method: string,
|
|
498
|
+
payload?: Record<string, unknown>,
|
|
499
|
+
signal?: AbortSignal,
|
|
500
|
+
): Promise<unknown>
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
Calls an arbitrary method string on the transport. Use this for Telegram methods or new parameters not yet included in `TelegramMethodMap`. Responses with `ok: false` are still converted into a `TelegramError`.
|
|
504
|
+
|
|
505
|
+
### Available typed parameters and results
|
|
506
|
+
|
|
507
|
+
The following types are specially mapped in this release.
|
|
508
|
+
|
|
509
|
+
| Method | Parameter | Result |
|
|
510
|
+
|---|---|---|
|
|
511
|
+
| `getMe` | tidak ada | `User` |
|
|
512
|
+
| `getUpdates` | `GetUpdatesParams` | `Update[]` |
|
|
513
|
+
| `setWebhook` | `SetWebhookParams` | `boolean` |
|
|
514
|
+
| `deleteWebhook` | `{ drop_pending_updates?: boolean }` | `boolean` |
|
|
515
|
+
| `getWebhookInfo` | tidak ada | `WebhookInfo` |
|
|
516
|
+
| `sendMessage` | `SendMessageParams` | `Message` |
|
|
517
|
+
| `editMessageText` | `EditMessageTextParams` | `Message \| true` |
|
|
518
|
+
| `deleteMessage` | `DeleteMessageParams` | `true` |
|
|
519
|
+
| `answerCallbackQuery` | `AnswerCallbackQueryParams` | `true` |
|
|
520
|
+
| `getChat` | `GetChatParams` | `Chat` |
|
|
521
|
+
| `getFile` | `GetFileParams` | `File` |
|
|
522
|
+
| `getUserProfilePhotos` | `{ user_id: number; offset?: number; limit?: number }` | `UserProfilePhotos` |
|
|
523
|
+
| `sendPhoto` | `SendPhotoParams` | `Message` |
|
|
524
|
+
| `sendDocument` | `SendDocumentParams` | `Message` |
|
|
525
|
+
|
|
526
|
+
Additional parameter types available are `ReplyParameters`, `LinkPreviewOptions`, `InlineKeyboardButton`, `ReplyMarkup`, `BotCommand`, `BotCommandScope`, and all Telegram update types exported from `api/types.ts`.
|
|
527
|
+
|
|
528
|
+
### API Errors
|
|
529
|
+
|
|
530
|
+
```ts
|
|
531
|
+
type TelegramErrorKind =
|
|
532
|
+
| "retryable"
|
|
533
|
+
| "rate-limit"
|
|
534
|
+
| "authentication"
|
|
535
|
+
| "validation"
|
|
536
|
+
| "network"
|
|
537
|
+
| "server"
|
|
538
|
+
| "unknown";
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
#### `TelegramError`
|
|
542
|
+
|
|
543
|
+
```ts
|
|
544
|
+
new TelegramError(message: string, options: {
|
|
545
|
+
method: string;
|
|
546
|
+
payload: unknown;
|
|
547
|
+
errorCode?: number;
|
|
548
|
+
parameters?: ResponseParameters;
|
|
549
|
+
status?: number;
|
|
550
|
+
kind?: TelegramErrorKind;
|
|
551
|
+
cause?: unknown;
|
|
552
|
+
})
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
Public properties are `kind`, `errorCode`, `parameters`, `method`, `payload`, and `status`. The `retryAfter` getter reads `parameters.retry_after`; the `migrateToChatId` getter reads `parameters.migrate_to_chat_id`.
|
|
556
|
+
|
|
557
|
+
#### Subclass errors
|
|
558
|
+
|
|
559
|
+
| Class | `name` | forced `kind` |
|
|
560
|
+
|---|---|---|
|
|
561
|
+
| `TelegramRateLimitError` | `TelegramRateLimitError` | `rate-limit` |
|
|
562
|
+
| `TelegramAuthError` | `TelegramAuthError` | `authentication` |
|
|
563
|
+
| `TelegramValidationError` | `TelegramValidationError` | `validation` |
|
|
564
|
+
| `TelegramNetworkError` | `TelegramNetworkError` | `network` |
|
|
565
|
+
|
|
566
|
+
All four subclasses use the same constructor options as `TelegramError`.
|
|
567
|
+
|
|
568
|
+
#### `classifyTelegramError(errorCode?, status?)`
|
|
569
|
+
|
|
570
|
+
```ts
|
|
571
|
+
classifyTelegramError(
|
|
572
|
+
errorCode?: number,
|
|
573
|
+
status?: number,
|
|
574
|
+
): TelegramErrorKind
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
Actual classification: `429` becomes `rate-limit`; error `401` or HTTP `401/403` becomes `authentication`; error codes `400–499` become `validation`; HTTP `500+` becomes `server`; otherwise `unknown`.
|
|
578
|
+
|
|
579
|
+
#### `telegramErrorFromResponse(response, context)`
|
|
580
|
+
|
|
581
|
+
```ts
|
|
582
|
+
telegramErrorFromResponse<T>(
|
|
583
|
+
response: TelegramResponse<T>,
|
|
584
|
+
context: { method: string; payload: unknown; status?: number },
|
|
585
|
+
): TelegramError
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
Converts a failed Telegram response into the appropriate subclass. `429`, auth, and validation errors produce specific subclasses; other errors produce a plain `TelegramError`.
|
|
589
|
+
|
|
590
|
+
---
|
|
591
|
+
|
|
592
|
+
## 4. Context
|
|
593
|
+
|
|
594
|
+
### `ContextOptions<S>`
|
|
595
|
+
|
|
596
|
+
```ts
|
|
597
|
+
interface ContextOptions<S extends object = Record<string, unknown>> {
|
|
598
|
+
update: Update;
|
|
599
|
+
api: ApiClient;
|
|
600
|
+
session: S;
|
|
601
|
+
services: Record<string, unknown>;
|
|
602
|
+
}
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
### `Context<S>` properties
|
|
606
|
+
|
|
607
|
+
| Properti | Isi |
|
|
608
|
+
|---|---|
|
|
609
|
+
| `update` | Raw Telegram update. |
|
|
610
|
+
| `api` | The bot's `ApiClient`. |
|
|
611
|
+
| `session` | Mutable session object for the current update key. |
|
|
612
|
+
| `state` | Per-context transient object, not automatically saved to the session. |
|
|
613
|
+
| `services` | Services injected via `BotOptions.services`. |
|
|
614
|
+
| `params` | Route parameters object; the built-in router currently does not populate it automatically. |
|
|
615
|
+
| `message` | The main message from message/edited/channel/business/guest updates. |
|
|
616
|
+
| `chat` | `message.chat` when available. |
|
|
617
|
+
| `from` / `sender` | User from the message, callback query, or inline query. |
|
|
618
|
+
| `callbackQuery` | `update.callback_query`. |
|
|
619
|
+
| `inlineQuery` | `update.inline_query`. |
|
|
620
|
+
| `poll` | `update.poll`. |
|
|
621
|
+
| `pollAnswer` | `update.poll_answer`. |
|
|
622
|
+
| `chatMember` | `update.chat_member`. |
|
|
623
|
+
| `myChatMember` | `update.my_chat_member`. |
|
|
624
|
+
| `chatJoinRequest` | `update.chat_join_request`. |
|
|
625
|
+
| `reaction` | `update.message_reaction`. |
|
|
626
|
+
| `boost` | `chat_boost` or `removed_chat_boost`. |
|
|
627
|
+
|
|
628
|
+
### `new Context(options)`
|
|
629
|
+
|
|
630
|
+
```ts
|
|
631
|
+
new Context<S>(options: ContextOptions<S>): Context<S>
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
### Context message methods
|
|
635
|
+
|
|
636
|
+
| Method | Signature | Behavior |
|
|
637
|
+
|---|---|---|
|
|
638
|
+
| `reply` | `reply(text, extra?): Promise<Message>` | Sends a message to the update chat and sets `reply_parameters.message_id` if there is a message. |
|
|
639
|
+
| `send` | `send(text, extra?): Promise<Message>` | Sends a message to the update chat without a reply reference. |
|
|
640
|
+
| `edit` | `edit(text, extra?): Promise<Message \| true>` | Edits the update message using `editMessageText`. |
|
|
641
|
+
| `delete` | `delete(): Promise<true>` | Deletes the update message. |
|
|
642
|
+
| `copy` | `copy(fromChatId, messageId, extra?): Promise<unknown>` | Calls `copyMessage` to the context chat. |
|
|
643
|
+
| `forward` | `forward(fromChatId, messageId, extra?): Promise<Message>` | Calls `forwardMessage` to the context chat. |
|
|
644
|
+
| `pin` | `pin(messageId?, extra?): Promise<true>` | Calls `pinChatMessage`; defaults to the context message id. |
|
|
645
|
+
| `unpin` | `unpin(messageId?, extra?): Promise<true>` | Calls `unpinChatMessage`; defaults to the context message id. |
|
|
646
|
+
| `react` | `react(reaction, extra?): Promise<true>` | Calls `setMessageReaction`. |
|
|
647
|
+
| `answerCallbackQuery` | `answerCallbackQuery(text?, extra?): Promise<true>` | Answers the active callback query. Throws an error if the update is not a callback. |
|
|
648
|
+
| `answerInlineQuery` | `answerInlineQuery(results, extra?): Promise<true>` | Answers the active inline query. Throws an error if the update is not an inline query. |
|
|
649
|
+
| `getChat` | `getChat(): Promise<Chat>` | Fetches the context chat details. |
|
|
650
|
+
| `getUserProfilePhotos` | `getUserProfilePhotos(userId?, extra?): Promise<unknown>` | Fetches the context user's profile photos. |
|
|
651
|
+
| `getFile` | `getFile(fileId): Promise<unknown>` | Fetches a file by id. |
|
|
652
|
+
| `withReplyMarkup` | `withReplyMarkup(markup): this` | Stores markup in `ctx.state.reply_markup` and returns the context. This method does not automatically send a message. |
|
|
653
|
+
|
|
654
|
+
`reply`, `send`, `getChat`, and some other helpers throw an error when the update does not have the required chat. `edit` and `delete` require both chat and message.
|
|
655
|
+
|
|
656
|
+
---
|
|
657
|
+
|
|
658
|
+
## 5. Middleware and router
|
|
659
|
+
|
|
660
|
+
### Types of middleware
|
|
661
|
+
|
|
662
|
+
```ts
|
|
663
|
+
type Next = () => Promise<void>;
|
|
664
|
+
type Middleware<Context> = (ctx: Context, next: Next) => void | Promise<void>;
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
### `compose(middleware)`
|
|
668
|
+
|
|
669
|
+
```ts
|
|
670
|
+
compose<Context>(
|
|
671
|
+
middleware: readonly Middleware<Context>[],
|
|
672
|
+
): (ctx: Context) => Promise<void>
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
Compose middleware in an onion pattern. `next()` runs the next middleware. If the same middleware calls `next()` more than once, compose throws `Error("next() called multiple times")`.
|
|
676
|
+
|
|
677
|
+
### `middleware(handler)`
|
|
678
|
+
|
|
679
|
+
```ts
|
|
680
|
+
middleware<Context>(handler: Middleware<Context>): Middleware<Context>
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
Identity helper to provide type annotation/inference for middleware.
|
|
684
|
+
|
|
685
|
+
### `RoutableContext`
|
|
686
|
+
|
|
687
|
+
Minimal context required by the router: `update`, `message`, `callbackQuery`, and `params`.
|
|
688
|
+
|
|
689
|
+
### `Router<Context>`
|
|
690
|
+
|
|
691
|
+
```ts
|
|
692
|
+
new Router<Context extends RoutableContext>(): Router<Context>
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
Routes are processed according to priority and registration order. A matching route does not automatically stop subsequent routes; all matching routes may run. If no route matches, `terminal` on `handle` is called.
|
|
696
|
+
|
|
697
|
+
| Method | Signature | Matching |
|
|
698
|
+
|---|---|---|
|
|
699
|
+
| `use` | `use(...middleware): this` | Router-global middleware with the highest priority, executed early. |
|
|
700
|
+
| `route` | `route(matcher, ...middleware): this` | Boolean or async custom matcher. |
|
|
701
|
+
| `command` | `command(name: string \| RegExp, ...middleware): this` | First command from message text starting with `/`. |
|
|
702
|
+
| `text` | `text(value: string, ...middleware): this` | Exact text matching. |
|
|
703
|
+
| `regex` | `regex(expression: RegExp, ...middleware): this` | `RegExp.test` against the message text or empty string. |
|
|
704
|
+
| `callback` | `callback(pattern: string \| RegExp, ...middleware): this` | Exact, prefix with suffix `*`, or regex against callback data. |
|
|
705
|
+
| `chat` | `chat(chatId: number \| string, ...middleware): this` | Match `message.chat.id`, numeric or string-equivalent. |
|
|
706
|
+
| `predicate` | `predicate(matcher, ...middleware): this` | Semantic alias for a custom matcher. |
|
|
707
|
+
| `nest` | `nest(child: Router<Context>): this` | Run a child router as a nested route. |
|
|
708
|
+
| `handle` | `handle(ctx, terminal?): Promise<void>` | Evaluate and execute all matching routes. |
|
|
709
|
+
|
|
710
|
+
```ts
|
|
711
|
+
const router = new Router<Context>();
|
|
712
|
+
router.use(async (ctx, next) => {
|
|
713
|
+
console.log("before");
|
|
714
|
+
await next();
|
|
715
|
+
});
|
|
716
|
+
router.callback("page:*", async (ctx) => {
|
|
717
|
+
await ctx.answerCallbackQuery();
|
|
718
|
+
});
|
|
719
|
+
router.predicate((ctx) => Boolean(ctx.from?.id), async (ctx) => {
|
|
720
|
+
await ctx.reply("Authenticated update");
|
|
721
|
+
});
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
**RegExp note.** The router calls `.test()` directly. For expressions with flags `g` or `y`, JavaScript's stateful `lastIndex` property can affect repeated matching.
|
|
725
|
+
|
|
726
|
+
---
|
|
727
|
+
|
|
728
|
+
## 6. Keyboard builders
|
|
729
|
+
|
|
730
|
+
### `InlineKeyboard`
|
|
731
|
+
|
|
732
|
+
```ts
|
|
733
|
+
new InlineKeyboard(): InlineKeyboard
|
|
734
|
+
InlineKeyboard.from(rows: InlineKeyboardButton[][]): InlineKeyboard
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
The builder stores rows mutably and all builder methods return `this`.
|
|
738
|
+
|
|
739
|
+
| Method | Signature | Description |
|
|
740
|
+
|---|---|---|
|
|
741
|
+
| `from` | `static from(rows): InlineKeyboard` | Creates a keyboard from rows and copies each row. |
|
|
742
|
+
| `text` | `text(text, callbackData): this` | Callback button. |
|
|
743
|
+
| `url` | `url(text, url): this` | URL button. |
|
|
744
|
+
| `webApp` | `webApp(text, url): this` | Web App button. |
|
|
745
|
+
| `pay` | `pay(text = "Pay"): this` | Payment button. |
|
|
746
|
+
| `copy` | `copy(text, copiedText): this` | Copy text button. |
|
|
747
|
+
| `button` | `button(button): this` | Adds a single button to the last row or creates the first row. |
|
|
748
|
+
| `row` | `row(...buttons): this` | Adds a new row. |
|
|
749
|
+
| `conditional` | `conditional(condition, factory): this` | Runs the factory only if the condition is true. |
|
|
750
|
+
| `grid` | `grid(buttons, columns): this` | Splits buttons into rows based on the number of columns. |
|
|
751
|
+
| `build` | `build(): InlineKeyboardMarkup` | Produces a new markup. |
|
|
752
|
+
| `asReplyMarkup` | `asReplyMarkup(): InlineKeyboardMarkup` | Alias for `build`. |
|
|
753
|
+
|
|
754
|
+
Each inline button must have `text` and exactly one action. Callback data is limited to a maximum of 64 UTF-8 bytes; violations throw `RangeError`.
|
|
755
|
+
|
|
756
|
+
```ts
|
|
757
|
+
const keyboard = new InlineKeyboard()
|
|
758
|
+
.text("Allow", "approve:123")
|
|
759
|
+
.url("Documentation", "https://example.com")
|
|
760
|
+
.row(
|
|
761
|
+
{ text: "A", callback_data: "a" },
|
|
762
|
+
{ text: "B", callback_data: "b" },
|
|
763
|
+
)
|
|
764
|
+
.build();
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
### `ReplyKeyboard`
|
|
768
|
+
|
|
769
|
+
```ts
|
|
770
|
+
new ReplyKeyboard(): ReplyKeyboard
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
| Method | Signature | Description |
|
|
774
|
+
|---|---|---|
|
|
775
|
+
| `text` | `text(text): this` | Plain text button. |
|
|
776
|
+
| `contact` | `contact(text): this` | Requests contact. |
|
|
777
|
+
| `location` | `location(text): this` | Requests location. |
|
|
778
|
+
| `poll` | `poll(text, type?): this` | Requests a poll of type `quiz` or `regular`. |
|
|
779
|
+
| `webApp` | `webApp(text, url): this` | Web App button. |
|
|
780
|
+
| `button` | `button(button): this` | Adds one button to the last row. |
|
|
781
|
+
| `row` | `row(...buttons): this` | Adds a new row. |
|
|
782
|
+
| `grid` | `grid(buttons, columns): this` | Splits buttons into a grid. |
|
|
783
|
+
| `build` | `build(options?): ReplyKeyboardMarkup` | Produces the markup and merges options. |
|
|
784
|
+
| `asReplyMarkup` | `asReplyMarkup(): ReplyKeyboardMarkup` | Alias for `build()` without options. |
|
|
785
|
+
|
|
786
|
+
`columns` must be a positive integer; otherwise `grid` throws `RangeError`.
|
|
787
|
+
|
|
788
|
+
### `removeKeyboard(selective?)`
|
|
789
|
+
|
|
790
|
+
```ts
|
|
791
|
+
removeKeyboard(selective = false): ReplyMarkup
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
Generates `{ remove_keyboard: true }`, with `selective: true` if requested.
|
|
795
|
+
|
|
796
|
+
### `forceReply(placeholder?, selective?)`
|
|
797
|
+
|
|
798
|
+
```ts
|
|
799
|
+
forceReply(placeholder?: string, selective = false): ReplyMarkup
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
Generates a ForceReply. The placeholder is only added if it is truthy.
|
|
803
|
+
|
|
804
|
+
---
|
|
805
|
+
|
|
806
|
+
## 7. Storage and cache
|
|
807
|
+
|
|
808
|
+
### `Storage<K, V>`
|
|
809
|
+
|
|
810
|
+
```ts
|
|
811
|
+
interface Storage<K, V> {
|
|
812
|
+
get(key: K): Promise<V | undefined>;
|
|
813
|
+
set(key: K, value: V, options?: { ttlMs?: number }): Promise<void>;
|
|
814
|
+
delete(key: K): Promise<boolean>;
|
|
815
|
+
has(key: K): Promise<boolean>;
|
|
816
|
+
clear(): Promise<void>;
|
|
817
|
+
keys(): AsyncIterable<K>;
|
|
818
|
+
values(): AsyncIterable<V>;
|
|
819
|
+
entries(): AsyncIterable<[K, V]>;
|
|
820
|
+
update<T extends V>(
|
|
821
|
+
key: K,
|
|
822
|
+
updater: (current: V | undefined) => T | Promise<T>,
|
|
823
|
+
options?: { ttlMs?: number },
|
|
824
|
+
): Promise<T>;
|
|
825
|
+
}
|
|
826
|
+
```
|
|
827
|
+
|
|
828
|
+
### `MemoryStorage<K, V>`
|
|
829
|
+
|
|
830
|
+
```ts
|
|
831
|
+
new MemoryStorage<K, V>(): MemoryStorage<K, V>
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
In-memory implementation based on `Map`. TTLs are cleaned up lazily when keys are read or iterated; there is no background timer. `update` ensures per-key updater operations run serially so concurrent updates for the same key do not unpredictably overwrite each other.
|
|
835
|
+
|
|
836
|
+
```ts
|
|
837
|
+
const sessions = new MemoryStorage<string, { count: number }>();
|
|
838
|
+
await sessions.set("user:1", { count: 0 }, { ttlMs: 60_000 });
|
|
839
|
+
await sessions.update("user:1", (current) => ({
|
|
840
|
+
count: (current?.count ?? 0) + 1,
|
|
841
|
+
}));
|
|
842
|
+
```
|
|
843
|
+
|
|
844
|
+
### `Cache<K, V>`
|
|
845
|
+
|
|
846
|
+
```ts
|
|
847
|
+
interface Cache<K = string, V = unknown> {
|
|
848
|
+
get(key: K): Promise<V | undefined>;
|
|
849
|
+
set(key: K, value: V, ttlMs?: number): Promise<void>;
|
|
850
|
+
delete(key: K): Promise<boolean>;
|
|
851
|
+
invalidate(prefix?: string): Promise<void>;
|
|
852
|
+
getOrSet(key: K, factory: () => V | Promise<V>, ttlMs?: number): Promise<V>;
|
|
853
|
+
}
|
|
854
|
+
```
|
|
855
|
+
|
|
856
|
+
### `MemoryCache`
|
|
857
|
+
|
|
858
|
+
```ts
|
|
859
|
+
new MemoryCache(namespace = "telebibz"): MemoryCache
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
Cache that uses strings as keys and applies an internal namespace to each key.
|
|
863
|
+
|
|
864
|
+
| Method | Behavior |
|
|
865
|
+
|---|---|
|
|
866
|
+
| `get` | Retrieves the value or `undefined`. |
|
|
867
|
+
| `set` | Stores the value with an optional TTL. |
|
|
868
|
+
| `delete` | Deletes the key and returns a boolean. |
|
|
869
|
+
| `invalidate(prefix = "")` | Removes all keys in the namespace that start with the prefix. |
|
|
870
|
+
| `getOrSet` | Returns the value from cache if present; if not, runs the factory, stores its result, then returns it. |
|
|
871
|
+
|
|
872
|
+
`getOrSet` does not use deduplication locking; the factory may run more than once if called concurrently while the key is missing.
|
|
873
|
+
|
|
874
|
+
### `RateLimitResult`
|
|
875
|
+
|
|
876
|
+
```ts
|
|
877
|
+
interface RateLimitResult {
|
|
878
|
+
allowed: boolean;
|
|
879
|
+
remaining: number;
|
|
880
|
+
resetAt: number;
|
|
881
|
+
retryAfterMs?: number;
|
|
882
|
+
}
|
|
883
|
+
```
|
|
884
|
+
|
|
885
|
+
### `TokenBucketLimiter`
|
|
886
|
+
|
|
887
|
+
```ts
|
|
888
|
+
new TokenBucketLimiter(
|
|
889
|
+
capacity: number,
|
|
890
|
+
refillPerSecond: number,
|
|
891
|
+
): TokenBucketLimiter
|
|
892
|
+
```
|
|
893
|
+
|
|
894
|
+
The constructor throws a `RangeError` if either value is not positive. `consume(key, cost = 1)` deducts tokens if available; if there are not enough, it returns `allowed: false` and an estimated `retryAfterMs`. `clear(key?)` removes a single bucket or all buckets.
|
|
895
|
+
|
|
896
|
+
---
|
|
897
|
+
|
|
898
|
+
## 8. Queue and scheduler
|
|
899
|
+
|
|
900
|
+
### `Job<T>` and `QueueOptions`
|
|
901
|
+
|
|
902
|
+
```ts
|
|
903
|
+
interface Job<T = unknown> {
|
|
904
|
+
id: string;
|
|
905
|
+
data: T;
|
|
906
|
+
attempts: number;
|
|
907
|
+
priority: number;
|
|
908
|
+
runAt: number;
|
|
909
|
+
status: "queued" | "running" | "completed" | "failed" | "cancelled";
|
|
910
|
+
error?: unknown;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
interface QueueOptions {
|
|
914
|
+
concurrency?: number;
|
|
915
|
+
retries?: number;
|
|
916
|
+
backoffMs?: number;
|
|
917
|
+
maxBackoffMs?: number;
|
|
918
|
+
}
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
### `TaskQueue<T>`
|
|
922
|
+
|
|
923
|
+
```ts
|
|
924
|
+
new TaskQueue<T>(
|
|
925
|
+
worker: (job: Job<T>, signal: AbortSignal) => Promise<void>,
|
|
926
|
+
options?: QueueOptions,
|
|
927
|
+
): TaskQueue<T>
|
|
928
|
+
```
|
|
929
|
+
|
|
930
|
+
| Method | Signature | Description |
|
|
931
|
+
|---|---|---|
|
|
932
|
+
| `add` | `add(data, options?): Job<T>` | Adds a job; options `id`, `priority`, `delayMs`. Job is scheduled immediately. |
|
|
933
|
+
| `get` | `get(id): Job<T> \| undefined` | Returns a copy of the job status. |
|
|
934
|
+
| `cancel` | `cancel(id): boolean` | Cancels a queued or running job and aborts the worker via its `AbortSignal`. |
|
|
935
|
+
| `onIdle` | `onIdle(): Promise<void>` | Waits until pending and active are empty. |
|
|
936
|
+
| `close` | `close(): Promise<void>` | Stops new draining and cancels the active controller. |
|
|
937
|
+
|
|
938
|
+
Jobs with higher `priority` are executed first; if equal, jobs with earlier `runAt` are executed first. Retries are attempted until the `retries` value is exceeded. Retry delays use exponential backoff with a default `maxBackoffMs` limit of 30 seconds.
|
|
939
|
+
|
|
940
|
+
### `ScheduledJob`
|
|
941
|
+
|
|
942
|
+
```ts
|
|
943
|
+
interface ScheduledJob {
|
|
944
|
+
id: string;
|
|
945
|
+
cancel: () => void;
|
|
946
|
+
}
|
|
947
|
+
```
|
|
948
|
+
|
|
949
|
+
### `Scheduler`
|
|
950
|
+
|
|
951
|
+
```ts
|
|
952
|
+
new Scheduler(): Scheduler
|
|
953
|
+
```
|
|
954
|
+
|
|
955
|
+
| Method | Signature | Description |
|
|
956
|
+
|---|---|---|
|
|
957
|
+
| `every` | `every(id, intervalMs, task): ScheduledJob` | Runs a task using `setInterval`. Replaces any timer with the same id. |
|
|
958
|
+
| `after` | `after(id, delayMs, task): ScheduledJob` | Runs the task once using `setTimeout`. |
|
|
959
|
+
| `cron` | `cron(id, expression, task): ScheduledJob` | Supports the simple `*/N` format in the minutes field, equivalent to an interval of `N * 60_000`. |
|
|
960
|
+
| `cancel` | `cancel(id): boolean` | Cancels a timer. |
|
|
961
|
+
| `clear` | `clear(): void` | Cancels all timers. |
|
|
962
|
+
|
|
963
|
+
The full cron format is not supported by the built-in scheduler. Expressions other than `*/N` throw an `Error`.
|
|
964
|
+
|
|
965
|
+
## 9. Plugins and services
|
|
966
|
+
|
|
967
|
+
### `Plugin<Context>`
|
|
968
|
+
|
|
969
|
+
```ts
|
|
970
|
+
interface Plugin<Context = unknown> {
|
|
971
|
+
name: string;
|
|
972
|
+
version?: string;
|
|
973
|
+
install?: (api: PluginApi<Context>) => void | Promise<void>;
|
|
974
|
+
setup?: (api: PluginApi<Context>) => void | Promise<void>;
|
|
975
|
+
onStart?: (api: PluginApi<Context>) => void | Promise<void>;
|
|
976
|
+
onUpdate?: (context: Context) => void | Promise<void>;
|
|
977
|
+
onStop?: (api: PluginApi<Context>) => void | Promise<void>;
|
|
978
|
+
dispose?: (api: PluginApi<Context>) => void | Promise<void>;
|
|
979
|
+
}
|
|
980
|
+
```
|
|
981
|
+
|
|
982
|
+
### `PluginApi<Context>`
|
|
983
|
+
|
|
984
|
+
```ts
|
|
985
|
+
interface PluginApi<Context> {
|
|
986
|
+
bot: unknown;
|
|
987
|
+
services: ServiceContainer;
|
|
988
|
+
registerMiddleware: (middleware: unknown) => void;
|
|
989
|
+
registerRoute: (route: unknown) => void;
|
|
990
|
+
}
|
|
991
|
+
```
|
|
992
|
+
|
|
993
|
+
In this release, `registerMiddleware` and `registerRoute` are available as API hooks but the implementation manager does not yet connect them automatically to the bot/router. Plugins may use `api.bot` and `api.services` directly.
|
|
994
|
+
|
|
995
|
+
### `ServiceContainer`
|
|
996
|
+
|
|
997
|
+
```ts
|
|
998
|
+
new ServiceContainer(): ServiceContainer
|
|
999
|
+
```
|
|
1000
|
+
|
|
1001
|
+
| Method | Signature | Description |
|
|
1002
|
+
|---|---|---|
|
|
1003
|
+
| `register` | `register<T>(name: string \| symbol, value: T): this` | Stores a service and supports chaining. |
|
|
1004
|
+
| `get` | `get<T>(name: string \| symbol): T` | Retrieves a service; throws if not registered. |
|
|
1005
|
+
| `has` | `has(name: string \| symbol): boolean` | Checks for the existence of a service. |
|
|
1006
|
+
| `delete` | `delete(name: string \| symbol): boolean` | Removes a service. |
|
|
1007
|
+
|
|
1008
|
+
### `PluginManager<Context>`
|
|
1009
|
+
|
|
1010
|
+
```ts
|
|
1011
|
+
new PluginManager<Context>(bot: unknown): PluginManager<Context>
|
|
1012
|
+
```
|
|
1013
|
+
|
|
1014
|
+
| Method | Behavior |
|
|
1015
|
+
|---|---|
|
|
1016
|
+
| `use(plugin)` | Adds a plugin; duplicate names throw an error. |
|
|
1017
|
+
| `setup()` | For each plugin, runs `install` then `setup`. |
|
|
1018
|
+
| `start()` | Executes `onStart` in registration order. |
|
|
1019
|
+
| `update(context)` | Executes `onUpdate` in registration order. |
|
|
1020
|
+
| `stop()` | Executes `onStop`. |
|
|
1021
|
+
| `dispose()` | Executes `dispose` in reverse registration order. |
|
|
1022
|
+
| `list()` | Returns a read-only list of plugins. |
|
|
1023
|
+
|
|
1024
|
+
`Bot.handleUpdate()` in this release does not call `plugins.update()` automatically; call the manager explicitly if plugins require an update lifecycle.
|
|
1025
|
+
|
|
1026
|
+
---
|
|
1027
|
+
|
|
1028
|
+
## 10. Webhook
|
|
1029
|
+
|
|
1030
|
+
### `WebhookOptions`
|
|
1031
|
+
|
|
1032
|
+
```ts
|
|
1033
|
+
interface WebhookOptions {
|
|
1034
|
+
secretToken?: string;
|
|
1035
|
+
maxBodyBytes?: number;
|
|
1036
|
+
onError?: (error: unknown) => void | Promise<void>;
|
|
1037
|
+
}
|
|
1038
|
+
```
|
|
1039
|
+
|
|
1040
|
+
### `createWebhookHandler(bot, options?)`
|
|
1041
|
+
|
|
1042
|
+
```ts
|
|
1043
|
+
createWebhookHandler<S extends object>(
|
|
1044
|
+
bot: Bot<S>,
|
|
1045
|
+
options?: WebhookOptions,
|
|
1046
|
+
): (request: Request) => Promise<Response>
|
|
1047
|
+
```
|
|
1048
|
+
|
|
1049
|
+
The handler accepts a standard Web `Request` and returns a `Response`.
|
|
1050
|
+
|
|
1051
|
+
| Condition | Response |
|
|
1052
|
+
|---|---|
|
|
1053
|
+
| Method is not POST | `405 Method Not Allowed`, header `allow: POST` |
|
|
1054
|
+
| Secret header does not match | `401 Unauthorized` |
|
|
1055
|
+
| Header `Content-Length` or body exceeds limit | `413 Payload Too Large` |
|
|
1056
|
+
| Invalid JSON or `update_id` is not an integer | `400 Bad Request` for update id; exception during parsing results in `500` |
|
|
1057
|
+
| `bot.handleUpdate` succeeds | `200 OK` with body `OK` |
|
|
1058
|
+
| Other exceptions | `500 Internal Server Error` and `onError` is called |
|
|
1059
|
+
|
|
1060
|
+
The default value of `maxBodyBytes` is `1_048_576` bytes. The Telegram secret token is read from the `x-telegram-bot-api-secret-token` header.
|
|
1061
|
+
|
|
1062
|
+
```ts
|
|
1063
|
+
import { Bot, createWebhookHandler } from "@xbibzlibrary/telebibz";
|
|
1064
|
+
|
|
1065
|
+
const bot = new Bot(process.env.TELEGRAM_BOT_TOKEN!);
|
|
1066
|
+
const handler = createWebhookHandler(bot, {
|
|
1067
|
+
secretToken: process.env.TELEGRAM_WEBHOOK_SECRET,
|
|
1068
|
+
});
|
|
1069
|
+
|
|
1070
|
+
export default { fetch: handler };
|
|
1071
|
+
```
|
|
1072
|
+
|
|
1073
|
+
---
|
|
1074
|
+
|
|
1075
|
+
## 11. Conversations, wizards, forms, and menus
|
|
1076
|
+
|
|
1077
|
+
### Conversations
|
|
1078
|
+
|
|
1079
|
+
```ts
|
|
1080
|
+
interface ConversationState {
|
|
1081
|
+
name: string;
|
|
1082
|
+
step: number;
|
|
1083
|
+
values: Record<string, unknown>;
|
|
1084
|
+
status: "active" | "completed" | "cancelled";
|
|
1085
|
+
updatedAt: number;
|
|
1086
|
+
}
|
|
1087
|
+
```
|
|
1088
|
+
|
|
1089
|
+
#### `ConversationFlow<S>`
|
|
1090
|
+
|
|
1091
|
+
```ts
|
|
1092
|
+
new ConversationFlow(ctx: Context<S>, state: ConversationState)
|
|
1093
|
+
```
|
|
1094
|
+
|
|
1095
|
+
| Method/property | Signature | Description |
|
|
1096
|
+
|---|---|---|
|
|
1097
|
+
| `ctx` | `Context<S>` | Current update context. |
|
|
1098
|
+
| `state` | `ConversationState` | Mutable conversation state. |
|
|
1099
|
+
| `values` | `Record<string, unknown>` | Alias for `state.values`. |
|
|
1100
|
+
| `set` | `set<T>(key, value): this` | Stores a value and updates `updatedAt`. |
|
|
1101
|
+
| `get` | `get<T>(key): T \| undefined` | Retrieves a typed value. |
|
|
1102
|
+
| `next` | `next(): this` | Advance the step by one. |
|
|
1103
|
+
| `previous` | `previous(): this` | Decrement the step, clamped at 0. |
|
|
1104
|
+
| `complete` | `complete(): void` | Sets status to `completed`. |
|
|
1105
|
+
| `cancel` | `cancel(): void` | Sets status to `cancelled`. |
|
|
1106
|
+
|
|
1107
|
+
#### `ConversationManager<S>`
|
|
1108
|
+
|
|
1109
|
+
```ts
|
|
1110
|
+
new ConversationManager<S>(): ConversationManager<S>
|
|
1111
|
+
```
|
|
1112
|
+
|
|
1113
|
+
| Method | Signature | Description |
|
|
1114
|
+
|---|---|---|
|
|
1115
|
+
| `start` | `start(key, name, values?): ConversationState` | Creates or replaces a conversation state. |
|
|
1116
|
+
| `get` | `get(key): ConversationState \| undefined` | Retrieves the active state. |
|
|
1117
|
+
| `cancel` | `cancel(key): boolean` | Marks as cancelled if it exists. |
|
|
1118
|
+
| `clearExpired` | `clearExpired(maxAgeMs): number` | Removes states whose `updatedAt` is older than the threshold. |
|
|
1119
|
+
| `run` | `run(ctx, key, name, steps): Promise<ConversationState>` | Runs steps according to `state.step`; if no step, status becomes completed. |
|
|
1120
|
+
|
|
1121
|
+
```ts
|
|
1122
|
+
const conversations = new ConversationManager();
|
|
1123
|
+
await conversations.run(ctx, "chat:1", "profile", [
|
|
1124
|
+
async (flow) => {
|
|
1125
|
+
flow.set("name", ctx.message?.text);
|
|
1126
|
+
flow.next();
|
|
1127
|
+
},
|
|
1128
|
+
async (flow) => {
|
|
1129
|
+
await flow.ctx.reply(`Name: ${flow.get<string>("name")}`);
|
|
1130
|
+
flow.complete();
|
|
1131
|
+
},
|
|
1132
|
+
]);
|
|
1133
|
+
```
|
|
1134
|
+
|
|
1135
|
+
#### `Wizard<S>` and `WizardStep<S>`
|
|
1136
|
+
|
|
1137
|
+
```ts
|
|
1138
|
+
interface WizardStep<S> {
|
|
1139
|
+
id: string;
|
|
1140
|
+
run: (flow: ConversationFlow<S>) => void | Promise<void>;
|
|
1141
|
+
optional?: boolean;
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
new Wizard<S>()
|
|
1145
|
+
```
|
|
1146
|
+
|
|
1147
|
+
| Method/property | Description |
|
|
1148
|
+
|---|---|
|
|
1149
|
+
| `step(definition)` | Adds a step and returns the wizard. `optional` is stored in the definition but not specially handled by the runner. |
|
|
1150
|
+
| `run(ctx, key, manager?)` | Runs the wizard steps via `ConversationManager` with the name `"wizard"`. |
|
|
1151
|
+
| `steps` | Read-only list of steps. |
|
|
1152
|
+
|
|
1153
|
+
### Forms
|
|
1154
|
+
|
|
1155
|
+
```ts
|
|
1156
|
+
interface ValidationIssue {
|
|
1157
|
+
path: string;
|
|
1158
|
+
message: string;
|
|
1159
|
+
code?: string;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
interface Field<T> {
|
|
1163
|
+
name: string;
|
|
1164
|
+
parse: (input: unknown) => T;
|
|
1165
|
+
validate?: (value: T) => string | undefined | Promise<string | undefined>;
|
|
1166
|
+
transform?: (value: T) => T | Promise<T>;
|
|
1167
|
+
required?: boolean;
|
|
1168
|
+
}
|
|
1169
|
+
```
|
|
1170
|
+
|
|
1171
|
+
#### `Form<T>`
|
|
1172
|
+
|
|
1173
|
+
```ts
|
|
1174
|
+
new Form<T extends Record<string, unknown>>(): Form<T>
|
|
1175
|
+
```
|
|
1176
|
+
|
|
1177
|
+
| Method | Description |
|
|
1178
|
+
|---|---|
|
|
1179
|
+
| `field(definition)` | Registers a typed field by `name`. |
|
|
1180
|
+
| `parse(input)` | Processes all fields. Returns a union of success or issues. Order: required check, parse, transform, validate. |
|
|
1181
|
+
| `reset()` | Clears internally stored parsed data. |
|
|
1182
|
+
|
|
1183
|
+
Parse result:
|
|
1184
|
+
|
|
1185
|
+
```ts
|
|
1186
|
+
type FormResult<T> =
|
|
1187
|
+
| { success: true; data: T }
|
|
1188
|
+
| { success: false; issues: ValidationIssue[] };
|
|
1189
|
+
```
|
|
1190
|
+
|
|
1191
|
+
Issues use the code `required`, `parse`, or `invalid`.
|
|
1192
|
+
|
|
1193
|
+
#### `validators`
|
|
1194
|
+
|
|
1195
|
+
| Validator | Input | Result/Error |
|
|
1196
|
+
|---|---|---|
|
|
1197
|
+
| `validators.string` | `unknown` | String; otherwise `TypeError("Expected string")`. |
|
|
1198
|
+
| `validators.number` | `unknown` | Finite number, including numeric strings; otherwise `TypeError("Expected number")`. |
|
|
1199
|
+
| `validators.integer` | `unknown` | Integer; otherwise `TypeError("Expected integer")`. |
|
|
1200
|
+
| `validators.email` | `unknown` | String matching a simple email pattern; otherwise `TypeError("Expected email")`. |
|
|
1201
|
+
| `validators.url` | `unknown` | String accepted by the `URL` constructor; otherwise `TypeError("Expected URL")`. |
|
|
1202
|
+
|
|
1203
|
+
### Pagination and menus
|
|
1204
|
+
|
|
1205
|
+
#### `Page<T>`
|
|
1206
|
+
|
|
1207
|
+
```ts
|
|
1208
|
+
interface Page<T> {
|
|
1209
|
+
items: T[];
|
|
1210
|
+
page: number;
|
|
1211
|
+
pageCount: number;
|
|
1212
|
+
hasPrevious: boolean;
|
|
1213
|
+
hasNext: boolean;
|
|
1214
|
+
}
|
|
1215
|
+
```
|
|
1216
|
+
|
|
1217
|
+
#### `paginate(items, page, pageSize)`
|
|
1218
|
+
|
|
1219
|
+
```ts
|
|
1220
|
+
paginate<T>(
|
|
1221
|
+
items: readonly T[],
|
|
1222
|
+
page: number,
|
|
1223
|
+
pageSize: number,
|
|
1224
|
+
): Page<T>
|
|
1225
|
+
```
|
|
1226
|
+
|
|
1227
|
+
Pages use 0-based indexing. Pages that exceed bounds are clamped to the last page. An empty collection still has `pageCount: 1`. Negative/non-integer `page` or `pageSize < 1` throws `RangeError`.
|
|
1228
|
+
|
|
1229
|
+
#### `paginationButtons(page, prefix)`
|
|
1230
|
+
|
|
1231
|
+
```ts
|
|
1232
|
+
paginationButtons(
|
|
1233
|
+
page: Page<unknown>,
|
|
1234
|
+
prefix: string,
|
|
1235
|
+
): InlineKeyboardButton[]
|
|
1236
|
+
```
|
|
1237
|
+
|
|
1238
|
+
Generates a `Previous` button, an indicator `${page + 1}/${pageCount}` with callback `${prefix}:noop`, and `Next` according to the page flags.
|
|
1239
|
+
|
|
1240
|
+
#### `MenuItem`
|
|
1241
|
+
|
|
1242
|
+
```ts
|
|
1243
|
+
interface MenuItem {
|
|
1244
|
+
id: string;
|
|
1245
|
+
label: string;
|
|
1246
|
+
callbackData?: string;
|
|
1247
|
+
url?: string;
|
|
1248
|
+
visible?: boolean | (() => boolean | Promise<boolean>);
|
|
1249
|
+
permission?: string;
|
|
1250
|
+
}
|
|
1251
|
+
```
|
|
1252
|
+
|
|
1253
|
+
#### `Menu`
|
|
1254
|
+
|
|
1255
|
+
```ts
|
|
1256
|
+
new Menu(id: string): Menu
|
|
1257
|
+
```
|
|
1258
|
+
|
|
1259
|
+
| Method/property | Description |
|
|
1260
|
+
|---|---|
|
|
1261
|
+
| `item(item)` | Adds an item and supports chaining. |
|
|
1262
|
+
| `breadcrumb(label)` | Adds a breadcrumb label. |
|
|
1263
|
+
| `build()` | Waits for visibility predicates, skips invisible items, then produces an `InlineKeyboard`. URL is prioritized over callbacks. |
|
|
1264
|
+
| `breadcrumbs` | Read-only array of breadcrumbs. |
|
|
1265
|
+
|
|
1266
|
+
`permission` is only stored as item metadata; `Menu.build()` does not perform automatic authorization.
|
|
1267
|
+
|
|
1268
|
+
---
|
|
1269
|
+
|
|
1270
|
+
## 12. Approval Gate
|
|
1271
|
+
|
|
1272
|
+
The approval gate sends a notification to the owner when a bot uses the library for the first time. The default message uses the label `Dev Gantenggg`, includes the bot ID/username and owner ID, and provides `Izinkan` and `Tidak Diizinkan` buttons.
|
|
1273
|
+
|
|
1274
|
+
### `ApprovalOptions`
|
|
1275
|
+
|
|
1276
|
+
| Property | Type | Default | Description |
|
|
1277
|
+
|---|---|---:|---|
|
|
1278
|
+
| `ownerChatId` | `ChatId` | wajib | Destination chat for notifications. |
|
|
1279
|
+
| `ownerUserId` | `number` | wajib | User ID allowed to press the buttons. |
|
|
1280
|
+
| `ownerLabel` | `string` | `Dev Gantenggg` | Label on the notification. |
|
|
1281
|
+
| `requireApproval` | `boolean` | `true` | `false` disables the gate. |
|
|
1282
|
+
| `notificationCooldownMs` | `number` | `600000` | Pending notification cooldown. |
|
|
1283
|
+
| `store` | `ApprovalStore` | `MemoryApprovalStore` | Custom approval storage. |
|
|
1284
|
+
|
|
1285
|
+
### Approval types
|
|
1286
|
+
|
|
1287
|
+
```ts
|
|
1288
|
+
type ApprovalStatus = "pending" | "approved" | "denied";
|
|
1289
|
+
|
|
1290
|
+
interface ApprovalRecord {
|
|
1291
|
+
key: string;
|
|
1292
|
+
botId: number;
|
|
1293
|
+
botUsername?: string;
|
|
1294
|
+
ownerUserId?: number;
|
|
1295
|
+
status: ApprovalStatus;
|
|
1296
|
+
nonce: string;
|
|
1297
|
+
requestedAt: number;
|
|
1298
|
+
decidedAt?: number;
|
|
1299
|
+
decidedBy?: number;
|
|
1300
|
+
notificationMessageId?: number;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
interface ApprovalIdentity {
|
|
1304
|
+
bot: User;
|
|
1305
|
+
configuredOwnerUserId?: number;
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
interface ApprovalCheck {
|
|
1309
|
+
allowed: boolean;
|
|
1310
|
+
status: ApprovalStatus | "disabled";
|
|
1311
|
+
record?: ApprovalRecord;
|
|
1312
|
+
}
|
|
1313
|
+
```
|
|
1314
|
+
|
|
1315
|
+
### `ApprovalStore`
|
|
1316
|
+
|
|
1317
|
+
```ts
|
|
1318
|
+
interface ApprovalStore {
|
|
1319
|
+
get(key: string): Promise<ApprovalRecord | undefined>;
|
|
1320
|
+
set(key: string, record: ApprovalRecord): Promise<void>;
|
|
1321
|
+
delete?(key: string): Promise<boolean>;
|
|
1322
|
+
}
|
|
1323
|
+
```
|
|
1324
|
+
|
|
1325
|
+
### `MemoryApprovalStore`
|
|
1326
|
+
|
|
1327
|
+
```ts
|
|
1328
|
+
new MemoryApprovalStore(): MemoryApprovalStore
|
|
1329
|
+
```
|
|
1330
|
+
|
|
1331
|
+
In-memory storage that returns a copy of the record on `get` and `set`.
|
|
1332
|
+
|
|
1333
|
+
### `ApprovalGate`
|
|
1334
|
+
|
|
1335
|
+
```ts
|
|
1336
|
+
new ApprovalGate(api: ApiClient, options: ApprovalOptions): ApprovalGate
|
|
1337
|
+
```
|
|
1338
|
+
|
|
1339
|
+
| Method | Signature | Description |
|
|
1340
|
+
|---|---|---|
|
|
1341
|
+
| `check` | `check(identity): Promise<ApprovalCheck>` | Returns approved if the record status is approved; sends a new request if none exists or the cooldown has expired. |
|
|
1342
|
+
| `handleCallback` | `handleCallback(callback): Promise<{ handled: boolean; status?: ApprovalStatus }>` | Validates the nonce and owner, then performs approve/deny. Invalid callbacks or non-approval callbacks are returned as `handled: false`. |
|
|
1343
|
+
| `isAllowed` | `isAllowed(botId): Promise<boolean>` | True if approved or the gate is disabled. |
|
|
1344
|
+
| `revoke` | `revoke(botId): Promise<boolean>` | Deletes the record if the store supports delete. |
|
|
1345
|
+
|
|
1346
|
+
Callbacks can only be decided by the configured `ownerUserId`. A random 16-character hexadecimal nonce prevents old callbacks from being reused. Expired callbacks produce an expiration alert.
|
|
1347
|
+
|
|
1348
|
+
```ts
|
|
1349
|
+
const bot = new Bot({
|
|
1350
|
+
token: process.env.TELEGRAM_BOT_TOKEN!,
|
|
1351
|
+
approval: {
|
|
1352
|
+
ownerChatId: 7377733784,
|
|
1353
|
+
ownerUserId: 7377733784,
|
|
1354
|
+
ownerLabel: "Dev Gantenggg",
|
|
1355
|
+
},
|
|
1356
|
+
});
|
|
1357
|
+
```
|
|
1358
|
+
|
|
1359
|
+
---
|
|
1360
|
+
|
|
1361
|
+
## 13. Text Utilities
|
|
1362
|
+
|
|
1363
|
+
### `escapeMarkdownV2(value)`
|
|
1364
|
+
|
|
1365
|
+
```ts
|
|
1366
|
+
escapeMarkdownV2(value: string): string
|
|
1367
|
+
```
|
|
1368
|
+
|
|
1369
|
+
Escapes Telegram MarkdownV2 characters: `\\_ * [ ] ( ) ~ ` > # + - = | { } . !`.
|
|
1370
|
+
|
|
1371
|
+
### `escapeHtml(value)`
|
|
1372
|
+
|
|
1373
|
+
```ts
|
|
1374
|
+
escapeHtml(value: string): string
|
|
1375
|
+
```
|
|
1376
|
+
|
|
1377
|
+
Converts `&`, `<`, `>`, and `\"` into HTML entities.
|
|
1378
|
+
|
|
1379
|
+
### `md`
|
|
1380
|
+
|
|
1381
|
+
The following MarkdownV2 helper object is available:
|
|
1382
|
+
|
|
1383
|
+
| Method | Conceptual output |
|
|
1384
|
+
|---|---|
|
|
1385
|
+
| `md.bold(value)` | `*escaped value*` |
|
|
1386
|
+
| `md.italic(value)` | `_escaped value_` |
|
|
1387
|
+
| `md.link(label, url)` | `[escaped label](escaped url)` |
|
|
1388
|
+
| `md.code(value)` | Inline code with backticks escaped. |
|
|
1389
|
+
| `md.pre(value, language?)` | Code block with an optional language label. |
|
|
1390
|
+
| `md.escape(value)` | Alias `escapeMarkdownV2`. |
|
|
1391
|
+
|
|
1392
|
+
### `splitMessage(text, options?)`
|
|
1393
|
+
|
|
1394
|
+
```ts
|
|
1395
|
+
splitMessage(
|
|
1396
|
+
text: string,
|
|
1397
|
+
options?: {
|
|
1398
|
+
limit?: number;
|
|
1399
|
+
parseMode?: "Markdown" | "MarkdownV2" | "HTML";
|
|
1400
|
+
},
|
|
1401
|
+
): string[]
|
|
1402
|
+
```
|
|
1403
|
+
|
|
1404
|
+
Splits text into chunks with a default limit of `4096` characters. When possible, splitting prefers paragraph, newline, or space boundaries; the hard limit is only used if it lies beyond half of the window. `parseMode` is accepted as an API option but does not yet change the splitting algorithm.
|
|
1405
|
+
|
|
1406
|
+
A limit less than 1 will throw a `RangeError`.
|
|
1407
|
+
|
|
1408
|
+
### `splitCaption(text)`
|
|
1409
|
+
|
|
1410
|
+
```ts
|
|
1411
|
+
splitCaption(text: string): string[]
|
|
1412
|
+
```
|
|
1413
|
+
|
|
1414
|
+
Alias `splitMessage(text, { limit: 1024 })`.
|
|
1415
|
+
|
|
1416
|
+
### `template(templateText, values)`
|
|
1417
|
+
|
|
1418
|
+
```ts
|
|
1419
|
+
template(
|
|
1420
|
+
templateText: string,
|
|
1421
|
+
values: Record<string, unknown>,
|
|
1422
|
+
): string
|
|
1423
|
+
```
|
|
1424
|
+
|
|
1425
|
+
Replaces placeholders like `{{ key }}` and nested paths such as `{{ user.name }}`. `null` or `undefined` values are replaced with an empty string; other values are converted with `String()`.
|
|
1426
|
+
|
|
1427
|
+
```ts
|
|
1428
|
+
template("Halo {{ user.name }}", { user: { name: "Ayu" } });
|
|
1429
|
+
// "Halo Ayu"
|
|
1430
|
+
```
|
|
1431
|
+
|
|
1432
|
+
---
|
|
1433
|
+
|
|
1434
|
+
## 14. Testing utilities
|
|
1435
|
+
|
|
1436
|
+
Import dari `@xbibzlibrary/telebibz/testing` atau root package.
|
|
1437
|
+
|
|
1438
|
+
### `MockTransport`
|
|
1439
|
+
|
|
1440
|
+
```ts
|
|
1441
|
+
new MockTransport(): MockTransport
|
|
1442
|
+
```
|
|
1443
|
+
|
|
1444
|
+
| API | Description |
|
|
1445
|
+
|---|---|
|
|
1446
|
+
| `calls` | Array of every received `TransportRequest`. |
|
|
1447
|
+
| `respond(method, response)` | Configures a static response or payload callback and returns the transport. |
|
|
1448
|
+
| `request(request)` | Records the request and returns a mock response. The default response is `{ ok: true, result: true }`. |
|
|
1449
|
+
|
|
1450
|
+
The mock status is `200` when `ok: true`, or `error_code`/`500` when `ok: false`.
|
|
1451
|
+
|
|
1452
|
+
```ts
|
|
1453
|
+
const transport = new MockTransport()
|
|
1454
|
+
.respond("getMe", {
|
|
1455
|
+
ok: true,
|
|
1456
|
+
result: { id: 1, is_bot: true, first_name: "Test" },
|
|
1457
|
+
});
|
|
1458
|
+
```
|
|
1459
|
+
|
|
1460
|
+
### `createMockUpdate(overrides?)`
|
|
1461
|
+
|
|
1462
|
+
```ts
|
|
1463
|
+
createMockUpdate(overrides?: Partial<Update>): Update
|
|
1464
|
+
```
|
|
1465
|
+
|
|
1466
|
+
Creates a default message update with `update_id: 1`, private chat id `1`, user id `2`, and text `/start`. The `overrides` object is shallow-merged with the defaults.
|
|
1467
|
+
|
|
1468
|
+
### `createTestBot()`
|
|
1469
|
+
|
|
1470
|
+
```ts
|
|
1471
|
+
createTestBot(): { bot: Bot; transport: MockTransport }
|
|
1472
|
+
```
|
|
1473
|
+
|
|
1474
|
+
Creates a bot with the test token `123456:TEST_TOKEN`, a mocked `getMe()` result for bot id `99`, and a transport that can be inspected through `transport.calls`.
|
|
1475
|
+
|
|
1476
|
+
### `createMockContext(bot, update?)`
|
|
1477
|
+
|
|
1478
|
+
```ts
|
|
1479
|
+
createMockContext(
|
|
1480
|
+
bot: Bot,
|
|
1481
|
+
update?: Update,
|
|
1482
|
+
): Context
|
|
1483
|
+
```
|
|
1484
|
+
|
|
1485
|
+
Creates a context using the bot API, an empty session, and empty services.
|
|
1486
|
+
|
|
1487
|
+
---
|
|
1488
|
+
|
|
1489
|
+
|
|
1490
|
+
|
|
1491
|
+
## 15. Generated Telegram methods namespace
|
|
1492
|
+
|
|
1493
|
+
`generated/api.ts` is the generator's internal source that defines:
|
|
1494
|
+
|
|
1495
|
+
```ts
|
|
1496
|
+
const TELEGRAM_API_VERSION = "10.2";
|
|
1497
|
+
const TELEGRAM_METHOD_NAMES: readonly string[];
|
|
1498
|
+
type TelegramMethodName = typeof TELEGRAM_METHOD_NAMES[number];
|
|
1499
|
+
type GeneratedMethodSpec = {
|
|
1500
|
+
params: Record<string, unknown>;
|
|
1501
|
+
result: unknown;
|
|
1502
|
+
};
|
|
1503
|
+
type GeneratedTelegramMethodMap = {
|
|
1504
|
+
[K in TelegramMethodName]: GeneratedMethodSpec;
|
|
1505
|
+
};
|
|
1506
|
+
const GENERATED_METHODS: Record<TelegramMethodName, TelegramMethodName>;
|
|
1507
|
+
```
|
|
1508
|
+
|
|
1509
|
+
`TELEGRAM_METHOD_NAMES` contains 184 method names in the generator source. That namespace forms the basis for the `api.methods`, `api.call`, and `api.request` proxies, but the generated file is not exported as a public package subpath in this release. Methods whose params/results are not specifically mapped can be invoked via `api.raw()` or by casting parameters in TypeScript.
|
|
1510
|
+
|
|
1511
|
+
For an ungrouped canonical list, the method names available on the generated runtime namespace are:
|
|
1512
|
+
|
|
1513
|
+
```text
|
|
1514
|
+
addStickerToSet,
|
|
1515
|
+
answerCallbackQuery,
|
|
1516
|
+
answerChatJoinRequestQuery,
|
|
1517
|
+
answerGuestQuery,
|
|
1518
|
+
answerInlineQuery,
|
|
1519
|
+
answerPreCheckoutQuery,
|
|
1520
|
+
answerShippingQuery,
|
|
1521
|
+
answerWebAppQuery,
|
|
1522
|
+
approveChatJoinRequest,
|
|
1523
|
+
approveSuggestedPost,
|
|
1524
|
+
banChatMember,
|
|
1525
|
+
banChatSenderChat,
|
|
1526
|
+
close,
|
|
1527
|
+
closeForumTopic,
|
|
1528
|
+
closeGeneralForumTopic,
|
|
1529
|
+
convertGiftToStars,
|
|
1530
|
+
copyMessage,
|
|
1531
|
+
copyMessages,
|
|
1532
|
+
createChatInviteLink,
|
|
1533
|
+
createChatSubscriptionInviteLink,
|
|
1534
|
+
createForumTopic,
|
|
1535
|
+
createInvoiceLink,
|
|
1536
|
+
createNewStickerSet,
|
|
1537
|
+
declineChatJoinRequest,
|
|
1538
|
+
declineSuggestedPost,
|
|
1539
|
+
deleteAllMessageReactions,
|
|
1540
|
+
deleteBusinessMessages,
|
|
1541
|
+
deleteChatPhoto,
|
|
1542
|
+
deleteChatStickerSet,
|
|
1543
|
+
deleteEphemeralMessage,
|
|
1544
|
+
deleteForumTopic,
|
|
1545
|
+
deleteMessage,
|
|
1546
|
+
deleteMessageReaction,
|
|
1547
|
+
deleteMessages,
|
|
1548
|
+
deleteMyCommands,
|
|
1549
|
+
deleteStickerFromSet,
|
|
1550
|
+
deleteStickerSet,
|
|
1551
|
+
deleteStory,
|
|
1552
|
+
deleteWebhook,
|
|
1553
|
+
editChatInviteLink,
|
|
1554
|
+
editChatSubscriptionInviteLink,
|
|
1555
|
+
editEphemeralMessageCaption,
|
|
1556
|
+
editEphemeralMessageMedia,
|
|
1557
|
+
editEphemeralMessageReplyMarkup,
|
|
1558
|
+
editEphemeralMessageText,
|
|
1559
|
+
editForumTopic,
|
|
1560
|
+
editGeneralForumTopic,
|
|
1561
|
+
editMessageCaption,
|
|
1562
|
+
editMessageChecklist,
|
|
1563
|
+
editMessageLiveLocation,
|
|
1564
|
+
editMessageMedia,
|
|
1565
|
+
editMessageReplyMarkup,
|
|
1566
|
+
editMessageText,
|
|
1567
|
+
editStory,
|
|
1568
|
+
editUserStarSubscription,
|
|
1569
|
+
exportChatInviteLink,
|
|
1570
|
+
forwardMessage,
|
|
1571
|
+
forwardMessages,
|
|
1572
|
+
getAvailableGifts,
|
|
1573
|
+
getBusinessAccountGifts,
|
|
1574
|
+
getBusinessAccountStarBalance,
|
|
1575
|
+
getBusinessConnection,
|
|
1576
|
+
getChat,
|
|
1577
|
+
getChatAdministrators,
|
|
1578
|
+
getChatGifts,
|
|
1579
|
+
getChatMember,
|
|
1580
|
+
getChatMemberCount,
|
|
1581
|
+
getChatMenuButton,
|
|
1582
|
+
getCustomEmojiStickers,
|
|
1583
|
+
getFile,
|
|
1584
|
+
getForumTopicIconStickers,
|
|
1585
|
+
getGameHighScores,
|
|
1586
|
+
getManagedBotAccessSettings,
|
|
1587
|
+
getManagedBotToken,
|
|
1588
|
+
getMe,
|
|
1589
|
+
getMyCommands,
|
|
1590
|
+
getMyDefaultAdministratorRights,
|
|
1591
|
+
getMyDescription,
|
|
1592
|
+
getMyName,
|
|
1593
|
+
getMyShortDescription,
|
|
1594
|
+
getMyStarBalance,
|
|
1595
|
+
getStarTransactions,
|
|
1596
|
+
getStickerSet,
|
|
1597
|
+
getUpdates,
|
|
1598
|
+
getUserChatBoosts,
|
|
1599
|
+
getUserGifts,
|
|
1600
|
+
getUserPersonalChatMessages,
|
|
1601
|
+
getUserProfileAudios,
|
|
1602
|
+
getUserProfilePhotos,
|
|
1603
|
+
getWebhookInfo,
|
|
1604
|
+
giftPremiumSubscription,
|
|
1605
|
+
hideGeneralForumTopic,
|
|
1606
|
+
leaveChat,
|
|
1607
|
+
logOut,
|
|
1608
|
+
pinChatMessage,
|
|
1609
|
+
postStory,
|
|
1610
|
+
promoteChatMember,
|
|
1611
|
+
readBusinessMessage,
|
|
1612
|
+
refundStarPayment,
|
|
1613
|
+
removeBusinessAccountProfilePhoto,
|
|
1614
|
+
removeChatVerification,
|
|
1615
|
+
removeMyProfilePhoto,
|
|
1616
|
+
removeUserVerification,
|
|
1617
|
+
reopenForumTopic,
|
|
1618
|
+
reopenGeneralForumTopic,
|
|
1619
|
+
replaceManagedBotToken,
|
|
1620
|
+
replaceStickerInSet,
|
|
1621
|
+
repostStory,
|
|
1622
|
+
restrictChatMember,
|
|
1623
|
+
revokeChatInviteLink,
|
|
1624
|
+
savePreparedInlineMessage,
|
|
1625
|
+
savePreparedKeyboardButton,
|
|
1626
|
+
sendAnimation,
|
|
1627
|
+
sendAudio,
|
|
1628
|
+
sendChatAction,
|
|
1629
|
+
sendChatJoinRequestWebApp,
|
|
1630
|
+
sendChecklist,
|
|
1631
|
+
sendContact,
|
|
1632
|
+
sendDice,
|
|
1633
|
+
sendDocument,
|
|
1634
|
+
sendGame,
|
|
1635
|
+
sendGift,
|
|
1636
|
+
sendInvoice,
|
|
1637
|
+
sendLivePhoto,
|
|
1638
|
+
sendLocation,
|
|
1639
|
+
sendMediaGroup,
|
|
1640
|
+
sendMessage,
|
|
1641
|
+
sendMessageDraft,
|
|
1642
|
+
sendPaidMedia,
|
|
1643
|
+
sendPhoto,
|
|
1644
|
+
sendPoll,
|
|
1645
|
+
sendRichMessage,
|
|
1646
|
+
sendRichMessageDraft,
|
|
1647
|
+
sendSticker,
|
|
1648
|
+
sendVenue,
|
|
1649
|
+
sendVideo,
|
|
1650
|
+
sendVideoNote,
|
|
1651
|
+
sendVoice,
|
|
1652
|
+
setBusinessAccountBio,
|
|
1653
|
+
setBusinessAccountGiftSettings,
|
|
1654
|
+
setBusinessAccountName,
|
|
1655
|
+
setBusinessAccountProfilePhoto,
|
|
1656
|
+
setBusinessAccountUsername,
|
|
1657
|
+
setChatAdministratorCustomTitle,
|
|
1658
|
+
setChatDescription,
|
|
1659
|
+
setChatMemberTag,
|
|
1660
|
+
setChatMenuButton,
|
|
1661
|
+
setChatPermissions,
|
|
1662
|
+
setChatPhoto,
|
|
1663
|
+
setChatStickerSet,
|
|
1664
|
+
setChatTitle,
|
|
1665
|
+
setCustomEmojiStickerSetThumbnail,
|
|
1666
|
+
setGameScore,
|
|
1667
|
+
setManagedBotAccessSettings,
|
|
1668
|
+
setMessageReaction,
|
|
1669
|
+
setMyCommands,
|
|
1670
|
+
setMyDefaultAdministratorRights,
|
|
1671
|
+
setMyDescription,
|
|
1672
|
+
setMyName,
|
|
1673
|
+
setMyProfilePhoto,
|
|
1674
|
+
setMyShortDescription,
|
|
1675
|
+
setPassportDataErrors,
|
|
1676
|
+
setStickerEmojiList,
|
|
1677
|
+
setStickerKeywords,
|
|
1678
|
+
setStickerMaskPosition,
|
|
1679
|
+
setStickerPositionInSet,
|
|
1680
|
+
setStickerSetThumbnail,
|
|
1681
|
+
setStickerSetTitle,
|
|
1682
|
+
setUserEmojiStatus,
|
|
1683
|
+
setWebhook,
|
|
1684
|
+
stopMessageLiveLocation,
|
|
1685
|
+
stopPoll,
|
|
1686
|
+
transferBusinessAccountStars,
|
|
1687
|
+
transferGift,
|
|
1688
|
+
unbanChatMember,
|
|
1689
|
+
unbanChatSenderChat,
|
|
1690
|
+
unhideGeneralForumTopic,
|
|
1691
|
+
unpinAllChatMessages,
|
|
1692
|
+
unpinAllForumTopicMessages,
|
|
1693
|
+
unpinAllGeneralForumTopicMessages,
|
|
1694
|
+
unpinChatMessage,
|
|
1695
|
+
upgradeGift,
|
|
1696
|
+
uploadStickerFile,
|
|
1697
|
+
verifyChat
|
|
1698
|
+
```
|
|
1699
|
+
|
|
1700
|
+
> The list above follows the generated source. If Telegram adds new methods, run `npm run update:telegram` or `telebibz generate` after the schema is updated.
|
|
1701
|
+
|
|
1702
|
+
---
|
|
1703
|
+
|
|
1704
|
+
## 16. CLI
|
|
1705
|
+
|
|
1706
|
+
Binary package is `telebibz`.
|
|
1707
|
+
|
|
1708
|
+
```bash
|
|
1709
|
+
npx telebibz <command>
|
|
1710
|
+
```
|
|
1711
|
+
|
|
1712
|
+
| Command | Behavior |
|
|
1713
|
+
|---|---|
|
|
1714
|
+
| `telebibz init [directory]` | Creates a directory, a minimal `index.ts`, and `.env.example`. Default directory `my-telebibz-bot`. |
|
|
1715
|
+
| `telebibz doctor` | Displays Node version, presence of `TELEGRAM_BOT_TOKEN`, cwd, package name, then health API if the token is available. Exit code becomes 1 if the API is not reachable. |
|
|
1716
|
+
| `telebibz generate` | Runs the generator method from `scripts/generate-api.mjs`. |
|
|
1717
|
+
| `telebibz build` | Runs `npm run build`. |
|
|
1718
|
+
| `telebibz test` | Runs `npm test`. |
|
|
1719
|
+
| `telebibz webhook` | Checks `TELEGRAM_BOT_TOKEN`, uses `TELEGRAM_WEBHOOK_SECRET` if present, creates a handler, and prints readiness. This command does not create an HTTP server. |
|
|
1720
|
+
| `telebibz inspect` | Displays cwd and Node version. |
|
|
1721
|
+
| without command | Displays the help command list. |
|
|
1722
|
+
|
|
1723
|
+
Environment variables used by the CLI are `TELEGRAM_BOT_TOKEN` and `TELEGRAM_WEBHOOK_SECRET`.
|
|
1724
|
+
|
|
1725
|
+
---
|
|
1726
|
+
|
|
1727
|
+
## 17. Main Telegram types
|
|
1728
|
+
|
|
1729
|
+
The package exports the most commonly used data types directly.
|
|
1730
|
+
|
|
1731
|
+
| Type | Important contents |
|
|
1732
|
+
|---|---|
|
|
1733
|
+
| `User` | ID, bot flag, name, username, language, and capability flags. |
|
|
1734
|
+
| `Chat` | ID, type, title/username/name, forum/direct message indicators. |
|
|
1735
|
+
| `Message` | ID, date, chat, sender, text/caption, entities, reply, markup, plus an index signature for additional Telegram fields. |
|
|
1736
|
+
| `Update` | All update fields supported by the source, including message, callback, inline, poll, member, join request, reaction, boost, business, and extension fields. |
|
|
1737
|
+
| `CallbackQuery` | ID, from, message/inline message id, chat instance, data. |
|
|
1738
|
+
| `InlineQuery` | ID, from, query, offset, chat type, location. |
|
|
1739
|
+
| `Poll`, `PollAnswer` | Poll data and answers. |
|
|
1740
|
+
| `ChatMemberUpdated`, `ChatJoinRequest` | Member changes and join requests. |
|
|
1741
|
+
| `InlineKeyboardMarkup`, `ReplyKeyboardMarkup`, `ReplyKeyboardRemove`, `ForceReply` | Telegram reply markup forms. |
|
|
1742
|
+
| `MessageEntity`, `ReplyParameters`, `LinkPreviewOptions` | Entity, reply, and link preview metadata. |
|
|
1743
|
+
| `BotCommand`, `BotCommandScope`, `WebhookInfo`, `File`, `UserProfilePhotos`, `ChatMember`, `ChatAdministratorRights` | Result/parameter types for API helpers. |
|
|
1744
|
+
|
|
1745
|
+
---
|
|
1746
|
+
|
|
1747
|
+
## 18. Persistence, full cron, menus, and complete Telegram declarations
|
|
1748
|
+
|
|
1749
|
+
### Persistent storage adapters
|
|
1750
|
+
|
|
1751
|
+
All storage adapters implement the same `Storage<K, V>` contract. The core package remains free of vendor runtime dependencies; Redis, SQL, and Mongo adapters receive a small driver interface supplied by the application or its chosen vendor client.
|
|
1752
|
+
|
|
1753
|
+
| Class | Constructor | Purpose |
|
|
1754
|
+
|---|---|---|
|
|
1755
|
+
| `MemoryStorage<K, V>` | `new MemoryStorage()` | Fast in-memory storage with TTL and per-key atomic `update()`. |
|
|
1756
|
+
| `JsonFileStorage<V>` | `new JsonFileStorage(filePath)` | Atomic JSON-file persistence for single-process deployments. |
|
|
1757
|
+
| `RedisStorage<V>` | `new RedisStorage(client, prefix?)` | Redis-backed storage through `RedisLikeClient`, including TTL and namespace operations. |
|
|
1758
|
+
| `SqlStorage<V>` | `new SqlStorage(driver)` | SQL-backed storage through an application-owned `SqlStorageDriver`. |
|
|
1759
|
+
| `MongoStorage<V>` | `new MongoStorage(collection)` | Mongo collection-backed storage through an application-owned `MongoStorageCollection`. |
|
|
1760
|
+
| `StorageApprovalStore` | `new StorageApprovalStore(storage)` | Persistent owner-approval records backed by any `Storage<string, ApprovalRecord>`. |
|
|
1761
|
+
|
|
1762
|
+
`BotOptions.session` accepts `Storage<string, S>`, so sessions can use any adapter. `ConversationManager` accepts the same storage abstraction and exposes `getAsync()`, `cancelAsync()`, and `clearExpiredAsync()` for durable conversation state.
|
|
1763
|
+
|
|
1764
|
+
```ts
|
|
1765
|
+
const session = new JsonFileStorage<Record<string, unknown>>("./data/sessions.json");
|
|
1766
|
+
const bot = new Bot({ token: process.env.TELEGRAM_BOT_TOKEN!, session });
|
|
1767
|
+
```
|
|
1768
|
+
|
|
1769
|
+
### Full five-field cron
|
|
1770
|
+
|
|
1771
|
+
`parseCronExpression()` supports the standard five fields `minute hour day-of-month month day-of-week`, including wildcards, lists, ranges, and steps such as `*/15 9-17 1,15 * 1-5`. `nextCronOccurrence()` calculates the next local occurrence. `Scheduler.cron()` schedules one-shot timers and reschedules after each execution; task failures are delivered to `Scheduler({ onError })` instead of becoming unhandled promise rejections.
|
|
1772
|
+
|
|
1773
|
+
### Router matching mode
|
|
1774
|
+
|
|
1775
|
+
`new Router()` is **first-match by default**. This prevents accidental double replies. Use `new Router({ matchMode: "all" })` only when intentional fan-out is required. RegExp matchers reset `lastIndex` before testing, so global or sticky expressions are safe to reuse.
|
|
1776
|
+
|
|
1777
|
+
### MenuController and permissions
|
|
1778
|
+
|
|
1779
|
+
`Menu` supports permission-aware items, asynchronous visibility and permission predicates, breadcrumbs, and multi-column layouts. `MenuController` adds stateful page rendering and callback dispatch for `select`, `page`, `noop`, and foreign callback data.
|
|
1780
|
+
|
|
1781
|
+
### Complete Telegram declaration namespace
|
|
1782
|
+
|
|
1783
|
+
The package vendors MIT-licensed Telegram declarations and exposes them as type-only exports through `TelegramTypes`, plus aliases such as `TelegramUser`, `TelegramMessage`, `TelegramUpdate`, and `TelegramApiMethods`. These declarations cover the complete object, union, enum, and method declaration surface without adding a runtime dependency. Core telebibz method maps remain specialized for the methods with direct request/result mappings.
|
|
1784
|
+
|
|
1785
|
+
---
|
|
1786
|
+
## 19. Compatibility and limitations to be aware of
|
|
1787
|
+
|
|
1788
|
+
The library targets Node.js `>=20`, uses ESM as the primary module, and also provides a CommonJS build. Webhooks require a runtime that provides Web `Request`, `Response`, `Headers`, `FormData`, `Blob`, and `AbortController`; modern Node.js provides these natively.
|
|
1789
|
+
|
|
1790
|
+
The list of generated API methods and the API method map are not the same. `TelegramMethodName` includes 184 runtime names, but `TelegramMethodMap` only has specially-typed parameters/results for the subset listed in the API client section. For other methods, use `api.raw()` or add a type declaration on the application side.
|
|
1791
|
+
|
|
1792
|
+
Approval state and other in-memory primitives are lost when the process restarts unless the application provides a persistent adapter. `BotOptions.session` accepts the generic `Storage<string, S>` contract, and `ApprovalGate` can use `StorageApprovalStore` or any custom `ApprovalStore`.
|
|
1793
|
+
|
|
1794
|
+
---
|
|
1795
|
+
|
|
1796
|
+
## References
|
|
1797
|
+
|
|
1798
|
+
[1]: https://core.telegram.org/bots/api "Telegram Bot API — official documentation"
|
|
1799
|
+
[2]: https://www.npmjs.com/package/@xbibzlibrary/telebibz "@xbibzlibrary/telebibz on npm"
|