@xbibzlibrary/telebibz 0.1.19 → 0.3.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 (95) hide show
  1. package/CHANGELOG.md +42 -8
  2. package/CONTRIBUTING.md +2 -2
  3. package/README.id.md +44 -5
  4. package/README.md +45 -6
  5. package/README.zh-CN.md +44 -5
  6. package/RELEASE_AUTOMATION.md +17 -5
  7. package/bin/telebibz.mjs +1 -1
  8. package/dist/src/api/client.d.ts +3 -1
  9. package/dist/src/api/client.d.ts.map +1 -1
  10. package/dist/src/api/client.js +3 -1
  11. package/dist/src/api/client.js.map +1 -1
  12. package/dist/src/api/transport.d.ts +18 -1
  13. package/dist/src/api/transport.d.ts.map +1 -1
  14. package/dist/src/api/transport.js +26 -2
  15. package/dist/src/api/transport.js.map +1 -1
  16. package/dist/src/branding/terminal.d.ts +62 -0
  17. package/dist/src/branding/terminal.d.ts.map +1 -1
  18. package/dist/src/branding/terminal.js +258 -0
  19. package/dist/src/branding/terminal.js.map +1 -1
  20. package/dist/src/broadcast/broadcast.d.ts +50 -0
  21. package/dist/src/broadcast/broadcast.d.ts.map +1 -0
  22. package/dist/src/broadcast/broadcast.js +56 -0
  23. package/dist/src/broadcast/broadcast.js.map +1 -0
  24. package/dist/src/cli.d.ts.map +1 -1
  25. package/dist/src/cli.js +7 -3
  26. package/dist/src/cli.js.map +1 -1
  27. package/dist/src/context/context.d.ts +24 -1
  28. package/dist/src/context/context.d.ts.map +1 -1
  29. package/dist/src/context/context.js +102 -8
  30. package/dist/src/context/context.js.map +1 -1
  31. package/dist/src/core/bot.d.ts +61 -2
  32. package/dist/src/core/bot.d.ts.map +1 -1
  33. package/dist/src/core/bot.js +180 -31
  34. package/dist/src/core/bot.js.map +1 -1
  35. package/dist/src/index.d.ts +2 -0
  36. package/dist/src/index.d.ts.map +1 -1
  37. package/dist/src/index.js +2 -0
  38. package/dist/src/index.js.map +1 -1
  39. package/dist/src/keyboard/index.d.ts +12 -0
  40. package/dist/src/keyboard/index.d.ts.map +1 -1
  41. package/dist/src/keyboard/index.js +13 -1
  42. package/dist/src/keyboard/index.js.map +1 -1
  43. package/dist/src/observability/logger.d.ts +28 -1
  44. package/dist/src/observability/logger.d.ts.map +1 -1
  45. package/dist/src/observability/logger.js +110 -0
  46. package/dist/src/observability/logger.js.map +1 -1
  47. package/dist/src/plugins/plugin.d.ts +2 -0
  48. package/dist/src/plugins/plugin.d.ts.map +1 -1
  49. package/dist/src/plugins/plugin.js +11 -4
  50. package/dist/src/plugins/plugin.js.map +1 -1
  51. package/dist/src/router/router.d.ts +19 -0
  52. package/dist/src/router/router.d.ts.map +1 -1
  53. package/dist/src/router/router.js +125 -23
  54. package/dist/src/router/router.js.map +1 -1
  55. package/dist/src/state/forms.d.ts +0 -1
  56. package/dist/src/state/forms.d.ts.map +1 -1
  57. package/dist/src/state/forms.js +27 -24
  58. package/dist/src/state/forms.js.map +1 -1
  59. package/dist/src/storage/storage.d.ts +10 -0
  60. package/dist/src/storage/storage.d.ts.map +1 -1
  61. package/dist/src/storage/storage.js +20 -2
  62. package/dist/src/storage/storage.js.map +1 -1
  63. package/dist/src/utils/concurrency.d.ts +25 -0
  64. package/dist/src/utils/concurrency.d.ts.map +1 -0
  65. package/dist/src/utils/concurrency.js +52 -0
  66. package/dist/src/utils/concurrency.js.map +1 -0
  67. package/dist/src/utils/text.d.ts +22 -0
  68. package/dist/src/utils/text.d.ts.map +1 -1
  69. package/dist/src/utils/text.js +0 -0
  70. package/dist/src/utils/text.js.map +1 -1
  71. package/dist/src/webhook/handler.d.ts +3 -0
  72. package/dist/src/webhook/handler.d.ts.map +1 -1
  73. package/dist/src/webhook/handler.js +85 -0
  74. package/dist/src/webhook/handler.js.map +1 -1
  75. package/dist-cjs/src/api/client.js +3 -1
  76. package/dist-cjs/src/api/transport.js +26 -2
  77. package/dist-cjs/src/branding/terminal.js +264 -1
  78. package/dist-cjs/src/broadcast/broadcast.js +58 -0
  79. package/dist-cjs/src/cli.js +7 -3
  80. package/dist-cjs/src/context/context.js +102 -8
  81. package/dist-cjs/src/core/bot.js +178 -29
  82. package/dist-cjs/src/index.js +2 -0
  83. package/dist-cjs/src/keyboard/index.js +13 -1
  84. package/dist-cjs/src/observability/logger.js +113 -1
  85. package/dist-cjs/src/plugins/plugin.js +11 -4
  86. package/dist-cjs/src/router/router.js +126 -24
  87. package/dist-cjs/src/state/forms.js +27 -24
  88. package/dist-cjs/src/storage/storage.js +20 -2
  89. package/dist-cjs/src/utils/concurrency.js +57 -0
  90. package/dist-cjs/src/utils/text.js +0 -0
  91. package/dist-cjs/src/webhook/handler.js +86 -0
  92. package/docs/API.id.md +120 -4
  93. package/docs/API.md +122 -4
  94. package/docs/API.zh-CN.md +119 -3
  95. package/package.json +3 -3
