@xbibzlibrary/telebibz 3.0.1 → 3.1.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 +18 -0
- package/README.id.md +642 -0
- package/README.md +556 -147
- package/examples/03-wizard.js +37 -8
- package/index.d.ts +28 -3
- package/index.js +2 -0
- package/lib/telebibz.js +3 -0
- package/lib/wizard.js +184 -18
- package/package.json +2 -2
- package/test/all.test.js +106 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.1.0 — wizard: tombol pilihan + mode edit/delete (2026-09-13)
|
|
4
|
+
|
|
5
|
+
- **Wizard mendukung tombol pilihan**: `step.buttons` sebagai reply keyboard
|
|
6
|
+
(`['A','B']`, `[{text,value}]`, atau baris eksplisit) atau inline keyboard
|
|
7
|
+
callback (`step.inline: true`) — klik tombol langsung menjadi nilai jawaban.
|
|
8
|
+
- `onlyButtons` menolak ketikan bebas; `parse`/`validate` tetap berlaku untuk
|
|
9
|
+
nilai tombol; tombol usang dijawab alert aman tanpa crash.
|
|
10
|
+
- **Wizard mendukung edit & delete pesan**: `mode: 'edit'` (satu pesan diedit
|
|
11
|
+
dari awal sampai akhir) dan `mode: 'delete'` (pesan tanya lama dihapus
|
|
12
|
+
sebelum pertanyaan berikutnya), bisa di-override per langkah via `step.mode`.
|
|
13
|
+
- `cleanup` menghapus pesan tanya terakhir saat wizard selesai (default aktif
|
|
14
|
+
pada mode `'delete'`); `removeKeyboard` otomatis menyingkirkan reply keyboard.
|
|
15
|
+
- Helper programatis baru: `wizard.cancel/editAsk/deleteAsk` + shortcut
|
|
16
|
+
`bot.wizardCancel()`, `bot.wizardEdit()`, `bot.wizardDelete()`.
|
|
17
|
+
- Modul `wizard` kini diekspor dari `index.js` (sebelumnya hanya lewat kelas).
|
|
18
|
+
- API lama 100% backward-compatible (tanpa `buttons`/`mode`, perilaku identik v3.0).
|
|
19
|
+
- Test offline bertambah 24 → **30/30 lulus**. Contoh `examples/03-wizard.js` diperbarui.
|
|
20
|
+
|
|
3
21
|
## 3.0.0 — production-grade parity grammY (2026-09-07)
|
|
4
22
|
|
|
5
23
|
- DEPENDENSI NYATA & TERTEST: axios (keep-alive transport), mime-types, https-proxy-agent, debug.
|
package/README.id.md
ADDED
|
@@ -0,0 +1,642 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
[🇬 **English**](README.md) · [🇮 **Indonesia**](README.id.md)
|
|
4
|
+
|
|
5
|
+
<br>
|
|
6
|
+
|
|
7
|
+
<a href="https://www.npmjs.com/package/@xbibzlibrary/telebibz" title="Buka telebibz di npm">
|
|
8
|
+
<img src="https://imgbs.com/uploads/telebibz-d7b30671.png" alt="telebibz — Telegram Bot Library" width="560">
|
|
9
|
+
</a>
|
|
10
|
+
|
|
11
|
+
<br><br>
|
|
12
|
+
|
|
13
|
+
**Library Telegram paling gampang untuk Node.js — set fitur penuh setara grammY.**<br>
|
|
14
|
+
Recode mandiri atas arsitektur elegan [grammY](https://grammy.dev), dengan dependency
|
|
15
|
+
produksi yang *benar-benar dipakai*, dokumentasi 🇮🇩 Indonesia-first, dan nol drama.
|
|
16
|
+
|
|
17
|
+
<br>
|
|
18
|
+
|
|
19
|
+
[](https://www.npmjs.com/package/@xbibzlibrary/telebibz)
|
|
20
|
+
[](https://www.npmjs.com/package/@xbibzlibrary/telebibz)
|
|
21
|
+
[](https://nodejs.org)
|
|
22
|
+
[](#-test--bukti-live)
|
|
23
|
+
[](#-analitik--statistik)
|
|
24
|
+
[](LICENSE)
|
|
25
|
+
[](https://github.com/XbibzOfficial777/telebibz)
|
|
26
|
+
|
|
27
|
+
<br>
|
|
28
|
+
|
|
29
|
+
`//—Xbibz Official—//`
|
|
30
|
+
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 📑 Daftar Isi
|
|
36
|
+
|
|
37
|
+
| | | |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| ⚡ [Kenapa telebibz?](#kenapa) | 📊 [Matriks fitur vs grammY](#matriks) | 📥 [Instalasi & persyaratan](#instalasi) |
|
|
40
|
+
| 🚀 [Mulai cepat](#mulai) | 🧠 [Cara kerja (arsitektur)](#arsitektur) | 📖 [Dokumentasi lengkap](#dokumentasi) |
|
|
41
|
+
| 🎛️ [Handler & filter](#handler) | 💬 [Shortcut Context](#context) | 🔘 [Keyboard & tombol](#keyboard) |
|
|
42
|
+
| 🍽️ [Menu interaktif](#menu) | 🧙 [Wizard (form + tombol + edit/delete)](#wizard) | ❓ [Mode inline](#inline) |
|
|
43
|
+
| 📣 [Broadcast](#broadcast) | 📎 [File & media](#file) | 🛡️ [Keandalan & rate limit](#ratelimit) |
|
|
44
|
+
| 🗃️ [Session](#session) | 🇮🇩 [Error manusiawi](#error) | 🕸️ [Webhook & serverless](#webhook) |
|
|
45
|
+
| 🔌 [Transport proxy](#proxy) | 🧪 [Transformer](#transformer) | 📈 [Analitik & statistik](#analitik) |
|
|
46
|
+
| 🧩 [Contoh siap jalan](#contoh) | 🔬 [Test & bukti live](#test) | 📂 [Struktur repo](#struktur) |
|
|
47
|
+
| 🕐 [Changelog](#changelog) | 📄 [Lisensi](#lisensi) | |
|
|
48
|
+
|
|
49
|
+
<a id="kenapa"></a>
|
|
50
|
+
## ⚡ Kenapa telebibz?
|
|
51
|
+
|
|
52
|
+
> [!TIP]
|
|
53
|
+
> **Satu prinsip:** semua fitur yang di grammY butuh plugin, di telebibz sudah
|
|
54
|
+
> **bawaan** — wizard, menu, rate-limit, broadcast, download file — dan polling
|
|
55
|
+
> yang *tidak mati* kena 409.
|
|
56
|
+
|
|
57
|
+
- 🧠 **API grammY yang sudah kamu kenal** — `bot.cmd()`, `bot.hears()`, `ctx.reply()`, middleware, transformer
|
|
58
|
+
- 🧙 **Wizard bawaan v3.1** — form tanya-jawab dengan **tombol pilihan** (reply/inline) dan mode **edit/delete** pesan
|
|
59
|
+
- 🛡️ **Tahan banting** — auto-retry 429, throttler, limiter anti-spam, polling retry saat konflik 409
|
|
60
|
+
- 🇮🇩 **Error manusiawi** — setiap error Telegram diterjemahkan + dikasih saran penyelesaian
|
|
61
|
+
- 🔌 **Proxy API segala metode** — `api.metodeApaPun({...})` otomatis tersedia, bahkan untuk metode yang belum rilis
|
|
62
|
+
- 🪶 **Ringan & jujur** — 4 dependency, semuanya terpakai nyata dan ter-test
|
|
63
|
+
|
|
64
|
+
<a id="matriks"></a>
|
|
65
|
+
## 📊 Matriks Fitur — parity grammY
|
|
66
|
+
|
|
67
|
+
| Fitur | grammY | telebibz |
|
|
68
|
+
|---|:---:|:---:|
|
|
69
|
+
| Proxy API **segala metode** (auto-generated) | ✅ | ✅ |
|
|
70
|
+
| ~60 shortcut bertipe (sendMessage, banChatMember…) | ✅ | ✅ |
|
|
71
|
+
| Context lengkap (~70 pintasan reply/edit/admin/react) | ✅ | ✅ |
|
|
72
|
+
| Context flavor business (`business_connection_id` otomatis) | plugin | ✅ bawaan |
|
|
73
|
+
| Filter `on('message:photo' / ':text' / 'chat_type:private' …)` | ✅ | ✅ |
|
|
74
|
+
| `cmd / hears / action / inlineQuery` | ✅ | ✅ (+ inlineQuery matcher) |
|
|
75
|
+
| `branch / filter / drop / route / lazy / fork` | ✅ | ✅ |
|
|
76
|
+
| Error boundary + catch | ✅ | ✅ (semua shortcut otomatis terlindungi) |
|
|
77
|
+
| Session + storage swappable | ✅ | ✅ |
|
|
78
|
+
| Transformer API (`api.config.use`) | ✅ | ✅ |
|
|
79
|
+
| `auto-retry` 429 hormati `retry_after` | plugin | ✅ bawaan `autoRetry()` |
|
|
80
|
+
| Throttler antre-rate-limit | plugin | ✅ bawaan `throttler()` |
|
|
81
|
+
| Rate limit per-user | plugin | ✅ bawaan `limiter()` |
|
|
82
|
+
| `InputFile` Buffer/path/stream + multipart `attach://` | ✅ | ✅ |
|
|
83
|
+
| `InputMedia` builder + media group | ✅ | ✅ `InputMediaBuilder` |
|
|
84
|
+
| Download file (`getFile`/`downloadFile`) | plugin | ✅ bawaan |
|
|
85
|
+
| Keyboard & InlineKeyboard fluent class | ✅ | ✅ |
|
|
86
|
+
| Menu interaktif | plugin | ✅ bawaan `Menu/MenuContainer` |
|
|
87
|
+
| Wizard/percakapan | plugin | ✅ bawaan — **+ tombol pilihan & mode `edit`/`delete`** |
|
|
88
|
+
| Long polling tahan-409 | ❌ (fatal crash) | ✅ bawaan (auto-retry 5 dtk) |
|
|
89
|
+
| Broadcast siap pakai | ❌ | ✅ `bot.broadcast()` |
|
|
90
|
+
| Humanisasi error + saran (🇮🇩) | ❌ | ✅ `humanize()` |
|
|
91
|
+
| Banner boot + log debug | ❌ | ✅ (`DEBUG=telebibz*`) |
|
|
92
|
+
| Proxy HTTP(S) untuk VPS | ⚠️ manual | ✅ opsi `proxy` transport |
|
|
93
|
+
| TypeScript | ✅ full | d.ts longgar (JS-first) |
|
|
94
|
+
| Bahasa dokumentasi | en | **🇬🇧 + 🇮🇩** |
|
|
95
|
+
|
|
96
|
+
<a id="instalasi"></a>
|
|
97
|
+
## 📥 Instalasi & Persyaratan
|
|
98
|
+
|
|
99
|
+
**Persyaratan:** Node.js ≥ 18 (memakai `FormData`/`Blob` global untuk upload).
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
npm install @xbibzlibrary/telebibz
|
|
103
|
+
# atau
|
|
104
|
+
yarn add @xbibzlibrary/telebibz
|
|
105
|
+
# atau
|
|
106
|
+
pnpm add @xbibzlibrary/telebibz
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Dependency runtime (semuanya dipakai & ter-test):**
|
|
110
|
+
|
|
111
|
+
| Paket | Untuk |
|
|
112
|
+
|---|---|
|
|
113
|
+
| `axios ^1.20` | transport keep-alive + streaming `downloadFile` |
|
|
114
|
+
| `mime-types ^3.0` | deteksi content-type upload |
|
|
115
|
+
| `https-proxy-agent ^9.1` | opsi proxy transport VPS |
|
|
116
|
+
| `debug ^4.4` | log `DEBUG=telebibz:net,telebibz:ratelimit` |
|
|
117
|
+
|
|
118
|
+
Ambil token bot dari **@BotFather** → `/newbot`. Konstruktor memvalidasi format
|
|
119
|
+
token (`123456:ABC…`) dan melempar error yang jelas kalau salah.
|
|
120
|
+
|
|
121
|
+
<a id="mulai"></a>
|
|
122
|
+
## 🚀 Mulai Cepat
|
|
123
|
+
|
|
124
|
+
```js
|
|
125
|
+
const { TeleBibz } = require('@xbibzlibrary/telebibz');
|
|
126
|
+
|
|
127
|
+
const bot = new TeleBibz('TOKEN_DARI_BOTFATHER');
|
|
128
|
+
|
|
129
|
+
bot.cmd('start', (ctx) => ctx.reply('Halo!'));
|
|
130
|
+
bot.hears(/halo|hai/i, (ctx) => ctx.reply('halo juga 👋'));
|
|
131
|
+
bot.hears('ping', (ctx) => ctx.reply('pong 🏓'));
|
|
132
|
+
|
|
133
|
+
bot.launch();
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
BOT_TOKEN=123:abc node index.js
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
┌──────────────────────────────────┐
|
|
142
|
+
│ 🤖 TeleBibz ON │
|
|
143
|
+
│ bot : @botkamu (id 123456) │
|
|
144
|
+
│ mode : long-polling │
|
|
145
|
+
│ library : telebibz 3.1.0 │
|
|
146
|
+
│ brand : //—Xbibz Official—// │
|
|
147
|
+
└──────────────────────────────────┘
|
|
148
|
+
✔ menunggu update… (Ctrl+C untuk berhenti)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
> [!NOTE]
|
|
152
|
+
> **Hidup di VPS:** kalau ada instance bot lain yang masih polling (409 Conflict —
|
|
153
|
+
> misal deploy ganda atau hosting restart), telebibz **otomatis retry tiap 5 detik
|
|
154
|
+
> tanpa crash** dan menyala begitu jalur bebas. Tidak perlu PM2 babysitter.
|
|
155
|
+
|
|
156
|
+
<a id="arsitektur"></a>
|
|
157
|
+
## 🧠 Cara Kerja (Arsitektur)
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
┌─────────────────────────────────────────────┐
|
|
161
|
+
Telegram Bot API ────►│ long polling (lib/runner.js) │
|
|
162
|
+
│ atau webhook / handleUpdate (lib/telebibz) │
|
|
163
|
+
└──────────────────┬──────────────────────────┘
|
|
164
|
+
│ update JSON mentah
|
|
165
|
+
▼
|
|
166
|
+
Context(update, api, me) lib/context.js
|
|
167
|
+
│
|
|
168
|
+
┌────────────────────────────▼───────────────────────────┐
|
|
169
|
+
│ Pohon middleware `_root` (urutan tetap): │
|
|
170
|
+
│ 1. session() lib/session.js │
|
|
171
|
+
│ 2. wizard.middleware() lib/wizard.js │
|
|
172
|
+
│ 3. errorBoundary(reporter) │
|
|
173
|
+
│ └─► handler kamu: use/cmd/hears/action/on/ │
|
|
174
|
+
│ inlineQuery/Menu/wizard lib/composer.js │
|
|
175
|
+
└────────────────────────────┬───────────────────────────┘
|
|
176
|
+
│ ctx.reply / ctx.api.*
|
|
177
|
+
▼
|
|
178
|
+
ApiBase + Proxy + pipeline transformer lib/api.js
|
|
179
|
+
(api.config.use → autoRetry / throttler)
|
|
180
|
+
│
|
|
181
|
+
▼
|
|
182
|
+
transport axios: JSON atau multipart attach:// lib/net.js
|
|
183
|
+
│
|
|
184
|
+
▼
|
|
185
|
+
https://api.telegram.org
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**Lifecycle satu update** (mis. `/start`): `getUpdates` → `pollLoop` →
|
|
189
|
+
`handleUpdate` → `Context` baru → session dimuat → middleware wizard (tak ada
|
|
190
|
+
wizard aktif → lanjut) → error boundary → handler kamu yang cocok jalan →
|
|
191
|
+
`ctx.reply()` → pipeline transformer → axios → Telegram. Error yang dilempar
|
|
192
|
+
jadi `BotError` dan mengalir ke `opts.onError` atau reporter manusiawi.
|
|
193
|
+
|
|
194
|
+
<a id="dokumentasi"></a>
|
|
195
|
+
## 📖 Dokumentasi Lengkap
|
|
196
|
+
|
|
197
|
+
### 🏗️ Konstruktor & opsi
|
|
198
|
+
|
|
199
|
+
```js
|
|
200
|
+
const bot = new TeleBibz('TOKEN', {
|
|
201
|
+
allowedUpdates: [...], // batasi tipe update (default: tipe umum + Business)
|
|
202
|
+
onError: (err, ctx) {}, // handle error sendiri (default: reporter manusiawi)
|
|
203
|
+
silent: false, // tanpa banner boot
|
|
204
|
+
dropPending: false, // buang update lama saat start
|
|
205
|
+
session: { ... }, // { initial, getKey, storage } — lihat bagian Session
|
|
206
|
+
transport: fn, // suntik transport custom (test / proxy)
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
<a id="handler"></a>
|
|
211
|
+
### 🎛️ Handler & filter
|
|
212
|
+
|
|
213
|
+
```js
|
|
214
|
+
bot.cmd('ping', (ctx) => ctx.reply('pong')); // /ping
|
|
215
|
+
bot.cmd(['a', 'b'], handler); // /a ATAU /b
|
|
216
|
+
bot.start('Selamat datang!'); // shortcut: daftarkan /start
|
|
217
|
+
bot.hears('daftar', handler); // teks persis "daftar" (case-insensitive)
|
|
218
|
+
bot.hears(/kuc?ing/i, handler); // regex bebas
|
|
219
|
+
bot.on('message:photo', handler); // filter gaya grammY
|
|
220
|
+
bot.on([':text', 'chat_type:private'], handler);
|
|
221
|
+
bot.action('menu:premium', handler); // callback_query data (string / RegExp)
|
|
222
|
+
bot.inlineQuery(/kucing/i, handler); // mode inline (regex / string / '*')
|
|
223
|
+
bot.use(middleware); // middleware manual
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Kombinator composer (semantik grammY):
|
|
227
|
+
|
|
228
|
+
```js
|
|
229
|
+
bot.branch(pred, kalauYa, kalauTidak); // pilih subpohon berdasar predikat
|
|
230
|
+
bot.filter(pred, ...mw); // jalan hanya jika pred(ctx) true
|
|
231
|
+
bot.drop(pred, ...mw); // dilewati jika pred(ctx) true
|
|
232
|
+
bot.route('chat.type', { private: mwA, group: mwB }); // petakan ctx → handler
|
|
233
|
+
bot.lazy((ctx) => ctx.from.is_bot ? mwBot : mwUser); // bangun mw per update
|
|
234
|
+
bot.fork(mwLambat); // jalan di latar, tidak menahan next()
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Filter yang didukung `on()`: field update (`message`, `edited_message`,
|
|
238
|
+
`callback_query`, `inline_query`, `my_chat_member`, …), properti pesan
|
|
239
|
+
(`message:photo`, `message:text`, `:caption`, `:document`, `:sticker`, `:media`, …),
|
|
240
|
+
tipe chat (`chat_type:private/group/supergroup/channel`), plus
|
|
241
|
+
`callback_query:data`, payment, reaksi, join request.
|
|
242
|
+
|
|
243
|
+
Handler perintah menerima argumen di `ctx.match`:
|
|
244
|
+
|
|
245
|
+
```js
|
|
246
|
+
bot.cmd('echo', (ctx) => ctx.reply(`argumen: ${ctx.match}`)); // /echo halo → "halo"
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
<a id="context"></a>
|
|
250
|
+
### 💬 Shortcut Context
|
|
251
|
+
|
|
252
|
+
`ctx` membungkus semua jenis update (message, edited, channel, business,
|
|
253
|
+
callback, inline…) dengan accessor seragam: `chat`, `from`, `chatId`, `msgId`,
|
|
254
|
+
`msg`, `senderChat`, `inlineMessageId`, `businessConnectionId`.
|
|
255
|
+
|
|
256
|
+
| Kategori | Shortcut |
|
|
257
|
+
|---|---|
|
|
258
|
+
| **Balasan** | `reply`, `replyWithHTML`, `replyWithMarkdown`, `replyWithPhoto/Video/Audio/Document/Animation/Voice/VideoNote/Sticker/MediaGroup/Location/Venue/Contact/Poll/Dice/Invoice/ChatAction` |
|
|
259
|
+
| **Edit & hapus** | `editMessageText/Caption/Media/ReplyMarkup`, `deleteMessage`, `deleteMessages` — sadar callback & inline-message |
|
|
260
|
+
| **Reaksi** | `react('👍')` |
|
|
261
|
+
| **Teruskan/salin** | `forwardMessage(tujuan)`, `copyMessage(tujuan)` (default pesan saat ini) |
|
|
262
|
+
| **Callback & inline** | `answerCallbackQuery` (string atau objek), `answerInlineQuery` |
|
|
263
|
+
| **Admin** | `banChatMember`, `restrictChatMember`, `promoteChatMember`, `banAuthor`, `restrictAuthor`, `getChat*`, `getAuthor`, `leaveChat`, `setChatTitle/Description`, `pin/unpinChatMessage` |
|
|
264
|
+
| **File** | `getFile()` (pintar: photo terbesar), `downloadFile(dest)` |
|
|
265
|
+
|
|
266
|
+
Akun business: balasan dalam konteks business otomatis menyertakan
|
|
267
|
+
`business_connection_id`.
|
|
268
|
+
|
|
269
|
+
<a id="keyboard"></a>
|
|
270
|
+
### 🔘 Keyboard & tombol
|
|
271
|
+
|
|
272
|
+
```js
|
|
273
|
+
const { btn, url, webApp, copy, kb, InlineKeyboard, Keyboard } = require('@xbibzlibrary/telebibz');
|
|
274
|
+
|
|
275
|
+
bot.cmd('menu', (ctx) =>
|
|
276
|
+
ctx.reply('Pilih:', kb([
|
|
277
|
+
[btn('💎 Premium', 'prem', 'primary'), // biru/ungu
|
|
278
|
+
btn('✅ Daftar', 'reg', 'success')], // hijau
|
|
279
|
+
[url('🌐 Web', 'https://situsmu.com')],
|
|
280
|
+
[btn('❌ Tutup', 'close', 'danger', '5408846744727334338')], // merah + IKON ANIMASI
|
|
281
|
+
])));
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
- 🎨 Warna `style` (`primary`/`success`/`danger`) butuh aplikasi Telegram rilis ≥ Feb 2026 — versi lama tampil biasa, tidak error.
|
|
285
|
+
- ✨ `icon_custom_emoji_id` butuh **owner bot ber-Premium** atau username Fragment.
|
|
286
|
+
- Helper: `copy(text, nilai)` (salin ke clipboard), `webApp(text, link)`, `kb.confirm(yaData, tidakData)`, `kb.markup(rows)`.
|
|
287
|
+
- Kelas fluent: `new InlineKeyboard().text(...).url(...).row().text(...).build()` dan `new Keyboard().text(...).requestContact(...).resized().build()` (reply keyboard asli).
|
|
288
|
+
|
|
289
|
+
<a id="menu"></a>
|
|
290
|
+
### 🍽️ Menu interaktif
|
|
291
|
+
|
|
292
|
+
```js
|
|
293
|
+
const { Menu, MenuContainer } = require('@xbibzlibrary/telebibz');
|
|
294
|
+
|
|
295
|
+
const mc = new MenuContainer();
|
|
296
|
+
const utama = mc.create('utama'), lanjut = mc.create('lanjut');
|
|
297
|
+
|
|
298
|
+
utama.text('🔔 Notif', async (ctx) => ctx.answerCallbackQuery('dinyalakan!'))
|
|
299
|
+
.row()
|
|
300
|
+
.url('🌐 Web', 'https://x.com')
|
|
301
|
+
.submenu('Lanjut ▶', 'lanjut');
|
|
302
|
+
lanjut.back('◀️ Kembali', 'utama');
|
|
303
|
+
|
|
304
|
+
bot.use(mc); // handler tombol terdaftar otomatis
|
|
305
|
+
bot.cmd('cfg', (ctx) => ctx.reply('Menu:', { reply_markup: utama.render(ctx) }));
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Submenu menukar keyboard di tempat lewat `editMessageReplyMarkup`; tombol usang
|
|
309
|
+
dijawab alert ramah, bukan crash.
|
|
310
|
+
|
|
311
|
+
<a id="wizard"></a>
|
|
312
|
+
### 🧙 Wizard — form percakapan, nol boilerplate
|
|
313
|
+
|
|
314
|
+
```js
|
|
315
|
+
bot.wizard('daftar', {
|
|
316
|
+
steps: [
|
|
317
|
+
{ key: 'nama', ask: 'Siapa namamu?' },
|
|
318
|
+
{ key: 'umur', ask: 'Umur?', parse: Number,
|
|
319
|
+
validate: (n) => (n > 0 && n < 120 ? null : 'Angka saja ya:') },
|
|
320
|
+
],
|
|
321
|
+
done: async (ans, ctx) => ctx.reply(`Oke ${ans.nama} (${ans.umur})!`),
|
|
322
|
+
});
|
|
323
|
+
// user tinggal /daftar → bot bertanya sampai selesai.
|
|
324
|
+
// ketik "batal" / "cancel" kapan pun untuk berhenti. Sesi otomatis aktif.
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
`bot.wizard(id, def, bindCommand = true)` otomatis mengikat `/id` sebagai
|
|
328
|
+
pemicu; pakai `bot.wizardStart(ctx, id)` dari handler mana pun (tombol, menu, …).
|
|
329
|
+
|
|
330
|
+
#### 🆕 v3.1 — tombol pilihan + mode `edit`/`delete`
|
|
331
|
+
|
|
332
|
+
```js
|
|
333
|
+
bot.wizard('survey', {
|
|
334
|
+
mode: 'edit', // 'send' (default) | 'edit' | 'delete'
|
|
335
|
+
steps: [
|
|
336
|
+
// reply keyboard — user ketuk, tak perlu mengetik
|
|
337
|
+
{ key: 'jk', ask: 'Jenis kelamin?', buttons: ['👨 Laki-laki', '👩 Perempuan'], onlyButtons: true },
|
|
338
|
+
|
|
339
|
+
// inline keyboard (callback) — nilai boleh beda dari label
|
|
340
|
+
{ key: 'pulau', ask: 'Domisili pulau?', inline: true, onlyButtons: true,
|
|
341
|
+
buttons: [[{ text: '🌋 Jawa', value: 'jawa' }, { text: '🌴 Sumatera', value: 'sumatera' }]] },
|
|
342
|
+
|
|
343
|
+
// ketikan bebas dengan validasi (mode bisa di-override per langkah)
|
|
344
|
+
{ key: 'umur', ask: 'Umur?', parse: Number, mode: 'send',
|
|
345
|
+
validate: (n) => (n > 0 && n < 120 ? null : 'Angka saja ya:') },
|
|
346
|
+
],
|
|
347
|
+
done: async (ans, ctx) => ctx.reply(`Tersimpan: ${JSON.stringify(ans)}`),
|
|
348
|
+
});
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
| Opsi | Level | Fungsi |
|
|
352
|
+
|---|:---:|---|
|
|
353
|
+
| `buttons` | step | `['A','B']`, `[{text,value}]`, atau baris eksplisit `[['A'],['B','C']]` |
|
|
354
|
+
| `inline` | step | `true` → tombol callback (klik = nilai, tanpa mengetik) |
|
|
355
|
+
| `onlyButtons` | step | `true`/string → tolak ketikan bebas, wajib pilih tombol |
|
|
356
|
+
| `mode` | def/step | `'send'` pesan baru · `'edit'` satu pesan diedit terus · `'delete'` pesan lama dihapus dulu |
|
|
357
|
+
| `cleanup` | def | hapus pesan tanya terakhir saat selesai (default aktif pada mode `'delete'`) |
|
|
358
|
+
| `removeKeyboard` | def | singkirkan reply keyboard saat selesai (default `true` bila sempat dipakai) |
|
|
359
|
+
|
|
360
|
+
Helper programatis: `bot.wizardCancel(ctx)`, `bot.wizardEdit(ctx, teks)`,
|
|
361
|
+
`bot.wizardDelete(ctx)`, plus modul `wizard` (`cancel/editAsk/deleteAsk`).
|
|
362
|
+
Tombol usang (diklik setelah wizard pindah/selesai) dijawab alert aman — bot
|
|
363
|
+
tidak pernah crash. `parse`/`validate` juga berlaku untuk nilai tombol.
|
|
364
|
+
|
|
365
|
+
<a id="inline"></a>
|
|
366
|
+
### ❓ Mode inline
|
|
367
|
+
|
|
368
|
+
```js
|
|
369
|
+
const { iq } = require('@xbibzlibrary/telebibz');
|
|
370
|
+
|
|
371
|
+
bot.inlineQuery(/kucing/i, async (ctx) => {
|
|
372
|
+
await ctx.answerInlineQuery([
|
|
373
|
+
iq.article('1', 'Fakta kucing', { message_text: 'meong!' }),
|
|
374
|
+
iq.photo('2', 'https://x/1.jpg'),
|
|
375
|
+
], { cache_time: 0 });
|
|
376
|
+
});
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
Builder hasil: `iq.article/photo/gif/video/audio/location/sticker`.
|
|
380
|
+
|
|
381
|
+
<a id="broadcast"></a>
|
|
382
|
+
### 📣 Broadcast (aman rate-limit)
|
|
383
|
+
|
|
384
|
+
```js
|
|
385
|
+
const hasil = await bot.broadcast([111, 222, 333], 'Pengumuman!', { delay: 35 });
|
|
386
|
+
// → { terkirim: 3, gagal: 0, errors: [] } (yang memblokir tercatat di errors)
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
`pesan` boleh string, objek payload `sendMessage`, atau fungsi
|
|
390
|
+
`(chatId) => payload` untuk personalisasi per penerima. Pacing default 35 ms
|
|
391
|
+
(≈28 pesan/detik, aman di bawah limit Telegram).
|
|
392
|
+
|
|
393
|
+
<a id="file"></a>
|
|
394
|
+
### 📎 File & media
|
|
395
|
+
|
|
396
|
+
```js
|
|
397
|
+
const { InputFile, InputMediaBuilder } = require('@xbibzlibrary/telebibz');
|
|
398
|
+
|
|
399
|
+
bot.cmd('foto', (ctx) => ctx.replyWithPhoto(new InputFile(buffer, 'x.jpg')));
|
|
400
|
+
bot.cmd('dok', (ctx) => ctx.replyWithDocument(new InputFile('/path/file.pdf')));
|
|
401
|
+
bot.cmd('album', (ctx) => ctx.replyWithMediaGroup([
|
|
402
|
+
InputMediaBuilder.photo('https://a/1.jpg'),
|
|
403
|
+
InputMediaBuilder.photo('https://a/2.jpg', { caption: 'dua' }),
|
|
404
|
+
]));
|
|
405
|
+
bot.on('message:photo', async (ctx) => {
|
|
406
|
+
const f = await ctx.getFile(); // ukuran photo terbesar, otomatis
|
|
407
|
+
await ctx.downloadFile('./foto.jpg'); // streaming ke disk
|
|
408
|
+
});
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
`InputFile` menerima Buffer / Uint8Array / path file / stream fs / async
|
|
412
|
+
iterable; upload dikirim sebagai `multipart` dengan `attach://` di mana pun
|
|
413
|
+
dalam payload (media group, thumbnail, …). `api.downloadFile(file_id, dest)`
|
|
414
|
+
juga bisa berdiri sendiri.
|
|
415
|
+
|
|
416
|
+
<a id="ratelimit"></a>
|
|
417
|
+
### 🛡️ Keandalan & rate limit
|
|
418
|
+
|
|
419
|
+
```js
|
|
420
|
+
const { autoRetry, throttler, limiter } = require('@xbibzlibrary/telebibz');
|
|
421
|
+
|
|
422
|
+
bot.api.config.use(autoRetry()); // retry 429, hormati retry_after (maks 5)
|
|
423
|
+
bot.api.config.use(throttler()); // antrean global ≤ 28 panggilan/detik
|
|
424
|
+
bot.use(limiter({ windowMs: 2000, limit: 3, onExceeded })); // anti-spam per-user
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
Long polling tahan banting secara default: konflik 409 retry tiap 5 detik
|
|
428
|
+
(atur via `launch({ conflictDelay: 5000 })`), gangguan jaringan backoff 1
|
|
429
|
+
detik, `stop()` keluar dengan bersih (`await bot.runPromise`).
|
|
430
|
+
|
|
431
|
+
<a id="session"></a>
|
|
432
|
+
### 🗃️ Session
|
|
433
|
+
|
|
434
|
+
```js
|
|
435
|
+
const { session } = require('@xbibzlibrary/telebibz');
|
|
436
|
+
|
|
437
|
+
const bot = new TeleBibz(token, {
|
|
438
|
+
session: {
|
|
439
|
+
initial: () => ({ hitung: 0 }),
|
|
440
|
+
getKey: (ctx) => `${ctx.from?.id}:${ctx.chat?.id}`, // default
|
|
441
|
+
storage: adapterRedisKu, // { read(k), write(k,v), delete(k) } — default: Map memori
|
|
442
|
+
},
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
bot.on(':text', (ctx) => { ctx.session.hitung++; });
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
`ctx.session` selalu ada bahkan tanpa konfigurasi apa pun.
|
|
449
|
+
|
|
450
|
+
<a id="error"></a>
|
|
451
|
+
### 🇮🇩 Error yang bisa dibaca manusia
|
|
452
|
+
|
|
453
|
+
Setiap error dilaporkan dengan saran yang bisa ditindaklanjuti:
|
|
454
|
+
|
|
455
|
+
```
|
|
456
|
+
✖ Telegram error (403): Forbidden: bot was blocked by the user
|
|
457
|
+
💡 saran: Bot diblokir pengguna — jangan kirim ulang, hapus dari daftar broadcast.
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
`humanize(err)` mengembalikan `{ pesan, saran, method, code }` untuk 15+ error
|
|
461
|
+
Telegram umum (token salah, chat not found, hak admin, parse error, rate
|
|
462
|
+
limit, callback basi, file kegedean, …). Override lewat
|
|
463
|
+
`new TeleBibz(token, { onError: (err, ctx) => {} })`.
|
|
464
|
+
|
|
465
|
+
<a id="webhook"></a>
|
|
466
|
+
### 🕸️ Webhook & serverless
|
|
467
|
+
|
|
468
|
+
```js
|
|
469
|
+
const http = require('http');
|
|
470
|
+
http.createServer((req, res) =>
|
|
471
|
+
req.url === '/tg' ? bot.webhook()(req, res) : res.end('ok')
|
|
472
|
+
).listen(8443);
|
|
473
|
+
|
|
474
|
+
// framework apa pun (Express/Fastify/Hono): pasang handler (req, res) dari bot.webhook()
|
|
475
|
+
// — atau serverless, langsung:
|
|
476
|
+
await bot.handleUpdate(req.body); // satu update mentah → pipeline penuh
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
Jangan lupa `await bot.init()` dulu kalau tidak memakai `launch()` (untuk
|
|
480
|
+
mengambil info bot), dan pasang webhook via `bot.api.setWebhook({ url })`.
|
|
481
|
+
|
|
482
|
+
<a id="proxy"></a>
|
|
483
|
+
### 🔌 Transport proxy (VPS di balik proxy)
|
|
484
|
+
|
|
485
|
+
```js
|
|
486
|
+
const { TeleBibz, createTransport } = require('@xbibzlibrary/telebibz');
|
|
487
|
+
const bot = new TeleBibz(token, {
|
|
488
|
+
transport: createTransport(token, { proxy: 'http://user:pass@proxy:8080' }),
|
|
489
|
+
});
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
`createTransport(token, { apiRoot, proxy, timeoutMs, headers })` juga bisa
|
|
493
|
+
diarahkan ke Bot API server lokal.
|
|
494
|
+
|
|
495
|
+
<a id="transformer"></a>
|
|
496
|
+
### 🧪 Transformer (escape hatch)
|
|
497
|
+
|
|
498
|
+
```js
|
|
499
|
+
bot.api.config.use(async (prev, method, payload) => {
|
|
500
|
+
console.log('→', method); // lihat/modifikasi semua panggilan Bot API
|
|
501
|
+
return prev(method, payload);
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
// metode apa pun, bahkan yang belum rilis (sihir Proxy):
|
|
505
|
+
await bot.api.sendDiceCustom({ chat_id: 1, emoji: '🎲' });
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
<a id="analitik"></a>
|
|
509
|
+
## 📈 Analitik & Statistik
|
|
510
|
+
|
|
511
|
+
### 📊 Repo ini dalam angka
|
|
512
|
+
|
|
513
|
+
| Metrik | Nilai |
|
|
514
|
+
|---|---|
|
|
515
|
+
| 📦 Modul sumber | **16 file** di `lib/` |
|
|
516
|
+
| 📝 Total baris kode | **±1.700** (tanpa build step) |
|
|
517
|
+
| 🔌 Metode Bot API | **90+** — 75 shortcut bertipe + Proxy tanpa batas |
|
|
518
|
+
| ⌨️ Shortcut Context | **50+** (reply/edit/delete/admin/react…) |
|
|
519
|
+
| 🧪 Test offline | **30/30 lulus**, tanpa jaringan |
|
|
520
|
+
| 🧩 Contoh siap jalan | **7** di `examples/` |
|
|
521
|
+
| 📦 Dependency runtime | **4** — semuanya terpakai & ter-test |
|
|
522
|
+
|
|
523
|
+
### ⬇️ Download & popularitas (live dari npm)
|
|
524
|
+
|
|
525
|
+
[](https://www.npmjs.com/package/@xbibzlibrary/telebibz)
|
|
526
|
+
[](https://www.npmjs.com/package/@xbibzlibrary/telebibz)
|
|
527
|
+
[](https://www.npmjs.com/package/@xbibzlibrary/telebibz)
|
|
528
|
+
[](https://www.npmjs.com/package/@xbibzlibrary/telebibz)
|
|
529
|
+
|
|
530
|
+
### 📏 Peta ukuran modul (baris kode)
|
|
531
|
+
|
|
532
|
+
```
|
|
533
|
+
wizard.js █████████████████████████ 247 ← form + tombol + edit/delete
|
|
534
|
+
telebibz.js ███████████████████▎ 193 ← kelas utama & siklus hidup
|
|
535
|
+
context.js ███████████████████ 190 ← ctx + 50-an shortcut
|
|
536
|
+
composer.js █████████████████▍ 174 ← mesin middleware & filter
|
|
537
|
+
api.js ███████████████▍ 154 ← 75 shortcut + Proxy + transformer
|
|
538
|
+
net.js ███████████▌ 115 ← transport axios + multipart
|
|
539
|
+
menus.js █████████ 90 ← Menu/MenuContainer
|
|
540
|
+
keyboard.js ████████▎ 83 ← btn/url/kb + kelas fluent
|
|
541
|
+
ratelimit.js ██████ 61 ← autoRetry · throttler · limiter
|
|
542
|
+
runner.js ████▌ 45 ← polling tahan-409
|
|
543
|
+
file.js ████ 41 ← InputFile + InputMediaBuilder
|
|
544
|
+
logger.js ███▊ 38 ← log + banner
|
|
545
|
+
session.js ███▌ 36 ← session swappable
|
|
546
|
+
errors.js ███▌ 35 ← humanize error 🇮
|
|
547
|
+
broadcast.js ███▌ 35 ← blast aman rate-limit
|
|
548
|
+
inline-query.js██▊ 28 ← matcher + builder hasil
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
### 🗺️ Kesehatan repo
|
|
552
|
+
|
|
553
|
+
<div align="center">
|
|
554
|
+
|
|
555
|
+
[](https://github.com/XbibzOfficial777/telebibz)
|
|
556
|
+
|
|
557
|
+
</div>
|
|
558
|
+
|
|
559
|
+
<details>
|
|
560
|
+
<summary>📅 Riwayat bintang (klik untuk buka)</summary>
|
|
561
|
+
|
|
562
|
+

|
|
563
|
+
|
|
564
|
+
</details>
|
|
565
|
+
|
|
566
|
+
<a id="contoh"></a>
|
|
567
|
+
## 🧩 Contoh Siap Jalan (`examples/`)
|
|
568
|
+
|
|
569
|
+
| File | Isi |
|
|
570
|
+
|---|---|
|
|
571
|
+
| `01-quickstart.js` | bot jalan dalam 6 baris |
|
|
572
|
+
| `02-menu-tombol.js` | keyboard berwarna + ikon animasi |
|
|
573
|
+
| `03-wizard.js` | form pendaftaran + **tombol + mode edit** |
|
|
574
|
+
| `04-broadcast.js` | blast admin |
|
|
575
|
+
| `05-kirim-file.js` | foto & dokumen dari buffer |
|
|
576
|
+
| `06-menu.js` | menu interaktif + submenu |
|
|
577
|
+
| `07-inline-query.js` | mode inline dengan builder hasil |
|
|
578
|
+
|
|
579
|
+
Jalankan dengan `BOT_TOKEN=123:abc node examples/01-quickstart.js`.
|
|
580
|
+
|
|
581
|
+
<a id="test"></a>
|
|
582
|
+
## 🔬 Test & Bukti Live
|
|
583
|
+
|
|
584
|
+
```bash
|
|
585
|
+
npm test # 30 kasus, TANPA jaringan (transport disuntik)
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
Tervalidasi **30/30 offline + 10 live** pada bot produksi `@xbibzrat_bot`:
|
|
589
|
+
getMe · keyboard berwarna & ikon animasi asli · upload multipart
|
|
590
|
+
(photo+document) · edit keyboard · broadcast · deleteMessage · polling 409
|
|
591
|
+
retry · wizard tombol & edit/delete.
|
|
592
|
+
|
|
593
|
+
Log debug: `DEBUG=telebibz:net,telebibz:ratelimit node botkamu.js`.
|
|
594
|
+
|
|
595
|
+
<a id="struktur"></a>
|
|
596
|
+
## 📂 Struktur Repo (16 file inti)
|
|
597
|
+
|
|
598
|
+
| File | Peran |
|
|
599
|
+
|---|---|
|
|
600
|
+
| `lib/net.js` | transport axios keep-alive + multipart `attach://` |
|
|
601
|
+
| `lib/api.js` | metode Bot API + Proxy segala metode + transformer |
|
|
602
|
+
| `lib/composer.js` | middleware, filter `on('message:photo')`, `errorBoundary` |
|
|
603
|
+
| `lib/context.js` | objek ctx + 50-an pintasan reply/edit/delete/callback |
|
|
604
|
+
| `lib/session.js` | sesi per user:chat (storage swappable) |
|
|
605
|
+
| `lib/runner.js` | long polling: retry 409, backoff jaringan, drop pending |
|
|
606
|
+
| `lib/wizard.js` | form percakapan + tombol pilihan + mode edit/delete |
|
|
607
|
+
| `lib/menus.js` | menu interaktif `Menu`/`MenuContainer` |
|
|
608
|
+
| `lib/keyboard.js` | builder tombol + kelas fluent `InlineKeyboard`/`Keyboard` |
|
|
609
|
+
| `lib/ratelimit.js` | `autoRetry` 429 · antre `throttler` · `limiter` per-user |
|
|
610
|
+
| `lib/broadcast.js` | blast aman rate-limit |
|
|
611
|
+
| `lib/file.js` | `File`/`InputFile` (Buffer/path/stream) + `InputMediaBuilder` |
|
|
612
|
+
| `lib/inline-query.js` | matcher query + builder hasil inline |
|
|
613
|
+
| `lib/errors.js` | humanisasi error + saran |
|
|
614
|
+
| `lib/logger.js` | log berbingkai + banner boot |
|
|
615
|
+
| `index.js` / `index.d.ts` | pintu ekspor + tipe TypeScript |
|
|
616
|
+
|
|
617
|
+
<a id="changelog"></a>
|
|
618
|
+
## 🕐 Changelog
|
|
619
|
+
|
|
620
|
+
- **3.1.0** — wizard: tombol pilihan (reply/inline), mode `edit`/`delete`, cleanup otomatis, helper programatis · test 24 → 30
|
|
621
|
+
- **3.0.0** — parity grammY production-grade: axios keep-alive, transformer, menu, inline query, limiter
|
|
622
|
+
- **2.0.0** — engine ditulis ulang dari nol, transport multipart, webhook Node murni
|
|
623
|
+
- **1.0.0** — recode arsitektur grammY
|
|
624
|
+
|
|
625
|
+
> Detail lengkap di [`CHANGELOG.md`](CHANGELOG.md). Studi arsitektur mendalam: [`ANALISIS-telebibz.md`](ANALISIS-telebibz.md).
|
|
626
|
+
|
|
627
|
+
<a id="lisensi"></a>
|
|
628
|
+
## 📄 Lisensi
|
|
629
|
+
|
|
630
|
+
**MIT** © Xbibz Official — arsitektur terinspirasi [grammY](https://grammy.dev) (MIT, lihat [`NOTICE.md`](NOTICE.md)).
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
<div align="center">
|
|
635
|
+
|
|
636
|
+
**Dibuat dengan ❤️ oleh //—Xbibz Official—//**
|
|
637
|
+
|
|
638
|
+
Kalau telebibz membantumu, bintang ⭐ repo ini sangat berarti.
|
|
639
|
+
|
|
640
|
+
[](https://github.com/XbibzOfficial777/telebibz)
|
|
641
|
+
|
|
642
|
+
</div>
|