@xbibzlibrary/telebibz 0.4.3 → 0.4.5

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 (71) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.id.md +20 -3
  3. package/README.md +20 -3
  4. package/README.zh-CN.md +20 -3
  5. package/dist/src/api/client.d.ts +28 -0
  6. package/dist/src/api/client.d.ts.map +1 -1
  7. package/dist/src/api/client.js +28 -0
  8. package/dist/src/api/client.js.map +1 -1
  9. package/dist/src/api/transport.d.ts +14 -0
  10. package/dist/src/api/transport.d.ts.map +1 -1
  11. package/dist/src/api/transport.js +67 -2
  12. package/dist/src/api/transport.js.map +1 -1
  13. package/dist/src/api/types.d.ts +25 -0
  14. package/dist/src/api/types.d.ts.map +1 -1
  15. package/dist/src/context/context.d.ts +13 -3
  16. package/dist/src/context/context.d.ts.map +1 -1
  17. package/dist/src/context/context.js +15 -0
  18. package/dist/src/context/context.js.map +1 -1
  19. package/dist/src/core/bot.d.ts +12 -0
  20. package/dist/src/core/bot.d.ts.map +1 -1
  21. package/dist/src/core/bot.js +16 -0
  22. package/dist/src/core/bot.js.map +1 -1
  23. package/dist/src/index.d.ts +1 -0
  24. package/dist/src/index.d.ts.map +1 -1
  25. package/dist/src/index.js +1 -0
  26. package/dist/src/index.js.map +1 -1
  27. package/dist/src/testing.d.ts +6 -0
  28. package/dist/src/testing.d.ts.map +1 -1
  29. package/dist/src/testing.js +6 -0
  30. package/dist/src/testing.js.map +1 -1
  31. package/dist/src/utils/files.d.ts +45 -0
  32. package/dist/src/utils/files.d.ts.map +1 -0
  33. package/dist/src/utils/files.js +53 -0
  34. package/dist/src/utils/files.js.map +1 -0
  35. package/dist-cjs/src/api/client.js +28 -0
  36. package/dist-cjs/src/api/transport.js +67 -2
  37. package/dist-cjs/src/context/context.js +15 -0
  38. package/dist-cjs/src/core/bot.js +16 -0
  39. package/dist-cjs/src/index.js +1 -0
  40. package/dist-cjs/src/testing.js +6 -0
  41. package/dist-cjs/src/utils/files.js +58 -0
  42. package/docs/API.id.md +70 -0
  43. package/docs/API.md +70 -0
  44. package/docs/API.zh-CN.md +70 -0
  45. package/docs/COOKBOOK.id.md +321 -0
  46. package/docs/COOKBOOK.md +321 -0
  47. package/docs/COOKBOOK.zh-CN.md +321 -0
  48. package/docs/ERRORS.id.md +194 -0
  49. package/docs/ERRORS.md +194 -0
  50. package/docs/ERRORS.zh-CN.md +194 -0
  51. package/docs/FILES.id.md +243 -0
  52. package/docs/FILES.md +243 -0
  53. package/docs/FILES.zh-CN.md +243 -0
  54. package/docs/GETTING_STARTED.id.md +6 -2
  55. package/docs/GETTING_STARTED.md +6 -2
  56. package/docs/GETTING_STARTED.zh-CN.md +6 -2
  57. package/docs/MIGRATION_TELEGRAF.id.md +147 -0
  58. package/docs/MIGRATION_TELEGRAF.md +154 -0
  59. package/docs/MIGRATION_TELEGRAF.zh-CN.md +147 -0
  60. package/docs/README.md +38 -19
  61. package/docs/STORAGE.id.md +105 -0
  62. package/docs/STORAGE.md +105 -0
  63. package/docs/STORAGE.zh-CN.md +105 -0
  64. package/docs/TESTING.id.md +203 -0
  65. package/docs/TESTING.md +203 -0
  66. package/docs/TESTING.zh-CN.md +203 -0
  67. package/docs/WEBHOOK.id.md +212 -0
  68. package/docs/WEBHOOK.md +215 -0
  69. package/docs/WEBHOOK.zh-CN.md +212 -0
  70. package/examples/files.ts +35 -0
  71. package/package.json +1 -1