package/docs/API.md CHANGED
@@ -67,11 +67,13 @@ type BotStatus =
67
67
  | `transportOptions` | `Omit<FetchTransportOptions, "baseUrl">` | `{}` | Timeout, retry, backoff, jitter, headers, and fetch implementation. |
68
68
  | `session` | `Storage<string, S>` | new storage | Session storage keyed by chat/user; any storage adapter may be used. |
69
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. |
70
71
  | `polling.timeout` | `number` | `30` | Long-poll timeout in seconds for `getUpdates`. |
71
72
  | `polling.limit` | `number` | `100` | Maximum number of updates per polling request. |
72
73
  | `polling.allowedUpdates` | `string[]` | `[]` | Telegram update filters. |
73
74
  | `polling.retryDelayMs` | `number` | `500` | Initial delay when polling fails. |
74
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. |
75
77
 
76
78
  ### Constructor `Bot`
77
79
 
@@ -139,6 +141,30 @@ onRegex(expression: RegExp, handler: Middleware<Context<S>>): this
139
141
 
140
142
  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.
141
143
 
144
+ ### `bot.on(filter, handler)`
145
+
146
+ ```ts
147
+ on(filter: UpdateFilter | UpdateFilter[], handler: Middleware<Context<S>>): this
148
+ ```
149
+
150
+ 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.
151
+
152
+ ### `bot.hears(trigger, handler)`
153
+
154
+ ```ts
155
+ hears(trigger: string | RegExp, handler: Middleware<Context<S>>): this
156
+ ```
157
+
158
+ Handles exact message text (string) or message text matching a `RegExp`.
159
+
160
+ ### `bot.catch(handler)`
161
+
162
+ ```ts
163
+ catch(handler: (error: unknown, ctx: Context<S>) => void | Promise<void>): this
164
+ ```
165
+
166
+ 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.
167
+
142
168
  ### `bot.usePlugin(plugin)`
143
169
 
144
170
  ```ts
@@ -193,7 +219,7 @@ launch(options?: {
193
219
  }): Promise<void>
194
220
  ```
195
221
 
196
- Runs the bot in polling mode. On start, the lifecycle moves through `starting` to `running`, then the `getUpdates()` loop processes each update sequentially. Polling failures emit `polling:reconnect` and use exponential backoff.
222
+ 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.
197
223
 
198
224
  Modes other than `"polling"` throw an error and suggest using `createWebhookHandler()` for webhooks.
199
225
 
@@ -270,8 +296,54 @@ handleUpdate(update: Update): Promise<void>
270
296
 
271
297
  Processes a single update manually. The method determines the session key from `chat.id` and `from.id`, creates a `Context`, emits `update` and `message` events, runs middleware then the router, and saves the session after the pipeline completes.
272
298
 
299
+ 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.
300
+
273
301
  Pipeline errors set the bot status to `error`, emit `bot:error`, and then rethrow the error.
274
302
 
