@xbibzlibrary/telebibz 0.4.4 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/CHANGELOG.md +35 -138
  2. package/LICENSE +1 -1
  3. package/NOTICE.md +9 -4
  4. package/README.md +173 -242
  5. package/examples/01-quickstart.js +13 -0
  6. package/examples/02-menu-tombol.js +22 -0
  7. package/examples/03-wizard.js +29 -0
  8. package/examples/04-broadcast.js +25 -0
  9. package/examples/05-kirim-file.js +19 -0
  10. package/examples/06-menu.js +35 -0
  11. package/examples/07-inline-query.js +18 -0
  12. package/index.d.ts +81 -0
  13. package/index.js +42 -0
  14. package/lib/api.js +154 -0
  15. package/lib/broadcast.js +35 -0
  16. package/lib/composer.js +174 -0
  17. package/lib/context.js +190 -0
  18. package/lib/errors.js +35 -0
  19. package/lib/file.js +41 -0
  20. package/lib/inline-query.js +28 -0
  21. package/lib/keyboard.js +83 -0
  22. package/lib/logger.js +38 -0
  23. package/lib/menus.js +90 -0
  24. package/lib/net.js +115 -0
  25. package/lib/ratelimit.js +61 -0
  26. package/lib/runner.js +45 -0
  27. package/lib/session.js +36 -0
  28. package/lib/telebibz.js +190 -0
  29. package/lib/wizard.js +81 -0
  30. package/package.json +35 -97
  31. package/test/all.test.js +334 -0
  32. package/CODE_OF_CONDUCT.md +0 -37
  33. package/CONTRIBUTING.md +0 -59
  34. package/CONTRIBUTION_RULES.md +0 -41
  35. package/GOVERNANCE.md +0 -47
  36. package/README.id.md +0 -292
  37. package/README.zh-CN.md +0 -292
  38. package/RELEASE_AUTOMATION.md +0 -78
  39. package/RELEASE_POLICY.md +0 -32
  40. package/SECURITY.md +0 -47
  41. package/SHOWCASE.md +0 -29
  42. package/SUPPORT.md +0 -30
  43. package/assets/readme-preview.html +0 -75
  44. package/assets/telebibz-logo.png +0 -0
  45. package/assets/telebibz-readme-preview.png +0 -0
  46. package/bin/telebibz.mjs +0 -3
  47. package/dist/generated/api.d.ts +0 -13
  48. package/dist/generated/api.d.ts.map +0 -1
  49. package/dist/generated/api.js +0 -192
  50. package/dist/generated/api.js.map +0 -1
  51. package/dist/src/api/client.d.ts +0 -62
  52. package/dist/src/api/client.d.ts.map +0 -1
  53. package/dist/src/api/client.js +0 -104
  54. package/dist/src/api/client.js.map +0 -1
  55. package/dist/src/api/errors.d.ts +0 -45
  56. package/dist/src/api/errors.d.ts.map +0 -1
  57. package/dist/src/api/errors.js +0 -65
  58. package/dist/src/api/errors.js.map +0 -1
  59. package/dist/src/api/index.d.ts +0 -6
  60. package/dist/src/api/index.d.ts.map +0 -1
  61. package/dist/src/api/index.js +0 -6
  62. package/dist/src/api/index.js.map +0 -1
  63. package/dist/src/api/telegram-types/LICENSE +0 -21
  64. package/dist/src/api/telegram-types/api.d.ts +0 -22
  65. package/dist/src/api/telegram-types/checklist.d.ts +0 -72
  66. package/dist/src/api/telegram-types/inline.d.ts +0 -692
  67. package/dist/src/api/telegram-types/langs.d.ts +0 -193
  68. package/dist/src/api/telegram-types/manage.d.ts +0 -1144
  69. package/dist/src/api/telegram-types/markup.d.ts +0 -268
  70. package/dist/src/api/telegram-types/message.d.ts +0 -1537
  71. package/dist/src/api/telegram-types/methods.d.ts +0 -2870
  72. package/dist/src/api/telegram-types/mod.d.ts +0 -14
  73. package/dist/src/api/telegram-types/passport.d.ts +0 -163
  74. package/dist/src/api/telegram-types/payment.d.ts +0 -570
  75. package/dist/src/api/telegram-types/rich.d.ts +0 -1010
  76. package/dist/src/api/telegram-types/settings.d.ts +0 -120
  77. package/dist/src/api/telegram-types/story.d.ts +0 -89
  78. package/dist/src/api/telegram-types/update.d.ts +0 -84
  79. package/dist/src/api/telegram.d.ts +0 -7
  80. package/dist/src/api/telegram.d.ts.map +0 -1
  81. package/dist/src/api/telegram.js +0 -2
  82. package/dist/src/api/telegram.js.map +0 -1
  83. package/dist/src/api/transport.d.ts +0 -68
  84. package/dist/src/api/transport.d.ts.map +0 -1
  85. package/dist/src/api/transport.js +0 -264
  86. package/dist/src/api/transport.js.map +0 -1
  87. package/dist/src/api/types.d.ts +0 -466
  88. package/dist/src/api/types.d.ts.map +0 -1
  89. package/dist/src/api/types.js +0 -2
  90. package/dist/src/api/types.js.map +0 -1
  91. package/dist/src/branding/terminal.d.ts +0 -77
  92. package/dist/src/branding/terminal.d.ts.map +0 -1
  93. package/dist/src/branding/terminal.js +0 -328
  94. package/dist/src/branding/terminal.js.map +0 -1
  95. package/dist/src/broadcast/broadcast.d.ts +0 -50
  96. package/dist/src/broadcast/broadcast.d.ts.map +0 -1
  97. package/dist/src/broadcast/broadcast.js +0 -56
  98. package/dist/src/broadcast/broadcast.js.map +0 -1
  99. package/dist/src/cache/cache.d.ts +0 -34
  100. package/dist/src/cache/cache.d.ts.map +0 -1
  101. package/dist/src/cache/cache.js +0 -41
  102. package/dist/src/cache/cache.js.map +0 -1
  103. package/dist/src/cli.d.ts +0 -2
  104. package/dist/src/cli.d.ts.map +0 -1
  105. package/dist/src/cli.js +0 -84
  106. package/dist/src/cli.js.map +0 -1
  107. package/dist/src/context/context.d.ts +0 -124
  108. package/dist/src/context/context.d.ts.map +0 -1
  109. package/dist/src/context/context.js +0 -302
  110. package/dist/src/context/context.js.map +0 -1
  111. package/dist/src/core/bot.d.ts +0 -204
  112. package/dist/src/core/bot.d.ts.map +0 -1
  113. package/dist/src/core/bot.js +0 -506
  114. package/dist/src/core/bot.js.map +0 -1
  115. package/dist/src/core/events.d.ts +0 -75
  116. package/dist/src/core/events.d.ts.map +0 -1
  117. package/dist/src/core/events.js +0 -35
  118. package/dist/src/core/events.js.map +0 -1
  119. package/dist/src/core/webhook-reply.d.ts +0 -34
  120. package/dist/src/core/webhook-reply.d.ts.map +0 -1
  121. package/dist/src/core/webhook-reply.js +0 -37
  122. package/dist/src/core/webhook-reply.js.map +0 -1
  123. package/dist/src/index.d.ts +0 -24
  124. package/dist/src/index.d.ts.map +0 -1
  125. package/dist/src/index.js +0 -24
  126. package/dist/src/index.js.map +0 -1
  127. package/dist/src/keyboard/index.d.ts +0 -46
  128. package/dist/src/keyboard/index.d.ts.map +0 -1
  129. package/dist/src/keyboard/index.js +0 -55
  130. package/dist/src/keyboard/index.js.map +0 -1
  131. package/dist/src/middleware/compose.d.ts +0 -5
  132. package/dist/src/middleware/compose.d.ts.map +0 -1
  133. package/dist/src/middleware/compose.js +0 -17
  134. package/dist/src/middleware/compose.js.map +0 -1
  135. package/dist/src/observability/logger.d.ts +0 -78
  136. package/dist/src/observability/logger.d.ts.map +0 -1
  137. package/dist/src/observability/logger.js +0 -285
  138. package/dist/src/observability/logger.js.map +0 -1
  139. package/dist/src/plugins/plugin.d.ts +0 -38
  140. package/dist/src/plugins/plugin.d.ts.map +0 -1
  141. package/dist/src/plugins/plugin.js +0 -59
  142. package/dist/src/plugins/plugin.js.map +0 -1
  143. package/dist/src/queue/queue.d.ts +0 -77
  144. package/dist/src/queue/queue.d.ts.map +0 -1
  145. package/dist/src/queue/queue.js +0 -213
  146. package/dist/src/queue/queue.js.map +0 -1
  147. package/dist/src/router/router.d.ts +0 -61
  148. package/dist/src/router/router.d.ts.map +0 -1
  149. package/dist/src/router/router.js +0 -183
  150. package/dist/src/router/router.js.map +0 -1
  151. package/dist/src/state/conversation.d.ts +0 -56
  152. package/dist/src/state/conversation.d.ts.map +0 -1
  153. package/dist/src/state/conversation.js +0 -133
  154. package/dist/src/state/conversation.js.map +0 -1
  155. package/dist/src/state/forms.d.ts +0 -34
  156. package/dist/src/state/forms.d.ts.map +0 -1
  157. package/dist/src/state/forms.js +0 -44
  158. package/dist/src/state/forms.js.map +0 -1
  159. package/dist/src/state/menu.d.ts +0 -78
  160. package/dist/src/state/menu.d.ts.map +0 -1
  161. package/dist/src/state/menu.js +0 -127
  162. package/dist/src/state/menu.js.map +0 -1
  163. package/dist/src/storage/storage.d.ts +0 -146
  164. package/dist/src/storage/storage.d.ts.map +0 -1
  165. package/dist/src/storage/storage.js +0 -195
  166. package/dist/src/storage/storage.js.map +0 -1
  167. package/dist/src/telegram-features.d.ts +0 -33
  168. package/dist/src/telegram-features.d.ts.map +0 -1
  169. package/dist/src/telegram-features.js +0 -71
  170. package/dist/src/telegram-features.js.map +0 -1
  171. package/dist/src/testing.d.ts +0 -24
  172. package/dist/src/testing.d.ts.map +0 -1
  173. package/dist/src/testing.js +0 -38
  174. package/dist/src/testing.js.map +0 -1
  175. package/dist/src/utils/concurrency.d.ts +0 -25
  176. package/dist/src/utils/concurrency.d.ts.map +0 -1
  177. package/dist/src/utils/concurrency.js +0 -52
  178. package/dist/src/utils/concurrency.js.map +0 -1
  179. package/dist/src/utils/files.d.ts +0 -45
  180. package/dist/src/utils/files.d.ts.map +0 -1
  181. package/dist/src/utils/files.js +0 -53
  182. package/dist/src/utils/files.js.map +0 -1
  183. package/dist/src/utils/text.d.ts +0 -39
  184. package/dist/src/utils/text.d.ts.map +0 -1
  185. package/dist/src/utils/text.js +0 -56
  186. package/dist/src/utils/text.js.map +0 -1
  187. package/dist/src/webhook/handler.d.ts +0 -19
  188. package/dist/src/webhook/handler.d.ts.map +0 -1
  189. package/dist/src/webhook/handler.js +0 -141
  190. package/dist/src/webhook/handler.js.map +0 -1
  191. package/dist-cjs/generated/api.js +0 -194
  192. package/dist-cjs/package.json +0 -3
  193. package/dist-cjs/src/api/client.js +0 -107
  194. package/dist-cjs/src/api/errors.js +0 -74
  195. package/dist-cjs/src/api/index.js +0 -21
  196. package/dist-cjs/src/api/telegram-types/LICENSE +0 -21
  197. package/dist-cjs/src/api/telegram-types/api.d.ts +0 -22
  198. package/dist-cjs/src/api/telegram-types/checklist.d.ts +0 -72
  199. package/dist-cjs/src/api/telegram-types/inline.d.ts +0 -692
  200. package/dist-cjs/src/api/telegram-types/langs.d.ts +0 -193
  201. package/dist-cjs/src/api/telegram-types/manage.d.ts +0 -1144
  202. package/dist-cjs/src/api/telegram-types/markup.d.ts +0 -268
  203. package/dist-cjs/src/api/telegram-types/message.d.ts +0 -1537
  204. package/dist-cjs/src/api/telegram-types/methods.d.ts +0 -2870
  205. package/dist-cjs/src/api/telegram-types/mod.d.ts +0 -14
  206. package/dist-cjs/src/api/telegram-types/passport.d.ts +0 -163
  207. package/dist-cjs/src/api/telegram-types/payment.d.ts +0 -570
  208. package/dist-cjs/src/api/telegram-types/rich.d.ts +0 -1010
  209. package/dist-cjs/src/api/telegram-types/settings.d.ts +0 -120
  210. package/dist-cjs/src/api/telegram-types/story.d.ts +0 -89
  211. package/dist-cjs/src/api/telegram-types/update.d.ts +0 -84
  212. package/dist-cjs/src/api/telegram.js +0 -2
  213. package/dist-cjs/src/api/transport.js +0 -267
  214. package/dist-cjs/src/api/types.js +0 -2
  215. package/dist-cjs/src/branding/terminal.js +0 -338
  216. package/dist-cjs/src/broadcast/broadcast.js +0 -58
  217. package/dist-cjs/src/cache/cache.js +0 -45
  218. package/dist-cjs/src/cli.js +0 -86
  219. package/dist-cjs/src/context/context.js +0 -305
  220. package/dist-cjs/src/core/bot.js +0 -510
  221. package/dist-cjs/src/core/events.js +0 -38
  222. package/dist-cjs/src/core/webhook-reply.js +0 -42
  223. package/dist-cjs/src/index.js +0 -47
  224. package/dist-cjs/src/keyboard/index.js +0 -61
  225. package/dist-cjs/src/middleware/compose.js +0 -20
  226. package/dist-cjs/src/observability/logger.js +0 -293
  227. package/dist-cjs/src/plugins/plugin.js +0 -63
  228. package/dist-cjs/src/queue/queue.js +0 -219
  229. package/dist-cjs/src/router/router.js +0 -186
  230. package/dist-cjs/src/state/conversation.js +0 -139
  231. package/dist-cjs/src/state/forms.js +0 -47
  232. package/dist-cjs/src/state/menu.js +0 -133
  233. package/dist-cjs/src/storage/storage.js +0 -202
  234. package/dist-cjs/src/telegram-features.js +0 -76
  235. package/dist-cjs/src/testing.js +0 -45
  236. package/dist-cjs/src/utils/concurrency.js +0 -57
  237. package/dist-cjs/src/utils/files.js +0 -58
  238. package/dist-cjs/src/utils/text.js +0 -63
  239. package/dist-cjs/src/webhook/handler.js +0 -144
  240. package/docs/API.id.md +0 -1935
  241. package/docs/API.md +0 -1969
  242. package/docs/API.zh-CN.md +0 -1929
  243. package/docs/GETTING_STARTED.id.md +0 -85
  244. package/docs/GETTING_STARTED.md +0 -85
  245. package/docs/GETTING_STARTED.zh-CN.md +0 -85
  246. package/docs/GITHUB_PACKAGES.id.md +0 -82
  247. package/docs/GITHUB_PACKAGES.md +0 -82
  248. package/docs/GITHUB_PACKAGES.zh-CN.md +0 -82
  249. package/docs/README.md +0 -48
  250. package/docs/STORAGE.id.md +0 -105
  251. package/docs/STORAGE.md +0 -105
  252. package/docs/STORAGE.zh-CN.md +0 -105
  253. package/examples/README.md +0 -37
  254. package/examples/files.ts +0 -35
  255. package/examples/minimal.ts +0 -12
  256. package/examples/tsconfig.json +0 -9
  257. package/examples/webhook.ts +0 -42
  258. package/examples/wizard-registration.ts +0 -42
