@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.
- package/CHANGELOG.md +35 -138
- package/LICENSE +1 -1
- package/NOTICE.md +9 -4
- package/README.md +173 -242
- package/examples/01-quickstart.js +13 -0
- package/examples/02-menu-tombol.js +22 -0
- package/examples/03-wizard.js +29 -0
- package/examples/04-broadcast.js +25 -0
- package/examples/05-kirim-file.js +19 -0
- package/examples/06-menu.js +35 -0
- package/examples/07-inline-query.js +18 -0
- package/index.d.ts +81 -0
- package/index.js +42 -0
- package/lib/api.js +154 -0
- package/lib/broadcast.js +35 -0
- package/lib/composer.js +174 -0
- package/lib/context.js +190 -0
- package/lib/errors.js +35 -0
- package/lib/file.js +41 -0
- package/lib/inline-query.js +28 -0
- package/lib/keyboard.js +83 -0
- package/lib/logger.js +38 -0
- package/lib/menus.js +90 -0
- package/lib/net.js +115 -0
- package/lib/ratelimit.js +61 -0
- package/lib/runner.js +45 -0
- package/lib/session.js +36 -0
- package/lib/telebibz.js +190 -0
- package/lib/wizard.js +81 -0
- package/package.json +35 -97
- package/test/all.test.js +334 -0
- package/CODE_OF_CONDUCT.md +0 -37
- package/CONTRIBUTING.md +0 -59
- package/CONTRIBUTION_RULES.md +0 -41
- package/GOVERNANCE.md +0 -47
- package/README.id.md +0 -292
- package/README.zh-CN.md +0 -292
- package/RELEASE_AUTOMATION.md +0 -78
- package/RELEASE_POLICY.md +0 -32
- package/SECURITY.md +0 -47
- package/SHOWCASE.md +0 -29
- package/SUPPORT.md +0 -30
- package/assets/readme-preview.html +0 -75
- package/assets/telebibz-logo.png +0 -0
- package/assets/telebibz-readme-preview.png +0 -0
- package/bin/telebibz.mjs +0 -3
- package/dist/generated/api.d.ts +0 -13
- package/dist/generated/api.d.ts.map +0 -1
- package/dist/generated/api.js +0 -192
- package/dist/generated/api.js.map +0 -1
- package/dist/src/api/client.d.ts +0 -62
- package/dist/src/api/client.d.ts.map +0 -1
- package/dist/src/api/client.js +0 -104
- package/dist/src/api/client.js.map +0 -1
- package/dist/src/api/errors.d.ts +0 -45
- package/dist/src/api/errors.d.ts.map +0 -1
- package/dist/src/api/errors.js +0 -65
- package/dist/src/api/errors.js.map +0 -1
- package/dist/src/api/index.d.ts +0 -6
- package/dist/src/api/index.d.ts.map +0 -1
- package/dist/src/api/index.js +0 -6
- package/dist/src/api/index.js.map +0 -1
- package/dist/src/api/telegram-types/LICENSE +0 -21
- package/dist/src/api/telegram-types/api.d.ts +0 -22
- package/dist/src/api/telegram-types/checklist.d.ts +0 -72
- package/dist/src/api/telegram-types/inline.d.ts +0 -692
- package/dist/src/api/telegram-types/langs.d.ts +0 -193
- package/dist/src/api/telegram-types/manage.d.ts +0 -1144
- package/dist/src/api/telegram-types/markup.d.ts +0 -268
- package/dist/src/api/telegram-types/message.d.ts +0 -1537
- package/dist/src/api/telegram-types/methods.d.ts +0 -2870
- package/dist/src/api/telegram-types/mod.d.ts +0 -14
- package/dist/src/api/telegram-types/passport.d.ts +0 -163
- package/dist/src/api/telegram-types/payment.d.ts +0 -570
- package/dist/src/api/telegram-types/rich.d.ts +0 -1010
- package/dist/src/api/telegram-types/settings.d.ts +0 -120
- package/dist/src/api/telegram-types/story.d.ts +0 -89
- package/dist/src/api/telegram-types/update.d.ts +0 -84
- package/dist/src/api/telegram.d.ts +0 -7
- package/dist/src/api/telegram.d.ts.map +0 -1
- package/dist/src/api/telegram.js +0 -2
- package/dist/src/api/telegram.js.map +0 -1
- package/dist/src/api/transport.d.ts +0 -68
- package/dist/src/api/transport.d.ts.map +0 -1
- package/dist/src/api/transport.js +0 -264
- package/dist/src/api/transport.js.map +0 -1
- package/dist/src/api/types.d.ts +0 -466
- package/dist/src/api/types.d.ts.map +0 -1
- package/dist/src/api/types.js +0 -2
- package/dist/src/api/types.js.map +0 -1
- package/dist/src/branding/terminal.d.ts +0 -77
- package/dist/src/branding/terminal.d.ts.map +0 -1
- package/dist/src/branding/terminal.js +0 -328
- package/dist/src/branding/terminal.js.map +0 -1
- package/dist/src/broadcast/broadcast.d.ts +0 -50
- package/dist/src/broadcast/broadcast.d.ts.map +0 -1
- package/dist/src/broadcast/broadcast.js +0 -56
- package/dist/src/broadcast/broadcast.js.map +0 -1
- package/dist/src/cache/cache.d.ts +0 -34
- package/dist/src/cache/cache.d.ts.map +0 -1
- package/dist/src/cache/cache.js +0 -41
- package/dist/src/cache/cache.js.map +0 -1
- package/dist/src/cli.d.ts +0 -2
- package/dist/src/cli.d.ts.map +0 -1
- package/dist/src/cli.js +0 -84
- package/dist/src/cli.js.map +0 -1
- package/dist/src/context/context.d.ts +0 -124
- package/dist/src/context/context.d.ts.map +0 -1
- package/dist/src/context/context.js +0 -302
- package/dist/src/context/context.js.map +0 -1
- package/dist/src/core/bot.d.ts +0 -204
- package/dist/src/core/bot.d.ts.map +0 -1
- package/dist/src/core/bot.js +0 -506
- package/dist/src/core/bot.js.map +0 -1
- package/dist/src/core/events.d.ts +0 -75
- package/dist/src/core/events.d.ts.map +0 -1
- package/dist/src/core/events.js +0 -35
- package/dist/src/core/events.js.map +0 -1
- package/dist/src/core/webhook-reply.d.ts +0 -34
- package/dist/src/core/webhook-reply.d.ts.map +0 -1
- package/dist/src/core/webhook-reply.js +0 -37
- package/dist/src/core/webhook-reply.js.map +0 -1
- package/dist/src/index.d.ts +0 -24
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js +0 -24
- package/dist/src/index.js.map +0 -1
- package/dist/src/keyboard/index.d.ts +0 -46
- package/dist/src/keyboard/index.d.ts.map +0 -1
- package/dist/src/keyboard/index.js +0 -55
- package/dist/src/keyboard/index.js.map +0 -1
- package/dist/src/middleware/compose.d.ts +0 -5
- package/dist/src/middleware/compose.d.ts.map +0 -1
- package/dist/src/middleware/compose.js +0 -17
- package/dist/src/middleware/compose.js.map +0 -1
- package/dist/src/observability/logger.d.ts +0 -78
- package/dist/src/observability/logger.d.ts.map +0 -1
- package/dist/src/observability/logger.js +0 -285
- package/dist/src/observability/logger.js.map +0 -1
- package/dist/src/plugins/plugin.d.ts +0 -38
- package/dist/src/plugins/plugin.d.ts.map +0 -1
- package/dist/src/plugins/plugin.js +0 -59
- package/dist/src/plugins/plugin.js.map +0 -1
- package/dist/src/queue/queue.d.ts +0 -77
- package/dist/src/queue/queue.d.ts.map +0 -1
- package/dist/src/queue/queue.js +0 -213
- package/dist/src/queue/queue.js.map +0 -1
- package/dist/src/router/router.d.ts +0 -61
- package/dist/src/router/router.d.ts.map +0 -1
- package/dist/src/router/router.js +0 -183
- package/dist/src/router/router.js.map +0 -1
- package/dist/src/state/conversation.d.ts +0 -56
- package/dist/src/state/conversation.d.ts.map +0 -1
- package/dist/src/state/conversation.js +0 -133
- package/dist/src/state/conversation.js.map +0 -1
- package/dist/src/state/forms.d.ts +0 -34
- package/dist/src/state/forms.d.ts.map +0 -1
- package/dist/src/state/forms.js +0 -44
- package/dist/src/state/forms.js.map +0 -1
- package/dist/src/state/menu.d.ts +0 -78
- package/dist/src/state/menu.d.ts.map +0 -1
- package/dist/src/state/menu.js +0 -127
- package/dist/src/state/menu.js.map +0 -1
- package/dist/src/storage/storage.d.ts +0 -146
- package/dist/src/storage/storage.d.ts.map +0 -1
- package/dist/src/storage/storage.js +0 -195
- package/dist/src/storage/storage.js.map +0 -1
- package/dist/src/telegram-features.d.ts +0 -33
- package/dist/src/telegram-features.d.ts.map +0 -1
- package/dist/src/telegram-features.js +0 -71
- package/dist/src/telegram-features.js.map +0 -1
- package/dist/src/testing.d.ts +0 -24
- package/dist/src/testing.d.ts.map +0 -1
- package/dist/src/testing.js +0 -38
- package/dist/src/testing.js.map +0 -1
- package/dist/src/utils/concurrency.d.ts +0 -25
- package/dist/src/utils/concurrency.d.ts.map +0 -1
- package/dist/src/utils/concurrency.js +0 -52
- package/dist/src/utils/concurrency.js.map +0 -1
- package/dist/src/utils/files.d.ts +0 -45
- package/dist/src/utils/files.d.ts.map +0 -1
- package/dist/src/utils/files.js +0 -53
- package/dist/src/utils/files.js.map +0 -1
- package/dist/src/utils/text.d.ts +0 -39
- package/dist/src/utils/text.d.ts.map +0 -1
- package/dist/src/utils/text.js +0 -56
- package/dist/src/utils/text.js.map +0 -1
- package/dist/src/webhook/handler.d.ts +0 -19
- package/dist/src/webhook/handler.d.ts.map +0 -1
- package/dist/src/webhook/handler.js +0 -141
- package/dist/src/webhook/handler.js.map +0 -1
- package/dist-cjs/generated/api.js +0 -194
- package/dist-cjs/package.json +0 -3
- package/dist-cjs/src/api/client.js +0 -107
- package/dist-cjs/src/api/errors.js +0 -74
- package/dist-cjs/src/api/index.js +0 -21
- package/dist-cjs/src/api/telegram-types/LICENSE +0 -21
- package/dist-cjs/src/api/telegram-types/api.d.ts +0 -22
- package/dist-cjs/src/api/telegram-types/checklist.d.ts +0 -72
- package/dist-cjs/src/api/telegram-types/inline.d.ts +0 -692
- package/dist-cjs/src/api/telegram-types/langs.d.ts +0 -193
- package/dist-cjs/src/api/telegram-types/manage.d.ts +0 -1144
- package/dist-cjs/src/api/telegram-types/markup.d.ts +0 -268
- package/dist-cjs/src/api/telegram-types/message.d.ts +0 -1537
- package/dist-cjs/src/api/telegram-types/methods.d.ts +0 -2870
- package/dist-cjs/src/api/telegram-types/mod.d.ts +0 -14
- package/dist-cjs/src/api/telegram-types/passport.d.ts +0 -163
- package/dist-cjs/src/api/telegram-types/payment.d.ts +0 -570
- package/dist-cjs/src/api/telegram-types/rich.d.ts +0 -1010
- package/dist-cjs/src/api/telegram-types/settings.d.ts +0 -120
- package/dist-cjs/src/api/telegram-types/story.d.ts +0 -89
- package/dist-cjs/src/api/telegram-types/update.d.ts +0 -84
- package/dist-cjs/src/api/telegram.js +0 -2
- package/dist-cjs/src/api/transport.js +0 -267
- package/dist-cjs/src/api/types.js +0 -2
- package/dist-cjs/src/branding/terminal.js +0 -338
- package/dist-cjs/src/broadcast/broadcast.js +0 -58
- package/dist-cjs/src/cache/cache.js +0 -45
- package/dist-cjs/src/cli.js +0 -86
- package/dist-cjs/src/context/context.js +0 -305
- package/dist-cjs/src/core/bot.js +0 -510
- package/dist-cjs/src/core/events.js +0 -38
- package/dist-cjs/src/core/webhook-reply.js +0 -42
- package/dist-cjs/src/index.js +0 -47
- package/dist-cjs/src/keyboard/index.js +0 -61
- package/dist-cjs/src/middleware/compose.js +0 -20
- package/dist-cjs/src/observability/logger.js +0 -293
- package/dist-cjs/src/plugins/plugin.js +0 -63
- package/dist-cjs/src/queue/queue.js +0 -219
- package/dist-cjs/src/router/router.js +0 -186
- package/dist-cjs/src/state/conversation.js +0 -139
- package/dist-cjs/src/state/forms.js +0 -47
- package/dist-cjs/src/state/menu.js +0 -133
- package/dist-cjs/src/storage/storage.js +0 -202
- package/dist-cjs/src/telegram-features.js +0 -76
- package/dist-cjs/src/testing.js +0 -45
- package/dist-cjs/src/utils/concurrency.js +0 -57
- package/dist-cjs/src/utils/files.js +0 -58
- package/dist-cjs/src/utils/text.js +0 -63
- package/dist-cjs/src/webhook/handler.js +0 -144
- package/docs/API.id.md +0 -1935
- package/docs/API.md +0 -1969
- package/docs/API.zh-CN.md +0 -1929
- package/docs/GETTING_STARTED.id.md +0 -85
- package/docs/GETTING_STARTED.md +0 -85
- package/docs/GETTING_STARTED.zh-CN.md +0 -85
- package/docs/GITHUB_PACKAGES.id.md +0 -82
- package/docs/GITHUB_PACKAGES.md +0 -82
- package/docs/GITHUB_PACKAGES.zh-CN.md +0 -82
- package/docs/README.md +0 -48
- package/docs/STORAGE.id.md +0 -105
- package/docs/STORAGE.md +0 -105
- package/docs/STORAGE.zh-CN.md +0 -105
- package/examples/README.md +0 -37
- package/examples/files.ts +0 -35
- package/examples/minimal.ts +0 -12
- package/examples/tsconfig.json +0 -9
- package/examples/webhook.ts +0 -42
- package/examples/wizard-registration.ts +0 -42
package/docs/API.id.md
DELETED
|
@@ -1,1935 +0,0 @@
|
|
|
1
|
-
# Referensi API telebibz — Bahasa Indonesia
|
|
2
|
-
|
|
3
|
-
[English](API.md) · **Bahasa Indonesia** · [简体中文](API.zh-CN.md)
|
|
4
|
-
|
|
5
|
-

