@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 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
+ [![npm version](https://img.shields.io/npm/v/@xbibzlibrary/telebibz?style=for-the-badge&logo=npm&logoColor=white&color=CB3837&label=telebibz)](https://www.npmjs.com/package/@xbibzlibrary/telebibz)
20
+ [![downloads](https://img.shields.io/npm/dm/@xbibzlibrary/telebibz?style=for-the-badge&logo=npm&logoColor=white&color=green&label=unduh%2Fbulan)](https://www.npmjs.com/package/@xbibzlibrary/telebibz)
21
+ [![node](https://img.shields.io/node/v/@xbibzlibrary/telebibz?style=for-the-badge&logo=node.js&logoColor=white&color=339933&label=node)](https://nodejs.org)
22
+ [![tests](https://img.shields.io/badge/test-30%2F30%20lulus-brightgreen?style=for-the-badge&logo=checkmarx&logoColor=white)](#-test--bukti-live)
23
+ [![size](https://img.shields.io/badge/kode-1.7k%20baris-orange?style=for-the-badge&logo=codeigniter&logoColor=white)](#-analitik--statistik)
24
+ [![license](https://img.shields.io/npm/l/@xbibzlibrary/telebibz?style=for-the-badge&color=blue)](LICENSE)
25
+ [![views](https://komarev.com/ghpvc/?username=XbibzOfficial777&repo=telebibz&style=for-the-badge&color=blueviolet&label=kunjungan+repo)](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
+ [![per hari](https://img.shields.io/npm/dd/@xbibzlibrary/telebibz?style=flat-square&label=hari&color=informational)](https://www.npmjs.com/package/@xbibzlibrary/telebibz)
526
+ [![per minggu](https://img.shields.io/npm/dw/@xbibzlibrary/telebibz?style=flat-square&label=minggu&color=informational)](https://www.npmjs.com/package/@xbibzlibrary/telebibz)
527
+ [![per bulan](https://img.shields.io/npm/dm/@xbibzlibrary/telebibz?style=flat-square&label=bulan&color=informational)](https://www.npmjs.com/package/@xbibzlibrary/telebibz)
528
+ [![total](https://img.shields.io/npm/dt/@xbibzlibrary/telebibz?style=flat-square&label=total&color=informational)](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
+ [![kartu repo](https://github-readme-stats.vercel.app/api/pin/?username=XbibzOfficial777&repo=telebibz&show_owner=false)](https://github.com/XbibzOfficial777/telebibz)
556
+
557
+ </div>
558
+
559
+ <details>
560
+ <summary>📅 Riwayat bintang (klik untuk buka)</summary>
561
+
562
+ ![Star History](https://api.star-history.com/svg?repos=XbibzOfficial777/telebibz&type=Date)
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
+ [![kunjungan repo](https://komarev.com/ghpvc/?username=XbibzOfficial777&repo=telebibz&style=flat-square&color=blueviolet&label=kunjungan+repo)](https://github.com/XbibzOfficial777/telebibz)
641
+
642
+ </div>