303
+ ### `bot.handleUpdates(updates)`
304
+
305
+ ```ts
306
+ handleUpdates(updates: readonly Update[]): Promise<void>
307
+ ```
308
+
309
+ 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.
310
+
311
+ ### `bot.broadcast(chatIds, send, options?)`
312
+
313
+ ```ts
314
+ broadcast(
315
+ chatIds: readonly ChatId[],
316
+ send: (chatId: ChatId) => Promise<unknown>,
317
+ options?: BroadcastOptions,
318
+ ): Promise<BroadcastReport>
319
+ ```
320
+
321
+ 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.
322
+
323
+ ```ts
324
+ const report = await bot.broadcast(
325
+ subscriberIds,
326
+ (chatId) => bot.api.methods.sendMessage({ chat_id: chatId, text: "Newsletter #42" }),
327
+ { onProgress: (progress) => console.log(`${progress.delivered}/${progress.total} delivered`) },
328
+ );
329
+ console.log(`Delivered ${report.delivered} of ${report.total} in ${report.durationMs}ms`);
330
+ for (const failure of report.failures) console.warn(`Failed: ${failure.chatId} — ${failure.error}`);
331
+ ```
332
+
333
+ #### `BroadcastOptions` and `BroadcastReport`
334
+
335
+ | Property | Type | Default | Description |
336
+ |---|---|---:|---|
337
+ | `BroadcastOptions.concurrency` | `number` | `Infinity` | How many chats are messaged at the same time. |
338
+ | `BroadcastOptions.maxAttempts` | `number` | `10` | Attempts per chat when Telegram answers 429. |
339
+ | `BroadcastOptions.onProgress` | `(progress: BroadcastProgress) => void` | — | Called after each chat settles. |
340
+ | `BroadcastOptions.signal` | `AbortSignal` | — | Aborts pending sends; delivered messages stay delivered. |
341
+ | `BroadcastReport.total` | `number` | — | Chats in the run. |
342
+ | `BroadcastReport.delivered` | `number` | — | Chats that received the message. |
343
+ | `BroadcastReport.failed` | `number` | — | Chats that did not. |
344
+ | `BroadcastReport.durationMs` | `number` | — | Wall-clock duration of the run. |
345
+ | `BroadcastReport.failures` | `BroadcastFailure[]` | — | Per-chat `{ chatId, attempts, error, errorKind }` records. |
346
+
275
347
  ### Minimal bot example
276
348
 
277
349
  ```ts
@@ -409,6 +481,7 @@ interface Transport {
409
481
  | `maxBackoffMs` | `8000` | Transport delay cap. |
410
482
  | `jitter` | `0.2` | Random variation ±20% of the exponential delay. |
411
483
  | `headers` | `{}` | Additional headers. |
484
+ | `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. |
412
485
 
413
486
  ### `new FetchTransport(options?)`
414
487
 
@@ -650,6 +723,23 @@ new Context<S>(options: ContextOptions<S>): Context<S>
650
723
  | `send` | `send(text, extra?): Promise<Message>` | Sends a message to the update chat without a reply reference. |
651
724
  | `edit` | `edit(text, extra?): Promise<Message \| true>` | Edits the update message using `editMessageText`. |
652
725
  | `delete` | `delete(): Promise<true>` | Deletes the update message. |
726
+ | `replyWithHTML` | `replyWithHTML(text, extra?): Promise<Message>` | Replies with `parse_mode: "HTML"`. |
727
+ | `replyWithMarkdown` | `replyWithMarkdown(text, extra?): Promise<Message>` | Replies with `parse_mode: "MarkdownV2"`. |
728
+ | `replyWithPhoto` | `replyWithPhoto(photo, extra?): Promise<Message>` | Sends `sendPhoto` with automatic quote-reply. |
729
+ | `replyWithDocument` | `replyWithDocument(document, extra?): Promise<Message>` | Sends `sendDocument` with automatic quote-reply. |
730
+ | `replyWithAudio` | `replyWithAudio(audio, extra?): Promise<Message>` | Sends `sendAudio` with automatic quote-reply. |
731
+ | `replyWithVideo` | `replyWithVideo(video, extra?): Promise<Message>` | Sends `sendVideo` with automatic quote-reply. |
732
+ | `replyWithVoice` | `replyWithVoice(voice, extra?): Promise<Message>` | Sends `sendVoice` with automatic quote-reply. |
733
+ | `replyWithAnimation` | `replyWithAnimation(animation, extra?): Promise<Message>` | Sends `sendAnimation` with automatic quote-reply. |
734
+ | `replyWithVideoNote` | `replyWithVideoNote(videoNote, extra?): Promise<Message>` | Sends `sendVideoNote` with automatic quote-reply. |
735
+ | `replyWithSticker` | `replyWithSticker(sticker, extra?): Promise<Message>` | Sends `sendSticker` with automatic quote-reply. |
736
+ | `replyWithMediaGroup` | `replyWithMediaGroup(media, extra?): Promise<Message[]>` | Sends an album via `sendMediaGroup` with automatic quote-reply. |
737
+ | `replyWithLocation` | `replyWithLocation(latitude, longitude, extra?): Promise<Message>` | Sends `sendLocation` with automatic quote-reply. |
738
+ | `replyWithVenue` | `replyWithVenue(latitude, longitude, title, address, extra?): Promise<Message>` | Sends `sendVenue` with automatic quote-reply. |
739
+ | `replyWithContact` | `replyWithContact(phoneNumber, firstName, extra?): Promise<Message>` | Sends `sendContact` with automatic quote-reply. |
740
+ | `replyWithPoll` | `replyWithPoll(question, options, extra?): Promise<Message>` | Sends `sendPoll` with automatic quote-reply. |
741
+ | `replyWithDice` | `replyWithDice(emoji?, extra?): Promise<Message>` | Sends `sendDice` with automatic quote-reply. |
742
+ | `sendChatAction` | `sendChatAction(action, extra?): Promise<true>` | Sends a chat action such as `typing`. |
653
743
  | `copy` | `copy(fromChatId, messageId, extra?): Promise<unknown>` | Calls `copyMessage` to the context chat. |