package/docs/API.md DELETED
@@ -1,1969 +0,0 @@
1
- # telebibz API Reference — English
2
- [English](API.md) · [Bahasa Indonesia](API.id.md) · [简体中文](API.zh-CN.md)
3
-
4
- ![telebibz overview](https://cdn.jsdelivr.net/npm/@xbibzlibrary/telebibz@latest/assets/telebibz-readme-preview.png)
5
-
6
- This document is the API reference for the current published `@xbibzlibrary/telebibz` release. 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 available in the current release. `JsonFileStorage`, driver-based Redis/SQL/Mongo storage, storage-backed sessions/conversations, full five-field cron, `MenuController`, terminal branding, structured redacted logging, Web App validation, PaymentsClient, and vendored `TelegramTypes` declarations are included. The core method map remains specialized for selected request/result inference, while `api.raw()` remains available for future Telegram methods.
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
- | "starting"
54
- | "running"
55
- | "stopping"
56
- | "stopped"
57
- | "error";
58
- ```
59
-
60
- ### `BotOptions<S>`
61
-
62
- | Property | Type | Default | Description |
63
- |---|---|---:|---|
64
- | `token` | `string` | required | BotFather token in the format `<digits>:<token>`. |
65
- | `apiBaseUrl` | `string` | `https://api.telegram.org` | Telegram API base URL. Trailing `/` is removed automatically. |
66
- | `transport` | `Transport` | `FetchTransport` | Custom transport for mocks, proxies, or other implementations. |
67
- | `transportOptions` | `Omit<FetchTransportOptions, "baseUrl">` | `{}` | Timeout, retry, backoff, jitter, headers, and fetch implementation. |
68
- | `session` | `Storage<string, S>` | new storage | Session storage keyed by chat/user; any storage adapter may be used. |
69
- | `services` | `Record<string, unknown>` | `{}` | Dependencies/services available via `ctx.services`. |
70
- | `branding` | `boolean` | `true` | Terminal startup experience: typing effect, glass progress bar, animated rainbow "Tele Bibz" banner, and human-readable update lines. Only renders on an interactive TTY. |
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
- | `updates.concurrency` | `number` | `Infinity` | Cap on how many updates are processed at the same time. Updates always run in parallel across chats and stay ordered within a single chat, so bursts of 1000+ messages are handled at once. |
77
- | `handlerTimeout` | `number` | `90000` | Per-update processing timeout in ms (`Infinity` disables). On timeout the update error flow runs (`update:error`, `bot:error`, `catch()` boundary) and `handleUpdate()` rejects with `UpdateTimeoutError`, while the handler keeps running to completion in the background. |
78
- | `contextType` | `new (options: ContextOptions<S>) => Context<S>` | `Context` | Custom `Context` subclass instantiated for every update (Telegraf's `contextType`). |
79
-
80
- ### Constructor `Bot`
81
-
82
- ```ts
83
- new Bot<S extends object = Record<string, unknown>>(
84
- options: string | BotOptions<S>,
85
- ): Bot<S>
86
- ```
87
-
88
- If the argument is a string, it is treated as the token. The constructor creates `ApiClient`, router, event bus, plugin manager, session storage, and structured runtime logging. The constructor emits the `bot:created` event asynchronously.
89
-
90
- The constructor throws `Error` if the token is empty or does not match the Telegram token pattern.
91
-
92
- ### Properties and getters `Bot`
93
-
94
- | API | Type | Description |
95
- |---|---|---|
96
- | `api` | `ApiClient` | Telegram typed/dynamic client. |
97
- | `router` | `Router<Context<S>>` | Bot's main router. |
98
- | `events` | `EventBus<EventMap>` | Event bus for lifecycle, updates, API, webhook, and polling. |
99
- | `plugins` | `PluginManager<Context<S>>` | Plugin lifecycle manager. |
100
- | `session` | `Storage<string, S>` | Bot session; any persistent adapter may be used. |
101
- | `services` | `Record<string, unknown>` | A copy of services provided to the constructor. |
102
- | `token` | `string` | Bot token used by the client. |
103
- | `status` | `BotStatus` | Current lifecycle status. |
104
- | `botInfo` | `User \| undefined` | Last stored result of `getMe()`. |
105
-
106
- ### `bot.use(...middleware)`
107
-
108
- ```ts
109
- use(...middleware: Middleware<Context<S>>[]): this
110
- ```
111
-
112
- Adds global middleware. Middleware are executed before the router on every update, in registration order. Returns the bot instance for chaining.
113
-
114
- ### `bot.command(name, handler)`
115
-
116
- ```ts
117
- command(name: string, handler: Middleware<Context<S>>): this
118
- ```
119
-
120
- 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"`.
121
-
122
- ### `bot.callback(pattern, handler)`
123
-
124
- ```ts
125
- callback(pattern: string | RegExp, handler: Middleware<Context<S>>): this
126
- ```
127
-
128
- Shortcut for a callback query route. A string ending with `*` means prefix matching; other strings must match exactly.
129
-
130
- ### `bot.onText(text, handler)`
131
-
132
- ```ts
133
- onText(text: string, handler: Middleware<Context<S>>): this
134
- ```
135
-
136
- Handles messages whose `message.text` is exactly equal to `text`.
137
-
138
- ### `bot.onRegex(expression, handler)`
139
-
140
- ```ts
141
- onRegex(expression: RegExp, handler: Middleware<Context<S>>): this
142
- ```
143
-
144
- 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.
145
-
146
- ### `bot.on(filter, handler)`
147
-
148
- ```ts
149
- on(filter: UpdateFilter | UpdateFilter[], handler: Middleware<Context<S>>): this
150
- ```
151
-
152
- Registers a handler for update types, optionally narrowed by a payload field. Examples: `"message"`, `"message:text"`, `"message:photo"`, `"edited_message"`, `"channel_post"`, `"callback_query"`, `"callback_query:data"`, `"inline_query"`, `"chat_member"`, `"message_reaction"`, or an array such as `["message:text", "callback_query:data"]`. Invalid update types throw a `TypeError` at registration time.
153
-
154
- ### `bot.hears(trigger, handler)`
155
-
156
- ```ts
157
- hears(trigger: string | RegExp, handler: Middleware<Context<S>>): this
158
- ```
159
-
160
- Handles exact message text (string) or message text matching a `RegExp`.
161
-
162
- ### `bot.catch(handler)`
163
-
164
- ```ts
165
- catch(handler: (error: unknown, ctx: Context<S>) => void | Promise<void>): this
166
- ```
167
-
168
- Registers the error boundary for update handlers. When set, a handler failure is logged, emitted as `update:error`/`bot:error`, and passed to this handler instead of rejecting `handleUpdate()` — webhook requests answer `200` and polling continues. Without a boundary, the error is rethrown.
169
-
170
- ### `bot.usePlugin(plugin)`
171
-
172
- ```ts
173
- usePlugin(plugin: Plugin<Context<S>>): this
174
- ```
175
-
176
- Registers a plugin. Plugin names must be unique.
177
-
178
- ### `bot.useWizard(wizard, options?)`
179
-
180
- ```ts
181
- useWizard(wizard: Wizard<S>, options?: { cancelCommand?: string }): this
182
- ```
183
-
184
- Installs conversation middleware for a `Wizard`. Once an application starts the wizard with `wizard.run(ctx)`, subsequent text messages from the same chat/user are automatically routed to the active step until the wizard is completed or cancelled. The default conversation key is `${chat.id}:${from.id}`; `/cancel` cancels the active wizard by default.
185
-
186
- ```ts
187
- const wizard = new Wizard()
188
- .step({ id: "prompt-name", run: async (flow) => { flow.next(); await flow.ctx.reply("Siapa nama kamu?"); } })
189
- .step({ id: "name", run: async (flow) => { flow.set("name", flow.ctx.message?.text?.trim()); flow.next(); await flow.ctx.reply("Berapa umur kamu?"); } })
190
- .step({ id: "age", run: (flow) => { const age = Number(flow.ctx.message?.text?.trim()); if (!Number.isInteger(age)) return; flow.set("age", age); flow.next(); } });
191
-
192
- bot.useWizard(wizard);
193
- bot.command("start", (ctx) => wizard.run(ctx));
194
- ```
195
-
196
- ### `bot.init()`
197
-
198
- ```ts
199
- init(): Promise<this>
200
- ```
201
-
202
- Calls `getMe()`, stores the bot information, initializes plugins, and returns an initialized bot ready for polling or manual update handling.
203
-
204
- `init()` is idempotent when the status is already `initialized` or `running`.
205
-
206
- ### `bot.start()`
207
-
208
- ```ts
209
- start(): Promise<void>
210
- ```
211
-
212
- Shortcut for `launch({ mode: "polling" })`. This method runs long polling and waits until polling is stopped or fails fatally.
213
-
214
- ### `bot.launch(options?)`
215
-
216
- ```ts
217
- launch(options?: {
218
- mode: "polling";
219
- timeout?: number;
220
- allowedUpdates?: string[];
221
- dropPendingUpdates?: boolean;
222
- }): Promise<void>
223
- ```
224
-
225
- Runs the bot in polling mode. On start, the lifecycle moves through `starting` to `running`, then the `getUpdates()` loop processes each batch of updates concurrently: updates for different chats run in parallel while updates for the same chat keep their arrival order. Polling failures emit `polling:reconnect` and use exponential backoff. `dropPendingUpdates: true` (also on `bot.start()`) drops everything Telegram is holding for the bot before the first `getUpdates` call, using the same `deleteWebhook({ drop_pending_updates: true })` mechanism Telegraf uses.
226
-
227
- Modes other than `"polling"` throw an error and suggest using `createWebhookHandler()` for webhooks.
228
-
229
- ### `bot.stop()`
230
-
231
- ```ts
232
- stop(): Promise<void>
233
- ```
234
-
235
- 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.
236
-
237
- ### `bot.restart()`
238
-
239
- ```ts
240
- restart(): Promise<void>
241
- ```
242
-
243
- Runs `stop()` and then `start()`.
244
-
245
- ### `bot.health()`
246
-
247
- ```ts
248
- health(): Promise<HealthStatus>
249
- ```
250
-
251
- Calls `getMe()` to check API reachability. It does not throw on request failures; failures are returned as `apiReachable: false` with an error message.
252
-
253
- ```ts
254
- interface HealthStatus {
255
- status: BotStatus;
256
- apiReachable: boolean;
257
- bot?: User;
258
- checkedAt: string; // ISO timestamp
259
- error?: string;
260
- }
261
- ```
262
-
263
- ### `bot.getMe()`
264
-
265
- ```ts
266
- getMe(): Promise<User>
267
- ```
268
-
269
- Fetches the bot data from Telegram and updates `botInfo`.
270
-
271
- ### `bot.setCommands(commands, scope?, languageCode?)`
272
-
273
- ```ts
274
- setCommands(
275
- commands: BotCommand[],
276
- scope?: BotCommandScope,
277
- languageCode?: string,
278
- ): Promise<true>
279
- ```
280
-
281
- Shortcut to `setMyCommands`. `languageCode` is mapped to Telegram's `language_code` field.
282
-
283
- ### `bot.deleteCommands(scope?, languageCode?)`
284
-
285
- ```ts
286
- deleteCommands(
287
- scope?: BotCommandScope,
288
- languageCode?: string,
289
- ): Promise<true>
290
- ```
291
-
292
- Shortcut to `deleteMyCommands`.
293
-
294
- ### `bot.downloadFile(fileId, options?)`
295
-
296
- ```ts
297
- downloadFile(
298
- fileId: string,
299
- options?: { signal?: AbortSignal; destination?: string },
300
- ): Promise<DownloadedFile>
301
- ```
302
-
303
- Resolves `fileId` through `getFile`, then downloads the raw bytes via the transport's download endpoint. Pass `destination` to also persist the bytes to a local file path (`savedTo` is set on the result). Throws a `TelegramError` (kind `validation`) when Telegram returns no `file_path` or the transport cannot download, and a `TelegramNetworkError` when the download fails. Telegram caps downloads at 20 MB; the returned `url` stays valid for at least one hour.
304
-
305
- ```ts
306
- const file = await bot.downloadFile(photoFileId, { destination: "downloads/photo.jpg" });
307
- console.log(file.fileName, file.sizeBytes, file.url, file.savedTo);
308
- ```
309
-
310
- ### `bot.handleUpdate(update)`
311
-
312
- ```ts
313
- handleUpdate(update: Update, options?: { webhookReply?: WebhookReplySink }): Promise<void>
314
- ```
315
-
316
- Processes a single update manually. The method determines the session key from `chat.id` and `from.id`, creates a `Context` (of the configured `contextType`), emits `update` and `message` events, runs middleware then the router, and saves the session after the pipeline completes.
317
-
318
- Updates for different chats are processed in parallel; updates for the same chat are serialized in arrival order, so sessions, wizards, and conversations never interleave and session writes are never lost. A burst of concurrent updates triggers exactly one `getMe` initialization. The whole per-update run is guarded by `handlerTimeout` (default 90s, matching Telegraf): on timeout the error flows through `update:error`/`bot:error` and the `catch()` boundary, and `handleUpdate()` rejects with `UpdateTimeoutError` while the handler keeps running in the background.
319
-
320
- `options.webhookReply` installs a Telegraf-style responder: the first outgoing API call during this update is answered through the webhook HTTP response instead of a separate request, and resolves with `true` (Telegram never sends the method result back to a webhook response).
321
-
322
- Pipeline errors set the bot status to `error`, emit `bot:error`, and then rethrow the error.
323
-
324
- ### `bot.handleUpdates(updates)`
325
-
326
- ```ts
327
- handleUpdates(updates: readonly Update[]): Promise<void>
328
- ```
329
-
330
- Handles a whole batch of updates at once: every chat in the batch is processed immediately — parallel across chats, ordered per chat — so a burst of 1000 messages is never stuck behind one slow handler. Individual handler failures are logged, emitted as `update:error`, and passed to the `catch()` error boundary; they never reject this promise. The polling loop uses this method for every `getUpdates` batch.
331
-
332
- ### `bot.broadcast(chatIds, send, options?)`
333
-
334
- ```ts
335
- broadcast(
336
- chatIds: readonly ChatId[],
337
- send: (chatId: ChatId) => Promise<unknown>,
338
- options?: BroadcastOptions,
339
- ): Promise<BroadcastReport>
340
- ```
341
-
342
- Sends to many chats in parallel — built for broadcasts to 1000+ users. There is no proactive cooldown: every chat is attempted at once (up to `options.concurrency`, default `Infinity`). When Telegram answers 429, the send is retried automatically after exactly the `retry_after` delay Telegram ordered (up to `options.maxAttempts`, default `10`), so bursts deliver completely instead of failing. Non-retryable errors (for example, a chat the bot cannot message) are recorded per chat in the returned report.
343
-
344
- ```ts
345
- const report = await bot.broadcast(
346
- subscriberIds,
347
- (chatId) => bot.api.methods.sendMessage({ chat_id: chatId, text: "Newsletter #42" }),
348
- { onProgress: (progress) => console.log(`${progress.delivered}/${progress.total} delivered`) },
349
- );
350
- console.log(`Delivered ${report.delivered} of ${report.total} in ${report.durationMs}ms`);
351
- for (const failure of report.failures) console.warn(`Failed: ${failure.chatId} — ${failure.error}`);
352
- ```
353
-
354
- #### `BroadcastOptions` and `BroadcastReport`
355
-
356
- | Property | Type | Default | Description |
357
- |---|---|---:|---|
358
- | `BroadcastOptions.concurrency` | `number` | `Infinity` | How many chats are messaged at the same time. |
359
- | `BroadcastOptions.maxAttempts` | `number` | `10` | Attempts per chat when Telegram answers 429. |
360
- | `BroadcastOptions.onProgress` | `(progress: BroadcastProgress) => void` | — | Called after each chat settles. |
361
- | `BroadcastOptions.signal` | `AbortSignal` | — | Aborts pending sends; delivered messages stay delivered. |
362
- | `BroadcastReport.total` | `number` | — | Chats in the run. |
363
- | `BroadcastReport.delivered` | `number` | — | Chats that received the message. |
364
- | `BroadcastReport.failed` | `number` | — | Chats that did not. |
365
- | `BroadcastReport.durationMs` | `number` | — | Wall-clock duration of the run. |
366
- | `BroadcastReport.failures` | `BroadcastFailure[]` | — | Per-chat `{ chatId, attempts, error, errorKind }` records. |
367
-
368
- ### `UpdateTimeoutError` and webhook-reply helpers
369
-
370
- ```ts
371
- class UpdateTimeoutError extends Error {
372
- readonly name = "UpdateTimeoutError";
373
- readonly updateId: number;
374
- }
375
- ```
376
-
377
- Rejected by `handleUpdate()` when a single update exceeds `handlerTimeout`. The handler itself keeps running; the error also flows through `update:error`, `bot:error`, and the `catch()` boundary.
378
-
379
- ```ts
380
- type WebhookReplySink = (payload: Record<string, unknown>) => void;
381
- runWithWebhookReply(sink, fn): Promise<T> // sets the responder for every API call inside fn
382
- runWithoutWebhookReply(fn): Promise<T> // library-internal calls that never claim the slot
383
- ```
384
-
385
- Exported so custom webhook servers can wire webhook replies the same way `createWebhookHandler` does.
386
-
387
- ### Minimal bot example
388
-
389
- ```ts
390
- import { Bot, InlineKeyboard } from "@xbibzlibrary/telebibz";
391
-
392
- const bot = new Bot({
393
- token: process.env.TELEGRAM_BOT_TOKEN!,
394
- polling: { allowedUpdates: ["message", "callback_query"] },
395
- });
396
-
397
- bot.command("start", async (ctx) => {
398
- await ctx.reply("Hello from telebibz", {
399
- reply_markup: new InlineKeyboard()
400
- .text("Status", "status")
401
- .build(),
402
- });
403
- });
404
-
405
- bot.callback("status", async (ctx) => {
406
- await ctx.answerCallbackQuery("Bot is active");
407
- await ctx.reply("Status: running");
408
- });
409
-
410
- await bot.start();
411
- ```
412
-
413
- ---
414
-
415
- ## 2. Event bus
416
-
417
- ### `EventMap`
418
-
419
- | Event | Payload |
420
- |---|---|
421
- | `bot:created` | `{ bot: unknown }` |
422
- | `bot:initialized` | `{ bot: unknown }` |
423
- | `bot:starting` | `{ bot: unknown }` |
424
- | `bot:started` | `{ bot: unknown }` |
425
- | `bot:stopping` | `{ bot: unknown }` |
426
- | `bot:stopped` | `{ bot: unknown }` |
427
- | `bot:error` | `{ bot: unknown; error: unknown }` |
428
- | `update` | `{ update: unknown }` |
429
- | `message` | `{ message: unknown }` |
430
- | `command` | `{ name: string; update: unknown }` |
431
- | `callback` | `{ data: string; update: unknown }` |
432
- | `api:request` | `{ method: string; payload: unknown }` |
433
- | `api:response` | `{ method: string; durationMs: number; response: unknown }` |
434
- | `api:error` | `{ method: string; durationMs: number; error: unknown }` |
435
- | `webhook:request` | `{ update: unknown }` |
436
- | `polling:reconnect` | `{ error: unknown; attempt: number }` |
437
-
438
- ### `EventBus<Events>`
439
-
440
- ```ts
441
- new EventBus<Events extends Record<string, unknown> = EventMap>()
442
- ```
443
-
444
- | Method | Signature | Behavior |
445
- |---|---|---|
446
- | `on` | `on<K>(event: K, listener: (payload: Events[K]) => void \| Promise<void>): () => void` | Adds a listener and returns an unsubscribe function. |
447
- | `once` | `once<K>(event: K, listener: ...): () => void` | Listener is called only once, then removed. |
448
- | `off` | `off<K>(event: K, listener: ...): void` | Removes a specific listener. |
449
- | `emit` | `emit<K>(event: K, payload: Events[K]): Promise<void>` | Calls listeners sequentially and awaits each. |
450
- | `removeAllListeners` | `removeAllListeners(): void` | Removes all listeners. |
451
- | `listenerCount` | `listenerCount<K>(event: K): number` | Returns the number of listeners for the event. |
452
-
453
- ```ts
454
- const unsubscribe = bot.events.on("bot:error", ({ error }) => {
455
- console.error(error);
456
- });
457
- unsubscribe();
458
- ```
459
-
460
- ---
461
-
462
- ## 3. API client, transport, and errors
463
-
464
- ### Basic types
465
-
466
- ```ts
467
- type ChatId = number | string;
468
- type ParseMode = "Markdown" | "MarkdownV2" | "HTML";
469
- type InputFile =
470
- | string
471
- | Uint8Array
472
- | ArrayBuffer
473
- | Blob
474
- | NodeJS.ReadableStream
475
- | { source: string | Uint8Array | ArrayBuffer | Blob | NodeJS.ReadableStream; filename?: string };
476
- ```
477
-
478
- `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.
479
-
480
- ### `TelegramResponse<T>`
481
-
482
- ```ts
483
- interface TelegramResponse<T> {
484
- ok: boolean;
485
- result?: T;
486
- description?: string;
487
- error_code?: number;
488
- parameters?: ResponseParameters;
489
- }
490
- ```
491
-
492
- ### `TransportRequest`, `TransportResponse`, and `Transport`
493
-
494
- ```ts
495
- interface TransportRequest {
496
- method: string;
497
- payload?: Record<string, unknown>;
498
- signal?: AbortSignal;
499
- }
500
-
501
- interface TransportResponse<T = unknown> {
502
- status: number;
503
- headers: Headers;
504
- data: TelegramResponse<T>;
505
- }
506
-
507
- interface Transport {
508
- request<T>(request: TransportRequest): Promise<TransportResponse<T>>;
509
- }
510
- ```
511
-
512
- ### `FetchTransportOptions`
513
-
514
- | Property | Default | Description |
515
- |---|---:|---|
516
- | `baseUrl` | `https://api.telegram.org` | URL prefix before `/<method>`. |
517
- | `fetch` | `globalThis.fetch` | Custom fetch implementation. |
518
- | `timeoutMs` | `30000` | Timeout per attempt. |
519
- | `retries` | `2` | Number of retries for network errors after the initial attempt. |
520
- | `backoffMs` | `250` | Initial exponential delay. |
521
- | `maxBackoffMs` | `8000` | Transport delay cap. |
522
- | `jitter` | `0.2` | Random variation ±20% of the exponential delay. |
523
- | `headers` | `{}` | Additional headers. |
524
- | `floodGate` | `true` | When Telegram answers 429, pauses NEW requests until the `retry_after` window Telegram ordered has elapsed. Never a proactive cooldown — the only waiting done is what Telegram itself demands. |
525
-
526
- ### `new FetchTransport(options?)`
527
-
528
- ```ts
529
- new FetchTransport(options?: FetchTransportOptions): FetchTransport
530
- ```
531
-
532
- 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`.
533
-
534
- ### `fetchTransport.request(request)`
535
-
536
- ```ts
537
- request<T>(request: TransportRequest): Promise<TransportResponse<T>>
538
- ```
539
-
540
- 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`.
541
-
542
- ### `ApiHookContext`, `ApiClientOptions`, and `ApiMethods`
543
-
544
- ```ts
545
- interface ApiHookContext {
546
- method: string;
547
- payload: unknown;
548
- startedAt: number;
549
- durationMs?: number;
550
- response?: TelegramResponse<unknown>;
551
- error?: unknown;
552
- }
553
-
554
- interface ApiClientOptions {
555
- transport: Transport;
556
- hooks?: {
557
- onRequest?: (context: ApiHookContext) => void | Promise<void>;
558
- onResponse?: (context: ApiHookContext) => void | Promise<void>;
559
- onError?: (context: ApiHookContext) => void | Promise<void>;
560
- };
561
- }
562
- ```
563
-
564
- `ApiMethods` is a mapped type of the 184 `TelegramMethodName`s:
565
-
566
- ```ts
567
- type ApiMethods = {
568
- [M in TelegramMethodName]:
569
- (...args: ApiCallArgs<M>) => Promise<ApiResult<M>>;
570
- };
571
- ```
572
-
573
- ### `new ApiClient(options)`
574
-
575
- ```ts
576
- new ApiClient(options: ApiClientOptions): ApiClient
577
- ```
578
-
579
- 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`.
580
-
581
- ### `api.methods.<method>(params?)`
582
-
583
- Dynamic methods can be called directly. Methods that have empty parameters like `getMe()` are called without arguments; other methods accept a single parameter object.
584
-
585
- ```ts
586
- const me = await bot.api.methods.getMe();
587
- const chat = await bot.api.methods.getChat({ chat_id: "@channel" });
588
- const message = await bot.api.methods.sendMessage({
589
- chat_id: 123456789,
590
- text: "Hello",
591
- });
592
- ```
593
-
594
- ### `api.call(method, ...args)`
595
-
596
- ```ts
597
- call<M extends TelegramMethodName>(
598
- method: M,
599
- ...args: ApiCallArgs<M>
600
- ): Promise<ApiResult<M>>
601
- ```
602
-
603
- Typed form for calling a method based on a string literal.
604
-
605
- ### `api.request(method, payload?, signal?)`
606
-
607
- ```ts
608
- request<M extends TelegramMethodName>(
609
- method: M,
610
- payload?: ApiParams<M>,
611
- signal?: AbortSignal,
612
- ): Promise<ApiResult<M>>
613
- ```
614
-
615
- Low-level request method that allows an explicit `AbortSignal`.
616
-
617
- ### `api.raw(method, payload?, signal?)`
618
-
619
- ```ts
620
- raw(
621
- method: string,
622
- payload?: Record<string, unknown>,
623
- signal?: AbortSignal,
624
- ): Promise<unknown>
625
- ```
626
-
627
- 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`.
628
-
629
- ### `api.downloadFile(fileId, options?)`
630
-
631
- ```ts
632
- downloadFile(fileId: string, options?: { signal?: AbortSignal }): Promise<DownloadedFile>
633
- ```
634
-
635
- The API-client core of `bot.downloadFile`: resolves `getFile`, validates that a `file_path` came back, and downloads the bytes through the transport.
636
-
637
- ### `DownloadedFile`
638
-
639
- ```ts
640
- interface DownloadedFile {
641
- file: File; // Telegram File object from getFile
642
- bytes: Uint8Array; // raw file bytes (max 20 MB per Telegram)
643
- filePath: string; // file_path used for the download
644
- url: string; // direct download URL, valid for at least one hour
645
- fileName: string; // last path segment of filePath
646
- sizeBytes: number; // byte length of bytes
647
- savedTo?: string; // set when Bot.downloadFile persisted the file to disk
648
- }
649
- ```
650
-
651
- ### `fetchTransport.fileUrl(filePath)` and `fetchTransport.download(filePath, signal?)`
652
-
653
- ```ts
654
- fileUrl(filePath: string): string
655
- download(filePath: string, signal?: AbortSignal): Promise<Uint8Array>
656
- ```
657
-
658
- `FetchTransport` maps its `/bot<token>` base URL to the `/file/bot<token>` download endpoint; `download` GETs the bytes (timeout floor of 120 s for large files) and throws `TelegramNetworkError` on HTTP failure. Both are optional members of the `Transport` interface, so custom transports may omit them — `downloadFile` then fails with a precise validation error instead of crashing.
659
-
660
- ### Available typed parameters and results
661
-
662
- The following types are specially mapped in this release.
663
-
664
- | Method | Parameter | Result |
665
- |---|---|---|
666
- | `getMe` | tidak ada | `User` |
667
- | `getUpdates` | `GetUpdatesParams` | `Update[]` |
668
- | `setWebhook` | `SetWebhookParams` | `boolean` |
669
- | `deleteWebhook` | `{ drop_pending_updates?: boolean }` | `boolean` |
670
- | `getWebhookInfo` | tidak ada | `WebhookInfo` |
671
- | `sendMessage` | `SendMessageParams` | `Message` |
672
- | `editMessageText` | `EditMessageTextParams` | `Message \| true` |
673
- | `deleteMessage` | `DeleteMessageParams` | `true` |
674
- | `answerCallbackQuery` | `AnswerCallbackQueryParams` | `true` |
675
- | `getChat` | `GetChatParams` | `Chat` |
676
- | `getFile` | `GetFileParams` | `File` |
677
- | `getUserProfilePhotos` | `{ user_id: number; offset?: number; limit?: number }` | `UserProfilePhotos` |
678
- | `sendPhoto` | `SendPhotoParams` | `Message` |
679
- | `sendDocument` | `SendDocumentParams` | `Message` |
680
-
681
- Additional parameter types available are `ReplyParameters`, `LinkPreviewOptions`, `InlineKeyboardButton`, `ReplyMarkup`, `BotCommand`, `BotCommandScope`, and all Telegram update types exported from `api/types.ts`.
682
-
683
- ### API Errors
684
-
685
- ```ts
686
- type TelegramErrorKind =
687
- | "retryable"
688
- | "rate-limit"
689
- | "authentication"
690
- | "validation"
691
- | "network"
692
- | "server"
693
- | "unknown";
694
- ```
695
-
696
- #### `TelegramError`
697
-
698
- ```ts
699
- new TelegramError(message: string, options: {
700
- method: string;
701
- payload: unknown;
702
- errorCode?: number;
703
- parameters?: ResponseParameters;
704
- status?: number;
705
- kind?: TelegramErrorKind;
706
- cause?: unknown;
707
- })
708
- ```
709
-
710
- 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`.
711
-
712
- #### Subclass errors
713
-
714
- | Class | `name` | forced `kind` |
715
- |---|---|---|
716
- | `TelegramRateLimitError` | `TelegramRateLimitError` | `rate-limit` |
717
- | `TelegramAuthError` | `TelegramAuthError` | `authentication` |
718
- | `TelegramValidationError` | `TelegramValidationError` | `validation` |
719
- | `TelegramNetworkError` | `TelegramNetworkError` | `network` |
720
-
721
- All four subclasses use the same constructor options as `TelegramError`.
722
-
723
- #### `classifyTelegramError(errorCode?, status?)`
724
-
725
- ```ts
726
- classifyTelegramError(
727
- errorCode?: number,
728
- status?: number,
729
- ): TelegramErrorKind
730
- ```
731
-
732
- 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`.
733
-
734
- #### `telegramErrorFromResponse(response, context)`
735
-
736
- ```ts
737
- telegramErrorFromResponse<T>(
738
- response: TelegramResponse<T>,
739
- context: { method: string; payload: unknown; status?: number },
740
- ): TelegramError
741
- ```
742
-
743
- Converts a failed Telegram response into the appropriate subclass. `429`, auth, and validation errors produce specific subclasses; other errors produce a plain `TelegramError`.
744
-
745
- ---
746
-
747
- ## 4. Context
748
-
749
- ### `ContextOptions<S>`
750
-
751
- ```ts
752
- interface ContextOptions<S extends object = Record<string, unknown>> {
753
- update: Update;
754
- api: ApiClient;
755
- session: S;
756
- services: Record<string, unknown>;
757
- }
758
- ```
759
-
760
- ### `Context<S>` properties
761
-
762
- | Properti | Isi |
763
- |---|---|
764
- | `update` | Raw Telegram update. |
765
- | `api` | The bot's `ApiClient`. |
766
- | `session` | Mutable session object for the current update key. |
767
- | `state` | Per-context transient object, not automatically saved to the session. |
768
- | `services` | Services injected via `BotOptions.services`. |
769
- | `params` | Route parameters object; the built-in router currently does not populate it automatically. |
770
- | `message` | The main message from message/edited/channel/business/guest updates. |
771
- | `chat` | `message.chat` when available. |
772
- | `from` / `sender` | User from the message, callback query, or inline query. |
773
- | `callbackQuery` | `update.callback_query`. |
774
- | `inlineQuery` | `update.inline_query`. |
775
- | `poll` | `update.poll`. |
776
- | `pollAnswer` | `update.poll_answer`. |
777
- | `chatMember` | `update.chat_member`. |
778
- | `myChatMember` | `update.my_chat_member`. |
779
- | `chatJoinRequest` | `update.chat_join_request`. |
780
- | `reaction` | `update.message_reaction`. |
781
- | `boost` | `chat_boost` or `removed_chat_boost`. |
782
-
783
- ### `new Context(options)`
784
-
785
- ```ts
786
- new Context<S>(options: ContextOptions<S>): Context<S>
787
- ```
788
-
789
- ### Context message methods
790
-
791
- | Method | Signature | Behavior |
792
- |---|---|---|
793
- | `reply` | `reply(text, extra?): Promise<Message>` | Sends a message to the update chat and sets `reply_parameters.message_id` if there is a message. |
794
- | `send` | `send(text, extra?): Promise<Message>` | Sends a message to the update chat without a reply reference. |
795
- | `edit` | `edit(text, extra?): Promise<Message \| true>` | Edits the update message using `editMessageText`. |
796
- | `delete` | `delete(): Promise<true>` | Deletes the update message. |
797
- | `replyWithHTML` | `replyWithHTML(text, extra?): Promise<Message>` | Replies with `parse_mode: "HTML"`. |
798
- | `replyWithMarkdown` | `replyWithMarkdown(text, extra?): Promise<Message>` | Replies with `parse_mode: "MarkdownV2"`. |
799
- | `replyWithPhoto` | `replyWithPhoto(photo, extra?): Promise<Message>` | Sends `sendPhoto` with automatic quote-reply. |
800
- | `replyWithDocument` | `replyWithDocument(document, extra?): Promise<Message>` | Sends `sendDocument` with automatic quote-reply. |
801
- | `replyWithAudio` | `replyWithAudio(audio, extra?): Promise<Message>` | Sends `sendAudio` with automatic quote-reply. |
802
- | `replyWithVideo` | `replyWithVideo(video, extra?): Promise<Message>` | Sends `sendVideo` with automatic quote-reply. |
803
- | `replyWithVoice` | `replyWithVoice(voice, extra?): Promise<Message>` | Sends `sendVoice` with automatic quote-reply. |
804
- | `replyWithAnimation` | `replyWithAnimation(animation, extra?): Promise<Message>` | Sends `sendAnimation` with automatic quote-reply. |
805
- | `replyWithVideoNote` | `replyWithVideoNote(videoNote, extra?): Promise<Message>` | Sends `sendVideoNote` with automatic quote-reply. |
806
- | `replyWithSticker` | `replyWithSticker(sticker, extra?): Promise<Message>` | Sends `sendSticker` with automatic quote-reply. |
807
- | `replyWithMediaGroup` | `replyWithMediaGroup(media, extra?): Promise<Message[]>` | Sends an album via `sendMediaGroup` with automatic quote-reply. |
808
- | `replyWithLocation` | `replyWithLocation(latitude, longitude, extra?): Promise<Message>` | Sends `sendLocation` with automatic quote-reply. |
809
- | `replyWithVenue` | `replyWithVenue(latitude, longitude, title, address, extra?): Promise<Message>` | Sends `sendVenue` with automatic quote-reply. |
810
- | `replyWithContact` | `replyWithContact(phoneNumber, firstName, extra?): Promise<Message>` | Sends `sendContact` with automatic quote-reply. |
811
- | `replyWithPoll` | `replyWithPoll(question, options, extra?): Promise<Message>` | Sends `sendPoll` with automatic quote-reply. |
812
- | `replyWithDice` | `replyWithDice(emoji?, extra?): Promise<Message>` | Sends `sendDice` with automatic quote-reply. |
813
- | `sendChatAction` | `sendChatAction(action, extra?): Promise<true>` | Sends a chat action such as `typing`. |
814
- | `copy` | `copy(fromChatId, messageId, extra?): Promise<unknown>` | Calls `copyMessage` to the context chat. |
815
- | `forward` | `forward(fromChatId, messageId, extra?): Promise<Message>` | Calls `forwardMessage` to the context chat. |
816
- | `pin` | `pin(messageId?, extra?): Promise<true>` | Calls `pinChatMessage`; defaults to the context message id. |
817
- | `unpin` | `unpin(messageId?, extra?): Promise<true>` | Calls `unpinChatMessage`; defaults to the context message id. |
818
- | `react` | `react(reaction, extra?): Promise<true>` | Calls `setMessageReaction`. |
819
- | `answerCallbackQuery` | `answerCallbackQuery(text?, extra?): Promise<true>` | Answers the active callback query. Throws an error if the update is not a callback. |
820
- | `answerInlineQuery` | `answerInlineQuery(results, extra?): Promise<true>` | Answers the active inline query. Throws an error if the update is not an inline query. |
821
- | `getChat` | `getChat(): Promise<Chat>` | Fetches the context chat details. |
822
- | `getUserProfilePhotos` | `getUserProfilePhotos(userId?, extra?): Promise<unknown>` | Fetches the context user's profile photos. |
823
- | `getFile` | `getFile(fileId): Promise<unknown>` | Fetches a file by id. |
824
- | `withReplyMarkup` | `withReplyMarkup(markup): this` | Stores markup in `ctx.state.reply_markup` and returns the context. This method does not automatically send a message. |
825
-
826
- All `replyWith*` senders accept the native Telegram parameters as `extra` and automatically quote the incoming message. Passing `reply_parameters` in `extra` merges with the automatic `message_id` instead of replacing it. `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.
827
-
828
- ### Context admin, chat, and forum methods (full Telegraf parity)
829
-
830
- Every method below acts on the update's chat (`ctx.chat`) and accepts native Telegram parameters through `extra`; they throw a clear error when the update has no chat. Use `ctx.api.methods.*` to target a different chat.
831
-
832
- | Group | Methods |
833
- |---|---|
834
- | Moderation | `banChatMember(userId, untilDate?, extra?)`, `unbanChatMember(userId, onlyIfBanned?, extra?)`, `restrictChatMember(userId, permissions, untilDate?, extra?)`, `promoteChatMember(userId, extra?)`, `banChatSenderChat(senderChatId, extra?)`, `unbanChatSenderChat(senderChatId, extra?)` |
835
- | Chat management | `setChatTitle(title)`, `setChatDescription(description?)`, `setChatPhoto(photo)`, `deleteChatPhoto()`, `setChatPermissions(permissions, extra?)`, `leaveChat()`, `unpinAllChatMessages(extra?)`, `setChatStickerSet(name)`, `deleteChatStickerSet()` |
836
- | Chat & member info | `getChatAdministrators(): Promise<ChatMember[]>`, `getChatMemberCount(): Promise<number>`, `getChatMember(userId): Promise<ChatMember>` |
837
- | Invite links | `exportChatInviteLink(): Promise<string>`, `createChatInviteLink(extra?)`, `editChatInviteLink(inviteLink, extra?)`, `revokeChatInviteLink(inviteLink)` |
838
- | Join requests | `approveChatJoinRequest(userId)`, `declineChatJoinRequest(userId)` |
839
- | Polls & live location | `replyWithQuiz(question, options, extra?)` (sendPoll with `type: "quiz"`), `stopPoll(messageId?, extra?)`, `editMessageLiveLocation(latitude?, longitude?, extra?)`, `stopMessageLiveLocation(extra?)` |
840
- | Games & payments | `replyWithGame(gameShortName, extra?)`, `setGameScore(userId, score, extra?)`, `getGameHighScores(userId?, extra?)`, `replyWithInvoice(title, description, payload, providerToken, currency, prices, extra?)` |
841
- | Forum topics | `createForumTopic(name, extra?)`, `editForumTopic(extra?)`, `closeForumTopic(threadId?)`, `reopenForumTopic(threadId?)`, `deleteForumTopic(threadId?)`, `unpinAllForumTopicMessages(threadId?)`, `getForumTopicIconStickers()`, `editGeneralForumTopic(name)`, `closeGeneralForumTopic()`, `reopenGeneralForumTopic()`, `hideGeneralForumTopic()`, `unhideGeneralForumTopic()` |
842
-
843
- `threadId` defaults to the context message's `message_thread_id`. `replyWithQuiz`, `replyWithGame`, and `replyWithInvoice` quote the incoming message like every `replyWith*` sender.
844
-
845
- ---
846
-
847
- ## 5. Middleware and router
848
-
849
- ### Types of middleware
850
-
851
- ```ts
852
- type Next = () => Promise<void>;
853
- type Middleware<Context> = (ctx: Context, next: Next) => void | Promise<void>;
854
- ```
855
-
856
- ### `compose(middleware)`
857
-
858
- ```ts
859
- compose<Context>(
860
- middleware: readonly Middleware<Context>[],
861
- ): (ctx: Context) => Promise<void>
862
- ```
863
-
864
- 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")`.
865
-
866
- ### `middleware(handler)`
867
-
868
- ```ts
869
- middleware<Context>(handler: Middleware<Context>): Middleware<Context>
870
- ```
871
-
872
- Identity helper to provide type annotation/inference for middleware.
873
-
874
- ### `RoutableContext`
875
-
876
- Minimal context required by the router: `update`, `message`, `callbackQuery`, and `params`.
877
-
878
- ### `Router<Context>`
879
-
880
- ```ts
881
- new Router<Context extends RoutableContext>(): Router<Context>
882
- ```
883
-
884
- 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.
885
-
886
- | Method | Signature | Matching |
887
- |---|---|---|
888
- | `use` | `use(...middleware): this` | Router-global middleware with the highest priority, executed early. |
889
- | `route` | `route(matcher, ...middleware): this` | Boolean or async custom matcher. |
890
- | `command` | `command(name: string \| RegExp, ...middleware): this` | First command from message text starting with `/`. |
891
- | `text` | `text(value: string, ...middleware): this` | Exact text matching. |
892
- | `regex` | `regex(expression: RegExp, ...middleware): this` | `RegExp.test` against the message text or empty string. |
893
- | `callback` | `callback(pattern: string \| RegExp, ...middleware): this` | Exact, prefix with suffix `*`, or regex against callback data. |
894
- | `chat` | `chat(chatId: number \| string, ...middleware): this` | Match `message.chat.id`, numeric or string-equivalent. |
895
- | `predicate` | `predicate(matcher, ...middleware): this` | Semantic alias for a custom matcher. |
896
- | `nest` | `nest(child: Router<Context>): this` | Run a child router as a nested route. |
897
- | `handle` | `handle(ctx, terminal?): Promise<void>` | Evaluate and execute all matching routes. |
898
-
899
- ```ts
900
- const router = new Router<Context>();
901
- router.use(async (ctx, next) => {
902
- console.log("before");
903
- await next();
904
- });
905
- router.callback("page:*", async (ctx) => {
906
- await ctx.answerCallbackQuery();
907
- });
908
- router.predicate((ctx) => Boolean(ctx.from?.id), async (ctx) => {
909
- await ctx.reply("Authenticated update");
910
- });
911
- ```
912
-
913
- **RegExp note.** The router calls `.test()` directly. For expressions with flags `g` or `y`, JavaScript's stateful `lastIndex` property can affect repeated matching.
914
-
915
- ---
916
-
917
- ## 6. Keyboard builders
918
-
919
- ### `InlineKeyboard`
920
-
921
- ```ts
922
- new InlineKeyboard(): InlineKeyboard
923
- InlineKeyboard.from(rows: InlineKeyboardButton[][]): InlineKeyboard
924
- ```
925
-
926
- The builder stores rows mutably and all builder methods return `this`.
927
-
928
- | Method | Signature | Description |
929
- |---|---|---|
930
- | `from` | `static from(rows): InlineKeyboard` | Creates a keyboard from rows and copies each row. |
931
- | `text` | `text(text, callbackData): this` | Callback button. |
932
- | `url` | `url(text, url): this` | URL button. |
933
- | `webApp` | `webApp(text, url): this` | Web App button. |
934
- | `pay` | `pay(text = "Pay"): this` | Payment button. |
935
- | `copy` | `copy(text, copiedText): this` | Copy text button. |
936
- | `button` | `button(button): this` | Adds a single button to the last row or creates the first row. |
937
- | `row` | `row(...buttons): this` | Adds a new row. |
938
- | `conditional` | `conditional(condition, factory): this` | Runs the factory only if the condition is true. |
939
- | `grid` | `grid(buttons, columns): this` | Splits buttons into rows based on the number of columns. |
940
- | `build` | `build(): InlineKeyboardMarkup` | Produces a new markup. |
941
- | `asReplyMarkup` | `asReplyMarkup(): InlineKeyboardMarkup` | Alias for `build`. |
942
-
943
- 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`.
944
-
945
- ```ts
946
- const keyboard = new InlineKeyboard()
947
- .text("Allow", "approve:123")
948
- .url("Documentation", "https://example.com")
949
- .row(
950
- { text: "A", callback_data: "a" },
951
- { text: "B", callback_data: "b" },
952
- )
953
- .build();
954
- ```
955
-
956
- ### `ReplyKeyboard`
957
-
958
- ```ts
959
- new ReplyKeyboard(): ReplyKeyboard
960
- ```
961
-
962
- | Method | Signature | Description |
963
- |---|---|---|
964
- | `text` | `text(text): this` | Plain text button. |
965
- | `contact` | `contact(text): this` | Requests contact. |
966
- | `location` | `location(text): this` | Requests location. |
967
- | `poll` | `poll(text, type?): this` | Requests a poll of type `quiz` or `regular`. |
968
- | `webApp` | `webApp(text, url): this` | Web App button. |
969
- | `button` | `button(button): this` | Adds one button to the last row. |
970
- | `row` | `row(...buttons): this` | Adds a new row. |
971
- | `grid` | `grid(buttons, columns): this` | Splits buttons into a grid. |
972
- | `build` | `build(options?): ReplyKeyboardMarkup` | Produces the markup and merges options. |
973
- | `asReplyMarkup` | `asReplyMarkup(): ReplyKeyboardMarkup` | Alias for `build()` without options. |
974
-
975
- `columns` must be a positive integer; otherwise `grid` throws `RangeError`.
976
-
977
- ### `removeKeyboard(selective?)`
978
-
979
- ```ts
980
- removeKeyboard(selective = false): ReplyMarkup
981
- ```
982
-
983
- Generates `{ remove_keyboard: true }`, with `selective: true` if requested.
984
-
985
- ### `forceReply(placeholder?, selective?)`
986
-
987
- ```ts
988
- forceReply(placeholder?: string, selective = false): ReplyMarkup
989
- ```
990
-
991
- Generates a ForceReply. The placeholder is only added if it is truthy.
992
-
993
- ---
994
-
995
- ## 7. Storage and cache
996
-
997
- ### `Storage<K, V>`
998
-
999
- ```ts
1000
- interface Storage<K, V> {
1001
- get(key: K): Promise<V | undefined>;
1002
- set(key: K, value: V, options?: { ttlMs?: number }): Promise<void>;
1003
- delete(key: K): Promise<boolean>;
1004
- has(key: K): Promise<boolean>;
1005
- clear(): Promise<void>;
1006
- keys(): AsyncIterable<K>;
1007
- values(): AsyncIterable<V>;
1008
- entries(): AsyncIterable<[K, V]>;
1009
- update<T extends V>(
1010
- key: K,
1011
- updater: (current: V | undefined) => T | Promise<T>,
1012
- options?: { ttlMs?: number },
1013
- ): Promise<T>;
1014
- }
1015
- ```
1016
-
1017
- ### `MemoryStorage<K, V>`
1018
-
1019
- ```ts
1020
- new MemoryStorage<K, V>(): MemoryStorage<K, V>
1021
- ```
1022
-
1023
- 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.
1024
-
1025
- ```ts
1026
- const sessions = new MemoryStorage<string, { count: number }>();
1027
- await sessions.set("user:1", { count: 0 }, { ttlMs: 60_000 });
1028
- await sessions.update("user:1", (current) => ({
1029
- count: (current?.count ?? 0) + 1,
1030
- }));
1031
- ```
1032
-
1033
- ### `Cache<K, V>`
1034
-
1035
- ```ts
1036
- interface Cache<K = string, V = unknown> {
1037
- get(key: K): Promise<V | undefined>;
1038
- set(key: K, value: V, ttlMs?: number): Promise<void>;
1039
- delete(key: K): Promise<boolean>;
1040
- invalidate(prefix?: string): Promise<void>;
1041
- getOrSet(key: K, factory: () => V | Promise<V>, ttlMs?: number): Promise<V>;
1042
- }
1043
- ```
1044
-
1045
- ### `MemoryCache`
1046
-
1047
- ```ts
1048
- new MemoryCache(namespace = "telebibz"): MemoryCache
1049
- ```
1050
-
1051
- Cache that uses strings as keys and applies an internal namespace to each key.
1052
-
1053
- | Method | Behavior |
1054
- |---|---|
1055
- | `get` | Retrieves the value or `undefined`. |
1056
- | `set` | Stores the value with an optional TTL. |
1057
- | `delete` | Deletes the key and returns a boolean. |
1058
- | `invalidate(prefix = "")` | Removes all keys in the namespace that start with the prefix. |
1059
- | `getOrSet` | Returns the value from cache if present; if not, runs the factory, stores its result, then returns it. |
1060
-
1061
- `getOrSet` does not use deduplication locking; the factory may run more than once if called concurrently while the key is missing.
1062
-
1063
- ### `RateLimitResult`
1064
-
1065
- ```ts
1066
- interface RateLimitResult {
1067
- allowed: boolean;
1068
- remaining: number;
1069
- resetAt: number;
1070
- retryAfterMs?: number;
1071
- }
1072
- ```
1073
-
1074
- ### `TokenBucketLimiter`
1075
-
1076
- ```ts
1077
- new TokenBucketLimiter(
1078
- capacity: number,
1079
- refillPerSecond: number,
1080
- ): TokenBucketLimiter
1081
- ```
1082
-
1083
- 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.
1084
-
1085
- ---
1086
-
1087
- ## 8. Queue and scheduler
1088
-
1089
- ### `Job<T>` and `QueueOptions`
1090
-
1091
- ```ts
1092
- interface Job<T = unknown> {
1093
- id: string;
1094
- data: T;
1095
- attempts: number;
1096
- priority: number;
1097
- runAt: number;
1098
- status: "queued" | "running" | "completed" | "failed" | "cancelled";
1099
- error?: unknown;
1100
- }
1101
-
1102
- interface QueueOptions {
1103
- concurrency?: number;
1104
- retries?: number;
1105
- backoffMs?: number;
1106
- maxBackoffMs?: number;
1107
- }
1108
- ```
1109
-
1110
- ### `TaskQueue<T>`
1111
-
1112
- ```ts
1113
- new TaskQueue<T>(
1114
- worker: (job: Job<T>, signal: AbortSignal) => Promise<void>,
1115
- options?: QueueOptions,
1116
- ): TaskQueue<T>
1117
- ```
1118
-
1119
- | Method | Signature | Description |
1120
- |---|---|---|
1121
- | `add` | `add(data, options?): Job<T>` | Adds a job; options `id`, `priority`, `delayMs`. Job is scheduled immediately. |
1122
- | `get` | `get(id): Job<T> \| undefined` | Returns a copy of the job status. |
1123
- | `cancel` | `cancel(id): boolean` | Cancels a queued or running job and aborts the worker via its `AbortSignal`. |
1124
- | `onIdle` | `onIdle(): Promise<void>` | Waits until pending and active are empty. |
1125
- | `close` | `close(): Promise<void>` | Stops new draining and cancels the active controller. |
1126
-
1127
- 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.
1128
-
1129
- ### `ScheduledJob`
1130
-
1131
- ```ts
1132
- interface ScheduledJob {
1133
- id: string;
1134
- cancel: () => void;
1135
- }
1136
- ```
1137
-
1138
- ### `Scheduler`
1139
-
1140
- ```ts
1141
- new Scheduler(): Scheduler
1142
- ```
1143
-
1144
- | Method | Signature | Description |
1145
- |---|---|---|
1146
- | `every` | `every(id, intervalMs, task): ScheduledJob` | Runs a task using `setInterval`. Replaces any timer with the same id. |
1147
- | `after` | `after(id, delayMs, task): ScheduledJob` | Runs the task once using `setTimeout`. |
1148
- | `cron` | `cron(id, expression, task): ScheduledJob` | Supports the simple `*/N` format in the minutes field, equivalent to an interval of `N * 60_000`. |
1149
- | `cancel` | `cancel(id): boolean` | Cancels a timer. |
1150
- | `clear` | `clear(): void` | Cancels all timers. |
1151
-
1152
- The full cron format is not supported by the built-in scheduler. Expressions other than `*/N` throw an `Error`.
1153
-
1154
- ### `Limiter` and `mapWithConcurrency`
1155
-
1156
- ```ts
1157
- new Limiter(limit: number): Limiter
1158
-
1159
- mapWithConcurrency<T, R>(
1160
- items: readonly T[],
1161
- limit: number,
1162
- worker: (item: T, index: number) => Promise<R>,
1163
- ): Promise<R[]>
1164
- ```
1165
-
1166
- `Limiter` is a promise semaphore: tasks run immediately while a slot is free and queue FIFO beyond that. `limit` accepts any positive integer or `Infinity` (fully parallel — the library default). `mapWithConcurrency` maps items through an async worker with the same cap while preserving result order; results and errors behave like `Promise.all` mapped arrays. These primitives add no delays of their own — they only bound how many tasks run at the same time. `Limiter` exposes `activeCount` and `queuedCount` for observability.
1167
-
1168
- ## 9. Plugins and services
1169
-
1170
- ### `Plugin<Context>`
1171
-
1172
- ```ts
1173
- interface Plugin<Context = unknown> {
1174
- name: string;
1175
- version?: string;
1176
- install?: (api: PluginApi<Context>) => void | Promise<void>;
1177
- setup?: (api: PluginApi<Context>) => void | Promise<void>;
1178
- onStart?: (api: PluginApi<Context>) => void | Promise<void>;
1179
- onUpdate?: (context: Context) => void | Promise<void>;
1180
- onStop?: (api: PluginApi<Context>) => void | Promise<void>;
1181
- dispose?: (api: PluginApi<Context>) => void | Promise<void>;
1182
- }
1183
- ```
1184
-
1185
- ### `PluginApi<Context>`
1186
-
1187
- ```ts
1188
- interface PluginApi<Context> {
1189
- bot: unknown;
1190
- services: ServiceContainer;
1191
- registerMiddleware: (middleware: unknown) => void;
1192
- registerRoute: (route: unknown) => void;
1193
- }
1194
- ```
1195
-
1196
- In this release, `registerMiddleware` connects plugin middleware to `bot.use()`, and `registerRoute` connects plugin routes to `bot.router.route()`. The bot lifecycle invokes plugin `onUpdate` and `onStop` hooks automatically.
1197
-
1198
- ### `ServiceContainer`
1199
-
1200
- ```ts
1201
- new ServiceContainer(): ServiceContainer
1202
- ```
1203
-
1204
- | Method | Signature | Description |
1205
- |---|---|---|
1206
- | `register` | `register<T>(name: string \| symbol, value: T): this` | Stores a service and supports chaining. |
1207
- | `get` | `get<T>(name: string \| symbol): T` | Retrieves a service; throws if not registered. |
1208
- | `has` | `has(name: string \| symbol): boolean` | Checks for the existence of a service. |
1209
- | `delete` | `delete(name: string \| symbol): boolean` | Removes a service. |
1210
-
1211
- ### `PluginManager<Context>`
1212
-
1213
- ```ts
1214
- new PluginManager<Context>(bot: unknown): PluginManager<Context>
1215
- ```
1216
-
1217
- | Method | Behavior |
1218
- |---|---|
1219
- | `use(plugin)` | Adds a plugin; duplicate names throw an error. |
1220
- | `setup()` | For each plugin, runs `install` then `setup`. |
1221
- | `start()` | Executes `onStart` in registration order. |
1222
- | `update(context)` | Executes `onUpdate` in registration order. |
1223
- | `stop()` | Executes `onStop`. |
1224
- | `dispose()` | Executes `dispose` in reverse registration order. |
1225
- | `list()` | Returns a read-only list of plugins. |
1226
-
1227
- `Bot.handleUpdate()` calls `plugins.update()` automatically after the update is processed, and `Bot.stop()` invokes plugin stop hooks before disposal.
1228
-
1229
- ---
1230
-
1231
- ## 10. Webhook
1232
-
1233
- ### `WebhookOptions`
1234
-
1235
- ```ts
1236
- interface WebhookOptions {
1237
- secretToken?: string;
1238
- maxBodyBytes?: number;
1239
- onError?: (error: unknown) => void | Promise<void>;
1240
- webhookReply?: boolean;
1241
- }
1242
- ```
1243
-
1244
- `webhookReply` (default `false`) enables Telegraf-style webhook replies: while handling an update, the first outgoing API call is answered through the webhook HTTP response itself (`{"method":"sendMessage", ...}`), so Telegram executes the method without a second request. That call resolves with `true` because Telegram never sends the method result back to a webhook response; every later call goes through the transport as usual. The lazy `getMe` initialization never claims the slot. Unlike Telegraf, this is opt-in so existing webhook deployments keep their exact behavior.
1245
-
1246
- ### `createWebhookHandler(bot, options?)`
1247
-
1248
- ```ts
1249
- createWebhookHandler<S extends object>(
1250
- bot: Bot<S>,
1251
- options?: WebhookOptions,
1252
- ): (request: Request) => Promise<Response>
1253
- ```
1254
-
1255
- The handler accepts a standard Web `Request` and returns a `Response`.
1256
-
1257
- | Condition | Response |
1258
- |---|---|
1259
- | Method is not POST | `405 Method Not Allowed`, header `allow: POST` |
1260
- | Secret header does not match | `401 Unauthorized` |
1261
- | Header `Content-Length` or body exceeds limit | `413 Payload Too Large` |
1262
- | Invalid JSON or `update_id` is not an integer | `400 Bad Request` for update id; exception during parsing results in `500` |
1263
- | `bot.handleUpdate` succeeds | `200 OK` with body `OK` |
1264
- | Other exceptions | `500 Internal Server Error` and `onError` is called |
1265
-
1266
- 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.
1267
-
1268
- ```ts
1269
- import { Bot, createWebhookHandler } from "@xbibzlibrary/telebibz";
1270
-
1271
- const bot = new Bot(process.env.TELEGRAM_BOT_TOKEN!);
1272
- const handler = createWebhookHandler(bot, {
1273
- secretToken: process.env.TELEGRAM_WEBHOOK_SECRET,
1274
- });
1275
-
1276
- export default { fetch: handler };
1277
- ```
1278
-
1279
- ---
1280
-
1281
- ## 11. Conversations, wizards, forms, and menus
1282
-
1283
- ### Conversations
1284
-
1285
- ```ts
1286
- interface ConversationState {
1287
- name: string;
1288
- step: number;
1289
- values: Record<string, unknown>;
1290
- status: "active" | "completed" | "cancelled";
1291
- updatedAt: number;
1292
- }
1293
- ```
1294
-
1295
- #### `ConversationFlow<S>`
1296
-
1297
- ```ts
1298
- new ConversationFlow(ctx: Context<S>, state: ConversationState)
1299
- ```
1300
-
1301
- | Method/property | Signature | Description |
1302
- |---|---|---|
1303
- | `ctx` | `Context<S>` | Current update context. |
1304
- | `state` | `ConversationState` | Mutable conversation state. |
1305
- | `values` | `Record<string, unknown>` | Alias for `state.values`. |
1306
- | `set` | `set<T>(key, value): this` | Stores a value and updates `updatedAt`. |
1307
- | `get` | `get<T>(key): T \| undefined` | Retrieves a typed value. |
1308
- | `next` | `next(): this` | Advance the step by one. |
1309
- | `previous` | `previous(): this` | Decrement the step, clamped at 0. |
1310
- | `complete` | `complete(): void` | Sets status to `completed`. |
1311
- | `cancel` | `cancel(): void` | Sets status to `cancelled`. |
1312
-
1313
- #### `ConversationManager<S>`
1314
-
1315
- ```ts
1316
- new ConversationManager<S>(): ConversationManager<S>
1317
- ```
1318
-
1319
- | Method | Signature | Description |
1320
- |---|---|---|
1321
- | `start` | `start(key, name, values?): ConversationState` | Creates or replaces a conversation state. |
1322
- | `get` | `get(key): ConversationState \| undefined` | Retrieves the active state. |
1323
- | `cancel` | `cancel(key): boolean` | Marks as cancelled if it exists. |
1324
- | `clearExpired` | `clearExpired(maxAgeMs): number` | Removes states whose `updatedAt` is older than the threshold. |
1325
- | `run` | `run(ctx, key, name, steps): Promise<ConversationState>` | Runs steps according to `state.step`; if no step, status becomes completed. |
1326
-
1327
- ```ts
1328
- const conversations = new ConversationManager();
1329
- await conversations.run(ctx, "chat:1", "profile", [
1330
- async (flow) => {
1331
- flow.set("name", ctx.message?.text);
1332
- flow.next();
1333
- },
1334
- async (flow) => {
1335
- await flow.ctx.reply(`Name: ${flow.get<string>("name")}`);
1336
- flow.complete();
1337
- },
1338
- ]);
1339
- ```
1340
-
1341
- #### `Wizard<S>` and `WizardStep<S>`
1342
-
1343
- ```ts
1344
- interface WizardStep<S> {
1345
- id: string;
1346
- run: (flow: ConversationFlow<S>) => void | Promise<void>;
1347
- optional?: boolean;
1348
- }
1349
-
1350
- new Wizard<S>()
1351
- ```
1352
-
1353
- | Method/property | Description |
1354
- |---|---|
1355
- | `step(definition)` | Adds a step and returns the wizard. `optional` is stored in the definition but not specially handled by the runner. |
1356
- | `run(ctx, key?, manager?)` | Runs the active wizard step. If `key` is omitted, it uses `${chat.id}:${from.id}` and reuses the Wizard's default manager across updates. |
1357
- | `steps` | Read-only list of steps. |
1358
- | `manager` | Reusable `ConversationManager<S>` for `bot.useWizard()` or explicit state inspection. |
1359
-
1360
- ### Forms
1361
-
1362
- ```ts
1363
- interface ValidationIssue {
1364
- path: string;
1365
- message: string;
1366
- code?: string;
1367
- }
1368
-
1369
- interface Field<T> {
1370
- name: string;
1371
- parse: (input: unknown) => T;
1372
- validate?: (value: T) => string | undefined | Promise<string | undefined>;
1373
- transform?: (value: T) => T | Promise<T>;
1374
- required?: boolean;
1375
- }
1376
- ```
1377
-
1378
- #### `Form<T>`
1379
-
1380
- ```ts
1381
- new Form<T extends Record<string, unknown>>(): Form<T>
1382
- ```
1383
-
1384
- | Method | Description |
1385
- |---|---|
1386
- | `field(definition)` | Registers a typed field by `name`. |
1387
- | `parse(input)` | Processes all fields. Returns a union of success or issues. Order: required check, parse, transform, validate. |
1388
- | `reset()` | Clears internally stored parsed data. |
1389
-
1390
- Parse result:
1391
-
1392
- ```ts
1393
- type FormResult<T> =
1394
- | { success: true; data: T }
1395
- | { success: false; issues: ValidationIssue[] };
1396
- ```
1397
-
1398
- Issues use the code `required`, `parse`, or `invalid`.
1399
-
1400
- #### `validators`
1401
-
1402
- | Validator | Input | Result/Error |
1403
- |---|---|---|
1404
- | `validators.string` | `unknown` | String; otherwise `TypeError("Expected string")`. |
1405
- | `validators.number` | `unknown` | Finite number, including numeric strings; otherwise `TypeError("Expected number")`. |
1406
- | `validators.integer` | `unknown` | Integer; otherwise `TypeError("Expected integer")`. |
1407
- | `validators.email` | `unknown` | String matching a simple email pattern; otherwise `TypeError("Expected email")`. |
1408
- | `validators.url` | `unknown` | String accepted by the `URL` constructor; otherwise `TypeError("Expected URL")`. |
1409
-
1410
- ### Pagination and menus
1411
-
1412
- #### `Page<T>`
1413
-
1414
- ```ts
1415
- interface Page<T> {
1416
- items: T[];
1417
- page: number;
1418
- pageCount: number;
1419
- hasPrevious: boolean;
1420
- hasNext: boolean;
1421
- }
1422
- ```
1423
-
1424
- #### `paginate(items, page, pageSize)`
1425
-
1426
- ```ts
1427
- paginate<T>(
1428
- items: readonly T[],
1429
- page: number,
1430
- pageSize: number,
1431
- ): Page<T>
1432
- ```
1433
-
1434
- 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`.
1435
-
1436
- #### `paginationButtons(page, prefix)`
1437
-
1438
- ```ts
1439
- paginationButtons(
1440
- page: Page<unknown>,
1441
- prefix: string,
1442
- ): InlineKeyboardButton[]
1443
- ```
1444
-
1445
- Generates a `Previous` button, an indicator `${page + 1}/${pageCount}` with callback `${prefix}:noop`, and `Next` according to the page flags.
1446
-
1447
- #### `MenuItem`
1448
-
1449
- ```ts
1450
- interface MenuItem {
1451
- id: string;
1452
- label: string;
1453
- callbackData?: string;
1454
- url?: string;
1455
- visible?: boolean | ((context: MenuContext, item: MenuItem) => boolean | Promise<boolean>);
1456
- permission?: string | ((context: MenuContext, item: MenuItem) => boolean | Promise<boolean>);
1457
- }
1458
- ```
1459
-
1460
- #### `Menu`
1461
-
1462
- ```ts
1463
- new Menu(id: string): Menu
1464
- ```
1465
-
1466
- | Method/property | Description |
1467
- |---|---|
1468
- | `item(item)` | Adds an item and supports chaining. |
1469
- | `breadcrumb(label)` | Adds a breadcrumb label. |
1470
- | `build()` | Waits for visibility predicates, skips invisible items, then produces an `InlineKeyboard`. URL is prioritized over callbacks. |
1471
- | `breadcrumbs` | Read-only array of breadcrumbs. |
1472
-
1473
- `permission` is only stored as item metadata; `Menu.build()` does not perform automatic authorization.
1474
-
1475
- ---
1476
-
1477
- ## 12. Terminal Logging
1478
-
1479
- When stdout is an interactive TTY, every `bot.start()` / `bot.launch()` plays a startup sequence: a typing effect for `Installing Dependencies......`, a glass progress bar with a sweeping highlight, and the animated rainbow ASCII banner `Tele Bibz` (figlet `Speed` font) that keeps flowing until the bot connects, then freezes with `✓ Connected as @<username>`.
1480
-
1481
- Every update the bot handles is logged on a human-readable line:
1482
-
1483
- ```text
1484
- [ => ] Message From 123456789 John Doe 29/08/2026 15:04:05
1485
- ↳ Text: /start
1486
- [ => ] Callback From 123456789 John Doe 29/08/2026 15:04:07
1487
- ↳ Data: menu:open
1488
- ```
1489
-
1490
- Message and command text is truncated to 50 characters; callback button data is shown in full. Errors are printed in red and include the full stack. Pass `branding: false` to `Bot` to disable the startup sequence, and set `logger.format: "json"` for machine ingestion — in that mode incoming updates are emitted as structured `update.received` entries. Non-interactive stdout (pipes, Docker, CI) automatically falls back to plain, uncolored output without animations.
1491
-
1492
- ```ts
1493
- const bot = new Bot({
1494
- token: process.env.TELEGRAM_BOT_TOKEN!,
1495
- branding: false, // turn off the startup sequence
1496
- logger: {
1497
- level: "debug",
1498
- format: "pretty",
1499
- color: true,
1500
- includeUpdateContent: false,
1501
- },
1502
- });
1503
- ```
1504
-
1505
- Additional branding helpers exported for applications: `runStartupSequence()`, `startTeleBibzBanner()`, `printTeleBibzBanner()`, `paintRainbow()`, and `printStatusLine()`.
1506
-
1507
- ---
1508
-
1509
- ## 13. Text Utilities
1510
-
1511
- ### `escapeMarkdownV2(value)`
1512
-
1513
- ```ts
1514
- escapeMarkdownV2(value: string): string
1515
- ```
1516
-
1517
- Escapes Telegram MarkdownV2 characters: `\\_ * [ ] ( ) ~ ` > # + - = | { } . !`.
1518
-
1519
- ### `escapeHtml(value)`
1520
-
1521
- ```ts
1522
- escapeHtml(value: string): string
1523
- ```
1524
-
1525
- Converts `&`, `<`, `>`, and `\"` into HTML entities.
1526
-
1527
- ### `md`
1528
-
1529
- The following MarkdownV2 helper object is available:
1530
-
1531
- | Method | Conceptual output |
1532
- |---|---|
1533
- | `md.bold(value)` | `*escaped value*` |
1534
- | `md.italic(value)` | `_escaped value_` |
1535
- | `md.link(label, url)` | `[escaped label](escaped url)` |
1536
- | `md.code(value)` | Inline code with backticks escaped. |
1537
- | `md.pre(value, language?)` | Code block with an optional language label. |
1538
- | `md.escape(value)` | Alias `escapeMarkdownV2`. |
1539
-
1540
- ### `splitMessage(text, options?)`
1541
-
1542
- ```ts
1543
- splitMessage(
1544
- text: string,
1545
- options?: {
1546
- limit?: number;
1547
- parseMode?: "Markdown" | "MarkdownV2" | "HTML";
1548
- },
1549
- ): string[]
1550
- ```
1551
-
1552
- 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.
1553
-
1554
- A limit less than 1 will throw a `RangeError`.
1555
-
1556
- ### `splitCaption(text)`
1557
-
1558
- ```ts
1559
- splitCaption(text: string): string[]
1560
- ```
1561
-
1562
- Alias `splitMessage(text, { limit: 1024 })`.
1563
-
1564
- ### `template(templateText, values)`
1565
-
1566
- ```ts
1567
- template(
1568
- templateText: string,
1569
- values: Record<string, unknown>,
1570
- ): string
1571
- ```
1572
-
1573
- 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()`.
1574
-
1575
- ```ts
1576
- template("Halo {{ user.name }}", { user: { name: "Ayu" } });
1577
- // "Halo Ayu"
1578
- ```
1579
-
1580
- ---
1581
-
1582
- ### `validateUpload(upload, rules)`
1583
-
1584
- ```ts
1585
- validateUpload(upload: UploadLike, rules: UploadRules): UploadValidationIssue[]
1586
- ```
1587
-
1588
- Validates an upload before it is sent: `maxBytes` (size limit), `allowedMimeTypes` (exact or wildcard like `image/*`), and `allowedExtensions` (case-insensitive, with or without the leading dot). Returns every violation found — an empty array means the upload is acceptable.
1589
-
1590
- ### `assertValidUpload(upload, rules)`
1591
-
1592
- Same rules, but throws `UploadValidationError` (with all `issues` attached) instead of returning them.
1593
-
1594
- ```ts
1595
- import { assertValidUpload } from "@xbibzlibrary/telebibz";
1596
-
1597
- assertValidUpload(
1598
- { sizeBytes: fileBytes.length, mimeType: "image/png", fileName: "logo.png" },
1599
- { maxBytes: 5_000_000, allowedMimeTypes: ["image/png", "image/jpeg"], allowedExtensions: [".png", ".jpg"] },
1600
- );
1601
- ```
1602
-
1603
- ## 14. Testing utilities
1604
-
1605
- Import dari `@xbibzlibrary/telebibz/testing` atau root package.
1606
-
1607
- ### `MockTransport`
1608
-
1609
- ```ts
1610
- new MockTransport(): MockTransport
1611
- ```
1612
-
1613
- | API | Description |
1614
- |---|---|
1615
- | `calls` | Array of every received `TransportRequest`. |
1616
- | `respond(method, response)` | Configures a static response or payload callback and returns the transport. |
1617
- | `request(request)` | Records the request and returns a mock response. The default response is `{ ok: true, result: true }`. |
1618
-
1619
- The mock status is `200` when `ok: true`, or `error_code`/`500` when `ok: false`.
1620
-
1621
- ```ts
1622
- const transport = new MockTransport()
1623
- .respond("getMe", {
1624
- ok: true,
1625
- result: { id: 1, is_bot: true, first_name: "Test" },
1626
- });
1627
- ```
1628
-
1629
- `MockTransport` also implements the optional download members: `download(filePath)` records the path into `downloads` and returns `downloadBytes` (default: the UTF-8 encoding of the path), and `fileUrl(filePath)` returns `mock://files/<filePath>` — so `bot.downloadFile()` is fully testable without network access.
1630
-
1631
- ### `createMockUpdate(overrides?)`
1632
-
1633
- ```ts
1634
- createMockUpdate(overrides?: Partial<Update>): Update
1635
- ```
1636
-
1637
- 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.
1638
-
1639
- ### `createTestBot()`
1640
-
1641
- ```ts
1642
- createTestBot(): { bot: Bot; transport: MockTransport }
1643
- ```
1644
-
1645
- 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`.
1646
-
1647
- ### `createMockContext(bot, update?)`
1648
-
1649
- ```ts
1650
- createMockContext(
1651
- bot: Bot,
1652
- update?: Update,
1653
- ): Context
1654
- ```
1655
-
1656
- Creates a context using the bot API, an empty session, and empty services.
1657
-
1658
- ---
1659
-
1660
-
1661
-
1662
- ## 15. Generated Telegram methods namespace
1663
-
1664
- `generated/api.ts` is the generator's internal source that defines:
1665
-
1666
- ```ts
1667
- const TELEGRAM_API_VERSION = "10.2";
1668
- const TELEGRAM_METHOD_NAMES: readonly string[];
1669
- type TelegramMethodName = typeof TELEGRAM_METHOD_NAMES[number];
1670
- type GeneratedMethodSpec = {
1671
- params: Record<string, unknown>;
1672
- result: unknown;
1673
- };
1674
- type GeneratedTelegramMethodMap = {
1675
- [K in TelegramMethodName]: GeneratedMethodSpec;
1676
- };
1677
- const GENERATED_METHODS: Record<TelegramMethodName, TelegramMethodName>;
1678
- ```
1679
-
1680
- `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.
1681
-
1682
- For an ungrouped canonical list, the method names available on the generated runtime namespace are:
1683
-
1684
- ```text
1685
- addStickerToSet,
1686
- answerCallbackQuery,
1687
- answerChatJoinRequestQuery,
1688
- answerGuestQuery,
1689
- answerInlineQuery,
1690
- answerPreCheckoutQuery,
1691
- answerShippingQuery,
1692
- answerWebAppQuery,
1693
- approveChatJoinRequest,
1694
- approveSuggestedPost,
1695
- banChatMember,
1696
- banChatSenderChat,
1697
- close,
1698
- closeForumTopic,
1699
- closeGeneralForumTopic,
1700
- convertGiftToStars,
1701
- copyMessage,
1702
- copyMessages,
1703
- createChatInviteLink,
1704
- createChatSubscriptionInviteLink,
1705
- createForumTopic,
1706
- createInvoiceLink,
1707
- createNewStickerSet,
1708
- declineChatJoinRequest,
1709
- declineSuggestedPost,
1710
- deleteAllMessageReactions,
1711
- deleteBusinessMessages,
1712
- deleteChatPhoto,
1713
- deleteChatStickerSet,
1714
- deleteEphemeralMessage,
1715
- deleteForumTopic,
1716
- deleteMessage,
1717
- deleteMessageReaction,
1718
- deleteMessages,
1719
- deleteMyCommands,
1720
- deleteStickerFromSet,
1721
- deleteStickerSet,
1722
- deleteStory,
1723
- deleteWebhook,
1724
- editChatInviteLink,
1725
- editChatSubscriptionInviteLink,
1726
- editEphemeralMessageCaption,
1727
- editEphemeralMessageMedia,
1728
- editEphemeralMessageReplyMarkup,
1729
- editEphemeralMessageText,
1730
- editForumTopic,
1731
- editGeneralForumTopic,
1732
- editMessageCaption,
1733
- editMessageChecklist,
1734
- editMessageLiveLocation,
1735
- editMessageMedia,
1736
- editMessageReplyMarkup,
1737
- editMessageText,
1738
- editStory,
1739
- editUserStarSubscription,
1740
- exportChatInviteLink,
1741
- forwardMessage,
1742
- forwardMessages,
1743
- getAvailableGifts,
1744
- getBusinessAccountGifts,
1745
- getBusinessAccountStarBalance,
1746
- getBusinessConnection,
1747
- getChat,
1748
- getChatAdministrators,
1749
- getChatGifts,
1750
- getChatMember,
1751
- getChatMemberCount,
1752
- getChatMenuButton,
1753
- getCustomEmojiStickers,
1754
- getFile,
1755
- getForumTopicIconStickers,
1756
- getGameHighScores,
1757
- getManagedBotAccessSettings,
1758
- getManagedBotToken,
1759
- getMe,
1760
- getMyCommands,
1761
- getMyDefaultAdministratorRights,
1762
- getMyDescription,
1763
- getMyName,
1764
- getMyShortDescription,
1765
- getMyStarBalance,
1766
- getStarTransactions,
1767
- getStickerSet,
1768
- getUpdates,
1769
- getUserChatBoosts,
1770
- getUserGifts,
1771
- getUserPersonalChatMessages,
1772
- getUserProfileAudios,
1773
- getUserProfilePhotos,
1774
- getWebhookInfo,
1775
- giftPremiumSubscription,
1776
- hideGeneralForumTopic,
1777
- leaveChat,
1778
- logOut,
1779
- pinChatMessage,
1780
- postStory,
1781
- promoteChatMember,
1782
- readBusinessMessage,
1783
- refundStarPayment,
1784
- removeBusinessAccountProfilePhoto,
1785
- removeChatVerification,
1786
- removeMyProfilePhoto,
1787
- removeUserVerification,
1788
- reopenForumTopic,
1789
- reopenGeneralForumTopic,
1790
- replaceManagedBotToken,
1791
- replaceStickerInSet,
1792
- repostStory,
1793
- restrictChatMember,
1794
- revokeChatInviteLink,
1795
- savePreparedInlineMessage,
1796
- savePreparedKeyboardButton,
1797
- sendAnimation,
1798
- sendAudio,
1799
- sendChatAction,
1800
- sendChatJoinRequestWebApp,
1801
- sendChecklist,
1802
- sendContact,
1803
- sendDice,
1804
- sendDocument,
1805
- sendGame,
1806
- sendGift,
1807
- sendInvoice,
1808
- sendLivePhoto,
1809
- sendLocation,
1810
- sendMediaGroup,
1811
- sendMessage,
1812
- sendMessageDraft,
1813
- sendPaidMedia,
1814
- sendPhoto,
1815
- sendPoll,
1816
- sendRichMessage,
1817
- sendRichMessageDraft,
1818
- sendSticker,
1819
- sendVenue,
1820
- sendVideo,
1821
- sendVideoNote,
1822
- sendVoice,
1823
- setBusinessAccountBio,
1824
- setBusinessAccountGiftSettings,
1825
- setBusinessAccountName,
1826
- setBusinessAccountProfilePhoto,
1827
- setBusinessAccountUsername,
1828
- setChatAdministratorCustomTitle,
1829
- setChatDescription,
1830
- setChatMemberTag,
1831
- setChatMenuButton,
1832
- setChatPermissions,
1833
- setChatPhoto,
1834
- setChatStickerSet,
1835
- setChatTitle,
1836
- setCustomEmojiStickerSetThumbnail,
1837
- setGameScore,
1838
- setManagedBotAccessSettings,
1839
- setMessageReaction,
1840
- setMyCommands,
1841
- setMyDefaultAdministratorRights,
1842
- setMyDescription,
1843
- setMyName,
1844
- setMyProfilePhoto,
1845
- setMyShortDescription,
1846
- setPassportDataErrors,
1847
- setStickerEmojiList,
1848
- setStickerKeywords,
1849
- setStickerMaskPosition,
1850
- setStickerPositionInSet,
1851
- setStickerSetThumbnail,
1852
- setStickerSetTitle,
1853
- setUserEmojiStatus,
1854
- setWebhook,
1855
- stopMessageLiveLocation,
1856
- stopPoll,
1857
- transferBusinessAccountStars,
1858
- transferGift,
1859
- unbanChatMember,
1860
- unbanChatSenderChat,
1861
- unhideGeneralForumTopic,
1862
- unpinAllChatMessages,
1863
- unpinAllForumTopicMessages,
1864
- unpinAllGeneralForumTopicMessages,
1865
- unpinChatMessage,
1866
- upgradeGift,
1867
- uploadStickerFile,
1868
- verifyChat
1869
- ```
1870
-
1871
- > 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.
1872
-
1873
- ---
1874
-
1875
- ## 16. CLI
1876
-
1877
- Binary package is `telebibz`.
1878
-
1879
- ```bash
1880
- npx telebibz <command>
1881
- ```
1882
-
1883
- | Command | Behavior |
1884
- |---|---|
1885
- | `telebibz init [directory]` | Creates a directory, a minimal `index.ts`, and `.env.example`. Default directory `my-telebibz-bot`. |
1886
- | `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. |
1887
- | `telebibz generate` | Runs the generator method from `scripts/generate-api.mjs`. |
1888
- | `telebibz build` | Runs `npm run build`. |
1889
- | `telebibz test` | Runs `npm test`. |
1890
- | `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. |
1891
- | `telebibz inspect` | Displays cwd and Node version. |
1892
- | without command | Displays the help command list. |
1893
-
1894
- Environment variables used by the CLI are `TELEGRAM_BOT_TOKEN` and `TELEGRAM_WEBHOOK_SECRET`.
1895
-
1896
- ---
1897
-
1898
- ## 17. Main Telegram types
1899
-
1900
- The package exports the most commonly used data types directly.
1901
-
1902
- | Type | Important contents |
1903
- |---|---|
1904
- | `User` | ID, bot flag, name, username, language, and capability flags. |
1905
- | `Chat` | ID, type, title/username/name, forum/direct message indicators. |
1906
- | `Message` | ID, date, chat, sender, text/caption, entities, reply, markup, plus an index signature for additional Telegram fields. |
1907
- | `Update` | All update fields supported by the source, including message, callback, inline, poll, member, join request, reaction, boost, business, and extension fields. |
1908
- | `CallbackQuery` | ID, from, message/inline message id, chat instance, data. |
1909
- | `InlineQuery` | ID, from, query, offset, chat type, location. |
1910
- | `Poll`, `PollAnswer` | Poll data and answers. |
1911
- | `ChatMemberUpdated`, `ChatJoinRequest` | Member changes and join requests. |
1912
- | `InlineKeyboardMarkup`, `ReplyKeyboardMarkup`, `ReplyKeyboardRemove`, `ForceReply` | Telegram reply markup forms. |
1913
- | `MessageEntity`, `ReplyParameters`, `LinkPreviewOptions` | Entity, reply, and link preview metadata. |
1914
- | `BotCommand`, `BotCommandScope`, `WebhookInfo`, `File`, `UserProfilePhotos`, `ChatMember`, `ChatAdministratorRights` | Result/parameter types for API helpers. |
1915
-
1916
- ---
1917
-
1918
- ## 18. Persistence, full cron, menus, and complete Telegram declarations
1919
-
1920
- ### Persistent storage adapters
1921
-
1922
- 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.
1923
-
1924
- | Class | Constructor | Purpose |
1925
- |---|---|---|
1926
- | `MemoryStorage<K, V>` | `new MemoryStorage()` | Fast in-memory storage with TTL and per-key atomic `update()`. |
1927
- | `JsonFileStorage<V>` | `new JsonFileStorage(filePath)` | Atomic JSON-file persistence for single-process deployments. |
1928
- | `RedisStorage<V>` | `new RedisStorage(client, prefix?)` | Redis-backed storage through `RedisLikeClient`, including TTL and namespace operations. |
1929
- | `SqlStorage<V>` | `new SqlStorage(driver)` | SQL-backed storage through an application-owned `SqlStorageDriver`. |
1930
- | `MongoStorage<V>` | `new MongoStorage(collection)` | Mongo collection-backed storage through an application-owned `MongoStorageCollection`. |
1931
-
1932
- `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.
1933
-
1934
- ```ts
1935
- const session = new JsonFileStorage<Record<string, unknown>>("./data/sessions.json");
1936
- const bot = new Bot({ token: process.env.TELEGRAM_BOT_TOKEN!, session });
1937
- ```
1938
-
1939
- ### Full five-field cron
1940
-
1941
- `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.
1942
-
1943
- ### Router matching mode
1944
-
1945
- `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.
1946
-
1947
- ### MenuController and permissions
1948
-
1949
- `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.
1950
-
1951
- ### Complete Telegram declaration namespace
1952
-
1953
- 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`. The CLI uses a colored Unicode box with the attribution `Library Bot Telegram By @xbibzofficial`. `Logger` emits structured terminal or JSON entries with configurable levels, redaction, update summaries, and opt-in user message/callback content. 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.
1954
-
1955
- ---
1956
- ## 19. Compatibility and limitations to be aware of
1957
-
1958
- The library targets Node.js `>=22`, 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.
1959
-
1960
- 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.
1961
-
1962
- Session 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.
1963
-
1964
- ---
1965
-
1966
- ## References
1967
-
1968
- [1]: https://core.telegram.org/bots/api "Telegram Bot API — official documentation"
1969
- [2]: https://www.npmjs.com/package/@xbibzlibrary/telebibz "@xbibzlibrary/telebibz on npm"