@xbibzlibrary/whatsbibz 1.3.2 → 1.4.0

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/README.id.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="https://cdn.jsdelivr.net/gh/XbibzOfficial777/whatsbibz@main/assets/logo/preview.png" alt="WhatsBibz" width="360">
2
+ <a href="https://www.npmjs.com/package/@xbibzlibrary/whatsbibz"><img src="https://cdn.jsdelivr.net/gh/XbibzOfficial777/whatsbibz@main/assets/logo/preview.webp" alt="WhatsBibz" width="640"></a>
3
3
  </p>
4
4
 
5
5
  <h1 align="center">WhatsBibz</h1>
@@ -18,7 +18,7 @@
18
18
  </p>
19
19
 
20
20
  <p align="center">
21
- <a href="README.md">English</a> · <b>Bahasa Indonesia</b>
21
+ <a href="README.md">English</a> · <b>Bahasa Indonesia</b> · <a href="README.cn.md">简体中文</a>
22
22
  </p>
23
23
 
24
24
  ---
@@ -39,6 +39,9 @@
39
39
  - [Mode kustom](#mode-kustom)
40
40
  - [Apa yang diterima WhatsApp](#apa-yang-diterima-whatsapp)
41
41
  - [Mengirim dan membaca pesan](#mengirim-dan-membaca-pesan)
42
+ - [Format teks dan markup chat](#format-teks-dan-markup-chat)
43
+ - [Tombol interaktif (Button)](#tombol-interaktif-button)
44
+ - [Pesan kaya bergaya AI](#pesan-kaya-bergaya-ai)
42
45
  - [API tingkat rendah (kompatibel Baileys)](#api-tingkat-rendah-kompatibel-baileys)
43
46
  - [TypeScript](#typescript)
44
47
  - [Migrasi dari Baileys / ourin-baileys](#migrasi-dari-baileys--ourin-baileys)
@@ -49,10 +52,11 @@
49
52
  - [Berkontribusi](#berkontribusi)
50
53
  - [Keamanan](#keamanan)
51
54
  - [Lisensi](#lisensi)
55
+ - [Dukungan dan komunitas](#dukungan-dan-komunitas)
52
56
 
53
57
  ## Mengapa WhatsBibz
54
58
 
55
- WhatsBibz adalah fork penuh dari [Baileys](https://github.com/WhiskeySockets/Baileys) v7 (lewat `ourin-baileys@9.0.21`), sudah di-patch sampai `master` upstream saat ini, ditambah lapisan yang menyelesaikan hal-hal yang selalu ditulis ulang oleh setiap pembuat bot:
59
+ WhatsBibz adalah fork penuh dari [Baileys](https://github.com/WhiskeySockets/Baileys) v7 (lewat `ourin-baileys@9.0.21`), sudah di-patch sampai `master` upstream saat ini, ditambah lapisan bawaan yang menangani koneksi, identitas, dan sesi:
56
60
 
57
61
  | Masalah | Yang dilakukan WhatsBibz |
58
62
  |---|---|
@@ -125,6 +129,7 @@ Contoh yang bisa langsung dijalankan ada di [`example/ping-bot.js`](example/ping
125
129
  | `companionPlatformDisplay` | `string \| null` | `null` | Override `companion_platform_display` saat pairing. Isi hanya bila kamu yakin nilainya ada di allow-list WhatsApp. |
126
130
  | `logger` | `{ info, warn, error, debug, ok }` | console | Objek apa pun dengan metode tersebut (semua opsional). |
127
131
  | `printQR` | `boolean` | `false` | Cetak QR sebagai ASCII saat QR ditampilkan (butuh `qrcode-terminal`). |
132
+ | `banner` | `boolean` | `auto` | Cetak banner ASCII *"WhatsBibz."* (huruf Small Slant, warna pelangi) di terminal saat client dibuat. Bawaan hanya di terminal interaktif; `true` memaksa, `false` mematikan. |
128
133
  | `socketConfig` | `Partial<SocketConfig>` | `{}` | Opsi mentah `makeWASocket`, digabung paling akhir — pintu keluar penuh. |
129
134
  | `fetchLatestVersion` | `boolean` | `true` | Ambil versi WhatsApp Web terkini di setiap connect. Versi bawaan tidak pernah diturunkan. |
130
135
  | `forceIPv4` | `boolean` | `true` | Paksa IPv4 untuk unggah media. |
@@ -279,6 +284,220 @@ import {
279
284
 
280
285
  `sock.sendMessage(jid, content)` mentah mendukung semua yang didukung Baileys: teks, gambar, video, audio, dokumen, stiker, paket stiker, lokasi, kontak, polling, reaksi, edit, hapus, pin, teruskan, view-once, tombol interaktif, pesan produk dan event, newsletter. Builder `Button`, `Carousel`, dan `AIRich` diekspor.
281
286
 
287
+ ## Format teks dan markup chat
288
+
289
+ ### 1) Format asli WhatsApp (tanpa konversi)
290
+
291
+ `sendText(..., { format: false })` dan `sock.sendMessage(jid, { text })` mengirim teks **apa adanya** — WhatsApp sendiri yang merender markup berikut di HP penerima:
292
+
293
+ | Kamu ketik | Hasil di WhatsApp |
294
+ |---|---|
295
+ | `*teks*` | **teks tebal** |
296
+ | `_teks_` | *teks miring* |
297
+ | `~teks~` | ~~teks coret~~ |
298
+ | `` `teks` `` | `teks monospace` |
299
+ | `*_kombinasi_*` / `_*kombinasi*_` | **_tebal dan miring_** |
300
+ | `` ```baris\nteks``` `` | blok kode monospace |
301
+
302
+ ```js
303
+ await sock.sendMessage(jid, { text: '*Halo* _dunia_ ~semua~ `kode`' });
304
+ // sendText dengan format:false juga meneruskannya apa adanya
305
+ await sendText(sock, jid, '*bold* _italic_ ~strike~ `mono`', { format: false });
306
+ ```
307
+
308
+ ### 2) Konversi Markdown (gaya ChatGPT/AI) otomatis
309
+
310
+ `sendText(..., { format: true })` (bawaan) menjalankan `whatsappify()` agar teks Markdown yang biasa keluar dari LLM tampil rapi sebagai format WhatsApp:
311
+
312
+ | Markdown sumber | Hasil WhatsApp |
313
+ |---|---|
314
+ | `**tebal**` atau `__tebal__` | `*tebal*` |
315
+ | `***tebal-miring***` | `*tebal-miring*` |
316
+ | `~~coret~~` | `~coret~` |
317
+ | `_miring_` | `_miring_` (dibiarkan, sudah format WA) |
318
+ | `# / ## / ### …` di awal baris | dihapus (tidak tampil) |
319
+ | `[label](https://url)` | `label (https://url)` |
320
+ | sisa `***`/`___` berlebih | dirapikan jadi `*`/`_` |
321
+
322
+ ```js
323
+ const jawabanAI = '## Ringkasan\n\n**Cuaca** hari ini *cerah*, ~~hujan~~ sudah berlalu.\nLihat [prakiraan](https://bmkg.go.id).';
324
+ await sendText(sock, jid, jawabanAI); // format: true secara default
325
+ // hasil: "Ringkasan" (tanpa #) + *Cuaca* + _cerah_ + ~hujan~ + "prakiraan (https://bmkg.go.id)"
326
+ ```
327
+
328
+ `splitText(teks, maxLen)` memecah teks > 4000 karakter (potong di baris/spasi, jeda 250 ms antar bagian) — `sendText` melakukannya otomatis.
329
+
330
+ ### 3) Mention & sebut semua
331
+
332
+ ```js
333
+ import { pnJid } from '@xbibzlibrary/whatsbibz';
334
+
335
+ await sock.sendMessage(jid, {
336
+ text: 'Halo @6281234567890, cek ini!',
337
+ mentions: [pnJid('6281234567890')], // [] array JID
338
+ });
339
+ await sock.sendMessage(groupJid, {
340
+ text: 'Perhatian semua anggota',
341
+ mentions: [], // atau isi [jidA, jidB, ...]
342
+ mentionAll: true, // menandai seluruh chat (broadcast mention)
343
+ });
344
+ ```
345
+
346
+ ## Tombol interaktif (Button)
347
+
348
+ Semua tombol modern WhatsApp memakai format **native flow**: konten tombol berbentuk markup `{ name, buttonParamsJson }`. WhatsBibz meneruskannya lewat `sock.sendMessage(jid, { interactiveMessage: {...} })` atau builder `ButtonV2`.
349
+
350
+ ### Cara 1 — Native flow (disarankan) lewat `sendMessage`
351
+
352
+ ```js
353
+ await sock.sendMessage(jid, {
354
+ interactiveMessage: {
355
+ title: 'Silakan pilih menu di bawah:', // → teks badan pesan
356
+ footer: 'WhatsBibz Bot', // teks kecil di bawah (opsional)
357
+ header: 'MENU MAKAN', // judul besar (opsional)
358
+ buttons: [
359
+ { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'Makanan', id: 'food' }) },
360
+ { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'Minuman', id: 'drink' }) },
361
+ { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'Batal', id: 'cancel' }) },
362
+ ],
363
+ },
364
+ });
365
+ ```
366
+
367
+ **Markup tombol native flow** (`name` + isi `buttonParamsJson`):
368
+
369
+ | `name` | Tampilan | `buttonParamsJson` (contoh) |
370
+ |---|---|---|
371
+ | `quick_reply` | tombol balas biasa | `{"display_text":"Ya","id":"yes"}` |
372
+ | `single_select` | dropdown daftar pilihan | `{"title":"Pilih Kota","sections":[{...}]}` (lihat Cara 3) |
373
+ | `cta_url` | tombol buka tautan | `{"display_text":"Kunjungi","url":"https://…","webview_interaction":false}` |
374
+ | `cta_call` | tombol telepon | `{"display_text":"Hubungi","id":"+628…"}` |
375
+ | `cta_copy` | tombol salin | `{"display_text":"Salin kode","copy_code":"ABC123"}` |
376
+ | `cta_reminder` / `cta_cancel_reminder` | atur / batalkan pengingat | `{"display_text":"Ingatkan saya","id":"…"}` |
377
+ | `address_message` | minta alamat | `{"display_text":"Kirim alamat","id":"…"}` |
378
+ | `send_location` | minta lokasi | `{"display_text":"…"}` |
379
+ | `limited_time_offer` | penawaran terbatas | `{"text":"…","url":"…","copy_code":"…","expiration_time":0}` |
380
+
381
+ Kunci yang dikenal: `display_text`, `id`, `url`, `copy_code`, `webview_interaction`, `expiration_time`, `sections`, `title`, `rows`. Tombol maksimal yang nyaman: 3 `quick_reply`, atau 1 `single_select` per pesan.
382
+
383
+ ### Cara 2 — Builder `ButtonV2` (format lama `buttonsMessage`)
384
+
385
+ ```js
386
+ import { ButtonV2 } from '@xbibzlibrary/whatsbibz';
387
+
388
+ const btn = new ButtonV2(sock)
389
+ .text('Pilih jawabanmu') // .title()/.text()/.footer()/.image(url)
390
+ .footer('Kuis WhatsBibz')
391
+ .addButton('Sangat Puas', 'a')
392
+ .addButton('Cukup', 'b')
393
+ .addButton('Kurang', 'c');
394
+
395
+ const msg = await btn.send(jid); // otomatis menyisipkan node <biz> yang diperlukan
396
+ // msg.key.id → id pesan terkirim
397
+ ```
398
+
399
+ ### Cara 3 — Dropdown pilihan (single_select)
400
+
401
+ ```js
402
+ await sock.sendMessage(jid, {
403
+ interactiveMessage: {
404
+ title: 'Pilih kota tujuan:',
405
+ buttons: [{
406
+ name: 'single_select',
407
+ buttonParamsJson: JSON.stringify({
408
+ title: 'Kota',
409
+ sections: [{
410
+ title: 'Pulau Jawa',
411
+ rows: [
412
+ { title: 'Jakarta', description: 'DKI Jakarta', id: 'jkt' },
413
+ { title: 'Bandung', description: 'Jawa Barat', id: 'bdg' },
414
+ { title: 'Surabaya', description: 'Jawa Timur', id: 'sby' },
415
+ ],
416
+ }],
417
+ }),
418
+ }],
419
+ },
420
+ });
421
+ ```
422
+
423
+ ### Menangkap klik / balasan tombol (inbound)
424
+
425
+ Ketika user menekan tombol (native flow maupun legacy), bot menerima `messages.upsert` dengan tipe balasan; `extractMessage` menormalkannya menjadi `type: 'button'`:
426
+
427
+ ```js
428
+ sock.ev.on('messages.upsert', async ({ messages, type }) => {
429
+ if (type !== 'notify') return;
430
+ for (const m of messages) {
431
+ if (m.key.fromMe || !m.message) continue;
432
+ const item = extractMessage(m); // unwrap otomatis
433
+ if (item?.type !== 'button') continue;
434
+
435
+ console.log('Tombol ditekan:', item.buttonId, '|', item.buttonText);
436
+ switch (item.buttonId) {
437
+ case 'food': return sendText(sock, m.key.remoteJid, 'Anda memilih *Makanan*', { quoted: m });
438
+ case 'drink': return sendText(sock, m.key.remoteJid, 'Anda memilih *Minuman*', { quoted: m });
439
+ case 'jkt': return sendText(sock, m.key.remoteJid, 'Tujuan: *Jakarta*', { quoted: m });
440
+ case 'cancel': return sendText(sock, m.key.remoteJid, 'Dibatalkan');
441
+ }
442
+ }
443
+ });
444
+ ```
445
+
446
+ Klik **quick_reply** juga bisa dibaca mentah: `m.message.interactiveResponseMessage.nativeFlowResponseMessage` berisi `name` (mis. `quick_reply`) dan `paramsJson` = string JSON `{"id":"food","text":"Makanan"}`. Balasan `listResponseMessage`, `buttonsResponseMessage`, dan `templateButtonReplyMessage` (legacy) juga masuk akun `extractMessage`.
447
+
448
+ ## Pesan kaya bergaya AI
449
+
450
+ WhatsBibz ikut menyediakan pembuat **rich message** (format yang sama dengan balasan Meta AI di WhatsApp: `botForwardedMessage`/`richResponseMessage`) sehingga bot bisa menampilkan tabel, blok kode ber-highlight, daftar tautan, dan saran lanjutan dalam satu pesan terformat.
451
+
452
+ ### Metode bawaan socket
453
+
454
+ ```js
455
+ // Tabel
456
+ await sock.sendTable(jid, 'Daftar Harga', ['Item', 'Harga'], [['Nasi Goreng', 'Rp15rb'], ['Es Teh', 'Rp5rb']], undefined, { footer: 'berlaku hari ini' });
457
+
458
+ // Blok kode dengan highlight sintaks
459
+ await sock.sendCodeBlock(jid, 'const x = 1;\nconsole.log(x);', undefined, { language: 'javascript', title: 'Contoh JS' });
460
+
461
+ // Daftar tautan terformat — links: string URL atau { url, displayName }
462
+ await sock.sendLink(jid, 'Sumber terpercaya:', [
463
+ { displayName: 'BMKG — Info Cuaca & Gempa', url: 'https://www.bmkg.go.id' },
464
+ 'https://www.bmkg.go.id/cuaca',
465
+ ], undefined);
466
+
467
+ // Pesan rich penuh dari submessage mentah
468
+ await sock.sendRichMessage(jid, [
469
+ { messageType: 2, messageText: 'Halo dari rich message' },
470
+ { messageType: 4, tableMetadata: { title: 'Skor', rows: [{ items: ['A', '1'], isHeading: true }] } },
471
+ ], undefined);
472
+ ```
473
+
474
+ Metode lain: `sendTableV2`, `sendList`, `sendCodeBlockV2`, `sendLinkV2`, `sendLatex`, `sendLatexImage`, `sendUnifiedResponse`, `captureUnifiedResponse` (lihat `Socket/messages-send.js`).
475
+
476
+ ### Builder `AIRich` (fluent)
477
+
478
+ ```js
479
+ import { AIRich } from '@xbibzlibrary/whatsbibz';
480
+
481
+ const rich = new AIRich(sock)
482
+ .addText('Berikut ringkasan cuaca hari ini untuk **Jakarta**:')
483
+ .addTable([
484
+ ['Waktu', 'Cuaca', 'Suhu'],
485
+ ['Pagi', 'Cerah', '26°C'],
486
+ ['Siang', 'Berawan','32°C'],
487
+ ['Malam', 'Hujan', '28°C'],
488
+ ])
489
+ .addCode('javascript', `async function cuaca(kota) {\n return await fetch('https://api/weather?q=' + kota);\n}`)
490
+ .addSuggest(['Bagaimana cuaca besok?', 'Cari prakiraan mingguan']);
491
+
492
+ await rich.send(jid, { forwarded: true, includesUnifiedResponse: true });
493
+ ```
494
+
495
+ Metode `AIRich` (semua mengembalikan `this`, bisa dirantai): `addText(text)`, `addTable(array2dString)`, `addCode(lang, code)`, `addSource([[ikon, url, teks], ...])`, `addImage(url/buffer | array)`, `addVideo(...)`, `addProduct({...}|[...])`, `addPost(...)`, `addReels(...)`, `addTip(text)`, `addSuggest(string | string[])`, `addSubmessage(...)`, `addSection(...)`. `send(jid, { forwarded, notification, includesUnifiedResponse, includesSubmessages })` — semua opsi bernilai default `true` kecuali `notification` (`false`). `ORich` adalah alias `AIRich`; utilitas statis: `AIRich.tokenizer(code, lang)`, `AIRich.toTableMetadata(arr)`, `AIRich.newLayout(...)`.
496
+
497
+ ### Catatan penggunaan yang etis
498
+
499
+ Pesan rich/AI ini tampil di HP penerima **seolah-olah berasal dari asisten AI resmi Meta** (memakai `forwardedAiBotMessageInfo`, `GenAI*` view-model, dll.). Gunakan hanya untuk bot yang memang meniru asisten AI secara transparan — jangan dipakai untuk menyamar, menipu, atau mengelabui pengguna. Demikian pula: library ini adalah klien WhatsApp **tidak resmi**; pakai di nomor cadangan dan sadari risiko pembatasan akun oleh WhatsApp.
500
+
282
501
  ## API tingkat rendah (kompatibel Baileys)
283
502
 
284
503
  ```js
@@ -372,3 +591,14 @@ Jangan buka issue publik untuk kerentanan. Lihat [SECURITY.md](SECURITY.md).
372
591
  MIT — © 2026 Xbibz Developer. Berbasis Baileys, MIT © Rajeh Taher / WhiskeySockets — lihat [LICENSE](LICENSE) dan [LICENSE.upstream](LICENSE.upstream).
373
592
 
374
593
  WhatsBibz tidak berafiliasi dengan, didukung oleh, atau disokong oleh WhatsApp maupun Meta. Gunakan nomor khusus, patuhi Ketentuan Layanan WhatsApp, dan jangan mengirim pesan yang tidak diminta.
594
+
595
+ ## Dukungan dan komunitas
596
+
597
+ <p align="center">
598
+ <a href="https://ko-fi.com/xbibzofficial"><img src="https://img.shields.io/badge/Ko--Fi-Donate-FF5E5B?style=for-the-badge&amp;logo=ko-fi&amp;logoColor=white" alt="Ko-Fi"></a>
599
+ <a href="https://saweria.co/XbibzOfficial"><img src="https://img.shields.io/badge/Saweria-Support-FFAA00?style=for-the-badge" alt="Saweria"></a>
600
+ <a href="https://tiktok.com/@xbibzofficial"><img src="https://img.shields.io/badge/TikTok-@xbibzofficial-000000?style=for-the-badge&amp;logo=tiktok&amp;logoColor=white" alt="TikTok"></a>
601
+ <a href="https://t.me/xbibzofc"><img src="https://img.shields.io/badge/Telegram-@xbibzofc-26A5E4?style=for-the-badge&amp;logo=telegram&amp;logoColor=white" alt="Telegram"></a>
602
+ </p>
603
+
604
+ [Ko-Fi](https://ko-fi.com/xbibzofficial) · [Saweria](https://saweria.co/XbibzOfficial) · [TikTok](https://tiktok.com/@xbibzofficial) · [Telegram](https://t.me/xbibzofc)
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="https://cdn.jsdelivr.net/gh/XbibzOfficial777/whatsbibz@main/assets/logo/preview.png" alt="WhatsBibz" width="360">
2
+ <a href="https://www.npmjs.com/package/@xbibzlibrary/whatsbibz"><img src="https://cdn.jsdelivr.net/gh/XbibzOfficial777/whatsbibz@main/assets/logo/preview.webp" alt="WhatsBibz" width="640"></a>
3
3
  </p>
4
4
 
5
5
  <h1 align="center">WhatsBibz</h1>
@@ -18,7 +18,7 @@
18
18
  </p>
19
19
 
20
20
  <p align="center">
21
- <b>English</b> · <a href="README.id.md">Bahasa Indonesia</a>
21
+ <b>English</b> · <a href="README.id.md">Bahasa Indonesia</a> · <a href="README.cn.md">简体中文</a>
22
22
  </p>
23
23
 
24
24
  ---
@@ -39,6 +39,9 @@
39
39
  - [Custom mode](#custom-mode)
40
40
  - [What WhatsApp accepts](#what-whatsapp-accepts)
41
41
  - [Sending and reading messages](#sending-and-reading-messages)
42
+ - [Text formatting and chat markup](#text-formatting-and-chat-markup)
43
+ - [Interactive buttons](#interactive-buttons)
44
+ - [Rich and AI-styled messages](#rich-and-ai-styled-messages)
42
45
  - [Low-level API (Baileys-compatible)](#low-level-api-baileys-compatible)
43
46
  - [TypeScript](#typescript)
44
47
  - [Migrating from Baileys / ourin-baileys](#migrating-from-baileys--ourin-baileys)
@@ -49,10 +52,11 @@
49
52
  - [Contributing](#contributing)
50
53
  - [Security](#security)
51
54
  - [License](#license)
55
+ - [Support & community](#support--community)
52
56
 
53
57
  ## Why WhatsBibz
54
58
 
55
- WhatsBibz is a full fork of [Baileys](https://github.com/WhiskeySockets/Baileys) v7 (via `ourin-baileys@9.0.21`), patched up to the current upstream `master`, plus a layer that solves the things every bot author ends up rewriting:
59
+ WhatsBibz is a full fork of [Baileys](https://github.com/WhiskeySockets/Baileys) v7 (via `ourin-baileys@9.0.21`), patched up to the current upstream `master`, with a built-in layer that handles the connection, identity and session plumbing:
56
60
 
57
61
  | Problem | What WhatsBibz does |
58
62
  |---|---|
@@ -125,6 +129,7 @@ A runnable example lives in [`example/ping-bot.js`](example/ping-bot.js).
125
129
  | `companionPlatformDisplay` | `string \| null` | `null` | Override the `companion_platform_display` sent at pairing. Only set this if you know the value is on WhatsApp's allow-list. |
126
130
  | `logger` | `{ info, warn, error, debug, ok }` | console | Any object with those methods (all optional). |
127
131
  | `printQR` | `boolean` | `false` | Print the QR as ASCII when a QR is shown (requires `qrcode-terminal`). |
132
+ | `banner` | `boolean` | `auto` | Print the rainbow *"WhatsBibz."* ASCII banner (Small Slant) to the terminal when the client starts. Default prints only in an interactive terminal; `true` forces it, `false` disables it. |
128
133
  | `socketConfig` | `Partial<SocketConfig>` | `{}` | Raw `makeWASocket` options merged last — full escape hatch. |
129
134
  | `fetchLatestVersion` | `boolean` | `true` | Fetch the current WhatsApp Web version on every connect. The built-in version is never downgraded. |
130
135
  | `forceIPv4` | `boolean` | `true` | Force IPv4 for media uploads. |
@@ -279,6 +284,220 @@ import {
279
284
 
280
285
  The raw `sock.sendMessage(jid, content)` supports everything Baileys does: text, image, video, audio, document, sticker, sticker packs, location, contacts, polls, reactions, edits, deletes, pins, forwards, view-once, interactive buttons, product and event messages, newsletters. Builders `Button`, `Carousel` and `AIRich` are exported.
281
286
 
287
+ ## Text formatting and chat markup
288
+
289
+ ### 1) Native WhatsApp formatting (raw, no conversion)
290
+
291
+ `sendText(..., { format: false })` and `sock.sendMessage(jid, { text })` send text **as-is** — WhatsApp renders the markup itself on the recipient's phone:
292
+
293
+ | You type | Shows in WhatsApp |
294
+ |---|---|
295
+ | `*text*` | **bold** |
296
+ | `_text_` | _italic_ |
297
+ | `~text~` | ~~strikethrough~~ |
298
+ | `` `text` `` | `monospace` |
299
+ | `*_combined_*` / `_*combined*_` | **_bold italic_** |
300
+ | `` ```line\ntext``` `` | monospace code block |
301
+
302
+ ```js
303
+ await sock.sendMessage(jid, { text: '*Hello* _world_ ~everyone~ `code`' });
304
+ // sendText with format:false also passes it through untouched
305
+ await sendText(sock, jid, '*bold* _italic_ ~strike~ `mono`', { format: false });
306
+ ```
307
+
308
+ ### 2) Automatic Markdown → WhatsApp conversion
309
+
310
+ `sendText(..., { format: true })` (default) runs `whatsappify()` so Markdown coming from an LLM looks clean as WhatsApp formatting:
311
+
312
+ | Markdown source | WhatsApp result |
313
+ |---|---|
314
+ | `**bold**` or `__bold__` | `*bold*` |
315
+ | `***bold-italic***` | `*bold-italic*` |
316
+ | `~~strike~~` | `~strike~` |
317
+ | `_italic_` | `_italic_` (kept — already WhatsApp syntax) |
318
+ | `# / ## / ### …` at line start | removed |
319
+ | `[label](https://url)` | `label (https://url)` |
320
+ | stray `***`/`___` | collapsed to `*`/`_` |
321
+
322
+ ```js
323
+ const llmAnswer = '## Summary\n\n**Weather** today is *clear*, ~~rain~~ has passed.\nSee [forecast](https://bmkg.go.id).';
324
+ await sendText(sock, jid, llmAnswer); // format: true by default
325
+ // renders as: "Summary" (no #) + *Weather* + _clear_ + ~rain~ + "forecast (https://bmkg.go.id)"
326
+ ```
327
+
328
+ `splitText(text, maxLen)` splits text over 4000 chars (breaks at newlines/spaces, 250 ms pause between parts) — `sendText` does this automatically.
329
+
330
+ ### 3) Mentions & mention-all
331
+
332
+ ```js
333
+ import { pnJid } from '@xbibzlibrary/whatsbibz';
334
+
335
+ await sock.sendMessage(jid, {
336
+ text: 'Hi @6281234567890, check this!',
337
+ mentions: [pnJid('6281234567890')], // array of JIDs
338
+ });
339
+ await sock.sendMessage(groupJid, {
340
+ text: 'Attention all members',
341
+ mentions: [], // or [jidA, jidB, ...]
342
+ mentionAll: true, // highlights the whole chat (broadcast mention)
343
+ });
344
+ ```
345
+
346
+ ## Interactive buttons
347
+
348
+ All modern WhatsApp buttons use the **native flow** format: a button is the markup `{ name, buttonParamsJson }`. WhatsBibz forwards that through `sock.sendMessage(jid, { interactiveMessage: {...} })` or the `ButtonV2` builder.
349
+
350
+ ### Way 1 — Native flow (recommended) via `sendMessage`
351
+
352
+ ```js
353
+ await sock.sendMessage(jid, {
354
+ interactiveMessage: {
355
+ title: 'Please pick a menu option below:', // → message body text
356
+ footer: 'WhatsBibz Bot', // small footer text (optional)
357
+ header: 'FOOD MENU', // big header title (optional)
358
+ buttons: [
359
+ { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'Food', id: 'food' }) },
360
+ { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'Drinks', id: 'drink' }) },
361
+ { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'Cancel', id: 'cancel' }) },
362
+ ],
363
+ },
364
+ });
365
+ ```
366
+
367
+ **Native-flow button markup** (`name` + contents of `buttonParamsJson`):
368
+
369
+ | `name` | Shows as | `buttonParamsJson` example |
370
+ |---|---|---|
371
+ | `quick_reply` | plain reply button | `{"display_text":"Yes","id":"yes"}` |
372
+ | `single_select` | list dropdown | `{"title":"Pick City","sections":[{...}]}` (see Way 3) |
373
+ | `cta_url` | open-link button | `{"display_text":"Visit","url":"https://…","webview_interaction":false}` |
374
+ | `cta_call` | call button | `{"display_text":"Call","id":"+628…"}` |
375
+ | `cta_copy` | copy button | `{"display_text":"Copy code","copy_code":"ABC123"}` |
376
+ | `cta_reminder` / `cta_cancel_reminder` | set / cancel reminder | `{"display_text":"Remind me","id":"…"}` |
377
+ | `address_message` | request address | `{"display_text":"Send address","id":"…"}` |
378
+ | `send_location` | request location | `{"display_text":"…"}` |
379
+ | `limited_time_offer` | limited-time offer | `{"text":"…","url":"…","copy_code":"…","expiration_time":0}` |
380
+
381
+ Known keys: `display_text`, `id`, `url`, `copy_code`, `webview_interaction`, `expiration_time`, `sections`, `title`, `rows`. Comfortable limits: up to 3 `quick_reply`, or 1 `single_select` per message.
382
+
383
+ ### Way 2 — `ButtonV2` builder (legacy `buttonsMessage`)
384
+
385
+ ```js
386
+ import { ButtonV2 } from '@xbibzlibrary/whatsbibz';
387
+
388
+ const btn = new ButtonV2(sock)
389
+ .text('Pick your answer') // .title()/.text()/.footer()/.image(url)
390
+ .footer('WhatsBibz Quiz')
391
+ .addButton('Very satisfied', 'a')
392
+ .addButton('Okay', 'b')
393
+ .addButton('Not great', 'c');
394
+
395
+ const msg = await btn.send(jid); // automatically injects the required <biz> node
396
+ // msg.key.id → id of the sent message
397
+ ```
398
+
399
+ ### Way 3 — Single-select dropdown list
400
+
401
+ ```js
402
+ await sock.sendMessage(jid, {
403
+ interactiveMessage: {
404
+ title: 'Pick a destination city:',
405
+ buttons: [{
406
+ name: 'single_select',
407
+ buttonParamsJson: JSON.stringify({
408
+ title: 'Cities',
409
+ sections: [{
410
+ title: 'Java Island',
411
+ rows: [
412
+ { title: 'Jakarta', description: 'DKI Jakarta', id: 'jkt' },
413
+ { title: 'Bandung', description: 'West Java', id: 'bdg' },
414
+ { title: 'Surabaya', description: 'East Java', id: 'sby' },
415
+ ],
416
+ }],
417
+ }),
418
+ }],
419
+ },
420
+ });
421
+ ```
422
+
423
+ ### Reading button taps (inbound)
424
+
425
+ When a user taps a button (native flow or legacy), the bot gets a `messages.upsert`; `extractMessage` normalises it to `type: 'button'`:
426
+
427
+ ```js
428
+ sock.ev.on('messages.upsert', async ({ messages, type }) => {
429
+ if (type !== 'notify') return;
430
+ for (const m of messages) {
431
+ if (m.key.fromMe || !m.message) continue;
432
+ const item = extractMessage(m); // auto-unwrapped
433
+ if (item?.type !== 'button') continue;
434
+
435
+ console.log('Button pressed:', item.buttonId, '|', item.buttonText);
436
+ switch (item.buttonId) {
437
+ case 'food': return sendText(sock, m.key.remoteJid, 'You picked *Food*', { quoted: m });
438
+ case 'drink': return sendText(sock, m.key.remoteJid, 'You picked *Drinks*', { quoted: m });
439
+ case 'jkt': return sendText(sock, m.key.remoteJid, 'Destination: *Jakarta*', { quoted: m });
440
+ case 'cancel': return sendText(sock, m.key.remoteJid, 'Cancelled');
441
+ }
442
+ }
443
+ });
444
+ ```
445
+
446
+ Raw **quick_reply** taps can also be read directly: `m.message.interactiveResponseMessage.nativeFlowResponseMessage` carries `name` (e.g. `quick_reply`) and `paramsJson` — a JSON string like `{"id":"food","text":"Food"}`. Replies from `listResponseMessage`, `buttonsResponseMessage` and `templateButtonReplyMessage` (legacy) are covered by `extractMessage` too.
447
+
448
+ ## Rich and AI-styled messages
449
+
450
+ WhatsBibz ships a **rich message** builder (the same format as Meta AI replies on WhatsApp: `botForwardedMessage` / `richResponseMessage`) so a bot can show tables, syntax-highlighted code blocks, formatted link lists and follow-up suggestions in one formatted message.
451
+
452
+ ### Built-in socket methods
453
+
454
+ ```js
455
+ // Table
456
+ await sock.sendTable(jid, 'Price List', ['Item', 'Price'], [['Fried rice', 'Rp15k'], ['Iced tea', 'Rp5k']], undefined, { footer: 'valid today' });
457
+
458
+ // Syntax-highlighted code block
459
+ await sock.sendCodeBlock(jid, 'const x = 1;\nconsole.log(x);', undefined, { language: 'javascript', title: 'JS sample' });
460
+
461
+ // Formatted link list — links: a URL string or { url, displayName }
462
+ await sock.sendLink(jid, 'Trusted sources:', [
463
+ { displayName: 'BMKG — Weather & quakes', url: 'https://www.bmkg.go.id' },
464
+ 'https://www.bmkg.go.id/cuaca',
465
+ ], undefined);
466
+
467
+ // Full rich message from raw submessages
468
+ await sock.sendRichMessage(jid, [
469
+ { messageType: 2, messageText: 'Hello from a rich message' },
470
+ { messageType: 4, tableMetadata: { title: 'Score', rows: [{ items: ['A', '1'], isHeading: true }] } },
471
+ ], undefined);
472
+ ```
473
+
474
+ Other methods: `sendTableV2`, `sendList`, `sendCodeBlockV2`, `sendLinkV2`, `sendLatex`, `sendLatexImage`, `sendUnifiedResponse`, `captureUnifiedResponse` (see `Socket/messages-send.js`).
475
+
476
+ ### `AIRich` fluent builder
477
+
478
+ ```js
479
+ import { AIRich } from '@xbibzlibrary/whatsbibz';
480
+
481
+ const rich = new AIRich(sock)
482
+ .addText('Here is today\'s weather summary for **Jakarta**:')
483
+ .addTable([
484
+ ['Time', 'Weather', 'Temp'],
485
+ ['Morning','Clear', '26°C'],
486
+ ['Noon', 'Cloudy', '32°C'],
487
+ ['Evening','Rain', '28°C'],
488
+ ])
489
+ .addCode('javascript', `async function weather(city) {\n return await fetch('https://api/weather?q=' + city);\n}`)
490
+ .addSuggest(['What is the weather tomorrow?', 'Weekly forecast']);
491
+
492
+ await rich.send(jid, { forwarded: true, includesUnifiedResponse: true });
493
+ ```
494
+
495
+ Chainable `AIRich` methods: `addText(text)`, `addTable(array2dOfStrings)`, `addCode(lang, code)`, `addSource([[icon, url, text], ...])`, `addImage(url/buffer | array)`, `addVideo(...)`, `addProduct({...}|[...])`, `addPost(...)`, `addReels(...)`, `addTip(text)`, `addSuggest(string | string[])`, `addSubmessage(...)`, `addSection(...)`. `send(jid, { forwarded, notification, includesUnifiedResponse, includesSubmessages })` — options default to `true` except `notification` (`false`). `ORich` is an alias of `AIRich`; statics: `AIRich.tokenizer(code, lang)`, `AIRich.toTableMetadata(arr)`, `AIRich.newLayout(...)`.
496
+
497
+ ### Ethical usage note
498
+
499
+ These rich/AI messages render on the recipient's phone **as if they came from Meta's official AI assistant** (they reuse `forwardedAiBotMessageInfo`, `GenAI*` view models, etc.). Use them only for bots that transparently mimic an AI assistant — never for impersonation, deception or tricking users. Likewise, this is an **unofficial** WhatsApp client; run it on a spare number and accept the risk of WhatsApp restricting the account.
500
+
282
501
  ## Low-level API (Baileys-compatible)
283
502
 
284
503
  ```js
@@ -372,3 +591,14 @@ Do not open public issues for vulnerabilities. See [SECURITY.md](SECURITY.md).
372
591
  MIT — © 2026 Xbibz Developer. Based on Baileys, MIT © Rajeh Taher / WhiskeySockets — see [LICENSE](LICENSE) and [LICENSE.upstream](LICENSE.upstream).
373
592
 
374
593
  WhatsBibz is not affiliated with, endorsed by, or supported by WhatsApp or Meta. Use a dedicated number, respect WhatsApp's Terms of Service and do not send unsolicited messages.
594
+
595
+ ## Support & community
596
+
597
+ <p align="center">
598
+ <a href="https://ko-fi.com/xbibzofficial"><img src="https://img.shields.io/badge/Ko--Fi-Donate-FF5E5B?style=for-the-badge&amp;logo=ko-fi&amp;logoColor=white" alt="Ko-Fi"></a>
599
+ <a href="https://saweria.co/XbibzOfficial"><img src="https://img.shields.io/badge/Saweria-Support-FFAA00?style=for-the-badge" alt="Saweria"></a>
600
+ <a href="https://tiktok.com/@xbibzofficial"><img src="https://img.shields.io/badge/TikTok-@xbibzofficial-000000?style=for-the-badge&amp;logo=tiktok&amp;logoColor=white" alt="TikTok"></a>
601
+ <a href="https://t.me/xbibzofc"><img src="https://img.shields.io/badge/Telegram-@xbibzofc-26A5E4?style=for-the-badge&amp;logo=telegram&amp;logoColor=white" alt="Telegram"></a>
602
+ </p>
603
+
604
+ [Ko-Fi](https://ko-fi.com/xbibzofficial) · [Saweria](https://saweria.co/XbibzOfficial) · [TikTok](https://tiktok.com/@xbibzofficial) · [Telegram](https://t.me/xbibzofc)
@@ -1,21 +1,19 @@
1
1
  # Logo WhatsBibz
2
2
 
3
- Gelembung pesan hijau (`#0a6958`) dengan buku terbuka di dalamnya, wordmark **WhatsBib'S** dan
4
- tagline *WHATSAPP LIBRARY*. Sumber utamanya adalah `preview-2048.png` (raster 2048×2048, dari
5
- pemilik proyek); semua berkas lain diturunkan dari situ.
3
+ Logo utama (banner/logo lebar 1672×940) diberikan oleh pemilik proyek sebagai WebP
4
+ dan disimpan sebagai `preview.webp`; turunan PNG-nya ada di `preview.png`.
5
+ Keduanya dipakai untuk README dan halaman npm.
6
6
 
7
7
  | Berkas | Pakai untuk |
8
8
  |---|---|
9
- | `preview.png` | lockup lengkap 1024×1024 — README, halaman npm, dokumen |
10
- | `preview-2048.png` | master resolusi penuh (tidak ikut dipublish ke npm) |
11
- | `png/logo-1600.png`, `png/logo-800.png` | lockup dipangkas rapi (tanpa margin besar) |
12
- | `png/mark-1024.png`, `png/mark-512.png` | gelembung saja, **latar transparan** — avatar, watermark |
13
- | `png/icon-{16…1024}.png` | ikon persegi sudut membulat (tile putih + gelembung) — avatar npm/GitHub, app icon |
9
+ | `preview.webp` | master asli (WebP 1672×940) — README, halaman npm |
10
+ | `preview.png` | versi PNG `preview.webp` (1080×607) |
11
+ | `preview-2048.png` | master persegi 2048×2048 dari rebrand sebelumnya (arsip) |
12
+ | `png/logo-1600.png`, `png/logo-800.png` | lockup lama yang dipangkas rapi |
13
+ | `png/mark-1024.png`, `png/mark-512.png` | gelembung saja, latar transparan — avatar, watermark |
14
+ | `png/icon-{16…1024}.png` | ikon persegi sudut membulat — avatar npm/GitHub, app icon |
14
15
  | `png/banner-1200x360.png` | banner README/sosial |
15
16
  | `whatsbibz.ico` | favicon multi-ukuran 16–256 |
16
17
 
17
- Warna: hijau utama `#0a6958`, teks `#2b2e33`, latar putih. Ruang kosong minimal di sekeliling
18
- lockup = tinggi huruf **B**. Jangan dimiringkan, diberi outline, atau diganti fontnya.
19
-
20
- Regenerasi turunan (mark transparan, ikon, ICO, banner) dari master: skrip yang dipakai ada di
21
- riwayat proyek (`scripts/` tidak menyertakannya karena hanya dijalankan sekali saat rebrand).
18
+ Ikon, mark, banner, dan favicon masih turunan dari lockup persegi versi lama.
19
+ Setelah versi final disepakati, turunan tersebut perlu diregenerasi dari `preview.webp`.
Binary file
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Banner ASCII "WhatsBibz." yang dicetak saat client dibuat.
3
+ * Huruf: "Small Slant" (figlet). Warna: filter pelangi (Rainbow 2).
4
+ */
5
+
6
+ export const BANNER_FONT: string;
7
+ export const BANNER_FILTER: string;
8
+
9
+ /** Banner polos tanpa kode warna ANSI (4 baris, tanpa newline tambahan). */
10
+ export const BANNER_TEXT: string;
11
+
12
+ export interface BannerRenderOptions {
13
+ /** true = selalu berwarna, false = polos, 'auto' (default) = ikuti terminal. */
14
+ color?: boolean | 'auto';
15
+ /** Berapa kali spektrum pelangi diulang sepanjang lebar banner (default 1). */
16
+ cycles?: number;
17
+ /** Environment untuk deteksi warna (default process.env). */
18
+ env?: NodeJS.ProcessEnv;
19
+ /** Stream untuk deteksi TTY (default process.stdout). */
20
+ stream?: unknown;
21
+ }
22
+
23
+ export function colorEnabled(opts?: { env?: NodeJS.ProcessEnv; stream?: unknown }): boolean;
24
+
25
+ /** Render banner menjadi string siap cetak (tanpa newline tambahan). */
26
+ export function renderBanner(options?: BannerRenderOptions): string;
27
+
28
+ /** Cetak banner ke terminal. */
29
+ export function printBanner(
30
+ options?: BannerRenderOptions & { write?: (chunk: string) => void },
31
+ ): boolean;