654
744
  | `forward` | `forward(fromChatId, messageId, extra?): Promise<Message>` | Calls `forwardMessage` to the context chat. |
655
745
  | `pin` | `pin(messageId?, extra?): Promise<true>` | Calls `pinChatMessage`; defaults to the context message id. |
@@ -662,7 +752,7 @@ new Context<S>(options: ContextOptions<S>): Context<S>
662
752
  | `getFile` | `getFile(fileId): Promise<unknown>` | Fetches a file by id. |
663
753
  | `withReplyMarkup` | `withReplyMarkup(markup): this` | Stores markup in `ctx.state.reply_markup` and returns the context. This method does not automatically send a message. |
664
754
 
665
- `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.
755
+ 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.
666
756
 
667
757
  ---
668
758
 
@@ -973,6 +1063,20 @@ new Scheduler(): Scheduler
973
1063
 
974
1064
  The full cron format is not supported by the built-in scheduler. Expressions other than `*/N` throw an `Error`.
975
1065
 
1066
+ ### `Limiter` and `mapWithConcurrency`
1067
+
1068
+ ```ts
1069
+ new Limiter(limit: number): Limiter
1070
+
1071
+ mapWithConcurrency<T, R>(
1072
+ items: readonly T[],
1073
+ limit: number,
1074
+ worker: (item: T, index: number) => Promise<R>,
1075
+ ): Promise<R[]>
1076
+ ```
1077
+
1078
+ `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.
1079
+
976
1080
  ## 9. Plugins and services
977
1081
 
978
1082
  ### `Plugin<Context>`
@@ -1281,11 +1385,23 @@ new Menu(id: string): Menu
1281
1385
 
1282
1386
  ## 12. Terminal Logging
1283
1387
 
1284
- The CLI prints a colored Unicode attribution box and an animated startup status when attached to a TTY. The default logger emits compact, readable terminal lines with colored levels and structured context. Use `format: "json"` for machine ingestion, `includeUpdateContent: true` when message text or callback data is explicitly required, and a custom `sink` for application monitoring.
1388
+ 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>`.
1389
+
1390
+ Every update the bot handles is logged on a human-readable line:
1391
+
1392
+ ```text
1393
+ [ => ] Message From 123456789 John Doe 29/08/2026 15:04:05
1394
+ ↳ Text: /start
1395
+ [ => ] Callback From 123456789 John Doe 29/08/2026 15:04:07
1396
+ ↳ Data: menu:open
1397
+ ```
1398
+
1399
+ 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.
1285
1400
 
1286
1401
  ```ts