|
|
6
|
-
|
|
7
|
-
Dokumen ini adalah referensi API untuk rilis `@xbibzlibrary/telebibz` yang sedang dipublikasikan. Seluruh signature dan perilaku yang dijelaskan di sini dipetakan dari source TypeScript yang diekspor package. Jika suatu tipe Telegram belum memiliki pemetaan parameter/result khusus, package tetap menyediakan akses runtime melalui API dinamis, tetapi tipe parameternya masih generik.
|
|
8
|
-
|
|
9
|
-
> **Status implementasi.** Dokumentasi ini menjelaskan kemampuan yang tersedia pada rilis saat ini. `JsonFileStorage`, storage Redis/SQL/Mongo berbasis driver, session/conversation berbasis Storage, cron lima field lengkap, `MenuController`, terminal status output branded, structured logging dengan redaction, validasi Web App, `PaymentsClient`, dan declaration `TelegramTypes` sudah tersedia. Core method map tetap khusus untuk inferensi request/result tertentu, sedangkan `api.raw()` tersedia untuk method Telegram berikutnya.
|
|
10
|
-
|
|
11
|
-
## Instalasi dan import
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
npm install @xbibzlibrary/telebibz
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
ESM:
|
|
18
|
-
|
|
19
|
-
```ts
|
|
20
|
-
import {
|
|
21
|
-
Bot,
|
|
22
|
-
InlineKeyboard,
|
|
23
|
-
compose,
|
|
24
|
-
escapeHtml,
|
|
25
|
-
type Context,
|
|
26
|
-
} from "@xbibzlibrary/telebibz";
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
CommonJS:
|
|
30
|
-
|
|
31
|
-
```js
|
|
32
|
-
const { Bot, InlineKeyboard } = require("@xbibzlibrary/telebibz");
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
Subpath exports yang tersedia adalah sebagai berikut.
|
|
36
|
-
|
|
37
|
-
| Subpath | Isi |
|
|
38
|
-
|---|---|
|
|
39
|
-
| `@xbibzlibrary/telebibz` | Seluruh public API utama dari `src/index.ts` |
|
|
40
|
-
| `@xbibzlibrary/telebibz/api` | Client, transport, errors, dan semua tipe API Telegram |
|
|
41
|
-
| `@xbibzlibrary/telebibz/keyboard` | `InlineKeyboard`, `ReplyKeyboard`, dan helpers keyboard |
|
|
42
|
-
| `@xbibzlibrary/telebibz/testing` | `MockTransport` dan test factories |
|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
## 1. Bot inti
|
|
47
|
-
|
|
48
|
-
### `BotStatus`
|
|
49
|
-
|
|
50
|
-
```ts
|
|
51
|
-
type BotStatus =
|
|
52
|
-
| "created"
|
|
53
|
-
| "initialized"
|
|
54
|
-
| "starting"
|
|
55
|
-
| "running"
|
|
56
|
-
| "stopping"
|
|
57
|
-
| "stopped"
|
|
58
|
-
| "error";
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### `BotOptions<S>`
|
|
62
|
-
|
|
63
|
-
| Properti | Tipe | Default | Keterangan |
|
|
64
|
-
|---|---|---:|---|
|
|
65
|
-
| `token` | `string` | wajib | Token BotFather dengan format `<digits>:<token>`. |
|
|
66
|
-
| `apiBaseUrl` | `string` | `https://api.telegram.org` | Base URL API Telegram. Akhiran `/` dihapus secara otomatis. |
|
|
67
|
-
| `transport` | `Transport` | `FetchTransport` | Transport kustom untuk mock, proxy, atau implementasi lain. |
|
|
68
|
-
| `transportOptions` | `Omit<FetchTransportOptions, "baseUrl">` | `{}` | Timeout, retry, backoff, jitter, headers, dan fetch implementation. |
|
|
69
|
-
| `session` | `Storage<string, S>` | storage baru | Penyimpanan session berdasarkan kunci chat/user; dapat memakai adapter persistent. |
|
|
70
|
-
| `services` | `Record<string, unknown>` | `{}` | Dependency/service yang tersedia melalui `ctx.services`. |
|
|
71
|
-
| `branding` | `boolean` | `true` | Pengalaman startup terminal: efek ketik, glass progress bar, banner rainbow animasi `Tele Bibz`, dan baris update yang mudah dibaca. Hanya dirender pada TTY interaktif. |
|
|
72
|
-
| `polling.timeout` | `number` | `30` | Long-poll timeout dalam detik untuk `getUpdates`. |
|
|
73
|
-
| `polling.limit` | `number` | `100` | Jumlah maksimum update per request polling. |
|
|
74
|
-
| `polling.allowedUpdates` | `string[]` | `[]` | Filter update Telegram. |
|
|
75
|
-
| `polling.retryDelayMs` | `number` | `500` | Delay awal ketika polling gagal. |
|
|
76
|
-
| `polling.maxRetryDelayMs` | `number` | `30000` | Batas maksimum delay reconnect. |
|
|
77
|
-
| `updates.concurrency` | `number` | `Infinity` | Batas jumlah update yang diproses bersamaan. Update selalu berjalan paralel antar chat dan tetap berurutan di dalam satu chat, sehingga burst 1000+ pesan tertangani sekaligus. |
|
|
78
|
-
| `handlerTimeout` | `number` | `90000` | Timeout pemrosesan per update dalam ms (`Infinity` untuk menonaktifkan). Saat timeout, alur error update berjalan (`update:error`, `bot:error`, boundary `catch()`) dan `handleUpdate()` melempar `UpdateTimeoutError`, sementara handler tetap berjalan sampai selesai di background. |
|
|
79
|
-
| `contextType` | `new (options: ContextOptions<S>) => Context<S>` | `Context` | Subclass `Context` kustom yang diinstansiasi untuk setiap update (`contextType` milik Telegraf). |
|
|
80
|
-
|
|
81
|
-
### Konstruktor `Bot`
|
|
82
|
-
|
|
83
|
-
```ts
|
|
84
|
-
new Bot<S extends object = Record<string, unknown>>(
|
|
85
|
-
options: string | BotOptions<S>,
|
|
86
|
-
): Bot<S>
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
Jika argumen berupa string, string tersebut dianggap sebagai token. Konstruktor membuat `ApiClient`, router, event bus, plugin manager, session storage, dan structured runtime logging yang selalu aktif. Konstruktor langsung memancarkan event `bot:created` secara asinkron.
|
|
90
|
-
|
|
91
|
-
Konstruktor melempar `Error` jika token kosong atau tidak sesuai pola token Telegram.
|
|
92
|
-
|
|
93
|
-
### Properti dan getter `Bot`
|
|
94
|
-
|
|
95
|
-
| API | Tipe | Deskripsi |
|
|
96
|
-
|---|---|---|
|
|
97
|
-
| `api` | `ApiClient` | Client Telegram typed/dynamic. |
|
|
98
|
-
| `router` | `Router<Context<S>>` | Router utama bot. |
|
|
99
|
-
| `events` | `EventBus<EventMap>` | Event bus untuk lifecycle, update, API, webhook, dan polling. |
|
|
100
|
-
| `plugins` | `PluginManager<Context<S>>` | Manajer lifecycle plugin. |
|
|
101
|
-
| `session` | `Storage<string, S>` | Session bot; dapat memakai adapter persistent. |
|
|
102
|
-
| `services` | `Record<string, unknown>` | Salinan service yang diberikan saat konstruktor. |
|
|
103
|
-
| `token` | `string` | Token bot yang dipakai client. |
|
|
104
|
-
| `status` | `BotStatus` | Status lifecycle terkini. |
|
|
105
|
-
| `botInfo` | `User \| undefined` | Hasil `getMe()` terakhir yang tersimpan. |
|
|
106
|
-
|
|
107
|
-
### `bot.use(...middleware)`
|
|
108
|
-
|
|
109
|
-
```ts
|
|
110
|
-
use(...middleware: Middleware<Context<S>>[]): this
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
Menambahkan middleware global. Middleware dijalankan sebelum router pada setiap update, sesuai urutan registrasi. Mengembalikan instance bot untuk chaining.
|
|
114
|
-
|
|
115
|
-
### `bot.command(name, handler)`
|
|
116
|
-
|
|
117
|
-
```ts
|
|
118
|
-
command(name: string, handler: Middleware<Context<S>>): this
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
Mendaftarkan command Telegram tanpa awalan `/` maupun dengan awalan `/`. Pencocokan mengambil token pertama setelah `/` dan mengabaikan bot mention setelah `@`. Contoh `/start@my_bot` cocok dengan `"start"`.
|
|
122
|
-
|
|
123
|
-
### `bot.callback(pattern, handler)`
|
|
124
|
-
|
|
125
|
-
```ts
|
|
126
|
-
callback(pattern: string | RegExp, handler: Middleware<Context<S>>): this
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
Jalan pintas untuk route callback query. String yang berakhiran `*` berarti pencocokan prefix; string lain harus sama persis.
|
|
130
|
-
|
|
131
|
-
### `bot.onText(text, handler)`
|
|
132
|
-
|
|
133
|
-
```ts
|
|
134
|
-
onText(text: string, handler: Middleware<Context<S>>): this
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
Menangani message yang `message.text`-nya sama persis dengan `text`.
|
|
138
|
-
|
|
139
|
-
### `bot.onRegex(expression, handler)`
|
|
140
|
-
|
|
141
|
-
```ts
|
|
142
|
-
onRegex(expression: RegExp, handler: Middleware<Context<S>>): this
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
Menangani message text menggunakan `RegExp`. Parameter route tidak diekstrak otomatis ke `ctx.params`; gunakan predicate atau middleware custom jika memerlukan ekstraksi.
|
|
146
|
-
|
|
147
|
-
### `bot.on(filter, handler)`
|
|
148
|
-
|
|
149
|
-
```ts
|
|
150
|
-
on(filter: UpdateFilter | UpdateFilter[], handler: Middleware<Context<S>>): this
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
Mendaftarkan handler untuk tipe update, opsional dipersempit dengan field payload. Contoh: `"message"`, `"message:text"`, `"message:photo"`, `"edited_message"`, `"channel_post"`, `"callback_query"`, `"callback_query:data"`, `"inline_query"`, `"chat_member"`, `"message_reaction"`, atau array seperti `["message:text", "callback_query:data"]`. Tipe update tidak valid melempar `TypeError` saat registrasi.
|
|
154
|
-
|
|
155
|
-
### `bot.hears(trigger, handler)`
|
|
156
|
-
|
|
157
|
-
```ts
|
|
158
|
-
hears(trigger: string | RegExp, handler: Middleware<Context<S>>): this
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
Menangani message text yang sama persis (string) atau yang cocok dengan `RegExp`.
|
|
162
|
-
|
|
163
|
-
### `bot.catch(handler)`
|
|
164
|
-
|
|
165
|
-
```ts
|
|
166
|
-
catch(handler: (error: unknown, ctx: Context<S>) => void | Promise<void>): this
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
Mendaftarkan error boundary untuk handler update. Jika dipasang, kegagalan handler dicatat, dipancarkan sebagai `update:error`/`bot:error`, dan diteruskan ke handler ini alih-alih menolak `handleUpdate()` — webhook menjawab `200` dan polling berlanjut. Tanpa boundary, error dilempar ulang.
|
|
170
|
-
|
|
171
|
-
### `bot.usePlugin(plugin)`
|
|
172
|
-
|
|
173
|
-
```ts
|
|
174
|
-
usePlugin(plugin: Plugin<Context<S>>): this
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
Mendaftarkan plugin. Nama plugin harus unik.
|
|
178
|
-
|
|
179
|
-
### `bot.init()`
|
|
180
|
-
|
|
181
|
-
```ts
|
|
182
|
-
init(): Promise<this>
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
Memanggil `getMe()`, menyimpan informasi bot, menginisialisasi plugin, dan mengembalikan bot yang siap untuk polling atau pemrosesan update manual.
|
|
186
|
-
|
|
187
|
-
`init()` idempoten ketika status sudah `initialized` atau `running`.
|
|
188
|
-
|
|
189
|
-
### `bot.start()`
|
|
190
|
-
|
|
191
|
-
```ts
|
|
192
|
-
start(): Promise<void>
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
Jalan pintas untuk `launch({ mode: "polling" })`. Method ini menjalankan long polling dan menunggu sampai polling dihentikan atau gagal secara fatal.
|
|
196
|
-
|
|
197
|
-
### `bot.launch(options?)`
|
|
198
|
-
|
|
199
|
-
```ts
|
|
200
|
-
launch(options?: {
|
|
201
|
-
mode: "polling";
|
|
202
|
-
timeout?: number;
|
|
203
|
-
allowedUpdates?: string[];
|
|
204
|
-
dropPendingUpdates?: boolean;
|
|
205
|
-
}): Promise<void>
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
Menjalankan bot dalam mode polling. Saat mulai, lifecycle berpindah melalui `starting` lalu `running`, kemudian loop `getUpdates()` memproses setiap batch update secara konkuren: update dari chat berbeda berjalan paralel, sedangkan update dari chat yang sama menjaga urutan kedatangannya. Kegagalan polling memancarkan `polling:reconnect` dan menggunakan backoff eksponensial. `dropPendingUpdates: true` (juga tersedia di `bot.start()`) membuang semua update yang ditahan Telegram sebelum panggilan `getUpdates` pertama, memakai mekanisme `deleteWebhook({ drop_pending_updates: true })` yang sama dengan Telegraf.
|
|
209
|
-
|
|
210
|
-
Mode selain `"polling"` melempar error dan menyarankan penggunaan `createWebhookHandler()` untuk webhook.
|
|
211
|
-
|
|
212
|
-
### `bot.stop()`
|
|
213
|
-
|
|
214
|
-
```ts
|
|
215
|
-
stop(): Promise<void>
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
Menghentikan polling melalui `AbortController`, menjalankan `plugins.dispose()`, mengubah status menjadi `stopped`, dan memancarkan event stopping/stopped. Pemanggilan ketika status `created` atau `stopped` tidak melakukan apa-apa.
|
|
219
|
-
|
|
220
|
-
### `bot.restart()`
|
|
221
|
-
|
|
222
|
-
```ts
|
|
223
|
-
restart(): Promise<void>
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
Menjalankan `stop()` lalu `start()`.
|
|
227
|
-
|
|
228
|
-
### `bot.health()`
|
|
229
|
-
|
|
230
|
-
```ts
|
|
231
|
-
health(): Promise<HealthStatus>
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
Memanggil `getMe()` untuk memeriksa keterjangkauan API. Tidak melempar error untuk kegagalan request; kegagalan dikembalikan sebagai `apiReachable: false` dan pesan error.
|
|
235
|
-
|
|
236
|
-
```ts
|
|
237
|
-
interface HealthStatus {
|
|
238
|
-
status: BotStatus;
|
|
239
|
-
apiReachable: boolean;
|
|
240
|
-
bot?: User;
|
|
241
|
-
checkedAt: string; // ISO timestamp
|
|
242
|
-
error?: string;
|
|
243
|
-
}
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
### `bot.getMe()`
|
|
247
|
-
|
|
248
|
-
```ts
|
|
249
|
-
getMe(): Promise<User>
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
Mengambil data bot dari Telegram dan memperbarui `botInfo`.
|
|
253
|
-
|
|
254
|
-
### `bot.setCommands(commands, scope?, languageCode?)`
|
|
255
|
-
|
|
256
|
-
```ts
|
|
257
|
-
setCommands(
|
|
258
|
-
commands: BotCommand[],
|
|
259
|
-
scope?: BotCommandScope,
|
|
260
|
-
languageCode?: string,
|
|
261
|
-
): Promise<true>
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
Jalan pintas ke `setMyCommands`. `languageCode` dipetakan menjadi field Telegram `language_code`.
|
|
265
|
-
|
|
266
|
-
### `bot.deleteCommands(scope?, languageCode?)`
|
|
267
|
-
|
|
268
|
-
```ts
|
|
269
|
-
deleteCommands(
|
|
270
|
-
scope?: BotCommandScope,
|
|
271
|
-
languageCode?: string,
|
|
272
|
-
): Promise<true>
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
Jalan pintas ke `deleteMyCommands`.
|
|
276
|
-
|
|
277
|
-
### `bot.downloadFile(fileId, options?)`
|
|
278
|
-
|
|
279
|
-
```ts
|
|
280
|
-
downloadFile(
|
|
281
|
-
fileId: string,
|
|
282
|
-
options?: { signal?: AbortSignal; destination?: string },
|
|
283
|
-
): Promise<DownloadedFile>
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
Me-resolve `fileId` lewat `getFile`, lalu mengunduh byte mentahnya melalui endpoint download transport. Berikan `destination` untuk juga menyimpan byte ke path file lokal (`savedTo` terisi pada hasil). Melempar `TelegramError` (kind `validation`) saat Telegram tidak mengembalikan `file_path` atau transport tidak bisa mengunduh, dan `TelegramNetworkError` saat unduhan gagal. Telegram membatasi unduhan pada 20 MB; `url` hasilnya tetap valid minimal satu jam.
|
|
287
|
-
|
|
288
|
-
```ts
|
|
289
|
-
const file = await bot.downloadFile(photoFileId, { destination: "downloads/photo.jpg" });
|
|
290
|
-
console.log(file.fileName, file.sizeBytes, file.url, file.savedTo);
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
### `bot.handleUpdate(update)`
|
|
294
|
-
|
|
295
|
-
```ts
|
|
296
|
-
handleUpdate(update: Update, options?: { webhookReply?: WebhookReplySink }): Promise<void>
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
Memproses satu update secara manual. Method menentukan kunci session dari `chat.id` dan `from.id`, membuat `Context` (dari `contextType` yang dikonfigurasi), memancarkan event `update` dan `message`, menjalankan middleware lalu router, dan menyimpan session setelah pipeline selesai.
|
|
300
|
-
|
|
301
|
-
Update dari chat berbeda diproses paralel; update dari chat yang sama diserialisasi sesuai urutan kedatangan, sehingga session, wizard, dan conversation tidak pernah saling tumpang tindih dan penulisan session tidak pernah hilang. Burst update konkuren hanya memicu satu inisialisasi `getMe`. Seluruh proses per update dijaga `handlerTimeout` (default 90 detik, sama dengan Telegraf): saat timeout, error mengalir lewat `update:error`/`bot:error` dan boundary `catch()`, dan `handleUpdate()` melempar `UpdateTimeoutError` sementara handler tetap berjalan di background.
|
|
302
|
-
|
|
303
|
-
`options.webhookReply` memasang responder ala Telegraf: panggilan API keluar pertama selama update ini dijawab lewat respons HTTP webhook, bukan request terpisah, dan resolve dengan `true` (Telegram tidak pernah mengirim hasil method kembali ke respons webhook).
|
|
304
|
-
|
|
305
|
-
Error pipeline mengubah status bot menjadi `error`, memancarkan `bot:error`, lalu dilempar kembali.
|
|
306
|
-
|
|
307
|
-
### `bot.handleUpdates(updates)`
|
|
308
|
-
|
|
309
|
-
```ts
|
|
310
|
-
handleUpdates(updates: readonly Update[]): Promise<void>
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
Menangani satu batch update sekaligus: setiap chat dalam batch langsung diproses — paralel antar chat, berurutan per chat — sehingga burst 1000 pesan tidak pernah terhambat oleh satu handler yang lambat. Kegagalan handler individual dicatat ke log, dipancarkan sebagai `update:error`, dan diteruskan ke error boundary `catch()`; kegagalan tersebut tidak pernah menolak promise ini. Loop polling memakai method ini untuk setiap batch `getUpdates`.
|
|
314
|
-
|
|
315
|
-
### `bot.broadcast(chatIds, send, options?)`
|
|
316
|
-
|
|
317
|
-
```ts
|
|
318
|
-
broadcast(
|
|
319
|
-
chatIds: readonly ChatId[],
|
|
320
|
-
send: (chatId: ChatId) => Promise<unknown>,
|
|
321
|
-
options?: BroadcastOptions,
|
|
322
|
-
): Promise<BroadcastReport>
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
Mengirim ke banyak chat secara paralel — dibuat untuk broadcast ke 1000+ user. Tidak ada cooldown proaktif: semua chat langsung dicoba sekaligus (sampai `options.concurrency`, default `Infinity`). Ketika Telegram menjawab 429, pengiriman otomatis diulang setelah tepat delay `retry_after` yang diperintahkan Telegram (maksimal `options.maxAttempts`, default `10`), sehingga burst tetap terkirim lengkap, bukan gagal. Error yang tidak bisa di-retry (misalnya chat yang tidak bisa dihubungi bot) dicatat per chat pada laporan yang dikembalikan.
|
|
326
|
-
|
|
327
|
-
```ts
|
|
328
|
-
const report = await bot.broadcast(
|
|
329
|
-
subscriberIds,
|
|
330
|
-
(chatId) => bot.api.methods.sendMessage({ chat_id: chatId, text: "Newsletter #42" }),
|
|
331
|
-
{ onProgress: (progress) => console.log(`${progress.delivered}/${progress.total} terkirim`) },
|
|
332
|
-
);
|
|
333
|
-
console.log(`Terkirim ${report.delivered} dari ${report.total} dalam ${report.durationMs}ms`);
|
|
334
|
-
for (const failure of report.failures) console.warn(`Gagal: ${failure.chatId} — ${failure.error}`);
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
#### `BroadcastOptions` dan `BroadcastReport`
|
|
338
|
-
|
|
339
|
-
| Properti | Tipe | Default | Deskripsi |
|
|
340
|
-
|---|---|---:|---|
|
|
341
|
-
| `BroadcastOptions.concurrency` | `number` | `Infinity` | Berapa chat dikirimi pesan secara bersamaan. |
|
|
342
|
-
| `BroadcastOptions.maxAttempts` | `number` | `10` | Percobaan per chat ketika Telegram menjawab 429. |
|
|
343
|
-
| `BroadcastOptions.onProgress` | `(progress: BroadcastProgress) => void` | — | Dipanggil setelah setiap chat selesai. |
|
|
344
|
-
| `BroadcastOptions.signal` | `AbortSignal` | — | Membatalkan pengiriman tertunda; pesan yang sudah terkirim tetap terkirim. |
|
|
345
|
-
| `BroadcastReport.total` | `number` | — | Jumlah chat dalam sesi broadcast. |
|
|
346
|
-
| `BroadcastReport.delivered` | `number` | — | Chat yang menerima pesan. |
|
|
347
|
-
| `BroadcastReport.failed` | `number` | — | Chat yang tidak menerima. |
|
|
348
|
-
| `BroadcastReport.durationMs` | `number` | — | Durasi total sesi broadcast. |
|
|
349
|
-
| `BroadcastReport.failures` | `BroadcastFailure[]` | — | Catatan per chat `{ chatId, attempts, error, errorKind }`. |
|
|
350
|
-
|
|
351
|
-
### `UpdateTimeoutError` dan helper webhook-reply
|
|
352
|
-
|
|
353
|
-
```ts
|
|
354
|
-
class UpdateTimeoutError extends Error {
|
|
355
|
-
readonly name = "UpdateTimeoutError";
|
|
356
|
-
readonly updateId: number;
|
|
357
|
-
}
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
Dilempar oleh `handleUpdate()` ketika satu update melebihi `handlerTimeout`. Handler itu sendiri tetap berjalan; error juga mengalir lewat `update:error`, `bot:error`, dan boundary `catch()`.
|
|
361
|
-
|
|
362
|
-
```ts
|
|
363
|
-
type WebhookReplySink = (payload: Record<string, unknown>) => void;
|
|
364
|
-
runWithWebhookReply(sink, fn): Promise<T> // memasang responder untuk semua panggilan API di dalam fn
|
|
365
|
-
runWithoutWebhookReply(fn): Promise<T> // panggilan internal library yang tidak pernah mengklaim slot
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
Diekspor agar webhook server kustom bisa memasang webhook reply dengan cara yang sama seperti `createWebhookHandler`.
|
|
369
|
-
|
|
370
|
-
### Contoh bot minimal
|
|
371
|
-
|
|
372
|
-
```ts
|
|
373
|
-
import { Bot, InlineKeyboard } from "@xbibzlibrary/telebibz";
|
|
374
|
-
|
|
375
|
-
const bot = new Bot({
|
|
376
|
-
token: process.env.TELEGRAM_BOT_TOKEN!,
|
|
377
|
-
polling: { allowedUpdates: ["message", "callback_query"] },
|
|
378
|
-
});
|
|
379
|
-
|
|
380
|
-
bot.command("start", async (ctx) => {
|
|
381
|
-
await ctx.reply("Halo dari telebibz", {
|
|
382
|
-
reply_markup: new InlineKeyboard()
|
|
383
|
-
.text("Status", "status")
|
|
384
|
-
.build(),
|
|
385
|
-
});
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
bot.callback("status", async (ctx) => {
|
|
389
|
-
await ctx.answerCallbackQuery("Bot aktif");
|
|
390
|
-
await ctx.reply("Status: running");
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
await bot.start();
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
---
|
|
397
|
-
|
|
398
|
-
## 2. Bus peristiwa
|
|
399
|
-
|
|
400
|
-
### `EventMap`
|
|
401
|
-
|
|
402
|
-
| Peristiwa | Muatan |
|
|
403
|
-
|---|---|
|
|
404
|
-
| `bot:created` | `{ bot: unknown }` |
|
|
405
|
-
| `bot:initialized` | `{ bot: unknown }` |
|
|
406
|
-
| `bot:starting` | `{ bot: unknown }` |
|
|
407
|
-
| `bot:started` | `{ bot: unknown }` |
|
|
408
|
-
| `bot:stopping` | `{ bot: unknown }` |
|
|
409
|
-
| `bot:stopped` | `{ bot: unknown }` |
|
|
410
|
-
| `bot:error` | `{ bot: unknown; error: unknown }` |
|
|
411
|
-
| `update` | `{ update: unknown }` |
|
|
412
|
-
| `message` | `{ message: unknown }` |
|
|
413
|
-
| `command` | `{ name: string; update: unknown }` |
|
|
414
|
-
| `callback` | `{ data: string; update: unknown }` |
|
|
415
|
-
| `api:request` | `{ method: string; payload: unknown }` |
|
|
416
|
-
| `api:response` | `{ method: string; durationMs: number; response: unknown }` |
|
|
417
|
-
| `api:error` | `{ method: string; durationMs: number; error: unknown }` |
|
|
418
|
-
| `webhook:request` | `{ update: unknown }` |
|
|
419
|
-
| `polling:reconnect` | `{ error: unknown; attempt: number }` |
|
|
420
|
-
|
|
421
|
-
### `EventBus<Events>`
|
|
422
|
-
|
|
423
|
-
```ts
|
|
424
|
-
new EventBus<Events extends Record<string, unknown> = EventMap>()
|
|
425
|
-
```
|
|
426
|
-
|
|
427
|
-
| Metode | Tanda tangan | Perilaku |
|
|
428
|
-
|---|---|---|
|
|
429
|
-
| `on` | `on<K>(event: K, listener: (payload: Events[K]) => void \| Promise<void>): () => void` | Menambah listener dan mengembalikan fungsi unsubscribe. |
|
|
430
|
-
| `once` | `once<K>(event: K, listener: ...): () => void` | Listener hanya dipanggil sekali, lalu dilepas. |
|
|
431
|
-
| `off` | `off<K>(event: K, listener: ...): void` | Melepas listener tertentu. |
|
|
432
|
-
| `emit` | `emit<K>(event: K, payload: Events[K]): Promise<void>` | Memanggil listener secara berurutan dan menunggu masing-masing. |
|
|
433
|
-
| `removeAllListeners` | `removeAllListeners(): void` | Menghapus semua listener. |
|
|
434
|
-
| `listenerCount` | `listenerCount<K>(event: K): number` | Mengembalikan jumlah listener event. |
|
|
435
|
-
|
|
436
|
-
```ts
|
|
437
|
-
const unsubscribe = bot.events.on("bot:error", ({ error }) => {
|
|
438
|
-
console.error(error);
|
|
439
|
-
});
|
|
440
|
-
unsubscribe();
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
---
|
|
444
|
-
|
|
445
|
-
## 3. API client, transport, dan error
|
|
446
|
-
|
|
447
|
-
### Tipe dasar
|
|
448
|
-
|
|
449
|
-
```ts
|
|
450
|
-
type ChatId = number | string;
|
|
451
|
-
type ParseMode = "Markdown" | "MarkdownV2" | "HTML";
|
|
452
|
-
type InputFile =
|
|
453
|
-
| string
|
|
454
|
-
| Uint8Array
|
|
455
|
-
| ArrayBuffer
|
|
456
|
-
| Blob
|
|
457
|
-
| NodeJS.ReadableStream
|
|
458
|
-
| { source: string | Uint8Array | ArrayBuffer | Blob | NodeJS.ReadableStream; filename?: string };
|
|
459
|
-
```
|
|
460
|
-
|
|
461
|
-
`InputFile` string dapat berupa string biasa atau path file ketika digunakan sebagai `source` dalam object upload. Pada Node.js, path absolut, `./...`, dan `../...` dibaca oleh `FetchTransport` lalu dikirim sebagai multipart file.
|
|
462
|
-
|
|
463
|
-
### `TelegramResponse<T>`
|
|
464
|
-
|
|
465
|
-
```ts
|
|
466
|
-
interface TelegramResponse<T> {
|
|
467
|
-
ok: boolean;
|
|
468
|
-
result?: T;
|
|
469
|
-
description?: string;
|
|
470
|
-
error_code?: number;
|
|
471
|
-
parameters?: ResponseParameters;
|
|
472
|
-
}
|
|
473
|
-
```
|
|
474
|
-
|
|
475
|
-
### `TransportRequest`, `TransportResponse`, dan `Transport`
|
|
476
|
-
|
|
477
|
-
```ts
|
|
478
|
-
interface TransportRequest {
|
|
479
|
-
method: string;
|
|
480
|
-
payload?: Record<string, unknown>;
|
|
481
|
-
signal?: AbortSignal;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
interface TransportResponse<T = unknown> {
|
|
485
|
-
status: number;
|
|
486
|
-
headers: Headers;
|
|
487
|
-
data: TelegramResponse<T>;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
interface Transport {
|
|
491
|
-
request<T>(request: TransportRequest): Promise<TransportResponse<T>>;
|
|
492
|
-
}
|
|
493
|
-
```
|
|
494
|
-
|
|
495
|
-
### `FetchTransportOptions`
|
|
496
|
-
|
|
497
|
-
| Properti | Default | Deskripsi |
|
|
498
|
-
|---|---:|---|
|
|
499
|
-
| `baseUrl` | `https://api.telegram.org` | Prefix URL sebelum `/<method>`. |
|
|
500
|
-
| `fetch` | `globalThis.fetch` | Implementasi fetch custom. |
|
|
501
|
-
| `timeoutMs` | `30000` | Timeout per attempt. |
|
|
502
|
-
| `retries` | `2` | Jumlah retry network error setelah attempt awal. |
|
|
503
|
-
| `backoffMs` | `250` | Delay exponential awal. |
|
|
504
|
-
| `maxBackoffMs` | `8000` | Batas delay transport. |
|
|
505
|
-
| `jitter` | `0.2` | Variasi acak ±20% dari exponential delay. |
|
|
506
|
-
| `floodGate` | `true` | Ketika Telegram menjawab 429, permintaan BARU ditunda sampai jendela `retry_after` yang diperintahkan Telegram berlalu. Bukan cooldown proaktif — penundaan satu-satunya hanyalah yang diminta Telegram sendiri. |
|
|
507
|
-
| `headers` | `{}` | Header tambahan. |
|
|
508
|
-
|
|
509
|
-
### `new FetchTransport(options?)`
|
|
510
|
-
|
|
511
|
-
```ts
|
|
512
|
-
new FetchTransport(options?: FetchTransportOptions): FetchTransport
|
|
513
|
-
```
|
|
514
|
-
|
|
515
|
-
Transport bawaan berbasis `fetch`. Payload tanpa upload dikirim sebagai JSON. Payload yang mengandung `Uint8Array`, `ArrayBuffer`, `Blob`, atau nested upload dikirim sebagai `multipart/form-data` menggunakan `FormData`.
|
|
516
|
-
|
|
517
|
-
### `fetchTransport.request(request)`
|
|
518
|
-
|
|
519
|
-
```ts
|
|
520
|
-
request<T>(request: TransportRequest): Promise<TransportResponse<T>>
|
|
521
|
-
```
|
|
522
|
-
|
|
523
|
-
Mengirim POST ke `${baseUrl}/${method}`. Method dengan awalan `/` dinormalisasi. AbortSignal eksternal diteruskan ke controller internal. Network error yang dianggap retryable akan diulang dengan exponential backoff dan jitter; ketika retry habis, error dibungkus sebagai `TelegramNetworkError`.
|
|
524
|
-
|
|
525
|
-
### `ApiHookContext`, `ApiClientOptions`, dan `ApiMethods`
|
|
526
|
-
|
|
527
|
-
```ts
|
|
528
|
-
interface ApiHookContext {
|
|
529
|
-
method: string;
|
|
530
|
-
payload: unknown;
|
|
531
|
-
startedAt: number;
|
|
532
|
-
durationMs?: number;
|
|
533
|
-
response?: TelegramResponse<unknown>;
|
|
534
|
-
error?: unknown;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
interface ApiClientOptions {
|
|
538
|
-
transport: Transport;
|
|
539
|
-
hooks?: {
|
|
540
|
-
onRequest?: (context: ApiHookContext) => void | Promise<void>;
|
|
541
|
-
onResponse?: (context: ApiHookContext) => void | Promise<void>;
|
|
542
|
-
onError?: (context: ApiHookContext) => void | Promise<void>;
|
|
543
|
-
};
|
|
544
|
-
}
|
|
545
|
-
```
|
|
546
|
-
|
|
547
|
-
`ApiMethods` adalah mapped type dari 184 `TelegramMethodName`:
|
|
548
|
-
|
|
549
|
-
```ts
|
|
550
|
-
type ApiMethods = {
|
|
551
|
-
[M in TelegramMethodName]:
|
|
552
|
-
(...args: ApiCallArgs<M>) => Promise<ApiResult<M>>;
|
|
553
|
-
};
|
|
554
|
-
```
|
|
555
|
-
|
|
556
|
-
### `new ApiClient(options)`
|
|
557
|
-
|
|
558
|
-
```ts
|
|
559
|
-
new ApiClient(options: ApiClientOptions): ApiClient
|
|
560
|
-
```
|
|
561
|
-
|
|
562
|
-
Membuat proxy method dinamis pada `client.methods`. Hook `onRequest` dipanggil sebelum transport, `onResponse` setelah response diterima, dan `onError` ketika request gagal atau response Telegram `ok: false`.
|
|
563
|
-
|
|
564
|
-
### `api.methods.<method>(params?)`
|
|
565
|
-
|
|
566
|
-
Method dinamis dapat dipanggil langsung. Method yang memiliki parameter kosong seperti `getMe()` dipanggil tanpa argumen; method lain menerima satu object parameter.
|
|
567
|
-
|
|
568
|
-
```ts
|
|
569
|
-
const me = await bot.api.methods.getMe();
|
|
570
|
-
const chat = await bot.api.methods.getChat({ chat_id: "@channel" });
|
|
571
|
-
const message = await bot.api.methods.sendMessage({
|
|
572
|
-
chat_id: 123456789,
|
|
573
|
-
text: "Hello",
|
|
574
|
-
});
|
|
575
|
-
```
|
|
576
|
-
|
|
577
|
-
### `api.call(method, ...args)`
|
|
578
|
-
|
|
579
|
-
```ts
|
|
580
|
-
call<M extends TelegramMethodName>(
|
|
581
|
-
method: M,
|
|
582
|
-
...args: ApiCallArgs<M>
|
|
583
|
-
): Promise<ApiResult<M>>
|
|
584
|
-
```
|
|
585
|
-
|
|
586
|
-
Bentuk bertipe untuk pemanggilan method berdasarkan string literal.
|
|
587
|
-
|
|
588
|
-
### `api.request(method, payload?, signal?)`
|
|
589
|
-
|
|
590
|
-
```ts
|
|
591
|
-
request<M extends TelegramMethodName>(
|
|
592
|
-
method: M,
|
|
593
|
-
payload?: ApiParams<M>,
|
|
594
|
-
signal?: AbortSignal,
|
|
595
|
-
): Promise<ApiResult<M>>
|
|
596
|
-
```
|
|
597
|
-
|
|
598
|
-
Method request tingkat rendah yang memungkinkan `AbortSignal` eksplisit.
|
|
599
|
-
|
|
600
|
-
### `api.raw(method, payload?, signal?)`
|
|
601
|
-
|
|
602
|
-
```ts
|
|
603
|
-
raw(
|
|
604
|
-
method: string,
|
|
605
|
-
payload?: Record<string, unknown>,
|
|
606
|
-
signal?: AbortSignal,
|
|
607
|
-
): Promise<unknown>
|
|
608
|
-
```
|
|
609
|
-
|
|
610
|
-
Memanggil method string sembarang di transport. Gunakan ini untuk method Telegram atau parameter baru yang belum masuk `TelegramMethodMap`. Response `ok: false` tetap diubah menjadi `TelegramError`.
|
|
611
|
-
|
|
612
|
-
### `api.downloadFile(fileId, options?)`
|
|
613
|
-
|
|
614
|
-
```ts
|
|
615
|
-
downloadFile(fileId: string, options?: { signal?: AbortSignal }): Promise<DownloadedFile>
|
|
616
|
-
```
|
|
617
|
-
|
|
618
|
-
Inti `bot.downloadFile` di level API client: me-resolve `getFile`, memvalidasi `file_path` tersedia, lalu mengunduh byte melalui transport.
|
|
619
|
-
|
|
620
|
-
### `DownloadedFile`
|
|
621
|
-
|
|
622
|
-
```ts
|
|
623
|
-
interface DownloadedFile {
|
|
624
|
-
file: File; // objek File Telegram dari getFile
|
|
625
|
-
bytes: Uint8Array; // byte mentah file (maks 20 MB sesuai Telegram)
|
|
626
|
-
filePath: string; // file_path yang dipakai untuk unduhan
|
|
627
|
-
url: string; // URL unduhan langsung, valid minimal satu jam
|
|
628
|
-
fileName: string; // segmen path terakhir dari filePath
|
|
629
|
-
sizeBytes: number; // panjang byte
|
|
630
|
-
savedTo?: string; // terisi saat Bot.downloadFile menyimpan file ke disk
|
|
631
|
-
}
|
|
632
|
-
```
|
|
633
|
-
|
|
634
|
-
### `fetchTransport.fileUrl(filePath)` dan `fetchTransport.download(filePath, signal?)`
|
|
635
|
-
|
|
636
|
-
```ts
|
|
637
|
-
fileUrl(filePath: string): string
|
|
638
|
-
download(filePath: string, signal?: AbortSignal): Promise<Uint8Array>
|
|
639
|
-
```
|
|
640
|
-
|
|
641
|
-
`FetchTransport` memetakan base URL `/bot<token>` ke endpoint download `/file/bot<token>`; `download` melakukan GET byte (batas bawah timeout 120 detik untuk file besar) dan melempar `TelegramNetworkError` saat HTTP gagal. Keduanya member opsional pada interface `Transport`, jadi transport kustom boleh menghilangkannya — `downloadFile` lalu gagal dengan error validasi yang jelas, bukan crash.
|
|
642
|
-
|
|
643
|
-
### Parameter dan hasil bertipe yang tersedia
|
|
644
|
-
|
|
645
|
-
Tipe berikut dipetakan khusus pada rilis ini.
|
|
646
|
-
|
|
647
|
-
| Method | Parameter | Result |
|
|
648
|
-
|---|---|---|
|
|
649
|
-
| `getMe` | tidak ada | `User` |
|
|
650
|
-
| `getUpdates` | `GetUpdatesParams` | `Update[]` |
|
|
651
|
-
| `setWebhook` | `SetWebhookParams` | `boolean` |
|
|
652
|
-
| `deleteWebhook` | `{ drop_pending_updates?: boolean }` | `boolean` |
|
|
653
|
-
| `getWebhookInfo` | tidak ada | `WebhookInfo` |
|
|
654
|
-
| `sendMessage` | `SendMessageParams` | `Message` |
|
|
655
|
-
| `editMessageText` | `EditMessageTextParams` | `Message \| true` |
|
|
656
|
-
| `deleteMessage` | `DeleteMessageParams` | `true` |
|
|
657
|
-
| `answerCallbackQuery` | `AnswerCallbackQueryParams` | `true` |
|
|
658
|
-
| `getChat` | `GetChatParams` | `Chat` |
|
|
659
|
-
| `getFile` | `GetFileParams` | `File` |
|
|
660
|
-
| `getUserProfilePhotos` | `{ user_id: number; offset?: number; limit?: number }` | `UserProfilePhotos` |
|
|
661
|
-
| `sendPhoto` | `SendPhotoParams` | `Message` |
|
|
662
|
-
| `sendDocument` | `SendDocumentParams` | `Message` |
|
|
663
|
-
|
|
664
|
-
Tipe parameter tambahan yang tersedia adalah `ReplyParameters`, `LinkPreviewOptions`, `InlineKeyboardButton`, `ReplyMarkup`, `BotCommand`, `BotCommandScope`, dan seluruh tipe update Telegram yang diekspor dari `api/types.ts`.
|
|
665
|
-
|
|
666
|
-
### Error API
|
|
667
|
-
|
|
668
|
-
```ts
|
|
669
|
-
type TelegramErrorKind =
|
|
670
|
-
| "retryable"
|
|
671
|
-
| "rate-limit"
|
|
672
|
-
| "authentication"
|
|
673
|
-
| "validation"
|
|
674
|
-
| "network"
|
|
675
|
-
| "server"
|
|
676
|
-
| "unknown";
|
|
677
|
-
```
|
|
678
|
-
|
|
679
|
-
#### `TelegramError`
|
|
680
|
-
|
|
681
|
-
```ts
|
|
682
|
-
new TelegramError(message: string, options: {
|
|
683
|
-
method: string;
|
|
684
|
-
payload: unknown;
|
|
685
|
-
errorCode?: number;
|
|
686
|
-
parameters?: ResponseParameters;
|
|
687
|
-
status?: number;
|
|
688
|
-
kind?: TelegramErrorKind;
|
|
689
|
-
cause?: unknown;
|
|
690
|
-
})
|
|
691
|
-
```
|
|
692
|
-
|
|
693
|
-
Properti publik adalah `kind`, `errorCode`, `parameters`, `method`, `payload`, dan `status`. Getter `retryAfter` membaca `parameters.retry_after`; getter `migrateToChatId` membaca `parameters.migrate_to_chat_id`.
|
|
694
|
-
|
|
695
|
-
#### Subclass error
|
|
696
|
-
|
|
697
|
-
| Class | `name` | `kind` paksa |
|
|
698
|
-
|---|---|---|
|
|
699
|
-
| `TelegramRateLimitError` | `TelegramRateLimitError` | `rate-limit` |
|
|
700
|
-
| `TelegramAuthError` | `TelegramAuthError` | `authentication` |
|
|
701
|
-
| `TelegramValidationError` | `TelegramValidationError` | `validation` |
|
|
702
|
-
| `TelegramNetworkError` | `TelegramNetworkError` | `network` |
|
|
703
|
-
|
|
704
|
-
Keempat subclass memakai constructor options yang sama seperti `TelegramError`.
|
|
705
|
-
|
|
706
|
-
#### `classifyTelegramError(errorCode?, status?)`
|
|
707
|
-
|
|
708
|
-
```ts
|
|
709
|
-
classifyTelegramError(
|
|
710
|
-
errorCode?: number,
|
|
711
|
-
status?: number,
|
|
712
|
-
): TelegramErrorKind
|
|
713
|
-
```
|
|
714
|
-
|
|
715
|
-
Klasifikasi aktual: `429` menjadi `rate-limit`; error `401` atau HTTP `401/403` menjadi `authentication`; error code `400–499` menjadi `validation`; HTTP `500+` menjadi `server`; selain itu `unknown`.
|
|
716
|
-
|
|
717
|
-
#### `telegramErrorFromResponse(response, context)`
|
|
718
|
-
|
|
719
|
-
```ts
|
|
720
|
-
telegramErrorFromResponse<T>(
|
|
721
|
-
response: TelegramResponse<T>,
|
|
722
|
-
context: { method: string; payload: unknown; status?: number },
|
|
723
|
-
): TelegramError
|
|
724
|
-
```
|
|
725
|
-
|
|
726
|
-
Mengubah response Telegram gagal menjadi subclass yang sesuai. Error `429`, auth, dan validation menghasilkan subclass khusus; error lain menghasilkan `TelegramError` biasa.
|
|
727
|
-
|
|
728
|
-
---
|
|
729
|
-
|
|
730
|
-
## 4. Konteks
|
|
731
|
-
|
|
732
|
-
### `ContextOptions<S>`
|
|
733
|
-
|
|
734
|
-
```ts
|
|
735
|
-
interface ContextOptions<S extends object = Record<string, unknown>> {
|
|
736
|
-
update: Update;
|
|
737
|
-
api: ApiClient;
|
|
738
|
-
session: S;
|
|
739
|
-
services: Record<string, unknown>;
|
|
740
|
-
}
|
|
741
|
-
```
|
|
742
|
-
|
|
743
|
-
### `Context<S>` properties
|
|
744
|
-
|
|
745
|
-
| Properti | Isi |
|
|
746
|
-
|---|---|
|
|
747
|
-
| `update` | Update mentah Telegram. |
|
|
748
|
-
| `api` | `ApiClient` bot. |
|
|
749
|
-
| `session` | Objek session yang dapat diubah milik update key saat ini. |
|
|
750
|
-
| `state` | Objek transient per-konteks, tidak otomatis disimpan ke session. |
|
|
751
|
-
| `services` | Layanan yang dikirim melalui `BotOptions.services`. |
|
|
752
|
-
| `params` | Objek parameter route; router bawaan saat ini tidak mengisi otomatis. |
|
|
753
|
-
| `message` | Message utama dari message/edited/channel/business/guest update. |
|
|
754
|
-
| `chat` | `message.chat` bila tersedia. |
|
|
755
|
-
| `from` / `sender` | Pengguna dari message, callback query, atau inline query. |
|
|
756
|
-
| `callbackQuery` | `update.callback_query`. |
|
|
757
|
-
| `inlineQuery` | `update.inline_query`. |
|
|
758
|
-
| `poll` | `update.poll`. |
|
|
759
|
-
| `pollAnswer` | `update.poll_answer`. |
|
|
760
|
-
| `chatMember` | `update.chat_member`. |
|
|
761
|
-
| `myChatMember` | `update.my_chat_member`. |
|
|
762
|
-
| `chatJoinRequest` | `update.chat_join_request`. |
|
|
763
|
-
| `reaction` | `update.message_reaction`. |
|
|
764
|
-
| `boost` | `chat_boost` atau `removed_chat_boost`. |
|
|
765
|
-
|
|
766
|
-
### `new Context(options)`
|
|
767
|
-
|
|
768
|
-
```ts
|
|
769
|
-
new Context<S>(options: ContextOptions<S>): Context<S>
|
|
770
|
-
```
|
|
771
|
-
|
|
772
|
-
### Metode pesan Context
|
|
773
|
-
|
|
774
|
-
| Method | Signature | Perilaku |
|
|
775
|
-
|---|---|---|
|
|
776
|
-
| `reply` | `reply(text, extra?): Promise<Message>` | Mengirim message ke chat update dan mengisi `reply_parameters.message_id` bila ada message. |
|
|
777
|
-
| `send` | `send(text, extra?): Promise<Message>` | Mengirim message ke chat update tanpa reply reference. |
|
|
778
|
-
| `edit` | `edit(text, extra?): Promise<Message \| true>` | Mengedit message update menggunakan `editMessageText`. |
|
|
779
|
-
| `delete` | `delete(): Promise<true>` | Menghapus message update. |
|
|
780
|
-
| `replyWithHTML` | `replyWithHTML(text, extra?): Promise<Message>` | Membalas dengan `parse_mode: "HTML"`. |
|
|
781
|
-
| `replyWithMarkdown` | `replyWithMarkdown(text, extra?): Promise<Message>` | Membalas dengan `parse_mode: "MarkdownV2"`. |
|
|
782
|
-
| `replyWithPhoto` | `replyWithPhoto(photo, extra?): Promise<Message>` | Mengirim `sendPhoto` dengan quote-reply otomatis. |
|
|
783
|
-
| `replyWithDocument` | `replyWithDocument(document, extra?): Promise<Message>` | Mengirim `sendDocument` dengan quote-reply otomatis. |
|
|
784
|
-
| `replyWithAudio` | `replyWithAudio(audio, extra?): Promise<Message>` | Mengirim `sendAudio` dengan quote-reply otomatis. |
|
|
785
|
-
| `replyWithVideo` | `replyWithVideo(video, extra?): Promise<Message>` | Mengirim `sendVideo` dengan quote-reply otomatis. |
|
|
786
|
-
| `replyWithVoice` | `replyWithVoice(voice, extra?): Promise<Message>` | Mengirim `sendVoice` dengan quote-reply otomatis. |
|
|
787
|
-
| `replyWithAnimation` | `replyWithAnimation(animation, extra?): Promise<Message>` | Mengirim `sendAnimation` dengan quote-reply otomatis. |
|
|
788
|
-
| `replyWithVideoNote` | `replyWithVideoNote(videoNote, extra?): Promise<Message>` | Mengirim `sendVideoNote` dengan quote-reply otomatis. |
|
|
789
|
-
| `replyWithSticker` | `replyWithSticker(sticker, extra?): Promise<Message>` | Mengirim `sendSticker` dengan quote-reply otomatis. |
|
|
790
|
-
| `replyWithMediaGroup` | `replyWithMediaGroup(media, extra?): Promise<Message[]>` | Mengirim album via `sendMediaGroup` dengan quote-reply otomatis. |
|
|
791
|
-
| `replyWithLocation` | `replyWithLocation(latitude, longitude, extra?): Promise<Message>` | Mengirim `sendLocation` dengan quote-reply otomatis. |
|
|
792
|
-
| `replyWithVenue` | `replyWithVenue(latitude, longitude, title, address, extra?): Promise<Message>` | Mengirim `sendVenue` dengan quote-reply otomatis. |
|
|
793
|
-
| `replyWithContact` | `replyWithContact(phoneNumber, firstName, extra?): Promise<Message>` | Mengirim `sendContact` dengan quote-reply otomatis. |
|
|
794
|
-
| `replyWithPoll` | `replyWithPoll(question, options, extra?): Promise<Message>` | Mengirim `sendPoll` dengan quote-reply otomatis. |
|
|
795
|
-
| `replyWithDice` | `replyWithDice(emoji?, extra?): Promise<Message>` | Mengirim `sendDice` dengan quote-reply otomatis. |
|
|
796
|
-
| `copy` | `copy(fromChatId, messageId, extra?): Promise<unknown>` | Memanggil `copyMessage` ke chat context. |
|
|
797
|
-
| `forward` | `forward(fromChatId, messageId, extra?): Promise<Message>` | Memanggil `forwardMessage` ke chat context. |
|
|
798
|
-
| `pin` | `pin(messageId?, extra?): Promise<true>` | Memanggil `pinChatMessage`, default message id dari context. |
|
|
799
|
-
| `unpin` | `unpin(messageId?, extra?): Promise<true>` | Memanggil `unpinChatMessage`, default message id dari context. |
|
|
800
|
-
| `react` | `react(reaction, extra?): Promise<true>` | Memanggil `setMessageReaction`. |
|
|
801
|
-
| `answerCallbackQuery` | `answerCallbackQuery(text?, extra?): Promise<true>` | Menjawab callback query aktif. Error jika bukan callback update. |
|
|
802
|
-
| `answerInlineQuery` | `answerInlineQuery(results, extra?): Promise<true>` | Menjawab inline query aktif. Error jika bukan inline update. |
|
|
803
|
-
| `getChat` | `getChat(): Promise<Chat>` | Mengambil detail chat context. |
|
|
804
|
-
| `getUserProfilePhotos` | `getUserProfilePhotos(userId?, extra?): Promise<unknown>` | Mengambil foto profil user context. |
|
|
805
|
-
| `getFile` | `getFile(fileId): Promise<unknown>` | Mengambil file berdasarkan id. |
|
|
806
|
-
| `withReplyMarkup` | `withReplyMarkup(markup): this` | Menyimpan markup di `ctx.state.reply_markup` dan mengembalikan context. Metode ini tidak otomatis mengirim message. |
|
|
807
|
-
|
|
808
|
-
Semua pengirim `replyWith*` menerima parameter native Telegram sebagai `extra` dan otomatis me-quote message yang masuk. `reply_parameters` pada `extra` digabung dengan `message_id` otomatis, bukan menggantikannya. `reply`, `send`, `getChat`, dan beberapa helper lain melempar error ketika update tidak memiliki chat yang diperlukan. `edit` dan `delete` membutuhkan chat serta message.
|
|
809
|
-
|
|
810
|
-
### Method admin, chat, dan forum pada Context (paritas penuh Telegraf)
|
|
811
|
-
|
|
812
|
-
Semua method di bawah beraksi pada chat update (`ctx.chat`) dan menerima parameter native Telegram lewat `extra`; semuanya melempar error jelas bila update tidak memiliki chat. Gunakan `ctx.api.methods.*` untuk menargetkan chat lain.
|
|
813
|
-
|
|
814
|
-
| Grup | Method |
|
|
815
|
-
|---|---|
|
|
816
|
-
| Moderasi | `banChatMember(userId, untilDate?, extra?)`, `unbanChatMember(userId, onlyIfBanned?, extra?)`, `restrictChatMember(userId, permissions, untilDate?, extra?)`, `promoteChatMember(userId, extra?)`, `banChatSenderChat(senderChatId, extra?)`, `unbanChatSenderChat(senderChatId, extra?)` |
|
|
817
|
-
| Manajemen chat | `setChatTitle(title)`, `setChatDescription(description?)`, `setChatPhoto(photo)`, `deleteChatPhoto()`, `setChatPermissions(permissions, extra?)`, `leaveChat()`, `unpinAllChatMessages(extra?)`, `setChatStickerSet(name)`, `deleteChatStickerSet()` |
|
|
818
|
-
| Info chat & member | `getChatAdministrators(): Promise<ChatMember[]>`, `getChatMemberCount(): Promise<number>`, `getChatMember(userId): Promise<ChatMember>` |
|
|
819
|
-
| Invite link | `exportChatInviteLink(): Promise<string>`, `createChatInviteLink(extra?)`, `editChatInviteLink(inviteLink, extra?)`, `revokeChatInviteLink(inviteLink)` |
|
|
820
|
-
| Join request | `approveChatJoinRequest(userId)`, `declineChatJoinRequest(userId)` |
|
|
821
|
-
| Poll & live location | `replyWithQuiz(question, options, extra?)` (sendPoll dengan `type: "quiz"`), `stopPoll(messageId?, extra?)`, `editMessageLiveLocation(latitude?, longitude?, extra?)`, `stopMessageLiveLocation(extra?)` |
|
|
822
|
-
| Game & pembayaran | `replyWithGame(gameShortName, extra?)`, `setGameScore(userId, score, extra?)`, `getGameHighScores(userId?, extra?)`, `replyWithInvoice(title, description, payload, providerToken, currency, prices, extra?)` |
|
|
823
|
-
| Forum topic | `createForumTopic(name, extra?)`, `editForumTopic(extra?)`, `closeForumTopic(threadId?)`, `reopenForumTopic(threadId?)`, `deleteForumTopic(threadId?)`, `unpinAllForumTopicMessages(threadId?)`, `getForumTopicIconStickers()`, `editGeneralForumTopic(name)`, `closeGeneralForumTopic()`, `reopenGeneralForumTopic()`, `hideGeneralForumTopic()`, `unhideGeneralForumTopic()` |
|
|
824
|
-
|
|
825
|
-
`threadId` default ke `message_thread_id` message context. `replyWithQuiz`, `replyWithGame`, dan `replyWithInvoice` me-quote message masuk seperti semua pengirim `replyWith*`.
|
|
826
|
-
|
|
827
|
-
---
|
|
828
|
-
|
|
829
|
-
## 5. Middleware dan router
|
|
830
|
-
|
|
831
|
-
### Jenis middleware
|
|
832
|
-
|
|
833
|
-
```ts
|
|
834
|
-
type Next = () => Promise<void>;
|
|
835
|
-
type Middleware<Context> = (ctx: Context, next: Next) => void | Promise<void>;
|
|
836
|
-
```
|
|
837
|
-
|
|
838
|
-
### `compose(middleware)`
|
|
839
|
-
|
|
840
|
-
```ts
|
|
841
|
-
compose<Context>(
|
|
842
|
-
middleware: readonly Middleware<Context>[],
|
|
843
|
-
): (ctx: Context) => Promise<void>
|
|
844
|
-
```
|
|
845
|
-
|
|
846
|
-
Menyusun middleware dengan pola onion. `next()` menjalankan middleware berikutnya. Jika middleware yang sama memanggil `next()` lebih dari sekali, compose melempar `Error("next() called multiple times")`.
|
|
847
|
-
|
|
848
|
-
### `middleware(handler)`
|
|
849
|
-
|
|
850
|
-
```ts
|
|
851
|
-
middleware<Context>(handler: Middleware<Context>): Middleware<Context>
|
|
852
|
-
```
|
|
853
|
-
|
|
854
|
-
Pembantu identitas untuk memberi anotasi/inferensi tipe pada middleware.
|
|
855
|
-
|
|
856
|
-
### `RoutableContext`
|
|
857
|
-
|
|
858
|
-
Context minimal yang dibutuhkan router: `update`, `message`, `callbackQuery`, dan `params`.
|
|
859
|
-
|
|
860
|
-
### `Router<Context>`
|
|
861
|
-
|
|
862
|
-
```ts
|
|
863
|
-
new Router<Context extends RoutableContext>(): Router<Context>
|
|
864
|
-
```
|
|
865
|
-
|
|
866
|
-
Route diproses menurut prioritas dan urutan registrasi. Route yang cocok tidak menghentikan route berikutnya secara otomatis; semua route yang cocok dapat dijalankan. Jika tidak ada route yang cocok, `terminal` pada `handle` dipanggil.
|
|
867
|
-
|
|
868
|
-
| Metode | Tanda tangan | Pencocokan |
|
|
869
|
-
|---|---|---|
|
|
870
|
-
| `use` | `use(...middleware): this` | Middleware global router dengan priority paling tinggi untuk dijalankan lebih awal. |
|
|
871
|
-
| `route` | `route(matcher, ...middleware): this` | Matcher boolean atau async custom. |
|
|
872
|
-
| `command` | `command(name: string \| RegExp, ...middleware): this` | Command pertama dari message text yang diawali `/`. |
|
|
873
|
-
| `text` | `text(value: string, ...middleware): this` | Pencocokan teks persis. |
|
|
874
|
-
| `regex` | `regex(expression: RegExp, ...middleware): this` | `RegExp.test` atas message text atau string kosong. |
|
|
875
|
-
| `callback` | `callback(pattern: string \| RegExp, ...middleware): this` | Exact, prefix dengan suffix `*`, atau regex atas callback data. |
|
|
876
|
-
| `chat` | `chat(chatId: number \| string, ...middleware): this` | Cocokkan `message.chat.id`, numeric atau string-equivalent. |
|
|
877
|
-
| `predicate` | `predicate(matcher, ...middleware): this` | Alias semantik untuk custom matcher. |
|
|
878
|
-
| `nest` | `nest(child: Router<Context>): this` | Menjalankan router child sebagai nested route. |
|
|
879
|
-
| `handle` | `handle(ctx, terminal?): Promise<void>` | Mengevaluasi dan menjalankan seluruh route yang cocok. |
|
|
880
|
-
|
|
881
|
-
```ts
|
|
882
|
-
const router = new Router<Context>();
|
|
883
|
-
router.use(async (ctx, next) => {
|
|
884
|
-
console.log("before");
|
|
885
|
-
await next();
|
|
886
|
-
});
|
|
887
|
-
router.callback("page:*", async (ctx) => {
|
|
888
|
-
await ctx.answerCallbackQuery();
|
|
889
|
-
});
|
|
890
|
-
router.predicate((ctx) => Boolean(ctx.from?.id), async (ctx) => {
|
|
891
|
-
await ctx.reply("Authenticated update");
|
|
892
|
-
});
|
|
893
|
-
```
|
|
894
|
-
|
|
895
|
-
**Catatan RegExp.** Router memanggil `.test()` langsung. Untuk ekspresi dengan flag `g` atau `y`, sifat stateful `lastIndex` JavaScript dapat memengaruhi pencocokan berulang.
|
|
896
|
-
|
|
897
|
-
---
|
|
898
|
-
|
|
899
|
-
## 6. Pembuat keyboard
|
|
900
|
-
|
|
901
|
-
### `InlineKeyboard`
|
|
902
|
-
|
|
903
|
-
```ts
|
|
904
|
-
new InlineKeyboard(): InlineKeyboard
|
|
905
|
-
InlineKeyboard.from(rows: InlineKeyboardButton[][]): InlineKeyboard
|
|
906
|
-
```
|
|
907
|
-
|
|
908
|
-
Builder menyimpan baris secara dapat diubah (mutable) dan seluruh metode builder mengembalikan `this`.
|
|
909
|
-
|
|
910
|
-
| Method | Signature | Deskripsi |
|
|
911
|
-
|---|---|---|
|
|
912
|
-
| `from` | `static from(rows): InlineKeyboard` | Membuat keyboard dari rows dan menyalin setiap row. |
|
|
913
|
-
| `text` | `text(text, callbackData): this` | Tombol callback. |
|
|
914
|
-
| `url` | `url(text, url): this` | Tombol URL. |
|
|
915
|
-
| `webApp` | `webApp(text, url): this` | Tombol Web App. |
|
|
916
|
-
| `pay` | `pay(text = "Pay"): this` | Tombol pembayaran. |
|
|
917
|
-
| `copy` | `copy(text, copiedText): this` | Tombol salin teks. |
|
|
918
|
-
| `button` | `button(button): this` | Menambahkan satu tombol ke baris terakhir atau membuat baris pertama. |
|
|
919
|
-
| `row` | `row(...buttons): this` | Menambahkan baris baru. |
|
|
920
|
-
| `conditional` | `conditional(condition, factory): this` | Menjalankan factory hanya jika kondisi bernilai true. |
|
|
921
|
-
| `grid` | `grid(buttons, columns): this` | Membagi tombol ke baris berdasarkan jumlah kolom. |
|
|
922
|
-
| `build` | `build(): InlineKeyboardMarkup` | Menghasilkan markup baru. |
|
|
923
|
-
| `asReplyMarkup` | `asReplyMarkup(): InlineKeyboardMarkup` | Alias dari `build`. |
|
|
924
|
-
|
|
925
|
-
Setiap inline button wajib memiliki text dan tepat satu action. Callback data dibatasi maksimum 64 bytes UTF-8; pelanggaran melempar `RangeError`.
|
|
926
|
-
|
|
927
|
-
```ts
|
|
928
|
-
const keyboard = new InlineKeyboard()
|
|
929
|
-
.text("Izinkan", "approve:123")
|
|
930
|
-
.url("Dokumentasi", "https://example.com")
|
|
931
|
-
.row(
|
|
932
|
-
{ text: "A", callback_data: "a" },
|
|
933
|
-
{ text: "B", callback_data: "b" },
|
|
934
|
-
)
|
|
935
|
-
.build();
|
|
936
|
-
```
|
|
937
|
-
|
|
938
|
-
### `ReplyKeyboard`
|
|
939
|
-
|
|
940
|
-
```ts
|
|
941
|
-
new ReplyKeyboard(): ReplyKeyboard
|
|
942
|
-
```
|
|
943
|
-
|
|
944
|
-
| Method | Signature | Deskripsi |
|
|
945
|
-
|---|---|---|
|
|
946
|
-
| `text` | `text(text): this` | Tombol teks biasa. |
|
|
947
|
-
| `contact` | `contact(text): this` | Meminta kontak. |
|
|
948
|
-
| `location` | `location(text): this` | Meminta lokasi. |
|
|
949
|
-
| `poll` | `poll(text, type?): this` | Meminta poll `quiz` atau `regular`. |
|
|
950
|
-
| `webApp` | `webApp(text, url): this` | Tombol Web App. |
|
|
951
|
-
| `button` | `button(button): this` | Tambah satu tombol ke baris terakhir. |
|
|
952
|
-
| `row` | `row(...buttons): this` | Tambah baris baru. |
|
|
953
|
-
| `grid` | `grid(buttons, columns): this` | Membagi tombol menjadi grid. |
|
|
954
|
-
| `build` | `build(options?): ReplyKeyboardMarkup` | Menghasilkan markup dan menggabungkan opsi. |
|
|
955
|
-
| `asReplyMarkup` | `asReplyMarkup(): ReplyKeyboardMarkup` | Alias dari `build()` tanpa opsi. |
|
|
956
|
-
|
|
957
|
-
`columns` harus integer positif; jika tidak, `grid` melempar `RangeError`.
|
|
958
|
-
|
|
959
|
-
### `removeKeyboard(selective?)`
|
|
960
|
-
|
|
961
|
-
```ts
|
|
962
|
-
removeKeyboard(selective = false): ReplyMarkup
|
|
963
|
-
```
|
|
964
|
-
|
|
965
|
-
Menghasilkan `{ remove_keyboard: true }`, dengan `selective: true` bila diminta.
|
|
966
|
-
|
|
967
|
-
### `forceReply(placeholder?, selective?)`
|
|
968
|
-
|
|
969
|
-
```ts
|
|
970
|
-
forceReply(placeholder?: string, selective = false): ReplyMarkup
|
|
971
|
-
```
|
|
972
|
-
|
|
973
|
-
Menghasilkan ForceReply. Placeholder hanya ditambahkan jika bernilai truthy.
|
|
974
|
-
|
|
975
|
-
---
|
|
976
|
-
|
|
977
|
-
## 7. Storage dan cache
|
|
978
|
-
|
|
979
|
-
### `Storage<K, V>`
|
|
980
|
-
|
|
981
|
-
```ts
|
|
982
|
-
interface Storage<K, V> {
|
|
983
|
-
get(key: K): Promise<V | undefined>;
|
|
984
|
-
set(key: K, value: V, options?: { ttlMs?: number }): Promise<void>;
|
|
985
|
-
delete(key: K): Promise<boolean>;
|
|
986
|
-
has(key: K): Promise<boolean>;
|
|
987
|
-
clear(): Promise<void>;
|
|
988
|
-
keys(): AsyncIterable<K>;
|
|
989
|
-
values(): AsyncIterable<V>;
|
|
990
|
-
entries(): AsyncIterable<[K, V]>;
|
|
991
|
-
update<T extends V>(
|
|
992
|
-
key: K,
|
|
993
|
-
updater: (current: V | undefined) => T | Promise<T>,
|
|
994
|
-
options?: { ttlMs?: number },
|
|
995
|
-
): Promise<T>;
|
|
996
|
-
}
|
|
997
|
-
```
|
|
998
|
-
|
|
999
|
-
### `MemoryStorage<K, V>`
|
|
1000
|
-
|
|
1001
|
-
```ts
|
|
1002
|
-
new MemoryStorage<K, V>(): MemoryStorage<K, V>
|
|
1003
|
-
```
|
|
1004
|
-
|
|
1005
|
-
Implementasi in-memory berbasis `Map`. TTL dibersihkan saat diperlukan ketika key dibaca atau diiterasi; tidak ada timer latar belakang. `update` membuat operasi updater per key berjalan serial sehingga update konkuren untuk key yang sama tidak saling menimpa secara tak terduga.
|
|
1006
|
-
|
|
1007
|
-
```ts
|
|
1008
|
-
const sessions = new MemoryStorage<string, { count: number }>();
|
|
1009
|
-
await sessions.set("user:1", { count: 0 }, { ttlMs: 60_000 });
|
|
1010
|
-
await sessions.update("user:1", (current) => ({
|
|
1011
|
-
count: (current?.count ?? 0) + 1,
|
|
1012
|
-
}));
|
|
1013
|
-
```
|
|
1014
|
-
|
|
1015
|
-
### `Cache<K, V>`
|
|
1016
|
-
|
|
1017
|
-
```ts
|
|
1018
|
-
interface Cache<K = string, V = unknown> {
|
|
1019
|
-
get(key: K): Promise<V | undefined>;
|
|
1020
|
-
set(key: K, value: V, ttlMs?: number): Promise<void>;
|
|
1021
|
-
delete(key: K): Promise<boolean>;
|
|
1022
|
-
invalidate(prefix?: string): Promise<void>;
|
|
1023
|
-
getOrSet(key: K, factory: () => V | Promise<V>, ttlMs?: number): Promise<V>;
|
|
1024
|
-
}
|
|
1025
|
-
```
|
|
1026
|
-
|
|
1027
|
-
### `MemoryCache`
|
|
1028
|
-
|
|
1029
|
-
```ts
|
|
1030
|
-
new MemoryCache(namespace = "telebibz"): MemoryCache
|
|
1031
|
-
```
|
|
1032
|
-
|
|
1033
|
-
Cache yang menggunakan string sebagai kunci dan menerapkan namespace internal pada setiap key.
|
|
1034
|
-
|
|
1035
|
-
| Method | Perilaku |
|
|
1036
|
-
|---|---|
|
|
1037
|
-
| `get` | Mengambil value atau `undefined`. |
|
|
1038
|
-
| `set` | Menyimpan value dengan TTL opsional. |
|
|
1039
|
-
| `delete` | Menghapus key dan mengembalikan boolean. |
|
|
1040
|
-
| `invalidate(prefix = "")` | Menghapus semua key dalam namespace yang diawali oleh prefix. |
|
|
1041
|
-
| `getOrSet` | Mengembalikan nilai dari cache jika ada; jika tidak ada, menjalankan factory, menyimpan hasilnya, lalu mengembalikannya. |
|
|
1042
|
-
|
|
1043
|
-
`getOrSet` tidak menggunakan lock deduplikasi; factory dapat dijalankan lebih dari sekali bila dipanggil konkuren saat key belum tersedia.
|
|
1044
|
-
|
|
1045
|
-
### `RateLimitResult`
|
|
1046
|
-
|
|
1047
|
-
```ts
|
|
1048
|
-
interface RateLimitResult {
|
|
1049
|
-
allowed: boolean;
|
|
1050
|
-
remaining: number;
|
|
1051
|
-
resetAt: number;
|
|
1052
|
-
retryAfterMs?: number;
|
|
1053
|
-
}
|
|
1054
|
-
```
|
|
1055
|
-
|
|
1056
|
-
### `TokenBucketLimiter`
|
|
1057
|
-
|
|
1058
|
-
```ts
|
|
1059
|
-
new TokenBucketLimiter(
|
|
1060
|
-
capacity: number,
|
|
1061
|
-
refillPerSecond: number,
|
|
1062
|
-
): TokenBucketLimiter
|
|
1063
|
-
```
|
|
1064
|
-
|
|
1065
|
-
Constructor melempar `RangeError` jika salah satu nilai tidak positif. `consume(key, cost = 1)` mengurangi token bila tersedia; jika tidak cukup, mengembalikan `allowed: false` serta estimasi `retryAfterMs`. `clear(key?)` menghapus satu bucket atau seluruh bucket.
|
|
1066
|
-
|
|
1067
|
-
---
|
|
1068
|
-
|
|
1069
|
-
## 8. Queue dan scheduler
|
|
1070
|
-
|
|
1071
|
-
### `Job<T>` dan `QueueOptions`
|
|
1072
|
-
|
|
1073
|
-
```ts
|
|
1074
|
-
interface Job<T = unknown> {
|
|
1075
|
-
id: string;
|
|
1076
|
-
data: T;
|
|
1077
|
-
attempts: number;
|
|
1078
|
-
priority: number;
|
|
1079
|
-
runAt: number;
|
|
1080
|
-
status: "queued" | "running" | "completed" | "failed" | "cancelled";
|
|
1081
|
-
error?: unknown;
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
|
-
interface QueueOptions {
|
|
1085
|
-
concurrency?: number;
|
|
1086
|
-
retries?: number;
|
|
1087
|
-
backoffMs?: number;
|
|
1088
|
-
maxBackoffMs?: number;
|
|
1089
|
-
}
|
|
1090
|
-
```
|
|
1091
|
-
|
|
1092
|
-
### `TaskQueue<T>`
|
|
1093
|
-
|
|
1094
|
-
```ts
|
|
1095
|
-
new TaskQueue<T>(
|
|
1096
|
-
worker: (job: Job<T>, signal: AbortSignal) => Promise<void>,
|
|
1097
|
-
options?: QueueOptions,
|
|
1098
|
-
): TaskQueue<T>
|
|
1099
|
-
```
|
|
1100
|
-
|
|
1101
|
-
| Method | Signature | Deskripsi |
|
|
1102
|
-
|---|---|---|
|
|
1103
|
-
| `add` | `add(data, options?): Job<T>` | Menambah job; options `id`, `priority`, `delayMs`. Job langsung dijadwalkan. |
|
|
1104
|
-
| `get` | `get(id): Job<T> \| undefined` | Mengembalikan salinan status job. |
|
|
1105
|
-
| `cancel` | `cancel(id): boolean` | Membatalkan queued/running job dan abort signal worker. |
|
|
1106
|
-
| `onIdle` | `onIdle(): Promise<void>` | Menunggu sampai pending dan active kosong. |
|
|
1107
|
-
| `close` | `close(): Promise<void>` | Menghentikan draining baru dan membatalkan controller aktif. |
|
|
1108
|
-
|
|
1109
|
-
Job dengan `priority` lebih besar dijalankan lebih dahulu; jika sama, job dengan `runAt` lebih awal dijalankan lebih dahulu. Percobaan ulang dilakukan sampai nilai `retries` terlampaui. Penundaan percobaan ulang bersifat eksponensial dengan batas `maxBackoffMs` bawaan 30 detik.
|
|
1110
|
-
|
|
1111
|
-
### `ScheduledJob`
|
|
1112
|
-
|
|
1113
|
-
```ts
|
|
1114
|
-
interface ScheduledJob {
|
|
1115
|
-
id: string;
|
|
1116
|
-
cancel: () => void;
|
|
1117
|
-
}
|
|
1118
|
-
```
|
|
1119
|
-
|
|
1120
|
-
### `Scheduler`
|
|
1121
|
-
|
|
1122
|
-
```ts
|
|
1123
|
-
new Scheduler(): Scheduler
|
|
1124
|
-
```
|
|
1125
|
-
|
|
1126
|
-
| Method | Signature | Deskripsi |
|
|
1127
|
-
|---|---|---|
|
|
1128
|
-
| `every` | `every(id, intervalMs, task): ScheduledJob` | Menjalankan task menggunakan `setInterval`. Mengganti timer dengan id sama. |
|
|
1129
|
-
| `after` | `after(id, delayMs, task): ScheduledJob` | Menjalankan task sekali menggunakan `setTimeout`. |
|
|
1130
|
-
| `cron` | `cron(id, expression, task): ScheduledJob` | Mendukung format sederhana `*/N` pada field menit, setara interval `N * 60_000`. |
|
|
1131
|
-
| `cancel` | `cancel(id): boolean` | Membatalkan timer. |
|
|
1132
|
-
| `clear` | `clear(): void` | Membatalkan semua timer. |
|
|
1133
|
-
|
|
1134
|
-
Format cron penuh tidak didukung oleh built-in scheduler. Ekspresi selain `*/N` melempar `Error`.
|
|
1135
|
-
|
|
1136
|
-
### `Limiter` dan `mapWithConcurrency`
|
|
1137
|
-
|
|
1138
|
-
```ts
|
|
1139
|
-
new Limiter(limit: number): Limiter
|
|
1140
|
-
|
|
1141
|
-
mapWithConcurrency<T, R>(
|
|
1142
|
-
items: readonly T[],
|
|
1143
|
-
limit: number,
|
|
1144
|
-
worker: (item: T, index: number) => Promise<R>,
|
|
1145
|
-
): Promise<R[]>
|
|
1146
|
-
```
|
|
1147
|
-
|
|
1148
|
-
`Limiter` adalah semaphore berbasis promise: task langsung berjalan selama ada slot kosong dan mengantre FIFO setelahnya. `limit` menerima bilangan bulat positif atau `Infinity` (sepenuhnya paralel — default library). `mapWithConcurrency` memetakan item melalui async worker dengan batas yang sama sambil menjaga urutan hasil. Primitif ini tidak menambahkan delay apa pun — hanya membatasi jumlah task yang berjalan bersamaan. `Limiter` mengekspos `activeCount` dan `queuedCount` untuk observability.
|
|
1149
|
-
|
|
1150
|
-
## 9. Plugin dan services
|
|
1151
|
-
|
|
1152
|
-
### `Plugin<Context>`
|
|
1153
|
-
|
|
1154
|
-
```ts
|
|
1155
|
-
interface Plugin<Context = unknown> {
|
|
1156
|
-
name: string;
|
|
1157
|
-
version?: string;
|
|
1158
|
-
install?: (api: PluginApi<Context>) => void | Promise<void>;
|
|
1159
|
-
setup?: (api: PluginApi<Context>) => void | Promise<void>;
|
|
1160
|
-
onStart?: (api: PluginApi<Context>) => void | Promise<void>;
|
|
1161
|
-
onUpdate?: (context: Context) => void | Promise<void>;
|
|
1162
|
-
onStop?: (api: PluginApi<Context>) => void | Promise<void>;
|
|
1163
|
-
dispose?: (api: PluginApi<Context>) => void | Promise<void>;
|
|
1164
|
-
}
|
|
1165
|
-
```
|
|
1166
|
-
|
|
1167
|
-
### `PluginApi<Context>`
|
|
1168
|
-
|
|
1169
|
-
```ts
|
|
1170
|
-
interface PluginApi<Context> {
|
|
1171
|
-
bot: unknown;
|
|
1172
|
-
services: ServiceContainer;
|
|
1173
|
-
registerMiddleware: (middleware: unknown) => void;
|
|
1174
|
-
registerRoute: (route: unknown) => void;
|
|
1175
|
-
}
|
|
1176
|
-
```
|
|
1177
|
-
|
|
1178
|
-
Pada rilis ini, `registerMiddleware` dan `registerRoute` tersedia sebagai hook API tetapi manajer implementasi belum menghubungkan keduanya secara otomatis ke bot/router. Plugin dapat memakai `api.bot` dan `api.services` secara langsung.
|
|
1179
|
-
|
|
1180
|
-
### `ServiceContainer`
|
|
1181
|
-
|
|
1182
|
-
```ts
|
|
1183
|
-
new ServiceContainer(): ServiceContainer
|
|
1184
|
-
```
|
|
1185
|
-
|
|
1186
|
-
| Method | Signature | Deskripsi |
|
|
1187
|
-
|---|---|---|
|
|
1188
|
-
| `register` | `register<T>(name: string \| symbol, value: T): this` | Menyimpan service dan mendukung chaining. |
|
|
1189
|
-
| `get` | `get<T>(name: string \| symbol): T` | Mengambil service; melempar jika belum terdaftar. |
|
|
1190
|
-
| `has` | `has(name: string \| symbol): boolean` | Memeriksa keberadaan service. |
|
|
1191
|
-
| `delete` | `delete(name: string \| symbol): boolean` | Menghapus service. |
|
|
1192
|
-
|
|
1193
|
-
### `PluginManager<Context>`
|
|
1194
|
-
|
|
1195
|
-
```ts
|
|
1196
|
-
new PluginManager<Context>(bot: unknown): PluginManager<Context>
|
|
1197
|
-
```
|
|
1198
|
-
|
|
1199
|
-
| Method | Perilaku |
|
|
1200
|
-
|---|---|
|
|
1201
|
-
| `use(plugin)` | Menambah plugin; nama duplikat melempar kesalahan. |
|
|
1202
|
-
| `setup()` | Untuk setiap plugin, menjalankan `install` lalu `setup`. |
|
|
1203
|
-
| `start()` | Menjalankan `onStart` sesuai urutan registrasi. |
|
|
1204
|
-
| `update(context)` | Menjalankan `onUpdate` sesuai urutan registrasi. |
|
|
1205
|
-
| `stop()` | Menjalankan `onStop`. |
|
|
1206
|
-
| `dispose()` | Menjalankan `dispose` dalam urutan pendaftaran terbalik. |
|
|
1207
|
-
| `list()` | Mengembalikan daftar plugin hanya baca. |
|
|
1208
|
-
|
|
1209
|
-
`Bot.handleUpdate()` pada rilis ini tidak memanggil `plugins.update()` secara otomatis; panggil manajer secara eksplisit bila plugin memerlukan siklus hidup pembaruan.
|
|
1210
|
-
|
|
1211
|
-
---
|
|
1212
|
-
|
|
1213
|
-
## 10. Webhook
|
|
1214
|
-
|
|
1215
|
-
### `WebhookOptions`
|
|
1216
|
-
|
|
1217
|
-
```ts
|
|
1218
|
-
interface WebhookOptions {
|
|
1219
|
-
secretToken?: string;
|
|
1220
|
-
maxBodyBytes?: number;
|
|
1221
|
-
onError?: (error: unknown) => void | Promise<void>;
|
|
1222
|
-
webhookReply?: boolean;
|
|
1223
|
-
}
|
|
1224
|
-
```
|
|
1225
|
-
|
|
1226
|
-
`webhookReply` (default `false`) mengaktifkan webhook reply ala Telegraf: saat memproses update, panggilan API keluar pertama dijawab lewat respons HTTP webhook itu sendiri (`{"method":"sendMessage", ...}`), sehingga Telegram mengeksekusi method tanpa request kedua. Panggilan itu resolve dengan `true` karena Telegram tidak pernah mengirim hasil method kembali ke respons webhook; setiap panggilan berikutnya tetap lewat transport seperti biasa. Inisialisasi `getMe` malas tidak pernah mengklaim slot tersebut. Berbeda dengan Telegraf, fitur ini opt-in agar deployment webhook yang sudah ada mempertahankan perilakunya persis.
|
|
1227
|
-
|
|
1228
|
-
### `createWebhookHandler(bot, options?)`
|
|
1229
|
-
|
|
1230
|
-
```ts
|
|
1231
|
-
createWebhookHandler<S extends object>(
|
|
1232
|
-
bot: Bot<S>,
|
|
1233
|
-
options?: WebhookOptions,
|
|
1234
|
-
): (request: Request) => Promise<Response>
|
|
1235
|
-
```
|
|
1236
|
-
|
|
1237
|
-
Handler menerima Request standar Web `Request` dan mengembalikan `Response`.
|
|
1238
|
-
|
|
1239
|
-
| Kondisi | Response |
|
|
1240
|
-
|---|---|
|
|
1241
|
-
| Metode bukan POST | `405 Method Not Allowed`, header `allow: POST` |
|
|
1242
|
-
| Header secret tidak cocok | `401 Unauthorized` |
|
|
1243
|
-
| Header `Content-Length` atau body melebihi batas | `413 Payload Too Large` |
|
|
1244
|
-
| JSON tidak valid atau `update_id` bukan integer | `400 Bad Request` untuk update id; exception saat parsing menghasilkan `500` |
|
|
1245
|
-
| `bot.handleUpdate` sukses | `200 OK` dengan body `OK` |
|
|
1246
|
-
| Pengecualian lain | `500 Internal Server Error` dan `onError` dipanggil |
|
|
1247
|
-
|
|
1248
|
-
Nilai default `maxBodyBytes` adalah `1_048_576` bytes. Token rahasia Telegram dibaca dari header `x-telegram-bot-api-secret-token`.
|
|
1249
|
-
|
|
1250
|
-
```ts
|
|
1251
|
-
import { Bot, createWebhookHandler } from "@xbibzlibrary/telebibz";
|
|
1252
|
-
|
|
1253
|
-
const bot = new Bot(process.env.TELEGRAM_BOT_TOKEN!);
|
|
1254
|
-
const handler = createWebhookHandler(bot, {
|
|
1255
|
-
secretToken: process.env.TELEGRAM_WEBHOOK_SECRET,
|
|
1256
|
-
});
|
|
1257
|
-
|
|
1258
|
-
export default { fetch: handler };
|
|
1259
|
-
```
|
|
1260
|
-
|
|
1261
|
-
---
|
|
1262
|
-
|
|
1263
|
-
## 11. Percakapan, wizard, formulir, dan menu
|
|
1264
|
-
|
|
1265
|
-
### Percakapan
|
|
1266
|
-
|
|
1267
|
-
```ts
|
|
1268
|
-
interface ConversationState {
|
|
1269
|
-
name: string;
|
|
1270
|
-
step: number;
|
|
1271
|
-
values: Record<string, unknown>;
|
|
1272
|
-
status: "active" | "completed" | "cancelled";
|
|
1273
|
-
updatedAt: number;
|
|
1274
|
-
}
|
|
1275
|
-
```
|
|
1276
|
-
|
|
1277
|
-
#### `ConversationFlow<S>`
|
|
1278
|
-
|
|
1279
|
-
```ts
|
|
1280
|
-
new ConversationFlow(ctx: Context<S>, state: ConversationState)
|
|
1281
|
-
```
|
|
1282
|
-
|
|
1283
|
-
| Method/property | Signature | Deskripsi |
|
|
1284
|
-
|---|---|---|
|
|
1285
|
-
| `ctx` | `Context<S>` | Context update saat ini. |
|
|
1286
|
-
| `state` | `ConversationState` | State percakapan mutable. |
|
|
1287
|
-
| `values` | `Record<string, unknown>` | Alias ke `state.values`. |
|
|
1288
|
-
| `set` | `set<T>(key, value): this` | Menyimpan value dan memperbarui `updatedAt`. |
|
|
1289
|
-
| `get` | `get<T>(key): T \| undefined` | Mengambil typed value. |
|
|
1290
|
-
| `next` | `next(): this` | Menaikkan step satu. |
|
|
1291
|
-
| `previous` | `previous(): this` | Menurunkan step dengan minimum 0. |
|
|
1292
|
-
| `complete` | `complete(): void` | Status menjadi `completed`. |
|
|
1293
|
-
| `cancel` | `cancel(): void` | Status menjadi `cancelled`. |
|
|
1294
|
-
|
|
1295
|
-
#### `ConversationManager<S>`
|
|
1296
|
-
|
|
1297
|
-
```ts
|
|
1298
|
-
new ConversationManager<S>(): ConversationManager<S>
|
|
1299
|
-
```
|
|
1300
|
-
|
|
1301
|
-
| Method | Signature | Deskripsi |
|
|
1302
|
-
|---|---|---|
|
|
1303
|
-
| `start` | `start(key, name, values?): ConversationState` | Membuat atau mengganti conversation state. |
|
|
1304
|
-
| `get` | `get(key): ConversationState \| undefined` | Mengambil state aktif. |
|
|
1305
|
-
| `cancel` | `cancel(key): boolean` | Menandai cancelled jika ada. |
|
|
1306
|
-
| `clearExpired` | `clearExpired(maxAgeMs): number` | Menghapus state yang `updatedAt` lebih lama dari threshold. |
|
|
1307
|
-
| `run` | `run(ctx, key, name, steps): Promise<ConversationState>` | Menjalankan step sesuai `state.step`; jika tidak ada step, status completed. |
|
|
1308
|
-
|
|
1309
|
-
```ts
|
|
1310
|
-
const conversations = new ConversationManager();
|
|
1311
|
-
await conversations.run(ctx, "chat:1", "profile", [
|
|
1312
|
-
async (flow) => {
|
|
1313
|
-
flow.set("name", ctx.message?.text);
|
|
1314
|
-
flow.next();
|
|
1315
|
-
},
|
|
1316
|
-
async (flow) => {
|
|
1317
|
-
await flow.ctx.reply(`Nama: ${flow.get<string>("name")}`);
|
|
1318
|
-
flow.complete();
|
|
1319
|
-
},
|
|
1320
|
-
]);
|
|
1321
|
-
```
|
|
1322
|
-
|
|
1323
|
-
#### `Wizard<S>` dan `WizardStep<S>`
|
|
1324
|
-
|
|
1325
|
-
```ts
|
|
1326
|
-
interface WizardStep<S> {
|
|
1327
|
-
id: string;
|
|
1328
|
-
run: (flow: ConversationFlow<S>) => void | Promise<void>;
|
|
1329
|
-
optional?: boolean;
|
|
1330
|
-
}
|
|
1331
|
-
|
|
1332
|
-
new Wizard<S>()
|
|
1333
|
-
```
|
|
1334
|
-
|
|
1335
|
-
| Method/property | Deskripsi |
|
|
1336
|
-
|---|---|
|
|
1337
|
-
| `step(definition)` | Menambahkan step dan mengembalikan wizard. `optional` disimpan dalam definition tetapi belum diproses khusus oleh runner. |
|
|
1338
|
-
| `run(ctx, key, manager?)` | Menjalankan step wizard melalui `ConversationManager` dengan name `"wizard"`. |
|
|
1339
|
-
| `steps` | Daftar step read-only. |
|
|
1340
|
-
|
|
1341
|
-
### Formulir
|
|
1342
|
-
|
|
1343
|
-
```ts
|
|
1344
|
-
interface ValidationIssue {
|
|
1345
|
-
path: string;
|
|
1346
|
-
message: string;
|
|
1347
|
-
code?: string;
|
|
1348
|
-
}
|
|
1349
|
-
|
|
1350
|
-
interface Field<T> {
|
|
1351
|
-
name: string;
|
|
1352
|
-
parse: (input: unknown) => T;
|
|
1353
|
-
validate?: (value: T) => string | undefined | Promise<string | undefined>;
|
|
1354
|
-
transform?: (value: T) => T | Promise<T>;
|
|
1355
|
-
required?: boolean;
|
|
1356
|
-
}
|
|
1357
|
-
```
|
|
1358
|
-
|
|
1359
|
-
#### `Form<T>`
|
|
1360
|
-
|
|
1361
|
-
```ts
|
|
1362
|
-
new Form<T extends Record<string, unknown>>(): Form<T>
|
|
1363
|
-
```
|
|
1364
|
-
|
|
1365
|
-
| Method | Deskripsi |
|
|
1366
|
-
|---|---|
|
|
1367
|
-
| `field(definition)` | Mendaftarkan field typed berdasarkan `name`. |
|
|
1368
|
-
| `parse(input)` | Memproses seluruh field. Return union success atau issues. Urutan: required check, parse, transform, validate. |
|
|
1369
|
-
| `reset()` | Menghapus data hasil parse yang tersimpan internal. |
|
|
1370
|
-
|
|
1371
|
-
Hasil parse:
|
|
1372
|
-
|
|
1373
|
-
```ts
|
|
1374
|
-
type FormResult<T> =
|
|
1375
|
-
| { success: true; data: T }
|
|
1376
|
-
| { success: false; issues: ValidationIssue[] };
|
|
1377
|
-
```
|
|
1378
|
-
|
|
1379
|
-
Issue memakai code `required`, `parse`, atau `invalid`.
|
|
1380
|
-
|
|
1381
|
-
#### `validators`
|
|
1382
|
-
|
|
1383
|
-
| Validator | Input | Hasil/eror |
|
|
1384
|
-
|---|---|---|
|
|
1385
|
-
| `validators.string` | `unknown` | String; selain itu `TypeError("Expected string")`. |
|
|
1386
|
-
| `validators.number` | `unknown` | Number finite, termasuk numeric string; selain itu `TypeError("Expected number")`. |
|
|
1387
|
-
| `validators.integer` | `unknown` | Integer; selain itu `TypeError("Expected integer")`. |
|
|
1388
|
-
| `validators.email` | `unknown` | String dengan pola email sederhana; selain itu `TypeError("Expected email")`. |
|
|
1389
|
-
| `validators.url` | `unknown` | String yang diterima constructor `URL`; selain itu `TypeError("Expected URL")`. |
|
|
1390
|
-
|
|
1391
|
-
### Pagination dan menu
|
|
1392
|
-
|
|
1393
|
-
#### `Page<T>`
|
|
1394
|
-
|
|
1395
|
-
```ts
|
|
1396
|
-
interface Page<T> {
|
|
1397
|
-
items: T[];
|
|
1398
|
-
page: number;
|
|
1399
|
-
pageCount: number;
|
|
1400
|
-
hasPrevious: boolean;
|
|
1401
|
-
hasNext: boolean;
|
|
1402
|
-
}
|
|
1403
|
-
```
|
|
1404
|
-
|
|
1405
|
-
#### `paginate(items, page, pageSize)`
|
|
1406
|
-
|
|
1407
|
-
```ts
|
|
1408
|
-
paginate<T>(
|
|
1409
|
-
items: readonly T[],
|
|
1410
|
-
page: number,
|
|
1411
|
-
pageSize: number,
|
|
1412
|
-
): Page<T>
|
|
1413
|
-
```
|
|
1414
|
-
|
|
1415
|
-
Page memakai index berbasis 0. Page yang melebihi batas di-clamp ke halaman terakhir. Collection kosong tetap memiliki `pageCount: 1`. `page` negatif/non-integer atau `pageSize < 1` melempar `RangeError`.
|
|
1416
|
-
|
|
1417
|
-
#### `paginationButtons(page, prefix)`
|
|
1418
|
-
|
|
1419
|
-
```ts
|
|
1420
|
-
paginationButtons(
|
|
1421
|
-
page: Page<unknown>,
|
|
1422
|
-
prefix: string,
|
|
1423
|
-
): InlineKeyboardButton[]
|
|
1424
|
-
```
|
|
1425
|
-
|
|
1426
|
-
Menghasilkan button `Previous`, indicator `${page + 1}/${pageCount}` dengan callback `${prefix}:noop`, dan `Next` sesuai flag page.
|
|
1427
|
-
|
|
1428
|
-
#### `MenuItem`
|
|
1429
|
-
|
|
1430
|
-
```ts
|
|
1431
|
-
interface MenuItem {
|
|
1432
|
-
id: string;
|
|
1433
|
-
label: string;
|
|
1434
|
-
callbackData?: string;
|
|
1435
|
-
url?: string;
|
|
1436
|
-
visible?: boolean | ((context: MenuContext, item: MenuItem) => boolean | Promise<boolean>);
|
|
1437
|
-
permission?: string | ((context: MenuContext, item: MenuItem) => boolean | Promise<boolean>);
|
|
1438
|
-
}
|
|
1439
|
-
```
|
|
1440
|
-
|
|
1441
|
-
#### `Menu`
|
|
1442
|
-
|
|
1443
|
-
```ts
|
|
1444
|
-
new Menu(id: string): Menu
|
|
1445
|
-
```
|
|
1446
|
-
|
|
1447
|
-
| Method/property | Deskripsi |
|
|
1448
|
-
|---|---|
|
|
1449
|
-
| `item(item)` | Menambah item dan mendukung chaining. |
|
|
1450
|
-
| `breadcrumb(label)` | Menambah label breadcrumb. |
|
|
1451
|
-
| `build()` | Menunggu predicate visibility, melewati item invisible, lalu menghasilkan `InlineKeyboard`. URL diprioritaskan dibanding callback. |
|
|
1452
|
-
| `breadcrumbs` | Array breadcrumb read-only. |
|
|
1453
|
-
|
|
1454
|
-
`permission` hanya disimpan sebagai metadata item; `Menu.build()` tidak melakukan authorization otomatis.
|
|
1455
|
-
|
|
1456
|
-
---
|
|
1457
|
-
|
|
1458
|
-
## 12. Logging Terminal
|
|
1459
|
-
|
|
1460
|
-
Saat stdout adalah TTY interaktif, setiap `bot.start()` / `bot.launch()` memainkan urutan startup: efek ketik `Installing Dependencies......`, glass progress bar dengan kilau menyapu, dan banner ASCII rainbow animasi `Tele Bibz` (font figlet `Speed`) yang terus mengalir sampai bot terhubung, lalu diam dengan `✓ Connected as @<username>`.
|
|
1461
|
-
|
|
1462
|
-
Setiap update yang ditangani bot dicatat dalam baris yang mudah dibaca:
|
|
1463
|
-
|
|
1464
|
-
```text
|
|
1465
|
-
[ => ] Message From 123456789 John Doe 29/08/2026 15:04:05
|
|
1466
|
-
↳ Text: /start
|
|
1467
|
-
[ => ] Callback From 123456789 John Doe 29/08/2026 15:04:07
|
|
1468
|
-
↳ Data: menu:open
|
|
1469
|
-
```
|
|
1470
|
-
|
|
1471
|
-
Teks pesan/command dibatasi 50 karakter; data tombol callback ditampilkan penuh. Error dicetak merah lengkap dengan stack. Nonaktifkan dengan `branding: false` pada `Bot`, atau set `logger.format: "json"` untuk log terstruktur — pada mode itu update masuk dikeluarkan sebagai entry `update.received`. Stdout non-interaktif (pipe, Docker, CI) otomatis fallback ke teks polos tanpa animasi.
|
|
1472
|
-
|
|
1473
|
-
Helper branding tambahan yang diekspor untuk aplikasi: `runStartupSequence()`, `startTeleBibzBanner()`, `printTeleBibzBanner()`, `paintRainbow()`, dan `printStatusLine()`.
|
|
1474
|
-
|
|
1475
|
-
## 13. Utilitas Teks
|
|
1476
|
-
|
|
1477
|
-
### `escapeMarkdownV2(value)`
|
|
1478
|
-
|
|
1479
|
-
```ts
|
|
1480
|
-
escapeMarkdownV2(value: string): string
|
|
1481
|
-
```
|
|
1482
|
-
|
|
1483
|
-
Meng-escape karakter MarkdownV2 Telegram: `\\_ * [ ] ( ) ~ ` > # + - = | { } . !`.
|
|
1484
|
-
|
|
1485
|
-
### `escapeHtml(value)`
|
|
1486
|
-
|
|
1487
|
-
```ts
|
|
1488
|
-
escapeHtml(value: string): string
|
|
1489
|
-
```
|
|
1490
|
-
|
|
1491
|
-
Mengubah `&`, `<`, `>`, dan `"` menjadi HTML entities.
|
|
1492
|
-
|
|
1493
|
-
### `md`
|
|
1494
|
-
|
|
1495
|
-
Object helper MarkdownV2 berikut tersedia:
|
|
1496
|
-
|
|
1497
|
-
| Method | Output konseptual |
|
|
1498
|
-
|---|---|
|
|
1499
|
-
| `md.bold(value)` | `*escaped value*` |
|
|
1500
|
-
| `md.italic(value)` | `_escaped value_` |
|
|
1501
|
-
| `md.link(label, url)` | `[escaped label](escaped url)` |
|
|
1502
|
-
| `md.code(value)` | Inline code dengan backtick yang di-escape. |
|
|
1503
|
-
| `md.pre(value, language?)` | Code block dengan language label opsional. |
|
|
1504
|
-
| `md.escape(value)` | Alias `escapeMarkdownV2`. |
|
|
1505
|
-
|
|
1506
|
-
### `splitMessage(text, options?)`
|
|
1507
|
-
|
|
1508
|
-
```ts
|
|
1509
|
-
splitMessage(
|
|
1510
|
-
text: string,
|
|
1511
|
-
options?: {
|
|
1512
|
-
limit?: number;
|
|
1513
|
-
parseMode?: "Markdown" | "MarkdownV2" | "HTML";
|
|
1514
|
-
},
|
|
1515
|
-
): string[]
|
|
1516
|
-
```
|
|
1517
|
-
|
|
1518
|
-
Memecah teks menjadi potongan dengan batas default `4096` karakter. Jika memungkinkan, pemotongan memilih batas paragraf, baris baru, atau spasi; batas hanya dipakai jika terletak lebih dari separuh jendela. `parseMode` diterima sebagai opsi API tetapi belum mengubah algoritma pemotongan.
|
|
1519
|
-
|
|
1520
|
-
Limit kurang dari 1 akan melempar `RangeError`.
|
|
1521
|
-
|
|
1522
|
-
### `splitCaption(text)`
|
|
1523
|
-
|
|
1524
|
-
```ts
|
|
1525
|
-
splitCaption(text: string): string[]
|
|
1526
|
-
```
|
|
1527
|
-
|
|
1528
|
-
Alias `splitMessage(text, { limit: 1024 })`.
|
|
1529
|
-
|
|
1530
|
-
### `template(templateText, values)`
|
|
1531
|
-
|
|
1532
|
-
```ts
|
|
1533
|
-
template(
|
|
1534
|
-
templateText: string,
|
|
1535
|
-
values: Record<string, unknown>,
|
|
1536
|
-
): string
|
|
1537
|
-
```
|
|
1538
|
-
|
|
1539
|
-
Mengganti placeholder `{{ key }}` dan nested path seperti `{{ user.name }}`. Nilai `null` atau `undefined` diganti string kosong; nilai lain dikonversi dengan `String()`.
|
|
1540
|
-
|
|
1541
|
-
```ts
|
|
1542
|
-
template("Halo {{ user.name }}", { user: { name: "Ayu" } });
|
|
1543
|
-
// "Halo Ayu"
|
|
1544
|
-
```
|
|
1545
|
-
|
|
1546
|
-
---
|
|
1547
|
-
|
|
1548
|
-
### `validateUpload(upload, rules)`
|
|
1549
|
-
|
|
1550
|
-
```ts
|
|
1551
|
-
validateUpload(upload: UploadLike, rules: UploadRules): UploadValidationIssue[]
|
|
1552
|
-
```
|
|
1553
|
-
|
|
1554
|
-
Memvalidasi unggahan sebelum dikirim: `maxBytes` (batas ukuran), `allowedMimeTypes` (persis atau wildcard seperti `image/*`), dan `allowedExtensions` (case-insensitive, dengan atau tanpa titik awal). Mengembalikan semua pelanggaran yang ditemukan — array kosong berarti unggahan diterima.
|
|
1555
|
-
|
|
1556
|
-
### `assertValidUpload(upload, rules)`
|
|
1557
|
-
|
|
1558
|
-
Aturan yang sama, tetapi melempar `UploadValidationError` (dengan seluruh `issues` terlampir) alih-alih mengembalikannya.
|
|
1559
|
-
|
|
1560
|
-
```ts
|
|
1561
|
-
import { assertValidUpload } from "@xbibzlibrary/telebibz";
|
|
1562
|
-
|
|
1563
|
-
assertValidUpload(
|
|
1564
|
-
{ sizeBytes: fileBytes.length, mimeType: "image/png", fileName: "logo.png" },
|
|
1565
|
-
{ maxBytes: 5_000_000, allowedMimeTypes: ["image/png", "image/jpeg"], allowedExtensions: [".png", ".jpg"] },
|
|
1566
|
-
);
|
|
1567
|
-
```
|
|
1568
|
-
|
|
1569
|
-
## 14. Testing utilities
|
|
1570
|
-
|
|
1571
|
-
Import dari `@xbibzlibrary/telebibz/testing` atau root package.
|
|
1572
|
-
|
|
1573
|
-
### `MockTransport`
|
|
1574
|
-
|
|
1575
|
-
```ts
|
|
1576
|
-
new MockTransport(): MockTransport
|
|
1577
|
-
```
|
|
1578
|
-
|
|
1579
|
-
| API | Deskripsi |
|
|
1580
|
-
|---|---|
|
|
1581
|
-
| `calls` | Array semua `TransportRequest` yang diterima. |
|
|
1582
|
-
| `respond(method, response)` | Mengatur response statis atau callback berdasarkan payload dan mengembalikan transport. |
|
|
1583
|
-
| `request(request)` | Mencatat request dan mengembalikan response mock. Response default adalah `{ ok: true, result: true }`. |
|
|
1584
|
-
|
|
1585
|
-
Status mock adalah `200` bila `ok: true`, atau `error_code`/`500` bila `ok: false`.
|
|
1586
|
-
|
|
1587
|
-
```ts
|
|
1588
|
-
const transport = new MockTransport()
|
|
1589
|
-
.respond("getMe", {
|
|
1590
|
-
ok: true,
|
|
1591
|
-
result: { id: 1, is_bot: true, first_name: "Test" },
|
|
1592
|
-
});
|
|
1593
|
-
```
|
|
1594
|
-
|
|
1595
|
-
`MockTransport` juga mengimplementasikan member download opsional: `download(filePath)` mencatat path ke `downloads` dan mengembalikan `downloadBytes` (default: encoding UTF-8 dari path), serta `fileUrl(filePath)` mengembalikan `mock://files/<filePath>` — sehingga `bot.downloadFile()` sepenuhnya bisa dites tanpa jaringan.
|
|
1596
|
-
|
|
1597
|
-
### `createMockUpdate(overrides?)`
|
|
1598
|
-
|
|
1599
|
-
```ts
|
|
1600
|
-
createMockUpdate(overrides?: Partial<Update>): Update
|
|
1601
|
-
```
|
|
1602
|
-
|
|
1603
|
-
Membuat update message default dengan `update_id: 1`, chat private id `1`, user id `2`, dan text `/start`. Object `overrides` digabung shallow dengan default.
|
|
1604
|
-
|
|
1605
|
-
### `createTestBot()`
|
|
1606
|
-
|
|
1607
|
-
```ts
|
|
1608
|
-
createTestBot(): { bot: Bot; transport: MockTransport }
|
|
1609
|
-
```
|
|
1610
|
-
|
|
1611
|
-
Membuat bot dengan token test `123456:TEST_TOKEN`, mock `getMe()` yang menghasilkan bot id `99`, dan transport yang dapat diperiksa melalui `transport.calls`.
|
|
1612
|
-
|
|
1613
|
-
### `createMockContext(bot, update?)`
|
|
1614
|
-
|
|
1615
|
-
```ts
|
|
1616
|
-
createMockContext(
|
|
1617
|
-
bot: Bot,
|
|
1618
|
-
update?: Update,
|
|
1619
|
-
): Context
|
|
1620
|
-
```
|
|
1621
|
-
|
|
1622
|
-
Membuat context menggunakan API bot, session kosong, dan services kosong.
|
|
1623
|
-
|
|
1624
|
-
---
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
## 15. Namespace metode Telegram yang dihasilkan
|
|
1628
|
-
|
|
1629
|
-
`generated/api.ts` adalah source internal generator yang mendefinisikan:
|
|
1630
|
-
|
|
1631
|
-
```ts
|
|
1632
|
-
const TELEGRAM_API_VERSION = "10.2";
|
|
1633
|
-
const TELEGRAM_METHOD_NAMES: readonly string[];
|
|
1634
|
-
type TelegramMethodName = typeof TELEGRAM_METHOD_NAMES[number];
|
|
1635
|
-
type GeneratedMethodSpec = {
|
|
1636
|
-
params: Record<string, unknown>;
|
|
1637
|
-
result: unknown;
|
|
1638
|
-
};
|
|
1639
|
-
type GeneratedTelegramMethodMap = {
|
|
1640
|
-
[K in TelegramMethodName]: GeneratedMethodSpec;
|
|
1641
|
-
};
|
|
1642
|
-
const GENERATED_METHODS: Record<TelegramMethodName, TelegramMethodName>;
|
|
1643
|
-
```
|
|
1644
|
-
|
|
1645
|
-
`TELEGRAM_METHOD_NAMES` berisi 184 nama method pada source generator. Namespace tersebut menjadi dasar proxy `api.methods`, `api.call`, dan `api.request`, tetapi file generated tidak diekspor sebagai package subpath publik pada release ini. Parameter/result yang belum dipetakan khusus dapat dipanggil dengan `api.raw()` atau dengan cast parameter pada TypeScript.
|
|
1646
|
-
|
|
1647
|
-
Untuk daftar canonical tanpa pengelompokan, nama method yang tersedia pada generated runtime namespace adalah:
|
|
1648
|
-
|
|
1649
|
-
```text
|
|
1650
|
-
addStickerToSet,
|
|
1651
|
-
answerCallbackQuery,
|
|
1652
|
-
answerChatJoinRequestQuery,
|
|
1653
|
-
answerGuestQuery,
|
|
1654
|
-
answerInlineQuery,
|
|
1655
|
-
answerPreCheckoutQuery,
|
|
1656
|
-
answerShippingQuery,
|
|
1657
|
-
answerWebAppQuery,
|
|
1658
|
-
approveChatJoinRequest,
|
|
1659
|
-
approveSuggestedPost,
|
|
1660
|
-
banChatMember,
|
|
1661
|
-
banChatSenderChat,
|
|
1662
|
-
close,
|
|
1663
|
-
closeForumTopic,
|
|
1664
|
-
closeGeneralForumTopic,
|
|
1665
|
-
convertGiftToStars,
|
|
1666
|
-
copyMessage,
|
|
1667
|
-
copyMessages,
|
|
1668
|
-
createChatInviteLink,
|
|
1669
|
-
createChatSubscriptionInviteLink,
|
|
1670
|
-
createForumTopic,
|
|
1671
|
-
createInvoiceLink,
|
|
1672
|
-
createNewStickerSet,
|
|
1673
|
-
declineChatJoinRequest,
|
|
1674
|
-
declineSuggestedPost,
|
|
1675
|
-
deleteAllMessageReactions,
|
|
1676
|
-
deleteBusinessMessages,
|
|
1677
|
-
deleteChatPhoto,
|
|
1678
|
-
deleteChatStickerSet,
|
|
1679
|
-
deleteEphemeralMessage,
|
|
1680
|
-
deleteForumTopic,
|
|
1681
|
-
deleteMessage,
|
|
1682
|
-
deleteMessageReaction,
|
|
1683
|
-
deleteMessages,
|
|
1684
|
-
deleteMyCommands,
|
|
1685
|
-
deleteStickerFromSet,
|
|
1686
|
-
deleteStickerSet,
|
|
1687
|
-
deleteStory,
|
|
1688
|
-
deleteWebhook,
|
|
1689
|
-
editChatInviteLink,
|
|
1690
|
-
editChatSubscriptionInviteLink,
|
|
1691
|
-
editEphemeralMessageCaption,
|
|
1692
|
-
editEphemeralMessageMedia,
|
|
1693
|
-
editEphemeralMessageReplyMarkup,
|
|
1694
|
-
editEphemeralMessageText,
|
|
1695
|
-
editForumTopic,
|
|
1696
|
-
editGeneralForumTopic,
|
|
1697
|
-
editMessageCaption,
|
|
1698
|
-
editMessageChecklist,
|
|
1699
|
-
editMessageLiveLocation,
|
|
1700
|
-
editMessageMedia,
|
|
1701
|
-
editMessageReplyMarkup,
|
|
1702
|
-
editMessageText,
|
|
1703
|
-
editStory,
|
|
1704
|
-
editUserStarSubscription,
|
|
1705
|
-
exportChatInviteLink,
|
|
1706
|
-
forwardMessage,
|
|
1707
|
-
forwardMessages,
|
|
1708
|
-
getAvailableGifts,
|
|
1709
|
-
getBusinessAccountGifts,
|
|
1710
|
-
getBusinessAccountStarBalance,
|
|
1711
|
-
getBusinessConnection,
|
|
1712
|
-
getChat,
|
|
1713
|
-
getChatAdministrators,
|
|
1714
|
-
getChatGifts,
|
|
1715
|
-
getChatMember,
|
|
1716
|
-
getChatMemberCount,
|
|
1717
|
-
getChatMenuButton,
|
|
1718
|
-
getCustomEmojiStickers,
|
|
1719
|
-
getFile,
|
|
1720
|
-
getForumTopicIconStickers,
|
|
1721
|
-
getGameHighScores,
|
|
1722
|
-
getManagedBotAccessSettings,
|
|
1723
|
-
getManagedBotToken,
|
|
1724
|
-
getMe,
|
|
1725
|
-
getMyCommands,
|
|
1726
|
-
getMyDefaultAdministratorRights,
|
|
1727
|
-
getMyDescription,
|
|
1728
|
-
getMyName,
|
|
1729
|
-
getMyShortDescription,
|
|
1730
|
-
getMyStarBalance,
|
|
1731
|
-
getStarTransactions,
|
|
1732
|
-
getStickerSet,
|
|
1733
|
-
getUpdates,
|
|
1734
|
-
getUserChatBoosts,
|
|
1735
|
-
getUserGifts,
|
|
1736
|
-
getUserPersonalChatMessages,
|
|
1737
|
-
getUserProfileAudios,
|
|
1738
|
-
getUserProfilePhotos,
|
|
1739
|
-
getWebhookInfo,
|
|
1740
|
-
giftPremiumSubscription,
|
|
1741
|
-
hideGeneralForumTopic,
|
|
1742
|
-
leaveChat,
|
|
1743
|
-
logOut,
|
|
1744
|
-
pinChatMessage,
|
|
1745
|
-
postStory,
|
|
1746
|
-
promoteChatMember,
|
|
1747
|
-
readBusinessMessage,
|
|
1748
|
-
refundStarPayment,
|
|
1749
|
-
removeBusinessAccountProfilePhoto,
|
|
1750
|
-
removeChatVerification,
|
|
1751
|
-
removeMyProfilePhoto,
|
|
1752
|
-
removeUserVerification,
|
|
1753
|
-
reopenForumTopic,
|
|
1754
|
-
reopenGeneralForumTopic,
|
|
1755
|
-
replaceManagedBotToken,
|
|
1756
|
-
replaceStickerInSet,
|
|
1757
|
-
repostStory,
|
|
1758
|
-
restrictChatMember,
|
|
1759
|
-
revokeChatInviteLink,
|
|
1760
|
-
savePreparedInlineMessage,
|
|
1761
|
-
savePreparedKeyboardButton,
|
|
1762
|
-
sendAnimation,
|
|
1763
|
-
sendAudio,
|
|
1764
|
-
sendChatAction,
|
|
1765
|
-
sendChatJoinRequestWebApp,
|
|
1766
|
-
sendChecklist,
|
|
1767
|
-
sendContact,
|
|
1768
|
-
sendDice,
|
|
1769
|
-
sendDocument,
|
|
1770
|
-
sendGame,
|
|
1771
|
-
sendGift,
|
|
1772
|
-
sendInvoice,
|
|
1773
|
-
sendLivePhoto,
|
|
1774
|
-
sendLocation,
|
|
1775
|
-
sendMediaGroup,
|
|
1776
|
-
sendMessage,
|
|
1777
|
-
sendMessageDraft,
|
|
1778
|
-
sendPaidMedia,
|
|
1779
|
-
sendPhoto,
|
|
1780
|
-
sendPoll,
|
|
1781
|
-
sendRichMessage,
|
|
1782
|
-
sendRichMessageDraft,
|
|
1783
|
-
sendSticker,
|
|
1784
|
-
sendVenue,
|
|
1785
|
-
sendVideo,
|
|
1786
|
-
sendVideoNote,
|
|
1787
|
-
sendVoice,
|
|
1788
|
-
setBusinessAccountBio,
|
|
1789
|
-
setBusinessAccountGiftSettings,
|
|
1790
|
-
setBusinessAccountName,
|
|
1791
|
-
setBusinessAccountProfilePhoto,
|
|
1792
|
-
setBusinessAccountUsername,
|
|
1793
|
-
setChatAdministratorCustomTitle,
|
|
1794
|
-
setChatDescription,
|
|
1795
|
-
setChatMemberTag,
|
|
1796
|
-
setChatMenuButton,
|
|
1797
|
-
setChatPermissions,
|
|
1798
|
-
setChatPhoto,
|
|
1799
|
-
setChatStickerSet,
|
|
1800
|
-
setChatTitle,
|
|
1801
|
-
setCustomEmojiStickerSetThumbnail,
|
|
1802
|
-
setGameScore,
|
|
1803
|
-
setManagedBotAccessSettings,
|
|
1804
|
-
setMessageReaction,
|
|
1805
|
-
setMyCommands,
|
|
1806
|
-
setMyDefaultAdministratorRights,
|
|
1807
|
-
setMyDescription,
|
|
1808
|
-
setMyName,
|
|
1809
|
-
setMyProfilePhoto,
|
|
1810
|
-
setMyShortDescription,
|
|
1811
|
-
setPassportDataErrors,
|
|
1812
|
-
setStickerEmojiList,
|
|
1813
|
-
setStickerKeywords,
|
|
1814
|
-
setStickerMaskPosition,
|
|
1815
|
-
setStickerPositionInSet,
|
|
1816
|
-
setStickerSetThumbnail,
|
|
1817
|
-
setStickerSetTitle,
|
|
1818
|
-
setUserEmojiStatus,
|
|
1819
|
-
setWebhook,
|
|
1820
|
-
stopMessageLiveLocation,
|
|
1821
|
-
stopPoll,
|
|
1822
|
-
transferBusinessAccountStars,
|
|
1823
|
-
transferGift,
|
|
1824
|
-
unbanChatMember,
|
|
1825
|
-
unbanChatSenderChat,
|
|
1826
|
-
unhideGeneralForumTopic,
|
|
1827
|
-
unpinAllChatMessages,
|
|
1828
|
-
unpinAllForumTopicMessages,
|
|
1829
|
-
unpinAllGeneralForumTopicMessages,
|
|
1830
|
-
unpinChatMessage,
|
|
1831
|
-
upgradeGift,
|
|
1832
|
-
uploadStickerFile,
|
|
1833
|
-
verifyChat
|
|
1834
|
-
```
|
|
1835
|
-
|
|
1836
|
-
> Daftar di atas mengikuti generated source. Jika Telegram menambahkan method baru, jalankan `npm run update:telegram` atau `telebibz generate` setelah schema diperbarui.
|
|
1837
|
-
|
|
1838
|
-
---
|
|
1839
|
-
|
|
1840
|
-
## 16. CLI
|
|
1841
|
-
|
|
1842
|
-
Binary package adalah `telebibz`.
|
|
1843
|
-
|
|
1844
|
-
```bash
|
|
1845
|
-
npx telebibz <command>
|
|
1846
|
-
```
|
|
1847
|
-
|
|
1848
|
-
| Command | Perilaku |
|
|
1849
|
-
|---|---|
|
|
1850
|
-
| `telebibz init [directory]` | Membuat directory, `index.ts` minimal, dan `.env.example`. Default directory `my-telebibz-bot`. |
|
|
1851
|
-
| `telebibz doctor` | Menampilkan Node version, presence `TELEGRAM_BOT_TOKEN`, cwd, package name, lalu health API jika token tersedia. Exit code menjadi 1 jika API tidak reachable. |
|
|
1852
|
-
| `telebibz generate` | Menjalankan generator method dari `scripts/generate-api.mjs`. |
|
|
1853
|
-
| `telebibz build` | Menjalankan `npm run build`. |
|
|
1854
|
-
| `telebibz test` | Menjalankan `npm test`. |
|
|
1855
|
-
| `telebibz webhook` | Memeriksa `TELEGRAM_BOT_TOKEN`, memakai `TELEGRAM_WEBHOOK_SECRET` bila ada, membuat handler, dan mencetak kesiapan. Command ini tidak membuat HTTP server. |
|
|
1856
|
-
| `telebibz inspect` | Menampilkan cwd dan Node version. |
|
|
1857
|
-
| tanpa command | Menampilkan daftar command bantuan. |
|
|
1858
|
-
|
|
1859
|
-
Environment variable yang dipakai CLI adalah `TELEGRAM_BOT_TOKEN` dan `TELEGRAM_WEBHOOK_SECRET`.
|
|
1860
|
-
|
|
1861
|
-
---
|
|
1862
|
-
|
|
1863
|
-
## 17. Tipe Telegram utama
|
|
1864
|
-
|
|
1865
|
-
Paket mengekspor tipe data yang paling sering digunakan secara langsung.
|
|
1866
|
-
|
|
1867
|
-
| Tipe | Isi penting |
|
|
1868
|
-
|---|---|
|
|
1869
|
-
| `User` | ID, penanda bot, nama, username, bahasa, dan penanda kemampuan. |
|
|
1870
|
-
| `Chat` | ID, tipe, title/username/nama, penanda forum/pesan langsung. |
|
|
1871
|
-
| `Message` | ID, tanggal, chat, pengirim, teks/caption, entity, reply, markup, plus index signature untuk field Telegram tambahan. |
|
|
1872
|
-
| `Update` | Semua field update yang didukung sumber, termasuk message, callback, inline, poll, member, join request, reaction, boost, business, dan field ekstensi. |
|
|
1873
|
-
| `CallbackQuery` | ID, from, message/inline message id, chat instance, data. |
|
|
1874
|
-
| `InlineQuery` | ID, from, query, offset, tipe chat, lokasi. |
|
|
1875
|
-
| `Poll`, `PollAnswer` | Data poll dan jawaban. |
|
|
1876
|
-
| `ChatMemberUpdated`, `ChatJoinRequest` | Perubahan anggota dan permintaan bergabung. |
|
|
1877
|
-
| `InlineKeyboardMarkup`, `ReplyKeyboardMarkup`, `ReplyKeyboardRemove`, `ForceReply` | Bentuk reply markup Telegram. |
|
|
1878
|
-
| `MessageEntity`, `ReplyParameters`, `LinkPreviewOptions` | Metadata entity, reply, dan pratinjau tautan. |
|
|
1879
|
-
| `BotCommand`, `BotCommandScope`, `WebhookInfo`, `File`, `UserProfilePhotos`, `ChatMember`, `ChatAdministratorRights` | Tipe hasil/parameter untuk helper API. |
|
|
1880
|
-
|
|
1881
|
-
---
|
|
1882
|
-
|
|
1883
|
-
## 18. Persistence, cron lengkap, menu, dan deklarasi Telegram lengkap
|
|
1884
|
-
|
|
1885
|
-
### Adapter storage persistent
|
|
1886
|
-
|
|
1887
|
-
Semua adapter mengimplementasikan kontrak `Storage<K, V>` yang sama. Package inti tetap tidak memiliki runtime dependency vendor; adapter Redis, SQL, dan Mongo menerima driver kecil yang disediakan aplikasi atau client vendor pilihan aplikasi.
|
|
1888
|
-
|
|
1889
|
-
| Class | Konstruktor | Tujuan |
|
|
1890
|
-
|---|---|---|
|
|
1891
|
-
| `MemoryStorage<K, V>` | `new MemoryStorage()` | Storage in-memory cepat dengan TTL dan `update()` atomik per key. |
|
|
1892
|
-
| `JsonFileStorage<V>` | `new JsonFileStorage(filePath)` | Persistensi JSON atomik untuk deployment single-process. |
|
|
1893
|
-
| `RedisStorage<V>` | `new RedisStorage(client, prefix?)` | Storage Redis melalui `RedisLikeClient`, termasuk TTL dan namespace. |
|
|
1894
|
-
| `SqlStorage<V>` | `new SqlStorage(driver)` | Storage SQL melalui `SqlStorageDriver` milik aplikasi. |
|
|
1895
|
-
| `MongoStorage<V>` | `new MongoStorage(collection)` | Storage Mongo melalui `MongoStorageCollection` milik aplikasi. |
|
|
1896
|
-
|
|
1897
|
-
`BotOptions.session` menerima `Storage<string, S>`, sehingga session dapat memakai adapter apa pun. `ConversationManager` menerima abstraction yang sama dan menyediakan `getAsync()`, `cancelAsync()`, serta `clearExpiredAsync()` untuk state conversation durable.
|
|
1898
|
-
|
|
1899
|
-
```ts
|
|
1900
|
-
const session = new JsonFileStorage<Record<string, unknown>>("./data/sessions.json");
|
|
1901
|
-
const bot = new Bot({ token: process.env.TELEGRAM_BOT_TOKEN!, session });
|
|
1902
|
-
```
|
|
1903
|
-
|
|
1904
|
-
### Cron lima field lengkap
|
|
1905
|
-
|
|
1906
|
-
`parseCronExpression()` mendukung lima field standar `minute hour day-of-month month day-of-week`, termasuk wildcard, list, range, dan step seperti `*/15 9-17 1,15 * 1-5`. `nextCronOccurrence()` menghitung occurrence lokal berikutnya. `Scheduler.cron()` memakai timer one-shot dan menjadwalkan ulang setelah setiap eksekusi; kegagalan task dikirim ke `Scheduler({ onError })`, bukan menjadi unhandled promise rejection.
|
|
1907
|
-
|
|
1908
|
-
### Mode matching router
|
|
1909
|
-
|
|
1910
|
-
`new Router()` menggunakan **first-match secara default** untuk mencegah double reply. Gunakan `new Router({ matchMode: "all" })` hanya untuk fan-out yang disengaja. Matcher RegExp mereset `lastIndex`, sehingga expression global atau sticky dapat digunakan ulang dengan aman.
|
|
1911
|
-
|
|
1912
|
-
### MenuController dan permission
|
|
1913
|
-
|
|
1914
|
-
`Menu` mendukung item berbasis permission, predicate visibility/permission asynchronous, breadcrumb, dan layout multi-kolom. `MenuController` menambahkan render halaman stateful dan dispatch callback untuk `select`, `page`, `noop`, serta callback asing.
|
|
1915
|
-
|
|
1916
|
-
### Namespace deklarasi Telegram lengkap
|
|
1917
|
-
|
|
1918
|
-
Package memvendorkan declaration Telegram berlisensi MIT dan mengeksposnya sebagai type-only export melalui `TelegramTypes`, serta alias seperti `TelegramUser`, `TelegramMessage`, `TelegramUpdate`, dan `TelegramApiMethods`. CLI memakai kotak Unicode berwarna dengan attribution `Library Bot Telegram By @xbibzofficial`. `Logger` menghasilkan output terminal atau JSON terstruktur dengan level, redaction, ringkasan update, dan opt-in untuk isi pesan user/callback. Declaration ini mencakup surface object, union, enum, dan method tanpa runtime dependency tambahan. Map method inti telebibz tetap khusus untuk method yang memiliki pemetaan parameter/result langsung.
|
|
1919
|
-
|
|
1920
|
-
---
|
|
1921
|
-
|
|
1922
|
-
## 19. Kompatibilitas dan batasan yang perlu diketahui
|
|
1923
|
-
|
|
1924
|
-
Perpustakaan menargetkan Node.js `>=22`, menggunakan ESM sebagai module utama, serta menyediakan build CommonJS. Webhook membutuhkan runtime yang menyediakan Web `Request`, `Response`, `Headers`, `FormData`, `Blob`, dan `AbortController`; Node.js modern menyediakannya secara native.
|
|
1925
|
-
|
|
1926
|
-
Daftar method yang dihasilkan API dan peta method API bukanlah hal yang sama. `TelegramMethodName` mencakup 184 nama runtime, tetapi `TelegramMethodMap` hanya memiliki parameter/hasil yang bertipe khusus untuk subset yang tercantum pada bagian API client. Untuk method lain, gunakan `api.raw()` atau tambahkan deklarasi tipe di sisi aplikasi.
|
|
1927
|
-
|
|
1928
|
-
State session dan primitive in-memory lainnya hilang saat proses dimulai ulang kecuali aplikasi menyediakan adapter persistent. `BotOptions.session` menerima kontrak generic `Storage<string, S>`.
|
|
1929
|
-
|
|
1930
|
-
---
|
|
1931
|
-
|
|
1932
|
-
## Referensi
|
|
1933
|
-
|
|
1934
|
-
[1]: https://core.telegram.org/bots/api "Telegram Bot API — dokumentasi resmi"
|
|
1935
|
-
[2]: https://www.npmjs.com/package/@xbibzlibrary/telebibz "@xbibzlibrary/telebibz di npm"
|