UNPKG

neroxbailx

Version:

baileys whatsapp-api

2,052 lines (1,683 loc) • 73 kB
# šŸ’¬ Baileys — API WhatsApp Indonesia <div align="center"> <img src="https://i.pinimg.com/736x/b1/7b/b0/b17bb0c5e75398ae8108d3688340b9fe.jpg" alt="WhatsApp Baileys" width="500" style="border-radius: 15px;"> > **āš ļø SECURITY WARNING āš ļø** > > This is a **private version** of Baileys with enhanced security features. > This repository is NOT for public use and contains proprietary security measures. > Unauthorized access or distribution is strictly prohibited. [![GitHub Stars](https://img.shields.io/github/stars/neroxkira/baileys?style=for-the-badge&logo=github&color=yellow)](https://github.com/neroxkira) [![NPM Version](https://img.shields.io/npm/v/neroxbails?style=for-the-badge&logo=npm&color=red)](https://www.npmjs.com/package/neroxbails) [![Downloads](https://img.shields.io/npm/dm/neroxbails?style=for-the-badge&logo=npm&color=blue)](https://www.npmjs.com/package/neroxbails) [![Node.js](https://img.shields.io/badge/Node.js-18%2B-green?style=for-the-badge&logo=node.js)](https://nodejs.org/) </div> --- ## šŸ’– Support Jika project ini membantu Anda, berikan ⭐ di GitHub! <div align="center"> **Made with ā¤ļø by [@neroxkira](https://github.com/neroxkira)** [![GitHub followers](https://img.shields.io/github/followers/neroxkira?style=social)](https://github.com/neroxkira) [![Instagram Follow](https://img.shields.io/badge/Follow-%40nerox-E4405F?style=social&logo=instagram)](https://instagram.com/nerox) </div> ## šŸ“– Deskripsi **Baileys** adalah pustaka JavaScript yang ringan dan powerful untuk terhubung dengan **WhatsApp Web API** melalui WebSocket. Memungkinkan Anda membuat bot WhatsApp, automasi, dan integrasi dengan mudah tanpa perlu WhatsApp Business API yang berbayar! ### ✨ Fitur Unggulan - šŸš€ **Ringan & Cepat** - Tanpa overhead TypeScript - šŸ”„ **Auto Reconnect** - Koneksi stabil dengan auto-reconnect - šŸ“± **Multi Device** - Mendukung WhatsApp Multi Device - šŸ–¼ļø **Media Support** - Kirim gambar, video, audio, dokumen - šŸŽÆ **Interactive Buttons** - Tombol interaktif dan katalog produk - šŸ“Š **Group Management** - Kelola grup dengan mudah - šŸ” **Session Management** - Simpan sesi untuk login otomatis - šŸ†“ **Gratis Selamanya** - Open source dan gratis digunakan --- ## 🌐 Links <div align="center"> [![GitHub](https://img.shields.io/badge/GitHub-@neroxkira-181717?style=for-the-badge&logo=github)](https://github.com/neroxkira) [![Instagram](https://img.shields.io/badge/Instagram-@nerox-E4405F?style=for-the-badge&logo=instagram)](https://instagram.com/nerox) [![Documentation](https://img.shields.io/badge/Docs-baileys.wiki-blue?style=for-the-badge&logo=gitbook)](https://baileys.wiki) </div> --- ## āš ļø Disclaimer > **PENTING:** Proyek ini **TIDAK berafiliasi** dengan WhatsApp Inc. atau Meta Platforms Inc. > > 🚫 **Dilarang untuk:** > - Spam massal > - Stalking atau harassment > - Melanggar Terms of Service WhatsApp > - Aktivitas ilegal lainnya > > āš–ļø **Segala bentuk penyalahgunaan adalah tanggung jawab pengguna sepenuhnya.** --- ## šŸ“¦ Instalasi ### šŸ“‹ Requirements - ![Node.js](https://img.shields.io/badge/Node.js-18%2B-green?logo=node.js) **Node.js versi 18 atau lebih tinggi** - ![NPM](https://img.shields.io/badge/NPM-Latest-red?logo=npm) **NPM, Yarn, atau PNPM** ### šŸ”§ Install Package ```bash # NPM npm install neroxbails # Yarn yarn add neroxbails # PNPM pnpm add neroxbails ``` --- ## šŸš€ Quick Start ### 1ļøāƒ£ Koneksi dengan QR Code (ESM) ```javascript import makeWASocket, { Browsers } from 'neroxbails' const socket = makeWASocket({ browser: Browsers.ubuntu('Safari'), printQRInTerminal: true }) console.log('šŸ” Scan QR code di terminal untuk login!') ``` ### 2ļøāƒ£ Koneksi dengan QR Code (CommonJS) ```javascript const { default: makeWASocket, Browsers } = require('neroxbails') const socket = makeWASocket({ browser: Browsers.ubuntu('Safari'), printQRInTerminal: true }) console.log('šŸ” Scan QR code di terminal untuk login!') ``` > āš ļø **Catatan:** Pastikan `package.json` **TIDAK** mengandung `"type": "module"` untuk CommonJS ### 3ļøāƒ£ Koneksi dengan Pairing Code (Tanpa QR) ```javascript import makeWASocket from 'neroxbails' const socket = makeWASocket({ printQRInTerminal: false }) // Login tanpa scan QR code if (!socket.authState.creds.registered) { const phoneNumber = '628123456789' // Nomor tanpa + atau - const pairingCode = await socket.requestPairingCode(phoneNumber) console.log('šŸ”¢ Kode Pairing:', pairingCode) console.log('šŸ“± Masukkan kode di WhatsApp > Linked Devices > Link a Device') } ``` --- ## šŸŽÆ Event Handling ### šŸ“Ø Menangani Pesan Masuk ```javascript socket.ev.on('messages.upsert', ({ messages }) => { const message = messages[0] if (!message.message) return console.log('šŸ“Ø Pesan baru:', message.message) // Balas pesan otomatis if (message.message.conversation === 'ping') { socket.sendMessage(message.key.remoteJid, { text: 'šŸ“ pong!' }) } }) ``` ### šŸ”Œ Status Koneksi ```javascript socket.ev.on('connection.update', ({ connection, lastDisconnect }) => { if (connection === 'close') { console.log('āŒ Koneksi terputus. Reconnecting...') // Logic untuk reconnect otomatis } else if (connection === 'open') { console.log('āœ… Berhasil terhubung ke WhatsApp!') } else if (connection === 'connecting') { console.log('šŸ”„ Sedang menghubungkan...') } }) ``` --- ## šŸ’¾ Session Management ### šŸ” Simpan Session untuk Auto Login ```javascript import makeWASocket, { useMultiFileAuthState } from 'neroxbails' // Load session dari folder const { state, saveCreds } = await useMultiFileAuthState('./auth_session') const socket = makeWASocket({ auth: state, printQRInTerminal: true }) // Auto save credentials socket.ev.on('creds.update', saveCreds) console.log('šŸ’¾ Session akan tersimpan otomatis') ``` --- ## šŸŽØ Contoh Penggunaan Lanjutan ### šŸ“ø Kirim Media ```javascript import fs from 'fs' // Kirim gambar await socket.sendMessage(chatId, { image: fs.readFileSync('./gambar.jpg'), caption: 'šŸ–¼ļø Ini adalah gambar' }) // Kirim video await socket.sendMessage(chatId, { video: fs.readFileSync('./video.mp4'), caption: 'šŸŽ¬ Video keren!' }) // Kirim dokumen await socket.sendMessage(chatId, { document: fs.readFileSync('./dokumen.pdf'), mimetype: 'application/pdf', fileName: 'Document.pdf' }) ``` ### šŸ“ Kirim Pesan dengan Format ```javascript // Pesan dengan format await socket.sendMessage(chatId, { text: `*Halo!* šŸ‘‹ _Ini adalah pesan dengan format:_ • Poin 1 • Poin 2 • Poin 3 ~Text tercoret~ \`\`\`javascript console.log("Code block") \`\`\` Kunjungi: https://github.com/neroxkira` }) ``` ### šŸ‘„ Manajemen Grup ```javascript // Buat grup baru const group = await socket.groupCreate('Nama Grup šŸš€', ['628xxx', '629xxx']) console.log('šŸ“± Grup dibuat:', group.id) // Tambah anggota await socket.groupParticipantsUpdate(groupId, ['628xxx'], 'add') // Hapus anggota await socket.groupParticipantsUpdate(groupId, ['628xxx'], 'remove') // Jadikan admin await socket.groupParticipantsUpdate(groupId, ['628xxx'], 'promote') // Update info grup await socket.groupUpdateDescription(groupId, 'Deskripsi grup baru šŸ“') ``` --- ## ⚔ Optimasi Performance ### šŸ—„ļø Group Metadata Caching ```javascript import NodeCache from 'node-cache' const groupCache = new NodeCache({ stdTTL: 5 * 60, // 5 menit useClones: false }) const socket = makeWASocket({ cachedGroupMetadata: async (jid) => groupCache.get(jid) }) // Auto update cache socket.ev.on('groups.update', async ([event]) => { const metadata = await socket.groupMetadata(event.id) groupCache.set(event.id, metadata) }) socket.ev.on('group-participants.update', async (event) => { const metadata = await socket.groupMetadata(event.id) groupCache.set(event.id, metadata) }) ``` ### šŸ“š Sync Full History ```javascript const socket = makeWASocket({ browser: Browsers.ubuntu('Safari'), // Penting untuk full history syncFullHistory: true, // Download semua riwayat chat fireInitQueries: true, }) ``` --- ## šŸ› ļø Konfigurasi Lengkap ```javascript import makeWASocket, { Browsers, useMultiFileAuthState, fetchLatestBaileysVersion } from 'neroxbails' const { version } = await fetchLatestBaileysVersion() const { state, saveCreds } = await useMultiFileAuthState('./auth') const socket = makeWASocket({ version, auth: state, browser: Browsers.ubuntu('Safari'), // Koneksi connectTimeoutMs: 20000, defaultQueryTimeoutMs: 20000, keepAliveIntervalMs: 10000, // QR & Pairing printQRInTerminal: true, qrTimeout: 40000, // Performance syncFullHistory: true, markOnlineOnConnect: false, emitOwnEvents: false, // Media generateHighQualityLinkPreview: true, linkPreviewImageThumbnailWidth: 120, // Custom functions getMessage: async (key) => { // Return message dari database Anda return await getMessageFromDB(key) } }) socket.ev.on('creds.update', saveCreds) ``` --- ## šŸ’” Tips & Best Practices ### āœ… Do's - āœ… **Selalu handle event `connection.update`** untuk auto reconnect - āœ… **Simpan session** agar tidak perlu login berulang - āœ… **Gunakan cache** untuk metadata grup yang sering diakses - āœ… **Handle error** dengan try-catch pada setiap operasi - āœ… **Respect rate limits** WhatsApp untuk avoid banned - āœ… **Update Baileys secara berkala** untuk fix bug terbaru ### āŒ Don'ts - āŒ **Jangan spam** pesan dalam jumlah besar - āŒ **Jangan expose credentials** di public repository - āŒ **Jangan abaikan event handling** yang penting - āŒ **Jangan lupa backup** file session Anda - āŒ **Jangan gunakan untuk aktivitas ilegal** --- ## šŸ†˜ Troubleshooting ### šŸ” Masalah Umum | Masalah | Solusi | |---------|--------| | QR Code tidak muncul | Cek koneksi internet & pastikan `printQRInTerminal: true` | | Koneksi sering putus | Gunakan `keepAliveIntervalMs` dan implement auto-reconnect | | Session hilang | Backup folder `auth_session` secara berkala | | Pesan tidak terkirim | Cek format `remoteJid` dan pastikan nomor valid | | Error "Cannot find module" | Install ulang dependencies dengan `npm install` | ### šŸ› Debug Mode ```javascript import pino from 'pino' const socket = makeWASocket({ logger: pino({ level: 'debug' }), printQRInTerminal: true }) ``` --- ## šŸ¤ Contributing Kontribusi sangat diterima! Silakan: 1. šŸ“ Fork repository ini 2. 🌿 Buat branch feature (`git checkout -b feature/AmazingFeature`) 3. šŸ’¾ Commit changes (`git commit -m 'Add some AmazingFeature'`) 4. šŸ“¤ Push ke branch (`git push origin feature/AmazingFeature`) 5. šŸ”„ Buat Pull Request --- ## šŸ“„ License Distributed unter der **MIT License**. Lihat `LICENSE` file untuk informasi lebih lanjut. --- ## šŸ“ˆ Stats <div align="center"> <img src="https://github-readme-stats.vercel.app/api?username=neroxkira&show_icons=true&theme=radical" alt="GitHub Stats"> </div> > [!IMPORTANT] > **Daftar lengkap event tersedia [di sini](https://baileys.whiskeysockets.io/types/BaileysEventMap.html)**. > Sangat penting untuk memahami setiap event yang bisa digunakan. Contoh penggunaan listener untuk menangani pesan masuk: ```javascript import makeWASocket from 'neroxbails' const sock = makeWASocket() sock.ev.on('messages.upsert', ({ messages }) => { console.log('Pesan diterima:', messages) }) ``` ## Menangani Event Baileys menggunakan sistem **EventEmitter** untuk menangani interaksi WhatsApp secara real-time. Semua event yang terjadi saat koneksi aktif akan dipancarkan melalui `sock.ev.on(...)`, dan kamu bisa menangkap serta meresponsnya sesuai kebutuhan bot kamu. > [!IMPORTANT] > **Daftar lengkap event tersedia [di sini](https://baileys.whiskeysockets.io/types/BaileysEventMap.html)**. > Disarankan untuk memahami struktur tiap event agar integrasi kamu lebih stabil dan efisien. ### Contoh: Menangani Pesan Masuk ```javascript sock.ev.on('messages.upsert', async ({ messages, type }) => { const msg = messages[0] if (!msg.message) return console.log('Pesan diterima:', msg.message) }) ``` - `type` bisa bernilai `notify`, `append`, `replace`, atau `remove`. - Kamu biasanya hanya perlu memproses `type === 'notify'` untuk pesan baru yang masuk. ### Contoh: Menangani Pembaruan Koneksi ```javascript sock.ev.on('connection.update', ({ connection, lastDisconnect }) => { if (connection === 'close') { console.log('Koneksi terputus.') } else if (connection === 'open') { console.log('Terhubung ke WhatsApp!') } }) ``` - Event ini sangat penting untuk memantau status koneksi socket. - Jika `connection === 'close'`, Kamu dapat mencoba reconnect otomatis. ### Contoh: Deteksi Peserta Masuk/Keluar Grup ```javascript sock.ev.on('group-participants.update', async ({ id, participants, action }) => { if (action === 'add') { console.log('Anggota baru masuk:', participants) } else if (action === 'remove') { console.log('Anggota keluar:', participants) } }) ``` - `id`: JID grup - `participants`: array nomor yang terlibat - `action`: `'add' | 'remove' | 'promote' | 'demote'` ### Contoh: Pembaruan Metadata Grup ```javascript sock.ev.on('groups.update', async (updates) => { for (let group of updates) { console.log('Grup diperbarui:', group) } }) ``` - Bisa digunakan untuk mendeteksi perubahan nama grup, gambar, deskripsi, dll. ### Tips - Event `messages.update` digunakan untuk mendeteksi status pesan seperti dibaca, diterima, atau gagal. - Event `messages.reaction` digunakan untuk menangkap reaksi (emoji) pada pesan kamu. > [!TIP] > Baileys tidak menyimpan cache pesan secara default. > Untuk menangani event dengan akurat (seperti retry atau polling), gunakan `getMessage()` bersama `store`. Jika kamu butuh event tambahan seperti **reaction**, **presence**, atau **call offer**, tinggal tambahkan listener-nya sesuai struktur [BaileysEventMap](https://baileys.whiskeysockets.io/types/BaileysEventMap.html). ## Menyimpan & Memulihkan Sesi Tentu kamu tidak ingin terus-menerus memindai QR code setiap kali ingin terkoneksi. Kamu bisa menyimpan kredensial dan menggunakannya kembali saat login berikutnya: ```javascript import makeWASocket, { useMultiFileAuthState } from 'neroxbails' const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys') // Akan menggunakan kredensial yang tersedia untuk koneksi ulang // Jika kredensial valid ditemukan, akan langsung login tanpa QR const sock = makeWASocket({ auth: state }) // Fungsi ini akan dipanggil setiap kali kredensial diperbarui sock.ev.on('creds.update', saveCreds) ``` > [!IMPORTANT] > `useMultiFileAuthState` adalah fungsi utilitas untuk menyimpan state autentikasi dalam satu folder. > Fungsi ini juga dapat dijadikan dasar untuk menulis sistem autentikasi dan penyimpanan kunci pada database SQL atau NoSQL — sangat direkomendasikan untuk sistem berskala produksi. ### Apa Isi Folder `auth_info_baileys`? Folder tersebut akan berisi beberapa file `.json` seperti: - `creds.json` — informasi kredensial utama - `keys/` — berisi subfile kunci Signal: pre-keys, session, senderKey, dll. > Folder ini **jangan pernah dimodifikasi atau dihapus secara manual**. > Perlakukan seperti file token yang sangat sensitif. ### Apa yang Terjadi Jika Folder Hilang? Jika folder `auth_info_baileys` dihapus: - Kamu **tidak bisa login ulang** tanpa memindai QR lagi - Semua sesi yang aktif akan invalid - Signal akan membuat ulang semua sesi enkripsi end-to-end Backup sangat disarankan jika kamu mengelola sesi penting. ### Tips Backup & Restore - Salin seluruh folder `auth_info_baileys` secara utuh. - Untuk restore, cukup salin folder kembali ke path yang sama sebelum memulai bot. - Gunakan `.gitignore` agar folder ini tidak ikut di-push ke GitHub: ``` auth_info_baileys/ ``` ### Menyimpan Berdasarkan ID Pengguna (Multi-Akun) Jika kamu mengelola banyak sesi pengguna (multi-client), buat direktori penyimpanan berdasarkan ID pengguna: ```javascript const { state, saveCreds } = await useMultiFileAuthState(`./sessions/${userId}`) ``` Dengan cara ini, kamu bisa memisahkan sesi tiap user tanpa saling bentrok. > Rekomendasi: kombinasikan dengan database seperti MongoDB/Redis untuk mencatat mapping antara userId dan path session-nya. ### Contoh untuk Memulai > [!NOTE] > Contoh ini juga sudah mencakup penyimpanan kredensial secara otomatis ```javascript import makeWASocket, { DisconnectReason, useMultiFileAuthState } from 'neroxbails' import { Boom } from '@hapi/boom' async function connectToWhatsApp () { const { state, saveCreds } = await useMultiFileAuthState('./auth_info_baileys') const sock = makeWASocket({ auth: state, printQRInTerminal: true }) sock.ev.on('connection.update', (update) => { const { connection, lastDisconnect } = update if (connection === 'close') { const shouldReconnect = (lastDisconnect.error as Boom)?.output?.statusCode !== DisconnectReason.loggedOut console.log('Koneksi terputus karena', lastDisconnect.error, ', mencoba sambung ulang:', shouldReconnect) if (shouldReconnect) { connectToWhatsApp() } } else if (connection === 'open') { console.log('Koneksi berhasil dibuka') } }) sock.ev.on('messages.upsert', async (event) => { for (const m of event.messages) { console.log(JSON.stringify(m, undefined, 2)) console.log('Membalas ke', m.key.remoteJid) await sock.sendMessage(m.key.remoteJid!, { text: 'Hello World' }) } }) // Menyimpan kredensial setiap kali diperbarui sock.ev.on('creds.update', saveCreds) } connectToWhatsApp() ``` ### Contoh Penggunaan `useSingleFileAuthState` dan `useMongoFileAuthState` ```javascript import makeWASocket, { useSingleFileAuthState, useMongoFileAuthState } from 'neroxbails' // Autentikasi menggunakan file tunggal (Single File Auth) const { state, saveState } = await useSingleFileAuthState('./auth_info_baileys.json') const sock = makeWASocket({ auth: state, printQRInTerminal: true }) sock.ev.on('creds.update', saveState) ``` ```javascript // Autentikasi menggunakan MongoDB import { MongoClient } from 'mongodb' const connectAuth = async () => { const client = new MongoClient('mongodb://localhost:27017') await client.connect() console.log('Berhasil terhubung ke MongoDB') const collection = client.db('neroxbails').collection('sessions') const { state, saveCreds } = await useMongoFileAuthState(collection) const sock = makeWASocket({ auth: state, printQRInTerminal: true }) sock.ev.on('creds.update', saveCreds) } connectAuth() ``` > [!IMPORTANT] > Dalam event `messages.upsert`, sangat disarankan menggunakan perulangan `for (const message of event.messages)` untuk menangani semua pesan dalam array secara individual. > Hal ini mencegah pesan terlewat dan memudahkan logging/debugging. > [!TIP] > Kamu bisa menggabungkan pendekatan penyimpanan sesi (`MultiFile`, `SingleFile`, atau `MongoDB`) dengan sistem login berbasis ID pengguna, sehingga mendukung banyak akun secara paralel. ### Mendekripsi Suara Polling Secara default, suara polling di WhatsApp dienkripsi dan diproses melalui event `messages.update`. ```javascript import pino from 'pino' import { makeInMemoryStore, getAggregateVotesInPollMessage } from 'neroxbails' const logger = pino({ timestamp: () => `,"time":"${new Date().toJSON()}"` }).child({ class: 'neroxbails' }) logger.level = 'fatal' const store = makeInMemoryStore({ logger }) async function getMessage(key) { if (store) { const msg = await store.loadMessage(key.remoteJid, key.id) return msg?.message } return { conversation: 'Polling Tidak Ditemukan' } } sock.ev.on('messages.update', async (chatUpdate) => { for (const { key, update } of chatUpdate) { if (update.pollUpdates && key.fromMe) { const pollCreation = await getMessage(key) if (pollCreation) { const pollUpdate = await getAggregateVotesInPollMessage({ message: pollCreation, pollUpdates: update.pollUpdates }) const toCmd = pollUpdate.filter(v => v.voters.length !== 0)[0]?.name if (!toCmd) return console.log('Pilihan terpilih:', toCmd) // Tambahkan aksi lanjutan di sini } } } }) ``` ### Penjelasan - **`store.loadMessage(jid, id)`** digunakan untuk mengambil ulang isi pesan polling (karena hasil polling hanya berisi update, bukan isi awal). - **`getAggregateVotesInPollMessage()`** menggabungkan seluruh `pollUpdates` dan menghasilkan daftar suara lengkap. - Sangat penting menggunakan `getMessage()` yang valid. Jika kamu tidak menyimpan store, dekripsi suara tidak akan berhasil. > [!TIP] > Untuk polling publik, kamu tidak perlu key khusus. > Tapi untuk polling private (atau jika polling berasal dari orang lain), pastikan kamu menyimpan pesan awalnya menggunakan store atau log pesan masuk. ### Ringkasan Event Saat Koneksi Pertama 1. Saat socket pertama kali terkoneksi, event `connection.update` akan dipicu. Biasanya status koneksi akan masuk ke `'open'` atau `'close'`. 2. Setelah itu, WhatsApp akan mengirimkan riwayat pesan (history chat) melalui event: **`messaging-history.set`** 3. Riwayat tersebut berisi pesan-pesan dari sesi sebelumnya, termasuk polling yang belum terjawab. > [!IMPORTANT] > Untuk menangani polling, kamu **wajib mengatur `getMessage()`** di konfigurasi `makeWASocket()`. > Ini memastikan Baileys bisa mendekripsi hasil polling dengan benar. ```javascript const sock = makeWASocket({ auth: state, getMessage: async (key) => await getMessage(key) }) ``` ## Mengimplementasikan Data Store Baileys tidak menyediakan sistem penyimpanan (*storage*) bawaan untuk chat, kontak, atau pesan. Namun, tersedia implementasi sederhana menggunakan **in-memory store**. Store ini akan memantau pembaruan chat, pesan baru, dan perubahan lainnya agar data kamu tetap mutakhir. > [!IMPORTANT] > Sangat disarankan untuk membangun sistem penyimpanan sendiri. > Menyimpan seluruh riwayat chat di RAM akan memakan memori yang besar dan tidak efisien untuk jangka panjang. --- ### Contoh Penggunaan Store ```javascript import makeWASocket, { makeInMemoryStore } from 'neroxbails' // Store akan menyimpan data koneksi WhatsApp dalam memori const store = makeInMemoryStore({}) // Membaca data dari file (jika tersedia) store.readFromFile('./baileys_store.json') // Menyimpan state ke file setiap 10 detik setInterval(() => { store.writeToFile('./baileys_store.json') }, 10_000) const sock = makeWASocket({}) // Store akan mulai mendengarkan event dari socket ini // Jika socket diganti, store masih bisa digunakan ulang store.bind(sock.ev) sock.ev.on('chats.upsert', () => { // Akses semua chat tersimpan console.log('Data chat diterima:', store.chats.all()) }) sock.ev.on('contacts.upsert', () => { // Akses semua kontak tersimpan console.log('Kontak diperbarui:', Object.values(store.contacts)) }) ``` ### Fitur Store - Menyimpan chat, pesan, dan kontak sementara di memori. - Mendukung pembacaan dan penulisan dari/ke file JSON. - Bisa digunakan bersama beberapa koneksi (socket) sekaligus. - Tersedia fungsi `loadMessages`, `loadMessage`, dan `loadMessageFromContent`. ### Kelebihan - Cepat dan ringan untuk penggunaan kecil-menengah. - Ideal untuk penggunaan lokal, testing, atau bot personal. ### Kekurangan - Data hilang saat proses dihentikan jika tidak ditulis ke file. - Tidak cocok untuk data skala besar (ribuan pesan atau kontak). - Tidak mendukung query kompleks (karena berbasis object literal di RAM). ### Rekomendasi Produksi Untuk sistem besar atau multi-user: - Gunakan database seperti: - MongoDB (untuk struktur fleksibel dan load besar) - Redis (untuk cache cepat) - PostgreSQL (untuk struktur relasional) - Sinkronkan event seperti `messages.upsert`, `chats.upsert`, dan `contacts.upsert` ke penyimpanan permanen. - Gunakan store hanya sebagai cache atau layer middleware sementara. > [!TIP] > Store ini sangat berguna untuk keperluan seperti: > - Menyimpan polling > - Retry pesan > - Melacak status kontak dan grup > - Menyediakan command `.listchat`, `.listgroup`, dll. dengan data real-time Jika kamu menggunakan custom `getMessage()`, store ini juga dapat dijadikan referensi lokal untuk mendekripsi polling dan mengirim ulang pesan. ## Penjelasan Tentang WhatsApp ID - `id` atau biasa disebut juga `jid` adalah **identitas WhatsApp** dari seseorang atau grup yang menjadi tujuan pengiriman pesan. - Format ID harus sesuai dengan jenis akun tujuan: ### Jenis Format ID WhatsApp #### 1. Pengguna Pribadi (User) **Format:** ``` [kode negara][nomor telepon]@s.whatsapp.net ``` **Contoh:** ``` 628123456789@s.whatsapp.net ``` #### 2. Grup WhatsApp **Format:** ``` [timestamp grup dibuat]-[random id]@g.us ``` **Contoh:** ``` 1234567890-987654321@g.us ``` #### 3. Broadcast (Daftar Siaran) **Format:** ``` [timestamp]@broadcast ``` **Contoh:** ``` 1685539347@broadcast ``` #### 4. Status (Story) **Format:** ``` status@broadcast ``` #### 5. Newsletter (Channel WhatsApp) **Format:** ``` [numeric id]@newsletter ``` **Contoh:** ``` 120363025487665599@newsletter ``` > **TIP:** > Kamu bisa mendapatkan `jid` dari: > - `m.key.remoteJid` > - `groupParticipantsUpdate` > - `messages.upsert`, dll > **CAUTION:** > Jangan pernah mengubah format `jid` secara manual tanpa validasi. > Salah format bisa menyebabkan error `bad jid` atau pesan tidak terkirim. ## Fungsi Utilitas (Utility Functions) Baileys menyediakan beberapa fungsi utilitas penting yang sangat membantu saat mengembangkan bot: - **`getContentType(message)`** Mengembalikan jenis konten dari pesan (misalnya: `imageMessage`, `conversation`, `buttonsMessage`, dll). - **`getDevice(jid)`** Mengembalikan jenis perangkat yang digunakan pengirim (jika tersedia), contoh: Android, iPhone, Web. - **`makeCacheableSignalKeyStore(authState)`** Membungkus SignalKeyStore menjadi versi yang lebih efisien dan bisa di-cache, untuk performa autentikasi yang lebih cepat. - **`downloadContentFromMessage(message, type)`** Mengunduh media dari pesan (seperti gambar, video, dokumen). `type` bisa berupa `'image'`, `'video'`, `'audio'`, `'document'`, dll. Contoh penggunaan: ```javascript const stream = await downloadContentFromMessage(msg.imageMessage, 'image') const buffer = Buffer.concat([]) for await (const chunk of stream) buffer.push(chunk) ``` > [!NOTE] > Sebagian besar fungsi utilitas tidak dipanggil otomatis — Kamu harus menggunakannya sesuai kebutuhan, terutama saat menangani pesan media, format jid, atau decrypt konten. ## Mengirim Pesan - Semua jenis pesan dapat dikirim menggunakan **satu fungsi saja**, yaitu `sendMessage()`. - Lihat daftar jenis pesan yang didukung [di sini](https://baileys.whiskeysockets.io/types/AnyMessageContent.html) - Dan semua opsi pengiriman pesan [di sini](https://baileys.whiskeysockets.io/types/MiscMessageGenerationOptions.html) Contoh: ```javascript const jid = '628XXXXXXXXX@s.whatsapp.net' // tujuan const content = { text: 'Halo, ini pesan dari bot!' } // isi pesan const options = { quoted: null } // opsi tambahan (misalnya: balasan) await sock.sendMessage(jid, content, options) ``` ### Pesan Non-Media #### Pesan Teks ```javascript await sock.sendMessage(jid, { text: 'Halo dunia' }) ``` #### Pesan Balasan (Quote) ```javascript await sock.sendMessage(jid, { text: 'Ini balasan pesan kamu' }, { quoted: message }) ``` #### Mention Pengguna (Tag) Gunakan `@nomor` dalam teks dan sertakan `mentions` di payload. ```javascript await sock.sendMessage( jid, { text: '@628XXXXXXXXX Hai Nerox!', mentions: ['628XXXXXXXXX@s.whatsapp.net'] } ) ``` #### Meneruskan Pesan (Forward) Butuh objek pesan (`WAMessage`). Bisa didapat dari store atau pesan sebelumnya. ```javascript const msg = getMessageFromStore() // Kamu buat sendiri sesuai struktur await sock.sendMessage(jid, { forward: msg, force: true }) ``` ### Pesan Interaktif #### Tombol Teks (Buttons) ```javascript await sock.sendMessage(jid, { text: 'Pilih salah satu:', buttons: [ { buttonId: 'btn_1', buttonText: { displayText: 'Tombol 1' }, type: 1 }, { buttonId: 'btn_2', buttonText: { displayText: 'Tombol 2' }, type: 1 } ], footer: 'Contoh footer' }) ``` #### Daftar (List Message) ```javascript await sock.sendMessage(jid, { text: 'Pilih dari daftar berikut:', footer: 'Contoh footer', title: 'Judul Daftar', buttonText: 'Buka List', sections: [ { title: 'Menu 1', rows: [ { title: 'Opsi A', rowId: 'pilih_a' }, { title: 'Opsi B', rowId: 'pilih_b' } ] }, { title: 'Menu 2', rows: [ { title: 'Opsi C', rowId: 'pilih_c' } ] } ] }) ``` > [!TIP] > Kamu bisa menggabungkan semua jenis pesan dengan opsi tambahan seperti `quoted`, `mentions`, `ephemeralExpiration`, dan lainnya untuk membuat interaksi bot yang lebih kaya dan interaktif. #### Lokasi Biasa ```javascript await sock.sendMessage( jid, { location: { degreesLatitude: -6.200000, degreesLongitude: 106.816666 } } ) ``` #### Lokasi Langsung (Live Location) ```javascript await sock.sendMessage( jid, { location: { degreesLatitude: -6.200000, degreesLongitude: 106.816666 }, live: true } ) ``` #### Kirim Kontak (vCard) ```javascript const vcard = 'BEGIN:VCARD\n' + 'VERSION:3.0\n' + 'FN:Nerox\n' + 'ORG:ZERO DEV;\n' + 'TEL;type=CELL;type=VOICE;waid=628XXXXXXXXX:+62 831-4366-3697\n' + 'END:VCARD' await sock.sendMessage( jid, { contacts: { displayName: 'Nerox', contacts: [{ vcard }] } } ) ``` #### Pesan Reaksi (Reaction Message) - Kamu perlu mengirimkan `key` dari pesan yang ingin diberikan reaksi. `key` bisa diambil dari [store](#mengimplementasikan-data-store) atau menggunakan [WAMessageKey](https://baileys.whiskeysockets.io/types/WAMessageKey.html). ```javascript await sock.sendMessage( jid, { react: { text: 'šŸ”„', // gunakan string kosong '' untuk menghapus reaksi key: message.key } } ) ``` #### Pin Pesan (Pin Message) - Kamu juga perlu memberikan `key` dari pesan yang ingin dipin. Kamu dapat mengatur durasi pin berdasarkan waktu dalam detik. | Durasi | Detik | |--------|--------------| | 24 jam | 86.400 | | 7 hari | 604.800 | | 30 hari| 2.592.000 | ```javascript await sock.sendMessage( jid, { pin: { type: 1, // 1 untuk pin, 2 untuk unpin time: 86400, key: message.key } } ) ``` ### Menandai Pesan (Keep Message) - Untuk menyimpan pesan tertentu agar tidak terhapus otomatis. ```javascript await sock.sendMessage( jid, { keep: { key: message.key, type: 1 // 1 = simpan, 2 = batalkan simpan } } ) ``` #### Pesan Polling (Poll Message) - Kirim polling ke grup atau kontak pribadi. Dapat menentukan apakah polling bersifat publik (announcement group). ```javascript await sock.sendMessage( jid, { poll: { name: 'Polling Hari Ini', values: ['Opsi A', 'Opsi B', 'Opsi C'], selectableCount: 1, toAnnouncementGroup: false } } ) ``` #### Pesan Hasil Polling (Poll Result) - Kirim hasil polling secara manual jika dibutuhkan. Cocok untuk sistem polling terintegrasi. ```javascript await sock.sendMessage( jid, { pollResult: { name: 'Hasil Polling', values: [ ['Opsi A', 120], ['Opsi B', 350], ['Opsi C', 75] ] } } ) ``` ### Pesan Panggilan (Call Message) - Digunakan untuk mengirim notifikasi panggilan, bisa suara atau video. ```javascript await sock.sendMessage( jid, { call: { name: 'Hay', type: 1 // 1 = suara, 2 = video } } ) ``` ### Pesan Event (Event Message) - Cocok untuk mengumumkan acara atau undangan dengan detail lokasi dan waktu. ```javascript await sock.sendMessage( jid, { event: { isCanceled: false, // true jika dibatalkan name: 'Liburan Bareng!', description: 'Siapa yang mau ikut?', location: { degreesLatitude: 24.121231, degreesLongitude: 55.1121221, name: 'Pantai Sanur' }, startTime: 1715000000, endTime: 1715086400, extraGuestsAllowed: true // apakah boleh bawa tamu } } ) ``` ### Pesan Pemesanan (Order Message) - Digunakan untuk menampilkan detail pemesanan dari katalog bisnis WhatsApp. ```javascript await sock.sendMessage( jid, { order: { orderId: '574XXX', thumbnail: 'your_thumbnail', itemCount: 3, status: 'INQUIRY', // atau ACCEPTED / DECLINED surface: 'CATALOG', message: 'Deskripsi pesanan', orderTitle: 'Judul Pesanan', sellerJid: '628xxx@s.whatsapp.net', token: 'your_token', totalAmount1000: '150000', totalCurrencyCode: 'IDR' } } ) ``` ### Pesan Produk (Product Message) - Menampilkan detail produk dari katalog bisnis. ```javascript await sock.sendMessage( jid, { product: { productImage: { url: 'https://your-image.url/image.jpg' }, productId: 'PRD-001', title: 'Produk Spesial', description: 'Deskripsi lengkap produk kamu di sini', currencyCode: 'IDR', priceAmount1000: '50000', retailerId: 'nerox', // opsional url: 'https://linkproduk.com', // opsional productImageCount: 1, firstImageId: 'img-001', // opsional salePriceAmount1000: '45000', signedUrl: 'https://your.signed.url' // opsional }, businessOwnerJid: '628xxx@s.whatsapp.net' } ) ``` ### Pesan Pembayaran (Payment Message) - Digunakan untuk mengirimkan informasi pembayaran, cocok untuk chatbot belanja. ```javascript await sock.sendMessage( jid, { payment: { note: 'Hi!', currency: 'IDR', offset: 0, amount: '10000', expiry: 0, from: '628xxxx@s.whatsapp.net', image: { placeholderArgb: '#222222', textArgb: '#FFFFFF', subtextArgb: '#AAAAAA' } } } ) ``` #### Pesan Undangan Pembayaran (Payment Invite Message) - Digunakan untuk mengundang pengguna lain melakukan pembayaran. ```javascript await sock.sendMessage( jid, { paymentInvite: { type: 1, // 1 = request, 2 = accept, 3 = decline (sesuaikan sesuai konteks) expiry: 0 } } ) ``` ### Pesan Undangan Admin Channel (Admin Invite Message) - Meminta pengguna untuk menjadi admin di saluran (newsletter) kamu. ```javascript await sock.sendMessage( jid, { adminInvite: { jid: '123xxx@newsletter', name: 'Channel Nerox', caption: 'Tolong jadi admin channel saya ya!', expiration: 86400, // dalam detik (24 jam) jpegThumbnail: Buffer // opsional, bisa berupa buffer gambar } } ) ``` ### Undangan Grup WhatsApp (Group Invite Message) - Mengirim undangan ke grup tertentu menggunakan kode undangan. ```javascript await sock.sendMessage( jid, { groupInvite: { jid: '123xxx@g.us', name: 'Grup Dev Nerox', caption: 'Ayo gabung ke grup WhatsApp kami!', code: 'ABCD1234', // kode undangan grup expiration: 86400, jpegThumbnail: Buffer // opsional } } ) ``` ### Pesan Bagikan Nomor Telepon (Share Phone Number) - Mengirim permintaan eksplisit untuk membagikan nomor telepon pengguna. ```javascript await sock.sendMessage( jid, { sharePhoneNumber: {} } ) ``` ### Pesan Permintaan Nomor Telepon (Request Phone Number) - Meminta pengguna untuk membagikan nomor telepon mereka secara langsung. ```javascript await sock.sendMessage( jid, { requestPhoneNumber: {} } ) ``` ### Pesan Balasan Tombol (Button Reply Message) - Digunakan untuk merespons interaksi tombol yang diklik pengguna. Tipe pesan dibedakan berdasarkan jenis tombol yang digunakan. #### Tombol Tipe List ```javascript await sock.sendMessage( jid, { buttonReply: { name: 'Hai', description: 'Deskripsi pilihan', rowId: 'pilihan_1' }, type: 'list' } ) ``` #### Tombol Tipe Plain ```javascript await sock.sendMessage( jid, { buttonReply: { displayText: 'Halo', id: 'plain_id' }, type: 'plain' } ) ``` #### Tombol Tipe Template ```javascript await sock.sendMessage( jid, { buttonReply: { displayText: 'Pilih Saya', id: 'template_id', index: 1 }, type: 'template' } ) ``` #### Tombol Tipe Interactive (Native Flow) ```javascript await sock.sendMessage( jid, { buttonReply: { body: 'Mau pilih yang mana?', nativeFlows: { name: 'menu_options', paramsJson: JSON.stringify({ id: 'menu_1', description: 'Deskripsi interaktif' }), version: 1 // bisa juga 2 atau 3 } }, type: 'interactive' } ) ``` ### Pesan dengan Tombol (Buttons Message) - Pesan biasa yang disertai hingga **3 tombol** untuk respon cepat. ```javascript await sock.sendMessage( jid, { text: 'Ini adalah pesan tombol!', caption: 'Gunakan jika memakai gambar/video', footer: 'Salam dari Nerox!', buttons: [ { buttonId: 'btn1', buttonText: { displayText: 'Tombol 1' } }, { buttonId: 'btn2', buttonText: { displayText: 'Tombol 2' } }, { buttonId: 'btn3', buttonText: { displayText: 'Tombol 3' } } ] } ) ``` ### Pesan List Tombol (Buttons List Message) - Hanya bisa digunakan di **chat pribadi**, bukan grup. ```javascript await sock.sendMessage( jid, { text: 'Ini adalah daftar pilihan!', footer: 'Dipersembahkan oleh Nerox', title: 'Judul Daftar Pilihan', buttonText: 'Klik untuk melihat opsi', sections: [ { title: 'Bagian 1', rows: [ { title: 'Opsi 1', rowId: 'opsi1' }, { title: 'Opsi 2', rowId: 'opsi2', description: 'Deskripsi Opsi 2' } ] }, { title: 'Bagian 2', rows: [ { title: 'Opsi 3', rowId: 'opsi3' }, { title: 'Opsi 4', rowId: 'opsi4', description: 'Deskripsi Opsi 4' } ] } ] } ) ``` ### Pesan Daftar Produk dengan Tombol (Buttons Product List Message) - Hanya dapat digunakan di **chat pribadi**, bukan grup. - Menampilkan daftar produk dari katalog bisnis WhatsApp kamu. ```javascript await sock.sendMessage( jid, { text: 'Ini adalah daftar produk!', footer: 'Dikirim oleh Nerox', title: 'Pilih Produk Unggulan', buttonText: 'Lihat Daftar Produk', productList: [ { title: 'Kategori Produk Utama', products: [ { productId: '1234' }, { productId: '5678' } ] } ], businessOwnerJid: '628xxx@s.whatsapp.net', thumbnail: 'https://example.jpg' // atau buffer gambar } ) ``` ### Pesan Kartu dengan Tombol (Buttons Cards Message) - Menampilkan beberapa kartu (card) interaktif dengan gambar atau video + tombol. ```javascript await sock.sendMessage( jid, { text: 'Isi Utama Pesan', title: 'Judul Utama', subtile: 'Subjudul Opsional', footer: 'Footer Pesan', cards: [ { image: { url: 'https://example.jpg' }, // bisa juga Buffer title: 'Judul Kartu', body: 'Isi Konten Kartu', footer: 'Footer Kartu', buttons: [ { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'Tombol Cepat', id: 'ID_TOMBOL_1' }) }, { name: 'cta_url', buttonParamsJson: JSON.stringify({ display_text: 'Kunjungi Website', url: 'https://www.example.com' }) } ] }, { video: { url: 'https://example.mp4' }, // bisa juga Buffer video title: 'Judul Kartu Video', body: 'Deskripsi Konten', footer: 'Footer Kartu', buttons: [ { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'Respon Cepat', id: 'ID_TOMBOL_2' }) }, { name: 'cta_url', buttonParamsJson: JSON.stringify({ display_text: 'Lihat Selengkapnya', url: 'https://www.example.com' }) } ] } ] } ) ``` ### Pesan Tombol Template (Buttons Template Message) - Menampilkan tombol dengan tipe URL, panggilan, atau tombol balasan cepat. ```javascript await sock.sendMessage( jid, { text: 'Ini adalah pesan template tombol!', footer: 'Dikirim oleh Nerox', templateButtons: [ { index: 1, urlButton: { displayText: 'Ikuti Channel', url: 'https://whatsapp.com/channel/0029Vag9VSI2ZjCocqa2lB1y' } }, { index: 2, callButton: { displayText: 'Hubungi Saya!', phoneNumber: '628xxxx' } }, { index: 3, quickReplyButton: { displayText: 'Balas Cepat', id: 'id-button-reply' } } ] } ) ``` ### Pesan Tombol Interaktif (Interactive Buttons) - Mendukung berbagai jenis tombol dan dapat digunakan dengan media. ```javascript await sock.sendMessage( jid, { text: 'Ini pesan interaktif!', title: 'Hai!', subtitle: 'Subjudul di sini', footer: 'Dikirim oleh Nerox', interactiveButtons: [ { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'Klik Aku!', id: 'id_kamu' }) }, { name: 'cta_url', buttonParamsJson: JSON.stringify({ display_text: 'Kunjungi Channel', url: 'https://whatsapp.com/channel/0029Vag9VSI2ZjCocqa2lB1y', merchant_url: 'https://whatsapp.com/channel/0029Vag9VSI2ZjCocqa2lB1y' }) }, { name: 'cta_copy', buttonParamsJson: JSON.stringify({ display_text: 'Salin Link', copy_code: 'https://whatsapp.com/channel/0029Vag9VSI2ZjCocqa2lB1y' }) }, { name: 'cta_call', buttonParamsJson: JSON.stringify({ display_text: 'Telepon Saya', phone_number: '628xxxx' }) }, { name: 'single_select', buttonParamsJson: JSON.stringify({ title: 'Pilih Opsi', sections: [ { title: 'Pilihan Utama', highlight_label: 'Rekomendasi', rows: [ { header: 'Header 1', title: 'Opsi 1', description: 'Deskripsi 1', id: 'id1' }, { header: 'Header 2', title: 'Opsi 2', description: 'Deskripsi 2', id: 'id2' } ] } ] }) } ] } ) ``` #### Versi dengan Media ##### Gambar ```javascript await sock.sendMessage( jid, { image: { url: 'https://example.jpg' }, caption: 'Isi Pesan', title: 'Judul', subtitle: 'Subjudul', footer: 'Footer', interactiveButtons: [ /* tombol seperti di atas */ ], hasMediaAttachment: false } ) ``` ##### Video ```javascript await sock.sendMessage( jid, { video: { url: 'https://example.mp4' }, caption: 'Isi Video', title: 'Judul', subtitle: 'Subjudul', footer: 'Footer', interactiveButtons: [ /* tombol seperti di atas */ ], hasMediaAttachment: false } ) ``` ##### Dokumen ```javascript await sock.sendMessage( jid, { document: { url: 'https://example.jpg' }, mimetype: 'image/jpeg', jpegThumbnail: await sock.resize('https://example.jpg', 320, 320), caption: 'Isi Dokumen', title: 'Judul', subtitle: 'Subjudul', footer: 'Footer', interactiveButtons: [ /* tombol seperti di atas */ ], hasMediaAttachment: false } ) ``` ##### Lokasi ```javascript await sock.sendMessage( jid, { location: { degreesLatitude: -6.2, degreesLongitude: 106.8, name: 'Nerox' }, caption: 'Ayo ke sini!', title: 'Lokasi Tujuan', subtitle: 'Subjudul Lokasi', footer: 'Peta lokasi', interactiveButtons: [ /* tombol seperti di atas */ ], hasMediaAttachment: false } ) ``` ##### Produk ```javascript await sock.sendMessage( jid, { product: { productImage: { url: 'https://example.jpg' }, productId: '836xxx', title: 'Produk Pilihan', description: 'Deskripsi produk terbaik', currencyCode: 'IDR', priceAmount1000: '283000', retailerId: 'Nerox', url: 'https://example.com', productImageCount: 1 }, businessOwnerJid: '628xxx@s.whatsapp.net', caption: 'Produk baru tersedia!', title: 'Nama Produk', subtitle: 'Subjudul Produk', footer: 'Info Produk', interactiveButtons: [ /* tombol seperti di atas */ ], hasMediaAttachment: false } ) ``` ### Mention Status (Status Mentions Message) - Digunakan untuk membuat status WhatsApp yang menyebut seseorang secara langsung. ```javascript await sock.sendStatusMentions( jid, { image: { url: 'https://example.com.jpg' }, caption: 'Halo dari Nerox!' } ) ``` ### Pesan Album (Send Album Message) - Mengirim beberapa gambar atau video sebagai album (sekuens media). Bisa pakai `Buffer` atau URL. ```javascript await sock.sendAlbumMessage( jid, [ { image: { url: 'https://example.jpg' }, caption: 'Gambar 1' }, { image: Buffer, caption: 'Gambar 2' }, { video: { url: 'https://example.mp4' }, caption: 'Video 1' }, { video: Buffer, caption: 'Video 2' } ], { quoted: message, // opsional, untuk membalas pesan delay: 2000 // jeda antar media (ms) } ) ``` ### Pesan Toko (Shop Message) - Digunakan untuk mengarahkan pengguna ke katalog atau produk dalam fitur bisnis WhatsApp. #### Teks Saja ```javascript await sock.sendMessage( jid, { text: 'Body pesan', title: 'Judul Toko', subtitle: 'Subjudul', footer: 'Powered by Nerox', shop: { surface: 1, id: 'https://example.com' }, viewOnce: true } ) ``` #### Gambar ```javascript await sock.sendMessage( jid, { image: { url: 'https://example.jpg' }, caption: 'Deskripsi produk', title: 'Judul', subtitle: 'Subjudul', footer: 'Footer', shop: { surface: 1, id: 'https://example.com' }, hasMediaAttachment: false, viewOnce: true } ) ``` #### Video ```javascript await sock.sendMessage( jid, { video: { url: 'https://example.mp4' }, caption: 'Tonton videonya!', title: 'Judul Video', subtitle: 'Subjudul', footer: 'Footer', shop: { surface: 1, id: 'https://example.com' }, hasMediaAttachment: false, viewOnce: true } ) ``` #### Dokumen ```javascript await sock.sendMessage( jid, { document: { url: 'https://example.jpg' }, mimetype: 'image/jpeg', jpegThumbnail: await sock.resize('https://example.jpg', 320, 320), caption: 'Lampiran dokumen', title: 'Judul', subtitle: 'Subjudul', footer: 'Footer', shop: { surface: 1, id: 'https://example.com' }, hasMediaAttachment: false, viewOnce: true } ) ``` #### Lokasi ```javascript await sock.sendMessage( jid, { location: { degreesLatitude: -6.2000, degreesLongitude: 106.8166, name: 'Lokasi Toko' }, caption: 'Lihat lokasi kami!', title: 'Judul Lokasi', subtitle: 'Subjudul', footer: 'Peta lokasi', shop: { surface: 1, id: 'https://example.com' }, hasMediaAttachment: false, viewOnce: true } ) ``` #### Produk ```javascript await sock.sendMessage( jid, { product: { productImage: { url: 'https://example.jpg' }, productId: '836xxx', title: 'Nama Produk', description: 'Deskripsi produk menarik', currencyCode: 'IDR', priceAmount1000: '283000', retailerId: 'Nerox', url: 'https://example.com', productImageCount: 1 }, businessOwnerJid: '628xxx@s.whatsapp.net', caption: 'Lihat produk unggulan kami!', title: 'Judul Produk', subtitle: 'Subjudul Produk', footer: 'Info produk', shop: { surface: 1, id: 'https://example.com' }, hasMediaAttachment: false, viewOnce: true } ) ``` ### Pesan Koleksi (Collection Message) - Fitur ini digunakan untuk menampilkan koleksi katalog dari bisnis tertentu di WhatsApp. #### Teks Saja ```javascript await sock.sendMessage( jid, { text: 'Isi pesan', title: 'Judul Koleksi', subtitle: 'Subjudul', footer: 'Dari Nerox', collection: { bizJid: '628xxx@s.whatsapp.net', id: 'https://example.com', version: 1 }, viewOnce: true } ) ``` #### Gambar ```javascript await sock.sendMessage( jid, { image: { url: 'https://example.jpg' }, caption: 'Koleksi Gambar', title: 'Judul Koleksi', subtitle: 'Subjudul', footer: 'Katalog Nerox', collection: { bizJid: '628xxx@s.whatsapp.net', id: 'https://example.com', version: 1 }, hasMediaAttachment: false, viewOnce: true } ) ``` #### Video ```javascript await sock.sendMessage( jid, { video: { url: 'https://example.mp4' }, caption: 'Koleksi Video', title: 'Judul Video', subtitle: 'Subjudul', footer: 'Video Katalog', collection: { bizJid: '628xxx@s.whatsapp.net', id: 'https://example.com', version: 1 }, hasMediaAttachment: false, viewOnce: true } ) ``` #### Dokumen ```javascript await sock.sendMessage( jid, { document: { url: 'https://example.jpg' },