1287
1402
  const bot = new Bot({
1288
1403
  token: process.env.TELEGRAM_BOT_TOKEN!,
1404
+ branding: false, // turn off the startup sequence
1289
1405
  logger: {
1290
1406
  level: "debug",
1291
1407
  format: "pretty",
@@ -1295,6 +1411,8 @@ const bot = new Bot({
1295
1411
  });
1296
1412
  ```
1297
1413
 
1414
+ Additional branding helpers exported for applications: `runStartupSequence()`, `startTeleBibzBanner()`, `printTeleBibzBanner()`, `paintRainbow()`, and `printStatusLine()`.
1415
+
1298
1416
  ---
1299
1417
 
1300
1418
  ## 13. Text Utilities
@@ -1723,7 +1841,7 @@ The package vendors MIT-licensed Telegram declarations and exposes them as type-
1723
1841
  ---
1724
1842
  ## 19. Compatibility and limitations to be aware of
1725
1843
 
1726
- The library targets Node.js `>=20`, uses ESM as the primary module, and also provides a CommonJS build. Webhooks require a runtime that provides Web `Request`, `Response`, `Headers`, `FormData`, `Blob`, and `AbortController`; modern Node.js provides these natively.
1844
+ 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.
1727
1845
 
1728
1846
  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.
1729
1847
 
package/docs/API.zh-CN.md CHANGED
@@ -68,11 +68,13 @@ type BotStatus =
68
68
  | `transportOptions` | `Omit<FetchTransportOptions, "baseUrl">` | `{}` | 超时、重试、退避、jitter、headers 和 fetch 实现。 |
69
69
  | `session` | `Storage<string, S>` | 新的存储 | 基于 chat/user key 的会话存储,可使用持久化适配器。 |
70
70
  | `services` | `Record<string, unknown>` | `{}` | 通过 `ctx.services` 可用的依赖/服务。 |
71
+ | `branding` | `boolean` | `true` | 终端启动体验:打字效果、glass 进度条、动画彩虹 `Tele Bibz` 横幅以及易读的 update 日志行。仅在交互式 TTY 上渲染。 |
71
72
  | `polling.timeout` | `number` | `30` | 用于 `getUpdates` 的长轮询超时(秒)。 |
72
73
  | `polling.limit` | `number` | `100` | 每次轮询请求的最大 update 数量。 |
73
74
  | `polling.allowedUpdates` | `string[]` | `[]` | Telegram 更新过滤器。 |
74
75
  | `polling.retryDelayMs` | `number` | `500` | 轮询失败时的初始延迟(毫秒)。 |
75
76
  | `polling.maxRetryDelayMs` | `number` | `30000` | 重连延迟的最大值(毫秒)。 |
77
+ | `updates.concurrency` | `number` | `Infinity` | 同时处理的 update 数量上限。不同 chat 的 update 始终并行,同一 chat 内保持顺序,因此 1000+ 条消息的突发可一次性处理。 |
76
78
 
77
79
  ### `Bot` constructor
78
80
 
@@ -140,6 +142,30 @@ onRegex(expression: RegExp, handler: Middleware<Context<S>>): this
140
142
 
141
143
  使用 `RegExp` 处理消息文本。路由参数不会自动提取到 `ctx.params`;如需提取请使用 predicate 或自定义 middleware。
142
144
 
145
+ ### `bot.on(filter, handler)`
146
+
147
+ ```ts
148
+ on(filter: UpdateFilter | UpdateFilter[], handler: Middleware<Context<S>>): this
149
+ ```
150
+
151
+ 按更新类型注册处理器,并可用 payload 字段收窄。示例:`"message"`、`"message:text"`、`"message:photo"`、`"edited_message"`、`"channel_post"`、`"callback_query"`、`"callback_query:data"`、`"inline_query"`、`"chat_member"`、`"message_reaction"`,或数组如 `["message:text", "callback_query:data"]`。无效的更新类型会在注册时抛出 `TypeError`。
152
+
153
+ ### `bot.hears(trigger, handler)`
154
+
155
+ ```ts
156
+ hears(trigger: string | RegExp, handler: Middleware<Context<S>>): this
157
+ ```
158
+
159
+ 处理完全匹配的文本(string)或匹配 `RegExp` 的消息文本。
160
+
161
+ ### `bot.catch(handler)`
162
+
163
+ ```ts
164
+ catch(handler: (error: unknown, ctx: Context<S>) => void | Promise<void>): this
165
+ ```
166
+
167
+ 注册更新处理器的错误边界。设置后,处理器失败会被记录、以 `update:error`/`bot:error` 事件发出,并转发给该 handler,而不是让 `handleUpdate()` 拒绝 —— webhook 返回 `200`,轮询继续。未设置边界时错误会被重新抛出。
168
+
143
169
  ### `bot.usePlugin(plugin)`
144
170
 
145
171
  ```ts
@@ -176,7 +202,7 @@ launch(options?: {
176
202
  }): Promise<void>
177
203
  ```
178
204
 
179
- 以 polling 模式运行 bot。启动时生命周期依次变为 `starting` 然后 `running`,之后 `getUpdates()` 循环按顺序处理每个 update。轮询失败会触发 `polling:reconnect` 并使用指数退避。
205
+ 以 polling 模式运行 bot。启动时生命周期依次变为 `starting` 然后 `running`,之后 `getUpdates()` 循环并发处理每一批 update:不同 chat 的 update 并行执行,同一 chat 的 update 保持到达顺序。轮询失败会触发 `polling:reconnect` 并使用指数退避。
180
206
 
181
207
  除 `"polling"` 外的模式会抛出错误,并建议对 webhook 使用 `createWebhookHandler()`。
182
208
 
@@ -253,8 +279,54 @@ handleUpdate(update: Update): Promise<void>
253
279
 
254
280
  手动处理单个 update。该方法根据 `chat.id` 和 `from.id` 确定会话 key,创建 `Context`,触发 `update` 和 `message` 事件,执行 middleware 然后路由器,并在流水线完成后保存会话。
255
281
 
282
+ 不同 chat 的 update 并行处理;同一 chat 的 update 按到达顺序串行处理,因此会话、wizard 和 conversation 永远不会交错,会话写入也不会丢失。并发的 update 突发只会触发一次 `getMe` 初始化。
283
+
256
284
  流水线错误会将 bot 状态置为 `error`,触发 `bot:error`,然后重新抛出错误。
257
285
 
286
+ ### `bot.handleUpdates(updates)`
287
+
288
+ ```ts
289
+ handleUpdates(updates: readonly Update[]): Promise<void>
290
+ ```
291
+
292
+ 一次性处理整批 update:批次中的每个 chat 立即处理——跨 chat 并行、同一 chat 内按序——因此 1000 条消息的突发绝不会卡在某个慢速 handler 后面。单个 handler 的失败会记录日志、以 `update:error` 触发事件并交给 `catch()` 错误边界;它们永远不会让该 promise 被 reject。轮询循环对每个 `getUpdates` 批次都使用此方法。
293
+
294
+ ### `bot.broadcast(chatIds, send, options?)`
295
+
296
+ ```ts
297
+ broadcast(
298
+ chatIds: readonly ChatId[],
299
+ send: (chatId: ChatId) => Promise<unknown>,
300
+ options?: BroadcastOptions,
301
+ ): Promise<BroadcastReport>
302
+ ```
303
+
304
+ 并行向大量 chat 发送消息——专为向 1000+ 用户广播而设计。没有主动冷却:所有 chat(至多 `options.concurrency`,默认 `Infinity`)同时尝试发送。当 Telegram 返回 429 时,会严格按照 Telegram 指定的 `retry_after` 延迟自动重试(至多 `options.maxAttempts` 次,默认 `10`),因此突发流量会完整送达而不是失败。不可重试的错误(例如 bot 无法发送的 chat)会按 chat 记录在返回的报告中。
305
+
306
+ ```ts
307
+ const report = await bot.broadcast(
308
+ subscriberIds,
309
+ (chatId) => bot.api.methods.sendMessage({ chat_id: chatId, text: "Newsletter #42" }),
310
+ { onProgress: (progress) => console.log(`${progress.delivered}/${progress.total} delivered`) },
311
+ );
312
+ console.log(`Delivered ${report.delivered} of ${report.total} in ${report.durationMs}ms`);
313
+ for (const failure of report.failures) console.warn(`Failed: ${failure.chatId} — ${failure.error}`);
314
+ ```
315
+
316
+ #### `BroadcastOptions` 和 `BroadcastReport`
317
+
318
+ | 属性 | 类型 | 默认值 | 说明 |
319
+ |---|---|---:|---|
320
+ | `BroadcastOptions.concurrency` | `number` | `Infinity` | 同时向多少个 chat 发送消息。 |
321
+ | `BroadcastOptions.maxAttempts` | `number` | `10` | Telegram 返回 429 时每个 chat 的尝试次数。 |
322
+ | `BroadcastOptions.onProgress` | `(progress: BroadcastProgress) => void` | — | 每个 chat 结束后调用。 |
323
+ | `BroadcastOptions.signal` | `AbortSignal` | — | 中止待发送的消息;已送达的消息保持送达。 |
324
+ | `BroadcastReport.total` | `number` | — | 本次广播的 chat 总数。 |
325
+ | `BroadcastReport.delivered` | `number` | — | 成功收到消息的 chat 数。 |
326
+ | `BroadcastReport.failed` | `number` | — | 未收到消息的 chat 数。 |
327
+ | `BroadcastReport.durationMs` | `number` | — | 本次广播的实际耗时(毫秒)。 |
328
+ | `BroadcastReport.failures` | `BroadcastFailure[]` | — | 按 chat 记录的 `{ chatId, attempts, error, errorKind }`。 |
329
+
258
330
  ### 最小 bot 示例
259
331
 
260
332
  ```ts
@@ -391,6 +463,7 @@ interface Transport {
391
463
  | `backoffMs` | `250` | 初始指数退避延迟(毫秒)。 |
392
464
  | `maxBackoffMs` | `8000` | 传输延迟上限(毫秒)。 |
393
465
  | `jitter` | `0.2` | 对指数延迟的随机抖动,范围为 ±20%。 |
466
+ | `floodGate` | `true` | 当 Telegram 返回 429 时,暂停新的请求直到 Telegram 指定的 `retry_after` 窗口结束。这不是主动冷却——唯一的等待就是 Telegram 自己要求的等待。 |
394
467
  | `headers` | `{}` | 额外的请求头。 |
395
468
 
396
469
  ### `new FetchTransport(options?)`
@@ -633,6 +706,22 @@ new Context<S>(options: ContextOptions<S>): Context<S>
633
706
  | `send` | `send(text, extra?): Promise<Message>` | 向更新的聊天发送消息,不带回复引用. |
634
707
  | `edit` | `edit(text, extra?): Promise<Message \| true>` | 使用 `editMessageText` 编辑更新的消息. |
635
708
  | `delete` | `delete(): Promise<true>` | 删除更新的消息. |
709
+ | `replyWithHTML` | `replyWithHTML(text, extra?): Promise<Message>` | 以 `parse_mode: "HTML"` 回复. |
710
+ | `replyWithMarkdown` | `replyWithMarkdown(text, extra?): Promise<Message>` | 以 `parse_mode: "MarkdownV2"` 回复. |
711
+ | `replyWithPhoto` | `replyWithPhoto(photo, extra?): Promise<Message>` | 发送 `sendPhoto`,自动引用回复. |
712
+ | `replyWithDocument` | `replyWithDocument(document, extra?): Promise<Message>` | 发送 `sendDocument`,自动引用回复. |
713
+ | `replyWithAudio` | `replyWithAudio(audio, extra?): Promise<Message>` | 发送 `sendAudio`,自动引用回复. |
714
+ | `replyWithVideo` | `replyWithVideo(video, extra?): Promise<Message>` | 发送 `sendVideo`,自动引用回复. |
715
+ | `replyWithVoice` | `replyWithVoice(voice, extra?): Promise<Message>` | 发送 `sendVoice`,自动引用回复. |
716
+ | `replyWithAnimation` | `replyWithAnimation(animation, extra?): Promise<Message>` | 发送 `sendAnimation`,自动引用回复. |
717
+ | `replyWithVideoNote` | `replyWithVideoNote(videoNote, extra?): Promise<Message>` | 发送 `sendVideoNote`,自动引用回复. |
718
+ | `replyWithSticker` | `replyWithSticker(sticker, extra?): Promise<Message>` | 发送 `sendSticker`,自动引用回复. |
719
+ | `replyWithMediaGroup` | `replyWithMediaGroup(media, extra?): Promise<Message[]>` | 通过 `sendMediaGroup` 发送相册,自动引用回复. |
720
+ | `replyWithLocation` | `replyWithLocation(latitude, longitude, extra?): Promise<Message>` | 发送 `sendLocation`,自动引用回复. |
721
+ | `replyWithVenue` | `replyWithVenue(latitude, longitude, title, address, extra?): Promise<Message>` | 发送 `sendVenue`,自动引用回复. |
722
+ | `replyWithContact` | `replyWithContact(phoneNumber, firstName, extra?): Promise<Message>` | 发送 `sendContact`,自动引用回复. |
723
+ | `replyWithPoll` | `replyWithPoll(question, options, extra?): Promise<Message>` | 发送 `sendPoll`,自动引用回复. |
724
+ | `replyWithDice` | `replyWithDice(emoji?, extra?): Promise<Message>` | 发送 `sendDice`,自动引用回复. |
636
725
  | `copy` | `copy(fromChatId, messageId, extra?): Promise<unknown>` | 向上下文聊天调用 `copyMessage`. |
637
726
  | `forward` | `forward(fromChatId, messageId, extra?): Promise<Message>` | 向上下文聊天调用 `forwardMessage`. |
638
727
  | `pin` | `pin(messageId?, extra?): Promise<true>` | 调用 `pinChatMessage`,默认消息 ID 来自上下文. |
@@ -948,6 +1037,20 @@ new Scheduler(): Scheduler
948
1037
 
949
1038
  内置调度器不支持完整的 cron 格式。除 `*/N` 外的表达式会抛出 `Error`。
950
1039
 
1040
+ ### `Limiter` 和 `mapWithConcurrency`
1041
+
1042
+ ```ts
1043
+ new Limiter(limit: number): Limiter
1044
+
1045
+ mapWithConcurrency<T, R>(
1046
+ items: readonly T[],
1047
+ limit: number,
1048
+ worker: (item: T, index: number) => Promise<R>,
1049
+ ): Promise<R[]>
1050
+ ```
1051
+
1052
+ `Limiter` 是一个 promise 信号量:有空闲槽位时任务立即执行,超出后按 FIFO 排队。`limit` 接受任意正整数或 `Infinity`(完全并行——即本库的默认值)。`mapWithConcurrency` 以相同的并发上限让 item 通过 async worker 映射,同时保持结果顺序。这些原语自身不会添加任何延迟——它们只限制同时运行的任务数量。`Limiter` 暴露 `activeCount` 和 `queuedCount` 用于可观测性。
1053
+
951
1054
  ---
952
1055
 
953
1056
  ## 9. 插件与服务
@@ -1257,7 +1360,20 @@ new Menu(id: string): Menu
1257
1360
 
1258
1361
  ## 12. Terminal Logging
1259
1362
 
1260
- This package starts directly after Telegram API connectivity is established. The terminal prints a boxed telebibz attribution, an animated startup status when attached to a TTY, and structured colorful logs for lifecycle, API, polling, webhook, and update events. Set logger format to `json` for machine ingestion.
1363
+ 当 stdout 是交互式 TTY 时,每次 `bot.start()` / `bot.launch()` 都会播放启动序列:`Installing Dependencies......` 打字效果、带扫过高光的 glass 进度条,以及动画彩虹 ASCII 横幅 `Tele Bibz`(figlet `Speed` 字体)——持续流动直到 bot 连接成功,随后定格为 `✓ Connected as @<username>`。
1364
+
1365
+ bot 处理的每条 update 都会以易读的行格式记录:
1366
+
1367
+ ```text
1368
+ [ => ] Message From 123456789 John Doe 29/08/2026 15:04:05
1369
+ ↳ Text: /start
1370
+ [ => ] Callback From 123456789 John Doe 29/08/2026 15:04:07
1371
+ ↳ Data: menu:open
1372
+ ```
1373
+
1374
+ 普通消息与命令文本截断为 50 个字符;回调按钮数据完整显示。错误以红色打印并附带完整堆栈。向 `Bot` 传入 `branding: false` 可关闭启动序列;设置 `logger.format: "json"` 时,进入的 update 会作为结构化 `update.received` entry 输出。非交互 stdout(管道、Docker、CI)自动回退为无动画的纯文本。
1375
+
1376
+ 面向应用导出的附加 branding helper:`runStartupSequence()`、`startTeleBibzBanner()`、`printTeleBibzBanner()`、`paintRainbow()` 和 `printStatusLine()`。
1261
1377
 
1262
1378
  ## 13. 文本工具
1263
1379
 
@@ -1685,7 +1801,7 @@ Package 内置 MIT 许可的 Telegram declaration,并通过 type-only export
1685
1801
 
1686
1802
  ## 19. 兼容性和需要注意的限制
1687
1803
 
1688
- Library menargetkan Node.js `>=20`,使用 ESM 作为主要模块,并提供 CommonJS 构建。Webhook 需要运行时提供 Web `Request`、`Response`、`Headers`、`FormData`、`Blob` 和 `AbortController`;现代 Node.js 原生提供了这些。
1804
+ 本库面向 Node.js `>=22`,使用 ESM 作为主要模块,并提供 CommonJS 构建。Webhook 需要运行时提供 Web `Request`、`Response`、`Headers`、`FormData`、`Blob` 和 `AbortController`;现代 Node.js 原生提供了这些。
1689
1805
 
1690
1806
  API 生成的方法列表(generated method list)和 API 方法映射(API method map)并不相同。`TelegramMethodName` 包含 184 个运行时名称,但 `TelegramMethodMap` 仅对 API 客户端部分列出的子集提供了带类型的参数/结果。对于其他方法,使用 `api.raw()` 或在应用端添加类型声明。
1691
1807
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xbibzlibrary/telebibz",
3
- "version": "0.1.19",
4
- "description": "Production-grade Telegram Bot framework for Node.js and TypeScript with typed API, routing, webhooks, keyboards, conversations, plugins, queues, and colorful CLI logs.",
3
+ "version": "0.3.1",
4
+ "description": "Telegram Bot framework for Node.js and TypeScript with a typed API client, routing, middleware, webhooks, keyboards, conversations, plugins, queues, and a polished terminal experience.",
5
5
  "keywords": [
6
6
  "telegram",
7
7
  "telegram-bot",
@@ -32,7 +32,7 @@
32
32
  "url": "https://github.com/XbibzOfficial777/telebibz/issues"
33
33
  },
34
34
  "engines": {
35
- "node": ">=20"
35
+ "node": ">=22"
36
36
  },
37
37
  "scripts": {
38
38
  "generate": "node scripts/generate-api.mjs",