@@ -0,0 +1,154 @@
1
+ # Migrating from Telegraf (English)
2
+
3
+ telebibz implements the Telegraf context surface and launch options deliberately, so most handlers port with little or no change. This guide maps every part of a Telegraf bot to its telebibz equivalent.
4
+
5
+ ## Contents
6
+
7
+ 1. [Side-by-side: a whole bot](#1-side-by-side-a-whole-bot)
8
+ 2. [Concept map](#2-concept-map)
9
+ 3. [Context methods](#3-context-methods)
10
+ 4. [Launch options](#4-launch-options)
11
+ 5. [Scenes → Wizards](#5-scenes--wizards)
12
+ 6. [Session storage](#6-session-storage)
13
+ 7. [Webhooks](#7-webhooks)
14
+ 8. [What has no direct equivalent](#8-what-has-no-direct-equivalent)
15
+
16
+ ## 1. Side-by-side: a whole bot
17
+
18
+ **Telegraf**
19
+
20
+ ```ts
21
+ import { Telegraf } from "telegraf";
22
+
23
+ const bot = new Telegraf(process.env.TELEGRAM_BOT_TOKEN!);
24
+
25
+ bot.use(async (ctx, next) => { console.time("update"); await next(); console.timeEnd("update"); });
26
+ bot.start((ctx) => ctx.reply("Welcome!"));
27
+ bot.command("help", (ctx) => ctx.reply("Help"));
28
+ bot.action("menu:open", async (ctx) => { await ctx.answerCbQuery(); await ctx.reply("Menu"); });
29
+ bot.on("message", (ctx) => ctx.reply("got it"));
30
+ bot.catch((error) => console.error(error));
31
+
32
+ bot.launch({ dropPendingUpdates: true });
33
+ ```
34
+
35
+ **telebibz**
36
+
37
+ ```ts
38
+ import { Bot } from "@xbibzlibrary/telebibz";
39
+
40
+ const bot = new Bot(process.env.TELEGRAM_BOT_TOKEN!);
41
+
42
+ bot.use(async (ctx, next) => { console.time("update"); await next(); console.timeEnd("update"); });
43
+ bot.command("start", async (ctx) => { await ctx.reply("Welcome!"); }); // named command, not bot.start()
44
+ bot.command("help", async (ctx) => { await ctx.reply("Help"); });
45
+ bot.action("menu:open", async (ctx) => { await ctx.answerCallbackQuery(); await ctx.reply("Menu"); });
46
+ bot.on("message", async (ctx) => { await ctx.reply("got it"); });
47
+ bot.catch(async (error) => { console.error(error); });
48
+
49
+ await bot.launch({ dropPendingUpdates: true }); // same option name
50
+ ```
51
+
52
+ Only two mechanical differences: `bot.start(handler)` becomes `bot.command("start", handler)`, and `answerCbQuery()` becomes `answerCallbackQuery()`.
53
+
54
+ ## 2. Concept map
55
+
56
+ | Telegraf | telebibz | Notes |
57
+ |---|---|---|
58
+ | `new Telegraf(token)` | `new Bot(token)` or `new Bot({ token, ... })` | |
59
+ | `bot.launch()` | `bot.launch()` / `bot.start()` | `mode: "polling"` is explicit on `launch` |
60
+ | `bot.stop()` | `bot.stop()` | telebibz drains in-flight handlers first |
61
+ | `bot.use(mw)` | `bot.use(mw)` | same middleware signature `(ctx, next)` |
62
+ | `bot.command(name, h)` | `bot.command(name, h)` | |
63
+ | `bot.on(filter, h)` | `bot.on(filter, h)` | same filter grammar (`message:photo`, arrays) |
64
+ | `bot.hears(trigger, h)` | `bot.hears(trigger, h)` | strings and RegExp |
65
+ | `bot.action(pattern, h)` | `bot.action(pattern, h)` | drop-in alias of `bot.callback` |
66
+ | `bot.catch(handler)` | `bot.catch(handler)` | receives `(error, ctx)` |
67
+ | `ctx.reply(text, extra)` | `ctx.reply(text, extra)` | |
68
+ | `ctx.telegram.callApi(m, p)` | `ctx.api.call(m, p)` / `ctx.api.raw(m, p)` | `raw` needs no type map entry |
69
+ | `ctx.telegram.api.config` | `transportOptions` on the `Bot` options | timeout, retries, flood gate |
70
+ | `Scenes.WizardScene` + `Stage` | `Wizard` + `bot.useWizard()` | see section 5 |
71
+ | `session` middleware | built-in `session` storage option | see section 6 |
72
+ | `webhookCallback(bot, app)` | `webhookCallback(bot, "express")` | framework is now an argument |
73
+ | Telegraf plugins (`telegraf-i18n`, …) | `bot.usePlugin({ install, onStop, dispose })` | explicit lifecycle |
74
+
75
+ ## 3. Context methods
76
+
77
+ Every Telegraf context shortcut exists — including the ones Telegraf leaves to plugins:
78
+
79
+ - **Replies**: `reply`, `replyWithPhoto`, `replyWithDocument`, `replyWithVideo`, `replyWithAudio`, `replyWithVoice`, `replyWithAnimation`, `replyWithVideoNote`, `replyWithSticker`, `replyWithMediaGroup`, `replyWithLocation`, `replyWithVenue`, `replyWithContact`, `replyWithPoll`, `replyWithQuiz`, `replyWithDice`, `replyWithGame`, `replyWithInvoice`, `replyWithHTML`, `replyWithMarkdown` (+V2)
80
+ - **Admin/moderation**: `banChatMember`, `unbanChatMember`, `restrictChatMember`, `promoteChatMember`, `banChatSenderChat`, `unbanChatSenderChat`
81
+ - **Chat**: `setChatTitle`, `setChatDescription`, `setChatPhoto`, `deleteChatPhoto`, `setChatPermissions`, `leaveChat`, `unpinAllChatMessages`, `setChatStickerSet`, `deleteChatStickerSet`
82
+ - **Info**: `getChat`, `getChatAdministrators`, `getChatMemberCount`, `getChatMember`
83
+ - **Invite links/join requests**: `exportChatInviteLink`, `createChatInviteLink`, `editChatInviteLink`, `revokeChatInviteLink`, `approveChatJoinRequest`, `declineChatJoinRequest`
84
+ - **Live location/polls/games**: `editMessageLiveLocation`, `stopMessageLiveLocation`, `stopPoll`, `setGameScore`, `getGameHighScores`
85
+ - **Forum**: full topic set (`createForumTopic` … `unhideGeneralForumTopic`)
86
+ - **New beyond Telegraf core**: `getFile` (typed), `downloadFile`, `edit` (rewrites the current message's text), plus standalone helpers exported from the package root — `validateUpload`/`assertValidUpload` — which are not context methods
87
+
88
+ Naming differences to fix while porting: `answerCbQuery` → `answerCallbackQuery`; `ctx.telegram` → `ctx.api`; keyboard helpers come from the package root (`InlineKeyboard`, `ReplyKeyboard`, `removeKeyboard`, `forceReply`) instead of `Markup`.
89
+
90
+ ## 4. Launch options
91
+
92
+ | Telegraf | telebibz |
93
+ |---|---|
94
+ | `launch({ dropPendingUpdates })` | `launch({ dropPendingUpdates })` — identical |
95
+ | `handlerTimeout` (90 000 default) | `handlerTimeout` (90 000 default; `0` disables) |
96
+ | `contextType` option | `contextType` option — your `Context` subclass is instantiated for every update |
97
+ | `webhookReply` (per-update) | `webhookReply` on the handler / `handleUpdate` options |
98
+ | `telegraf.use(session(...))` | `new Bot({ session: new MemoryStorage() })` (or JSON/Redis/SQL/Mongo) |
99
+
100
+ ## 5. Scenes → Wizards
101
+
102
+ Telegraf's `WizardScene` + `Stage` becomes a single `Wizard` with explicit steps and no global session keys:
103
+
104
+ ```ts
105
+ import { Bot, Wizard } from "@xbibzlibrary/telebibz";
106
+
107
+ const wizard = new Wizard()
108
+ .step({ id: "ask-name", run: async (flow) => { flow.next(); await flow.ctx.reply("Name?"); } })
109
+ .step({ id: "save", run: async (flow) => { await flow.ctx.reply(`Hi ${flow.ctx.message?.text}!`); } });
110
+
111
+ const bot = new Bot(process.env.TELEGRAM_BOT_TOKEN!);
112
+ bot.useWizard(wizard); // replaces Stage middleware
113
+ bot.command("start", async (ctx) => { await wizard.run(ctx); }); // replaces scene.enter()
114
+ ```
115
+
116
+ - The wizard key derives automatically from chat + sender — no manual key management.
117
+ - `flow.set(key, value)` / `flow.get(key)` replace `ctx.scene.session`.
118
+ - `/cancel` cancels; the conversation completes automatically after the last step.
119
+ - For non-linear graphs, compose `ConversationManager` with the router (telebibz deliberately keeps scene orchestration application-owned; see FEATURE_MATRIX "Design decisions").
120
+
121
+ ## 6. Session storage
122
+
123
+ Telegraf stores sessions in memory by default and needs a store plugin for persistence. telebibz takes storage on the constructor — swap the adapter, keep the code:
124
+
125
+ ```ts
126
+ import { Bot, MemoryStorage, JsonFileStorage, RedisStorage } from "@xbibzlibrary/telebibz";
127
+
128
+ const bot = new Bot({
129
+ token: process.env.TELEGRAM_BOT_TOKEN!,
130
+ session: new JsonFileStorage("state/sessions.json"), // or MemoryStorage / RedisStorage / SqlStorage / MongoStorage
131
+ });
132
+ ```
133
+
134
+ Full wiring recipes for every adapter: [STORAGE.md](STORAGE.md).
135
+
136
+ ## 7. Webhooks
137
+
138
+ ```ts
139
+ // Telegraf: webhookCallback(bot, app)
140
+ // telebibz: framework is explicit
141
+ import { webhookCallback } from "@xbibzlibrary/telebibz";
142
+ app.post("/telegram", webhookCallback(bot, "express", { secretToken: process.env.TELEGRAM_WEBHOOK_SECRET }));
143
+ ```
144
+
145
+ `createWebhookHandler()` additionally provides a Web-standard `Request → Response` handler for Bun/Deno/edge. Full deployment guide: [WEBHOOK.md](WEBHOOK.md).
146
+
147
+ ## 8. What has no direct equivalent
148
+
149
+ - **`bot.telegram` low-level client** — use `bot.api` (`call`, `raw`, `methods`, `downloadFile`); the flood gate and retries are built into the transport rather than configurable per call.
150
+ - **Telegraf's plugin ecosystem** — port plugins as `Plugin` objects with an explicit lifecycle (`install`, `onStop`, `dispose`); the plugin manager restarts cleanly.
151
+ - **`Composer.mount`/dynamic scenes** — build with `Router` nesting and `matchMode: "all"` instead.
152
+ - **Markup helper chains** (`Markup.keyboard(...).resize()`) — use `new ReplyKeyboard().text("A").resized().build()`; same payloads, builder style.
153
+
154
+ Bahasa Indonesia: [MIGRATION_TELEGRAF.id.md](MIGRATION_TELEGRAF.id.md) · 简体中文: [MIGRATION_TELEGRAF.zh-CN.md](MIGRATION_TELEGRAF.zh-CN.md)
@@ -0,0 +1,147 @@
1
+ # 从 Telegraf 迁移(简体中文)
2
+
3
+ telebibz 有意实现了 Telegraf 的 context 表面与启动选项,因此大多数 handler 只需极少改动即可移植。本指南把 Telegraf bot 的每个部分映射到 telebibz 对应物。
4
+
5
+ ## 目录
6
+
7
+ 1. [并排对照:完整 bot](#1-并排对照完整-bot)
8
+ 2. [概念映射](#2-概念映射)
9
+ 3. [Context 方法](#3-context-方法)
10
+ 4. [启动选项](#4-启动选项)
11
+ 5. [Scenes → Wizards](#5-scenes--wizards)
12
+ 6. [会话存储](#6-会话存储)
13
+ 7. [Webhook](#7-webhook)
14
+ 8. [没有直接对应物的部分](#8-没有直接对应物的部分)
15
+
16
+ ## 1. 并排对照:完整 bot
17
+
18
+ **Telegraf**
19
+
20
+ ```ts
21
+ import { Telegraf } from "telegraf";
22
+
23
+ const bot = new Telegraf(process.env.TELEGRAM_BOT_TOKEN!);
24
+
25
+ bot.use(async (ctx, next) => { console.time("update"); await next(); console.timeEnd("update"); });
26
+ bot.start((ctx) => ctx.reply("Welcome!"));
27
+ bot.command("help", (ctx) => ctx.reply("Help"));
28
+ bot.action("menu:open", async (ctx) => { await ctx.answerCbQuery(); await ctx.reply("Menu"); });
29
+ bot.on("message", (ctx) => ctx.reply("got it"));
30
+ bot.catch((error) => console.error(error));
31
+
32
+ bot.launch({ dropPendingUpdates: true });
33
+ ```
34
+
35
+ **telebibz**
36
+
37
+ ```ts
38
+ import { Bot } from "@xbibzlibrary/telebibz";
39
+
40
+ const bot = new Bot(process.env.TELEGRAM_BOT_TOKEN!);
41
+
42
+ bot.use(async (ctx, next) => { console.time("update"); await next(); console.timeEnd("update"); });
43
+ bot.command("start", async (ctx) => { await ctx.reply("Welcome!"); }); // 具名命令,而非 bot.start()
44
+ bot.command("help", async (ctx) => { await ctx.reply("Help"); });
45
+ bot.action("menu:open", async (ctx) => { await ctx.answerCallbackQuery(); await ctx.reply("Menu"); });
46
+ bot.on("message", async (ctx) => { await ctx.reply("got it"); });
47
+ bot.catch(async (error) => { console.error(error); });
48
+
49
+ await bot.launch({ dropPendingUpdates: true }); // 选项名相同
50
+ ```
51
+
52
+ 只有两处机械差异:`bot.start(handler)` 变为 `bot.command("start", handler)`;`answerCbQuery()` 变为 `answerCallbackQuery()`。
53
+
54
+ ## 2. 概念映射
55
+
56
+ | Telegraf | telebibz | 说明 |
57
+ |---|---|---|
58
+ | `new Telegraf(token)` | `new Bot(token)` 或 `new Bot({ token, ... })` | |
59
+ | `bot.launch()` | `bot.launch()` / `bot.start()` | `launch` 上显式声明 `mode: "polling"` |
60
+ | `bot.stop()` | `bot.stop()` | telebibz 先排空在途 handler |
61
+ | `bot.use(mw)` | `bot.use(mw)` | 中间件签名相同 `(ctx, next)` |
62
+ | `bot.command(name, h)` | `bot.command(name, h)` | |
63
+ | `bot.on(filter, h)` | `bot.on(filter, h)` | 过滤语法相同(`message:photo`、数组) |
64
+ | `bot.hears(trigger, h)` | `bot.hears(trigger, h)` | 字符串与 RegExp |
65
+ | `bot.action(pattern, h)` | `bot.action(pattern, h)` | `bot.callback` 的直接别名 |
66
+ | `bot.catch(handler)` | `bot.catch(handler)` | 接收 `(error, ctx)` |
67
+
68
+ ## 3. Context 方法
69
+
70
+ Telegraf context 的每个快捷方法都在 —— 包括 Telegraf 留给插件的那部分:
71
+
72
+ - **回复**:`reply`、`replyWithPhoto`、`replyWithDocument`、`replyWithVideo`、`replyWithAudio`、`replyWithVoice`、`replyWithAnimation`、`replyWithVideoNote`、`replyWithSticker`、`replyWithMediaGroup`、`replyWithLocation`、`replyWithVenue`、`replyWithContact`、`replyWithPoll`、`replyWithQuiz`、`replyWithDice`、`replyWithGame`、`replyWithInvoice`、`replyWithHTML`、`replyWithMarkdown`(+V2)
73
+ - **管理/群管**:`banChatMember`、`unbanChatMember`、`restrictChatMember`、`promoteChatMember`、`banChatSenderChat`、`unbanChatSenderChat`
74
+ - **聊天**:`setChatTitle`、`setChatDescription`、`setChatPhoto`、`deleteChatPhoto`、`setChatPermissions`、`leaveChat`、`unpinAllChatMessages`、`setChatStickerSet`、`deleteChatStickerSet`
75
+ - **信息**:`getChat`、`getChatAdministrators`、`getChatMemberCount`、`getChatMember`
76
+ - **邀请链接/加群申请**:`exportChatInviteLink`、`createChatInviteLink`、`editChatInviteLink`、`revokeChatInviteLink`、`approveChatJoinRequest`、`declineChatJoinRequest`
77
+ - **实时位置/投票/游戏**:`editMessageLiveLocation`、`stopMessageLiveLocation`、`stopPoll`、`setGameScore`、`getGameHighScores`
78
+ - **论坛**:完整话题方法集(`createForumTopic` … `unhideGeneralForumTopic`)
79
+ - **超越 Telegraf 核心的新增**:`getFile`(带类型)、`downloadFile`、`edit`(改写当前消息文本),以及从包根导出的独立助手 —— `validateUpload`/`assertValidUpload` —— 它们不是 context 方法
80
+
81
+ 移植时需修正的命名差异:`answerCbQuery` → `answerCallbackQuery`;`ctx.telegram` → `ctx.api`;键盘助手来自包根(`InlineKeyboard`、`ReplyKeyboard`、`removeKeyboard`、`forceReply`)而非 `Markup`。
82
+
83
+ ## 4. 启动选项
84
+
85
+ | Telegraf | telebibz |
86
+ |---|---|
87
+ | `launch({ dropPendingUpdates })` | `launch({ dropPendingUpdates })` —— 完全相同 |
88
+ | `handlerTimeout`(默认 90 000) | `handlerTimeout`(默认 90 000;`0` 禁用) |
89
+ | `contextType` 选项 | `contextType` 选项 —— 你的 `Context` 子类会为每个更新实例化 |
90
+ | `webhookReply`(按更新) | 处理器 / `handleUpdate` 选项上的 `webhookReply` |
91
+ | `telegraf.use(session(...))` | `new Bot({ session: new MemoryStorage() })`(或 JSON/Redis/SQL/Mongo) |
92
+
93
+ ## 5. Scenes → Wizards
94
+
95
+ Telegraf 的 `WizardScene` + `Stage` 变成单个 `Wizard`:显式步骤、无全局 session 键:
96
+
97
+ ```ts
98
+ import { Bot, Wizard } from "@xbibzlibrary/telebibz";
99
+
100
+ const wizard = new Wizard()
101
+ .step({ id: "ask-name", run: async (flow) => { flow.next(); await flow.ctx.reply("名字?"); } })
102
+ .step({ id: "save", run: async (flow) => { await flow.ctx.reply(`你好 ${flow.ctx.message?.text}!`); } });
103
+
104
+ const bot = new Bot(process.env.TELEGRAM_BOT_TOKEN!);
105
+ bot.useWizard(wizard); // 取代 Stage 中间件
106
+ bot.command("start", async (ctx) => { await wizard.run(ctx); }); // 取代 scene.enter()
107
+ ```
108
+
109
+ - 向导键自动由 chat + 发送者派生 —— 无需手工管理键。
110
+ - `flow.set(key, value)` / `flow.get(key)` 取代 `ctx.scene.session`。
111
+ - `/cancel` 取消;最后一步完成后对话自动收尾。
112
+ - 非线性流程图请用 `ConversationManager` 配合 router 组合(telebibz 刻意把场景编排留给应用;见 FEATURE_MATRIX 的 "Design decisions")。
113
+
114
+ ## 6. 会话存储
115
+
116
+ Telegraf 默认把会话放在内存,持久化需要 store 插件。telebibz 在构造函数上接收 storage —— 换适配器,不换代码:
117
+
118
+ ```ts
119
+ import { Bot, MemoryStorage, JsonFileStorage, RedisStorage } from "@xbibzlibrary/telebibz";
120
+
121
+ const bot = new Bot({
122
+ token: process.env.TELEGRAM_BOT_TOKEN!,
123
+ session: new JsonFileStorage("state/sessions.json"), // 或 MemoryStorage / RedisStorage / SqlStorage / MongoStorage
124
+ });
125
+ ```
126
+
127
+ 每个适配器的完整接线配方:[STORAGE.zh-CN.md](STORAGE.zh-CN.md)。
128
+
129
+ ## 7. Webhook
130
+
131
+ ```ts
132
+ // Telegraf: webhookCallback(bot, app)
133
+ // telebibz: 框架需显式指定
134
+ import { webhookCallback } from "@xbibzlibrary/telebibz";
135
+ app.post("/telegram", webhookCallback(bot, "express", { secretToken: process.env.TELEGRAM_WEBHOOK_SECRET }));
136
+ ```
137
+
138
+ `createWebhookHandler()` 另外提供 Web 标准 `Request → Response` 处理器,适配 Bun/Deno/edge。完整部署指南:[WEBHOOK.zh-CN.md](WEBHOOK.zh-CN.md)。
139
+
140
+ ## 8. 没有直接对应物的部分
141
+
142
+ - **`bot.telegram` 底层客户端** —— 使用 `bot.api`(`call`、`raw`、`methods`、`downloadFile`);flood gate 与重试内置于传输层,不能按调用配置。
143
+ - **Telegraf 插件生态** —— 把插件移植为带显式生命周期(`install`、`onStop`、`dispose`)的 `Plugin` 对象;插件管理器可干净重启。
144
+ - **`Composer.mount`/动态 scene** —— 改用 `Router` 嵌套与 `matchMode: "all"` 组合。
145
+ - **Markup 链式助手**(`Markup.keyboard(...).resize()`) —— 使用 `new ReplyKeyboard().text("A").resized().build()`;负载相同,builder 风格。
146
+
147
+ English: [MIGRATION_TELEGRAF.md](MIGRATION_TELEGRAF.md) · Bahasa Indonesia: [MIGRATION_TELEGRAF.id.md](MIGRATION_TELEGRAF.id.md)
package/docs/README.md CHANGED
@@ -1,39 +1,58 @@
1
1
  # telebibz Documentation
2
2
 
3
- The default documentation language is **English**. Translated README and API references are available below.
3
+ The default documentation language is **English**. Every guide below is available in English, Bahasa Indonesia, and 简体中文.
4
4
 
5
- | Language | README | Complete API reference |
6
- |---|---|---|
7
- | English (default) | [`README.md`](../README.md) | [`API.md`](API.md) |
8
- | Bahasa Indonesia | [`README.id.md`](../README.id.md) | [`API.id.md`](API.id.md) |
9
- | 简体中文 | [`README.zh-CN.md`](../README.zh-CN.md) | [`API.zh-CN.md`](API.zh-CN.md) |
5
+ | Language | README | Getting started | Complete API reference |
6
+ |---|---|---|---|
7
+ | English (default) | [`README.md`](../README.md) | [`GETTING_STARTED.md`](GETTING_STARTED.md) | [`API.md`](API.md) |
8
+ | Bahasa Indonesia | [`README.id.md`](../README.id.md) | [`GETTING_STARTED.id.md`](GETTING_STARTED.id.md) | [`API.id.md`](API.id.md) |
9
+ | 简体中文 | [`README.zh-CN.md`](../README.zh-CN.md) | [`GETTING_STARTED.zh-CN.md`](GETTING_STARTED.zh-CN.md) | [`API.zh-CN.md`](API.zh-CN.md) |
10
10
 
11
11
  ![telebibz overview](https://cdn.jsdelivr.net/npm/@xbibzlibrary/telebibz@latest/assets/telebibz-readme-preview.png)
12
12
 
13
- The documentation covers the complete lifecycle: onboarding, bot startup and shutdown, API client and transport, update routing, middleware and context, state/session, interaction UI, background work, deployment, testing, and migration boundaries.
13
+ The documentation covers the complete lifecycle: onboarding, bot startup and shutdown, API client and transport, update routing, middleware and context, state/session, interaction UI, background work, files, errors, webhook deployment, testing, migration, and production recipes.
14
14
 
15
- | Resource | Purpose |
16
- |---|---|
17
- | [`GETTING_STARTED.md`](GETTING_STARTED.md) | Five-minute English onboarding from installation to a working bot. |
18
- | [`GETTING_STARTED.id.md`](GETTING_STARTED.id.md) | Indonesian onboarding guide. |
19
- | [`GETTING_STARTED.zh-CN.md`](GETTING_STARTED.zh-CN.md) | Simplified Chinese onboarding guide. |
20
- | [`../examples/README.md`](../examples/README.md) | Runnable minimal, wizard, and webhook starters. |
21
- | [`../SHOWCASE.md`](../SHOWCASE.md) | Community project showcase and submission format. |
15
+ ## Complete guide catalog
16
+
17
+ Every topic guide ships in three languages (EN · ID · ZH). Pick a topic, pick a language:
18
+
19
+ | Guide | English | Bahasa Indonesia | 简体中文 | Purpose |
20
+ |---|---|---|---|---|
21
+ | Getting started | [`GETTING_STARTED.md`](GETTING_STARTED.md) | [`GETTING_STARTED.id.md`](GETTING_STARTED.id.md) | [`GETTING_STARTED.zh-CN.md`](GETTING_STARTED.zh-CN.md) | Five-minute onboarding from installation to a working bot. |
22
+ | Complete API reference | [`API.md`](API.md) | [`API.id.md`](API.id.md) | [`API.zh-CN.md`](API.zh-CN.md) | Every exported class, method, type, error, and generated Telegram method. |
23
+ | Files: upload & download | [`FILES.md`](FILES.md) | [`FILES.id.md`](FILES.id.md) | [`FILES.zh-CN.md`](FILES.zh-CN.md) | `downloadFile()`, manual `getFile()`, `file_path` vs `filePath`, upload sources, validation, limits, troubleshooting. |
24
+ | Errors | [`ERRORS.md`](ERRORS.md) | [`ERRORS.id.md`](ERRORS.id.md) | [`ERRORS.zh-CN.md`](ERRORS.zh-CN.md) | Error taxonomy, 429 and the flood gate, `bot.catch()`, `handlerTimeout`, retries, graceful shutdown. |
25
+ | Webhook | [`WEBHOOK.md`](WEBHOOK.md) | [`WEBHOOK.id.md`](WEBHOOK.id.md) | [`WEBHOOK.zh-CN.md`](WEBHOOK.zh-CN.md) | Polling vs webhook, `createWebhookHandler()`, Express/http/Fastify/Koa, `setWebhook`, secret tokens, tunnels, production checklist. |
26
+ | Testing | [`TESTING.md`](TESTING.md) | [`TESTING.id.md`](TESTING.id.md) | [`TESTING.zh-CN.md`](TESTING.zh-CN.md) | Fully offline testing with `MockTransport`, driving updates, wizards end to end, webhooks, error paths, Vitest patterns. |
27
+ | Migration from Telegraf | [`MIGRATION_TELEGRAF.md`](MIGRATION_TELEGRAF.md) | [`MIGRATION_TELEGRAF.id.md`](MIGRATION_TELEGRAF.id.md) | [`MIGRATION_TELEGRAF.zh-CN.md`](MIGRATION_TELEGRAF.zh-CN.md) | Side-by-side port, concept map, context methods, scenes → wizards, webhooks. |
28
+ | Storage | [`STORAGE.md`](STORAGE.md) | [`STORAGE.id.md`](STORAGE.id.md) | [`STORAGE.zh-CN.md`](STORAGE.zh-CN.md) | Memory/JSON/Redis/SQL/Mongo adapters, TTL, atomic `update()`. |
29
+ | Production cookbook | [`COOKBOOK.md`](COOKBOOK.md) | [`COOKBOOK.id.md`](COOKBOOK.id.md) | [`COOKBOOK.zh-CN.md`](COOKBOOK.zh-CN.md) | Thirteen verified recipes: rate limiting, auth, broadcast, scheduling, queues, menus, forms, caching, Mini Apps, payments, metrics. |
30
+ | GitHub Packages install | [`GITHUB_PACKAGES.md`](GITHUB_PACKAGES.md) | [`GITHUB_PACKAGES.id.md`](GITHUB_PACKAGES.id.md) | [`GITHUB_PACKAGES.zh-CN.md`](GITHUB_PACKAGES.zh-CN.md) | Installing via GitHub Packages with a personal access token. |
31
+
32
+ Also available: [`../examples/README.md`](../examples/README.md) — runnable minimal, wizard, file, and webhook starters, and [`../SHOWCASE.md`](../SHOWCASE.md) — community project showcase.
33
+
34
+ ## Coverage status
22
35
 
23
36
  | Area | Status |
24
37
  |---|---|
25
- | Getting started | Dedicated guides are available in English, Indonesian, and Simplified Chinese, with runnable examples. |
26
- | Complete API reference | Available in English, Indonesian, and Simplified Chinese |
38
+ | Getting started | Dedicated guides in EN/ID/ZH with runnable examples |
39
+ | Complete API reference | Available in EN/ID/ZH |
27
40
  | Bot lifecycle, polling, webhook | Core implementation, per-update error isolation, reconnect backoff, and tests available |
28
- | API client and generated method list | Available; full vendored Telegram declarations are exposed through `TelegramTypes` |
41
+ | API client and generated method list | Available; full vendored Telegram declarations exposed through `TelegramTypes` |
29
42
  | Router, middleware, context | Available and tested; first-match is default, all-match is explicit |
30
43
  | Keyboard, callback, menus, pagination | Keyboard/callback core, permission menus, MenuController, and pagination available |
31
44
  | Sessions, conversations, wizards, forms | Storage-backed session/conversation primitives and forms available; scene orchestration remains application-owned |
32
45
  | Storage, cache, queue, scheduler | Memory, JSON file, Redis, SQL, Mongo driver adapters, cache, queue, and full five-field cron available |
46
+ | Files | Dedicated guide: one-call `downloadFile()`, upload sources, validation, limits, troubleshooting (EN/ID/ZH) |
47
+ | Errors | Dedicated guide: taxonomy, 429/flood gate, boundaries, timeouts, retries (EN/ID/ZH) |
48
+ | Webhook deployment | Dedicated guide: handler, four frameworks, registration, secrets, tunnels, checklist (EN/ID/ZH) |
49
+ | Testing | Dedicated guide: MockTransport, update drivers, wizards, webhooks, error paths (EN/ID/ZH) |
50
+ | Migration | Dedicated Telegraf migration guide (EN/ID/ZH) |
51
+ | Production recipes | Cookbook with thirteen verified recipes (EN/ID/ZH) |
33
52
  | Plugins, services, observability | Lifecycle/plugin/service hooks available |
34
53
  | Mini Apps, payments, business features | Web App signature validation and PaymentsClient wrappers available; UI is application-owned |
35
54
  | Testing and security | Unit, integration, type-level, gated E2E, CI, and security policy available |
36
- | Deployment and migration | Release automation is documented in `RELEASE_AUTOMATION.md`; webhook and deployment onboarding is in `GETTING_STARTED.md` |
55
+ | Deployment and migration | Release automation is documented in `RELEASE_AUTOMATION.md`; webhook deployment is in `WEBHOOK.md` |
37
56
  | Governance and community | `CODE_OF_CONDUCT.md`, `GOVERNANCE.md`, `CONTRIBUTING.md`, `CONTRIBUTION_RULES.md`, and `SHOWCASE.md` |
38
57
  | Security and support | `SECURITY.md` and `SUPPORT.md` |
39
58
  | Third-party notices | `NOTICE.md` and `LICENSE` |
@@ -45,4 +64,4 @@ Issue forms are available for bug reports, feature requests, documentation probl
45
64
 
46
65
  ## Documentation principle
47
66
 
48
- The documentation describes only capabilities that are implemented and tested in the current package. Telegram-native API access, Mini App/Web App behavior, external persistence, and distributed adapters are described separately so the documentation does not promise features that are not included.
67
+ The documentation describes only capabilities that are implemented and tested in the current package, and every code snippet in the guides is verified against the actual implementation. Telegram-native API access, Mini App/Web App behavior, external persistence, and distributed adapters are described separately so the documentation does not promise features that are not included.
@@ -0,0 +1,105 @@
1
+ # Panduan cepat storage (Bahasa Indonesia)
2
+
3
+ telebibz menyediakan interface `Storage<K, V>` generik dengan lima adapter. Core package **tanpa runtime dependency**: adapter Redis, SQL, dan Mongo menerima driver interface kecil yang sudah Anda punya, jadi Anda yang memilih driver dan versinya.
4
+
5
+ Semua adapter memakai kontrak yang sama — `get` / `set` / `delete` / `has` / `clear` / `keys()` / `entries()` — ditambah **`update(key, updater, { ttlMs })`** yang menyalin penulisan per key sehingga update bersamaan ke key yang sama tidak pernah saling menimpa. TTL diatur per penulisan lewat `{ ttlMs }`.
6
+
7
+ ## MemoryStorage (default — tanpa konfigurasi)
8
+
9
+ ```ts
10
+ import { Bot } from "@xbibzlibrary/telebibz";
11
+
12
+ const bot = new Bot({ token: process.env.TELEGRAM_BOT_TOKEN! });
13
+ // bot.session secara default adalah MemoryStorage<string, S>.
14
+ ```
15
+
16
+ ## JsonFileStorage (persistensi satu file, tetap tanpa dependency)
17
+
18
+ ```ts
19
+ import { Bot, JsonFileStorage } from "@xbibzlibrary/telebibz";
20
+
21
+ const bot = new Bot({
22
+ token: process.env.TELEGRAM_BOT_TOKEN!,
23
+ session: new JsonFileStorage("state/sessions.json"),
24
+ });
25
+ ```
26
+
27
+ ## RedisStorage (bawa client Anda sendiri)
28
+
29
+ Adapter ini hanya butuh lima method callback-style yang dimiliki setiap client Redis — `node-redis` langsung cocok:
30
+
31
+ ```ts
32
+ import { Bot, RedisStorage } from "@xbibzlibrary/telebibz";
33
+ import { createClient } from "redis"; // driver dan versi pilihan Anda
34
+
35
+ const redis = createClient({ url: process.env.REDIS_URL });
36
+ await redis.connect();
37
+
38
+ const bot = new Bot({
39
+ token: process.env.TELEGRAM_BOT_TOKEN!,
40
+ session: new RedisStorage(redis, "mybot:"), // prefix untuk key Anda
41
+ });
42
+ // TTL per penulisan: await bot.session.set(key, value, { ttlMs: 24 * 60 * 60 * 1000 });
43
+ // (kedaluwarsa PX Redis diterapkan otomatis.)
44
+ ```
45
+
46
+ ## SqlStorage (semua database SQL)
47
+
48
+ Implementasikan driver lima method di atas library SQL Anda; contoh ini memakai `better-sqlite3`:
49
+
50
+ ```ts
51
+ import { Bot, SqlStorage } from "@xbibzlibrary/telebibz";
52
+ import Database from "better-sqlite3";
53
+
54
+ const db = new Database("state/bot.db");
55
+ db.exec("CREATE TABLE IF NOT EXISTS kv (key TEXT PRIMARY KEY, value TEXT NOT NULL, expires_at INTEGER)");
56
+
57
+ const storage = new SqlStorage({
58
+ async get(key) {
59
+ const row = db.prepare("SELECT value, expires_at FROM kv WHERE key = ?").get(key) as { value: string; expires_at: number | null } | undefined;
60
+ return row === undefined ? undefined : JSON.parse(row.value);
61
+ },
62
+ async set(key, value, expiresAt) {
63
+ db.prepare("INSERT INTO kv (key, value, expires_at) VALUES (?, ?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value, expires_at = excluded.expires_at")
64
+ .run(key, JSON.stringify(value), expiresAt ?? null);
65
+ },
66
+ async delete(key) { return db.prepare("DELETE FROM kv WHERE key = ?").run(key).changes > 0; },
67
+ async has(key) { return db.prepare("SELECT 1 FROM kv WHERE key = ?").get(key) !== undefined; },
68
+ async clear() { db.prepare("DELETE FROM kv").run(); },
69
+ async entries() {
70
+ const rows = db.prepare("SELECT key, value, expires_at FROM kv").all() as Array<{ key: string; value: string; expires_at: number | null }>;
71
+ return rows.map((row) => [row.key, JSON.parse(row.value), row.expiresAt ?? undefined] as [string, unknown, number | undefined]);
72
+ },
73
+ });
74
+
75
+ const bot = new Bot({ token: process.env.TELEGRAM_BOT_TOKEN!, session: storage });
76
+ ```
77
+
78
+ ## MongoStorage (bawa collection Anda sendiri)
79
+
80
+ Adapter ini berbicara langsung dengan bentuk collection MongoDB standar — cukup kirim collection Anda:
81
+
82
+ ```ts
83
+ import { Bot, MongoStorage } from "@xbibzlibrary/telebibz";
84
+ import { MongoClient } from "mongodb";
85
+
86
+ const client = new MongoClient(process.env.MONGODB_URL!);
87
+ await client.connect();
88
+
89
+ const bot = new Bot({
90
+ token: process.env.TELEGRAM_BOT_TOKEN!,
91
+ session: new MongoStorage(client.db("mybot").collection("sessions")),
92
+ });
93
+ ```
94
+
95
+ ## Memilih
96
+
97
+ | Adapter | Pakai saat | Persistensi | Dependency tambahan |
98
+ |---|---|---|---|
99
+ | `MemoryStorage` | bot satu proses, test | selama proses hidup | tidak ada |
100
+ | `JsonFileStorage` | bot kecil, deploy sederhana | file di disk | tidak ada |
101
+ | `RedisStorage` | multi-instance, state bersama | Redis | client Redis Anda |
102
+ | `SqlStorage` | aplikasi berbasis SQL | semua database SQL | driver SQL Anda |
103
+ | `MongoStorage` | stack Mongo yang sudah ada | MongoDB | driver Mongo Anda |
104
+
105
+ Signature API lengkap: [API.id.md](API.id.md). English: [STORAGE.md](STORAGE.md) · 简体中文: [STORAGE.zh-CN.md](STORAGE.zh-CN.md).
@@ -0,0 +1,105 @@
1
+ # Storage quick start (English)
2
+
3
+ telebibz ships a generic `Storage<K, V>` interface with five adapters. The core package has **zero runtime dependencies**: the Redis, SQL, and Mongo adapters accept a small driver interface you already have, so you pick the driver and version.
4
+
5
+ All adapters share one contract — `get` / `set` / `delete` / `has` / `clear` / `keys()` / `entries()` — plus **`update(key, updater, { ttlMs })`**, which serializes writes per key so concurrent updates to the same key never interleave. TTL is set per write through `{ ttlMs }`.
6
+
7
+ ## MemoryStorage (default — nothing to configure)
8
+
9
+ ```ts
10
+ import { Bot } from "@xbibzlibrary/telebibz";
11
+
12
+ const bot = new Bot({ token: process.env.TELEGRAM_BOT_TOKEN! });
13
+ // bot.session is a MemoryStorage<string, S> by default.
14
+ ```
15
+
16
+ ## JsonFileStorage (single-file persistence, still zero dependencies)
17
+
18
+ ```ts
19
+ import { Bot, JsonFileStorage } from "@xbibzlibrary/telebibz";
20
+
21
+ const bot = new Bot({
22
+ token: process.env.TELEGRAM_BOT_TOKEN!,
23
+ session: new JsonFileStorage("state/sessions.json"),
24
+ });
25
+ ```
26
+
27
+ ## RedisStorage (bring your own client)
28
+
29
+ The adapter needs exactly the five callback-style methods every Redis client exposes — `node-redis` works as-is:
30
+
31
+ ```ts
32
+ import { Bot, RedisStorage } from "@xbibzlibrary/telebibz";
33
+ import { createClient } from "redis"; // your choice of driver and version
34
+
35
+ const redis = createClient({ url: process.env.REDIS_URL });
36
+ await redis.connect();
37
+
38
+ const bot = new Bot({
39
+ token: process.env.TELEGRAM_BOT_TOKEN!,
40
+ session: new RedisStorage(redis, "mybot:"), // prefix for your keys
41
+ });
42
+ // Per-write TTL: await bot.session.set(key, value, { ttlMs: 24 * 60 * 60 * 1000 });
43
+ // (Redis PX expiry is applied automatically.)
44
+ ```
45
+
46
+ ## SqlStorage (any SQL database)
47
+
48
+ Implement the five-method driver over your SQL library; the example uses `better-sqlite3`:
49
+
50
+ ```ts
51
+ import { Bot, SqlStorage } from "@xbibzlibrary/telebibz";
52
+ import Database from "better-sqlite3";
53
+
54
+ const db = new Database("state/bot.db");
55
+ db.exec("CREATE TABLE IF NOT EXISTS kv (key TEXT PRIMARY KEY, value TEXT NOT NULL, expires_at INTEGER)");
56
+
57
+ const storage = new SqlStorage({
58
+ async get(key) {
59
+ const row = db.prepare("SELECT value, expires_at FROM kv WHERE key = ?").get(key) as { value: string; expires_at: number | null } | undefined;
60
+ return row === undefined ? undefined : JSON.parse(row.value);
61
+ },
62
+ async set(key, value, expiresAt) {
63
+ db.prepare("INSERT INTO kv (key, value, expires_at) VALUES (?, ?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value, expires_at = excluded.expires_at")
64
+ .run(key, JSON.stringify(value), expiresAt ?? null);
65
+ },
66
+ async delete(key) { return db.prepare("DELETE FROM kv WHERE key = ?").run(key).changes > 0; },
67
+ async has(key) { return db.prepare("SELECT 1 FROM kv WHERE key = ?").get(key) !== undefined; },
68
+ async clear() { db.prepare("DELETE FROM kv").run(); },
69
+ async entries() {
70
+ const rows = db.prepare("SELECT key, value, expires_at FROM kv").all() as Array<{ key: string; value: string; expires_at: number | null }>;
71
+ return rows.map((row) => [row.key, JSON.parse(row.value), row.expiresAt ?? undefined] as [string, unknown, number | undefined]);
72
+ },
73
+ });
74
+
75
+ const bot = new Bot({ token: process.env.TELEGRAM_BOT_TOKEN!, session: storage });
76
+ ```
77
+
78
+ ## MongoStorage (bring your own collection)
79
+
80
+ The adapter talks to a standard MongoDB collection shape — pass your collection directly:
81
+
82
+ ```ts
83
+ import { Bot, MongoStorage } from "@xbibzlibrary/telebibz";
84
+ import { MongoClient } from "mongodb";
85
+
86
+ const client = new MongoClient(process.env.MONGODB_URL!);
87
+ await client.connect();
88
+
89
+ const bot = new Bot({
90
+ token: process.env.TELEGRAM_BOT_TOKEN!,
91
+ session: new MongoStorage(client.db("mybot").collection("sessions")),
92
+ });
93
+ ```
94
+
95
+ ## Choosing
96
+
97
+ | Adapter | Use when | Persistence | Extra dependency |
98
+ |---|---|---|---|
99
+ | `MemoryStorage` | single-process bots, tests | process lifetime | none |
100
+ | `JsonFileStorage` | small bots, simple deploys | file on disk | none |
101
+ | `RedisStorage` | multi-instance, shared state | Redis | your Redis client |
102
+ | `SqlStorage` | SQL-backed apps | any SQL database | your SQL driver |
103
+ | `MongoStorage` | existing Mongo stack | MongoDB | your Mongo driver |
104
+
105
+ Full API signatures: [API.md](API.md). Bahasa Indonesia: [STORAGE.id.md](STORAGE.id.md) · 简体中文: [STORAGE.zh-CN.md](STORAGE.zh-CN.md).