merajah-sockets
v1.0.3
Published
WhatsApp Web Multi-Device Protocol Engine (Merajah Sockets) with Native Signal E2EE and Pure WebSocket Transport
Maintainers
Readme
Merajah Sockets
Merajah Sockets adalah library client native WhatsApp Web Multi-Device berbasis WebSocket murni dengan protokol E2EE Signal asli, dirancang dari nol (from scratch) dengan desain API modern, bebas, dan fleksibel tanpa konvensi usang library lama.
🚀 Bukan wrapper Baileys / WhatsApp-Web.js: Memiliki arsitektur event-driven yang bersih, sintaks pengiriman yang manusiawi, dan performa tinggi dengan konsumsi RAM di bawah 50MB.
📑 Daftar Isi
- Fitur Unggulan
- Instalasi
- Panduan Memulai (Quick Start)
- Panduan Koneksi & Sesi
- Sistem Event & Event Bus (client.ev / client.on)
- Pesan Mentah & Format Sendiri (Userland Serialization)
- Fungsi Mengirim Pesan (client.send...)
- Panduan Cache & MessageVault
- Penanganan Grup WhatsApp & Manajemen Utilitas
- Saluran WhatsApp (Newsletter / Channels)
- Pengendalian Panggilan Masuk (VoIP Calls)
- Pengaturan Privasi & Pemblokiran Akun
- Profil & Status Bio
- Uji Coba & Protokol
- Lisensi
🌟 Fitur Unggulan
- ⚡ Native WebSocket Engine: Beroperasi langsung di atas
wsRFC6455 dengan Noise XX 25519 Handshake. Zero browser di produksi. - 🔒 Real Signal E2EE: Enkripsi Curve25519, AES-CBC-256, HMAC-SHA256 dengan auto-repair session saat terjadi Bad MAC.
- 💬 CreativeMessage Abstraction: Pesan masuk otomatis di-parse: teks, command, argumen, mention, quote, tombol, dan media langsung siap pakai.
- 🛡️ Anti-Delete Bawaan: Event
client.on('message:delete')langsung menyediakan salinan pesan asli yang ditarik pengirim. - 👁️ Anti-ViewOnce Bawaan: Event
client.on('message:view_once')dan unwrap otomatis pesan sekali lihat. - 🎨 Meta Developers Cloud API Interactive Buttons: Tombol interaktif (URL, Webview, Salin Kode, Quick Reply) dan Single-Select List Menu tanpa tagihan iklan atau peringatan disclaimer.
- 📢 Throttled Broadcast: Siaran pesan massal dengan jeda interval aman dan callback pemantauan progres.
📦 Instalasi
# Node.js v18.0.0 atau lebih baru dibutuhkan
npm install ./merajah-sockets🚀 Panduan Memulai (Quick Start)
Hanya butuh beberapa baris untuk membuat bot WhatsApp modern:
const {
createMerajahClient,
useFileSession,
} = require('merajah-sockets');
async function main() {
// 1. Inisialisasi sesi penyimpanan lokal
const session = await useFileSession('./auth_info');
// 2. Buat client Merajah Sockets
const client = createMerajahClient({
session,
printQR: true,
});
// 3. Tangani event siap
client.on('ready', (user) => {
console.log(`✅ Bot Aktif sebagai: ${user.id}`);
});
// 4. Tangani pesan masuk (gaya modern, bersih, intuitif)
client.on('message', async (msg) => {
if (msg.fromMe) return;
if (msg.command === 'ping') {
await msg.reply('🏓 Pong!');
}
if (msg.command === 'halo') {
await msg.reply(`Halo @${msg.sender.split('@')[0]}!`, {
mentions: [msg.sender],
});
}
});
// 5. Hubungkan ke WhatsApp
await client.connect();
}
main().catch(console.error);🔌 Panduan Koneksi & Sesi
1. useFileSession(sessionFolder)
Menyimpan kredensial sesi multi-device, kunci enkripsi pre-key, dan identitas ke dalam folder disk secara modular.
const { useFileSession } = require('merajah-sockets');
// Membuat atau memuat sesi dari folder ./auth_info
const session = await useFileSession('./auth_info');2. createMerajahClient(options)
Fungsi factory untuk membuat instance client WhatsApp baru.
Opsi Konfigurasi:
session(Wajib): Hasil dariuseFileSession.vault(Opsional): InstanceMessageVaultuntuk caching pesan. Jika tidak diisi, vault in-memory default akan otomatis dibuat.printQR(Opsional, default:true): Menampilkan QR code di terminal.connectTimeoutMs(Opsional, default:20000): Timeout koneksi dalam milidetik.keepAliveIntervalMs(Opsional, default:25000): Interval heartbeat ping WhatsApp.browser(Opsional): Identitas browser platform (default:['Ubuntu', 'Chrome', '22.04.4']).
Mode 1: QR Code Terminal
const client = createMerajahClient({
session,
printQR: true,
});
await client.connect();Mode 2: 8-Digit Pairing Code
Bagi server VPS tanpa tampilan scan kamera, hubungkan langsung menggunakan kode pairing 8-digit:
const client = createMerajahClient({
session,
printQR: false,
});
await client.connect();
// Cek apakah akun belum terdaftar
if (!session.state.creds.registered && !session.state.creds.me) {
const pairingCode = await client.requestPairingCode('6285123456789');
console.log('🔑 MASUKKAN KODE PAIRING INI DI WHATSAPP:', pairingCode);
// Buka WhatsApp di HP: Perangkat Tertaut > Tautkan Perangkat > Tautkan dengan nomor telepon
}Penanganan Lifecycle Koneksi
// Saat bot berhasil terhubung dan siap memproses perintah
client.on('ready', (user) => {
console.log('🟢 Bot online! JID:', user.id);
});
// Saat proses jabat tangan (handshake) sedang berlangsung
client.on('connecting', () => {
console.log('🔄 Menghubungkan ke server WhatsApp Web...');
});
// Saat QR code baru dihasilkan
client.on('qr', (qrString) => {
console.log('QR Code diperbarui.');
});
// Saat koneksi terputus
client.on('disconnected', ({ error, statusCode }) => {
console.log(`⚠️ Terputus: ${error?.message} (Status: ${statusCode})`);
if (statusCode === 401) {
console.error('❌ Sesi logout (401). Hapus folder sesi lalu pairing ulang.');
process.exit(1);
} else {
// Reconnect otomatis
setTimeout(() => client.connect(), 3000);
}
});📡 Sistem Event Modern (client.on)
Merajah Sockets meninggalkan penamaan event lama seperti messages.upsert dan menggantikannya dengan event-event tingkat tinggi:
Event: ready / connected
Dipanggil saat koneksi WebSocket dan sesi E2EE selesai diautentikasi.
client.on('ready', (user) => {
console.log('User aktif:', user.id, user.name);
});Event: messages.upsert (Standar Baileys Murni)
Dipanggil setiap kali ada pesan masuk dari server WhatsApp dalam format standar Baileys:
client.ev.on('messages.upsert', async ({ messages, type }) => {
if (type !== 'notify') return;
for (const rawMsg of messages) {
// rawMsg adalah objek pesan mentah (raw WAMessage / proto.IWebMessageInfo)
console.log('[Upsert Raw ID]:', rawMsg.key.id);
}
});Event: message (Pesan Masuk Mentah)
Dipanggil untuk setiap pesan masuk individu dalam bentuk mentah (raw). Tidak ada pemaksaan serializer internal sehingga Anda bebas memformat objek pesan sesuai kebutuhan bot Anda:
client.on('message', async (rawMsg) => {
console.log('[Pesan Mentah]:', rawMsg.key.remoteJid, rawMsg.message);
});Event: message:delete (Anti-Delete)
Dipanggil secara otomatis ketika seseorang menarik/menghapus pesan (Delete for Everyone). Menyediakan salinan isi pesan asli yang tersimpan di memori cache vault:
client.on('message:delete', ({ chat, sender, targetKey, originalMessage, revokedAt }) => {
console.log(`🗑️ Pesan ${targetKey.id} ditarik oleh ${sender}`);
if (originalMessage) {
console.log('Isi pesan asli yang dihapus:', originalMessage.message);
}
});Event: message:view_once (Anti-ViewOnce)
Dipanggil saat menerima pesan sekali lihat (View-Once). Payload media langsung di-decode dan siap diinspeksi.
client.on('message:view_once', ({ msg, payload }) => {
console.log('👁️ Pesan sekali lihat diterima dari:', msg.key.participant || msg.key.remoteJid);
console.log('Tipe media sekali lihat:', Object.keys(payload));
});💬 Pesan Mentah & Format Sendiri (Userland Serialization)
1. Konsep Murni Baileys: Tanpa Internal Serialize
Sesuai dengan filosofi arsitektur Baileys, Merajah Sockets adalah library client/socket protokol murni:
- Library tidak menyuntikkan serializer opini pribadi (tidak memaksakan format
msg.command,msg.prefix, atau mengubah struktur objek pesan asli). - Semua pesan yang dipancarkan oleh event
messages.upsertmaupunmessageadalah objek pesan mentah (raw WAMessage). - Developer memiliki kendali penuh 100% untuk memformat, mengekstrak command, prefix, argumen, dan fungsi pembantu (helper) di dalam kode bot masing-masing (userland).
2. Struktur Objek Pesan Mentah (WAMessage):
{
key: {
remoteJid: '[email protected]', // JID chat / grup
fromMe: false, // Apakah dikirim oleh bot sendiri
id: '3EB07A8F9B1234567890', // ID unik pesan WhatsApp
participant: '[email protected]' // Pengirim (jika di grup)
},
messageTimestamp: 1789268340, // Waktu pesan (unix timestamp)
pushName: 'Alex', // Nama WhatsApp pengirim
message: { // Objek Protobuf asli
conversation: '!ping',
// atau extendedTextMessage, imageMessage, interactiveMessage, dll.
}
}3. Contoh Lengkap Fungsi serialize() di Userland:
Anda dapat menyalin fungsi serialize berikut ke file bot Anda (misal client.js atau lib/serialize.js):
/**
* Fungsi Serialize di Userland Bot
* @param {MerajahClient} client
* @param {object} m - Pesan mentah dari event message / messages.upsert
*/
function serialize(client, m) {
if (!m) return m;
const key = m.key || {};
const isGroup = Boolean(key.remoteJid && key.remoteJid.endsWith('@g.us'));
const chat = key.remoteJid || '';
const fromMe = Boolean(key.fromMe);
const sender = fromMe
? (client.user?.id || '')
: (isGroup ? (key.participant || '') : chat);
// 1. Ekstrak pesan bagian dalam (unwrapping ephemeral / viewOnce)
let msg = m.message;
let isViewOnce = false;
if (msg) {
while (msg) {
if (
msg.viewOnceMessage ||
msg.viewOnceMessageV2 ||
msg.viewOnceMessageV2Extension ||
msg.imageMessage?.viewOnce ||
msg.videoMessage?.viewOnce
) {
isViewOnce = true;
}
const next =
msg.ephemeralMessage?.message ||
msg.viewOnceMessage?.message ||
msg.viewOnceMessageV2?.message ||
msg.viewOnceMessageV2Extension?.message ||
msg.documentWithCaptionMessage?.message ||
msg.deviceSentMessage?.message;
if (!next) break;
msg = next;
}
}
// 2. Ekstrak teks atau respons tombol interaktif
let text = '';
let buttonResponse = null;
if (msg) {
// Tombol Interactive Native Flow
if (msg.interactiveResponseMessage?.nativeFlowResponseMessage) {
try {
const p = JSON.parse(msg.interactiveResponseMessage.nativeFlowResponseMessage.paramsJson || '{}');
const btnId = p.id || p.selectedRowId || p.rowId || '';
text = btnId;
buttonResponse = { id: btnId, text: btnId };
} catch {}
}
// List Menu Single Select
if (!text && msg.listResponseMessage?.singleSelectReply?.selectedRowId) {
const rowId = msg.listResponseMessage.singleSelectReply.selectedRowId;
text = rowId;
buttonResponse = { id: rowId, text: rowId };
}
// Buttons Quick Reply
if (!text && msg.buttonsResponseMessage?.selectedButtonId) {
const btnId = msg.buttonsResponseMessage.selectedButtonId;
text = btnId;
buttonResponse = { id: btnId, text: msg.buttonsResponseMessage.selectedDisplayText || btnId };
}
// Teks percakapan biasa atau caption media
if (!text) {
text =
msg.conversation ||
msg.extendedTextMessage?.text ||
msg.imageMessage?.caption ||
msg.videoMessage?.caption ||
msg.documentMessage?.caption ||
'';
}
}
// 3. Ekstrak Quoted Context (Pesan yang dikutip)
let quoted = null;
const ctx =
msg?.extendedTextMessage?.contextInfo ||
msg?.imageMessage?.contextInfo ||
msg?.videoMessage?.contextInfo ||
msg?.documentMessage?.contextInfo ||
msg?.audioMessage?.contextInfo ||
msg?.interactiveMessage?.contextInfo;
if (ctx && ctx.stanzaId) {
quoted = {
id: ctx.stanzaId,
sender: ctx.participant || key.remoteJid || '',
text: ctx.quotedMessage?.conversation || ctx.quotedMessage?.extendedTextMessage?.text || '',
message: ctx.quotedMessage || null,
};
}
// 4. Parsing prefix, command, dan arguments
const trimmed = (text || '').trim();
let prefix = '';
let command = '';
let args = [];
const match = trimmed.match(/^([!./#$])(\S+)/);
if (match) {
prefix = match[1];
command = match[2].toLowerCase();
args = trimmed.slice(prefix.length + command.length).trim().split(/\s+/).filter(Boolean);
} else {
const parts = trimmed.split(/\s+/);
command = (parts[0] || '').toLowerCase();
args = parts.slice(1);
}
return {
raw: m,
key,
id: key.id,
chat,
sender,
fromMe,
isGroup,
pushName: m.pushName || '',
timestamp: m.messageTimestamp || Math.floor(Date.now() / 1000),
message: msg,
text,
body: text,
prefix,
command,
args,
quoted,
isViewOnce,
buttonResponse,
// Method pembantu reply langsung
reply: (content, options) => {
const opts = { ...options };
if (isGroup && !opts.quotedParticipant) {
opts.quotedParticipant = sender;
}
return client.sendText(chat, typeof content === 'string' ? content : (content.text || ''), {
...opts,
quoted: m,
});
},
};
}4. Contoh Handler Pesan di Bot:
// Menggunakan event 'message' atau 'messages.upsert'
client.on('message', async (rawMsg) => {
// Format pesan mentah menggunakan fungsi serialize buatan sendiri
const msg = serialize(client, rawMsg);
if (msg.fromMe) return;
console.log(`[Pesan] Dari ${msg.sender}: "${msg.text}" (Cmd: ${msg.command})`);
if (msg.command === 'ping') {
await msg.reply('🏓 Pong!');
}
});📤 Fungsi Mengirim Pesan (client.send...)
Tidak perlu lagi menulis payload proto yang rumit. Merajah Sockets menyediakan fungsi modular tingkat tinggi:
1. client.sendText(to, text, options)
Mengirim pesan teks dengan opsi mention, quoted, link preview, dan view-once.
await client.sendText(chat, 'Halo semua anggota!');
// Dengan mention dan kutipan
await client.sendText(chat, 'Halo @6285123456789', {
mentions: ['[email protected]'],
quoted: msg.raw,
});
// Pesan teks View-Once (Sekali Lihat)
await client.sendText(chat, 'Kode rahasia: 8899', {
viewOnce: true,
});2. client.sendImage(to, image, options)
Mengirim gambar dari Buffer memori atau path file lokal.
// Mengirim dari file lokal
await client.sendImage(chat, './banner.jpg', {
caption: '🖼️ Banner Resmi Komunitas',
});
// Mengirim gambar View-Once (Sekali Lihat)
await client.sendImage(chat, fs.readFileSync('./foto.jpg'), {
caption: 'Foto ini hanya bisa dibuka sekali!',
viewOnce: true,
});3. client.sendVideo(to, video, options)
Mengirim video atau animasi GIF.
await client.sendVideo(chat, './tutorial.mp4', {
caption: '🎥 Video Tutorial Penggunaan Bot',
});
// Mengirim sebagai animasi GIF memutar otomatis
await client.sendVideo(chat, './animasi.mp4', {
gifPlayback: true,
});4. client.sendAudio(to, audio, options)
Mengirim file audio atau rekaman suara pesan suara (Voice Note / PTT).
// Mengirim sebagai Voice Note (VN / PTT)
await client.sendAudio(chat, './rekaman.ogg', {
ptt: true,
});
// Mengirim sebagai lagu / file audio biasa
await client.sendAudio(chat, './musik.mp3', {
ptt: false,
});5. client.sendDocument(to, document, options)
Mengirim dokumen file apa pun (PDF, ZIP, DOCX, APK, dll).
await client.sendDocument(chat, './laporan.pdf', {
fileName: 'Laporan_Tahunan_2026.pdf',
caption: 'Silakan unduh dokumen laporan terlampir.',
mimetype: 'application/pdf',
});6. client.sendButton(to, options)
Mengirim tombol Call-To-Action (URL, Buka Mini Web, Salin Kode) atau Quick Reply Buttons.
// Mode 1: Call-To-Action (CTA) Resmi Meta Developers API
await client.sendButton(chat, {
title: '✨ PUSAT BANTUAN CREATIVE',
body: 'Pilih aksi yang Anda butuhkan melalui tombol di bawah:',
footer: 'Merajah Sockets Native Engine',
buttons: [
{ type: 'url', text: '🌐 Kunjungi Situs', url: 'https://google.com' },
{ type: 'copy', text: '📋 Salin Token', copy: 'TOKEN-CREATIVE-2026' },
{ type: 'reply', text: '🏓 Cek Status', id: 'ping' },
],
});
// Mode 2: Quick Reply Cepat
await client.sendButton(chat, {
title: '⚡ PILIHAN CEPAT',
body: 'Pilih salah satu:',
footer: 'Pilih menu',
buttons: [
{ text: 'Opsi 1', id: 'opsi_1' },
{ text: 'Opsi 2', id: 'opsi_2' },
],
});7. client.sendList(to, options)
Mengirim Single-Select List Menu dengan judul seksi dan baris menu interaktif.
await client.sendList(chat, {
title: '📋 DAFTAR MENU BOT',
body: 'Pilih salah satu layanan dari daftar menu di bawah:',
footer: 'Merajah Sockets Standard',
buttonText: 'Buka Daftar Menu',
sections: [
{
title: 'Layanan Utama',
rows: [
{ id: 'ping', title: '🏓 Ping Pong', description: 'Uji latensi respon bot' },
{ id: 'status', title: '📊 Status Sistem', description: 'Informasi kesehatan server' },
],
},
{
title: 'Bantuan & Komunitas',
rows: [
{ id: 'group', title: '👥 Gabung Grup', description: 'Tautan resmi komunitas WhatsApp' },
{ id: 'owner', title: '👤 Kontak Admin', description: 'Hubungi pengembang langsung' },
],
},
],
});8. client.sendCard(to, options)
Mengirim kartu pratinjau tautan (ExternalAdReply Link Preview Card) dengan gambar banner besar nyata.
await client.sendCard(chat, {
text: '🌟 Bergabunglah ke saluran resmi kami untuk mendapatkan update terbaru!',
title: 'Komunitas Resmi Merajah Sockets',
body: 'Grup diskusi WhatsApp Multi-Device',
thumbnail: fs.readFileSync('./thumb.jpg'),
url: 'https://chat.whatsapp.com/KcFAwyGTo8RBhPv03LvoHZ',
renderLargerThumbnail: true,
});9. client.revoke(to, key)
Menghapus pesan bagi semua orang (Delete for Everyone). Alias: client.deleteMessage(to, key).
const sent = await client.sendText(chat, 'Pesan ini akan dihapus...');
// Hapus pesan setelah 3 detik
setTimeout(async () => {
await client.revoke(chat, sent.key);
}, 3000);10. client.edit(to, key, newText)
Mengedit teks pesan yang telah terkirim.
const sent = await client.sendText(chat, 'Teks salah ketik');
await client.edit(chat, sent.key, 'Teks yang sudah diperbaiki ✅');11. client.react(to, key, emoji)
Memberikan reaksi emoji pada pesan apa pun.
await client.react(chat, targetMessage.key, '🚀');12. client.broadcast(recipients, content, options)
Menyiarkan pesan ke banyak penerima secara berurutan dengan penundaan (throttling delay) agar terhindar dari pemblokiran server WhatsApp.
const recipients = [
'[email protected]',
'[email protected]',
'[email protected]',
];
const report = await client.broadcast(
recipients,
'📢 Pengumuman: Server sedang dalam pemeliharaan berkala.',
{
delayMs: 400, // Jeda 400ms antar pesan
onProgress: ({ current, total, jid, success, error }) => {
console.log(`[Progress ${current}/${total}] Mengirim ke ${jid}: ${success ? 'OK' : error}`);
},
}
);
console.log(`Broadcast selesai. Berhasil: ${report.sent.length}, Gagal: ${report.failed.length}`);13. client.sendAlbum(to, options)
Mengirimkan 2 atau lebih media (gambar atau video) yang ditampilkan secara otomatis dalam tata letak kisi (grid album layout) khas WhatsApp, lengkap dengan expectedImageCount, expectedVideoCount, dan messageAssociation:
const fs = require('fs');
const foto1 = fs.readFileSync('./foto1.jpg');
const foto2 = fs.readFileSync('./foto2.jpg');
await client.sendAlbum(chat, {
album: [
{ image: foto1, caption: 'Foto Produk 1' },
{ image: foto2, caption: 'Foto Produk 2' },
],
caption: '📸 *Koleksi Katalog Produk Terbaru*',
quoted: msg.raw,
});14. client.sendPoll(to, poll, options)
Mengirim pesan undian (Polling) dengan pilihan ganda atau pilihan tunggal.
await client.sendPoll(chat, {
name: '📊 Fitur apa yang paling Anda sukai di Merajah Sockets?',
values: [
'⚡ Pairing Code Cepat',
'🔒 Real Signal E2EE',
'🎨 Tombol Interaktif Resmi',
'🛡️ Anti-Delete Bawaan'
],
selectableCount: 1, // 1 untuk pilihan tunggal, > 1 untuk multi-choice
});15. client.pin(to, key, durationSeconds)
Menyematkan (Pin Message) pesan penting dalam percakapan peribadi atau grup.
// Sematkan selama 24 jam (86400 detik)
await client.pin(chat, targetMessage.key, 86400);
// Durasi lain yang didukung:
// 604800 (7 hari)
// 2592000 (30 hari)
// 0 (Lepas sematan / Unpin)16. client.sendStatus(content, options)
Menyiarkan status atau cerita (WhatsApp Story) ke status@broadcast.
// 1. Status teks
await client.sendStatus('🚀 Selamat datang di era baru Merajah Sockets!');
// 2. Status gambar
await client.sendStatus({
image: fs.readFileSync('./story.jpg'),
caption: 'Suasana pagi ini ☕',
});
// 3. Status video
await client.sendStatus({
video: fs.readFileSync('./story.mp4'),
caption: 'Video pendek perjalanan',
});🧠 Panduan Cache & MessageVault
MessageVault bertindak sebagai brankas memori performa tinggi untuk mengelola pesan masuk, mendeteksi duplikasi, serta mendukung fitur Anti-Delete dan Anti-ViewOnce.
1. createMessageVault(options)
const { createMessageVault } = require('merajah-sockets');
const vault = createMessageVault({
maxMessagesPerChat: 300, // Jumlah riwayat pesan yang disimpan per chat
maxSeenIds: 5000, // Batas cache deduplikasi pesan (LRU eviction)
});2. Pencarian Pesan & Riwayat
// Mencari pesan spesifik berdasarkan ID
const msg = vault.findMessage(chatJid, '3EB012345');
// Mengambil 20 pesan terbaru dari suatu chat
const history = vault.getHistory(chatJid, 20);
// Memeriksa apakah pesan sudah pernah diproses sebelumnya
if (vault.hasSeen(messageId)) {
console.log('Pesan sudah pernah diproses');
}3. Anti-Delete di Vault
Ketika pesan ditarik oleh pengirim, MessageVault otomatis menyalinnya ke arsip pesan terhapus:
const deletedRecord = vault.findRevoked(chatJid, messageId);
if (deletedRecord) {
console.log('Isi pesan asli:', deletedRecord.originalMessage.message);
console.log('Waktu dihapus:', new Date(deletedRecord.revokedAt * 1000).toLocaleString());
}4. Anti-ViewOnce di Vault
Setiap pesan sekali lihat yang masuk secara otomatis disimpan ke arsip khusus View-Once:
// Ambil pesan View-Once
const vo = vault.findViewOnce(chatJid, messageId);
// Dekode dan ekstrak payload media tanpa batasan
const payload = vault.decodeViewOnce(chatJid, messageId);
console.log('Media caption:', payload.imageMessage?.caption);5. Backup & Restore Disk JSON
Simpan seluruh memori vault ke file JSON agar data chat tetap ada meskipun server restart:
// Pulihkan data saat bot mulai
vault.restore('./store_backup.json');
// Simpan data setiap 30 detik
setInterval(() => {
vault.backup('./store_backup.json');
}, 30000);👥 Penanganan Grup WhatsApp (Group Handling & Fanout)
Merajah Sockets v1.0-beta mendukung penuh interaksi di dalam WhatsApp Group (@g.us) secara native, cepat, dan stabil.
1. Arsitektur Multi-Device Group Fanout
Pada protokol resmi WhatsApp Multi-Device XMPP Binary:
- Pesan keluar ke grup menggunakan stansa
<message to="...g.us">. - Konten pesan dienkripsi secara individual untuk setiap perangkat anggota grup menggunakan Signal Protocol E2EE asli dan disusun ke dalam node
<participants><to jid="user:dev@domain"><enc>...</enc></to></participants>. - Node
<enc v="2" type="skmsg" />disematkan untuk kompatibilitas protokol multi-device. - Sesi perangkat master/primer bot juga menerima salinan DSM (Device Sent Message) secara otomatis.
- Bebas Error 479: Library secara otomatis melakukan batch pre-key assertion dan memvalidasi JID setiap peserta agar tidak terjadi penolakan stansa oleh server WhatsApp.
2. Membaca Metadata Grup (client.groupMetadata)
const groupJid = '[email protected]';
// Ambil metadata grup (dengan auto-caching memori 5 menit)
const meta = await client.groupMetadata(groupJid);
console.log('Subjek Grup :', meta.subject);
console.log('Pembuat Grup:', meta.owner);
console.log('Deskripsi :', meta.desc);
console.log('Total Anggota:', meta.participants.length);
// Cek apakah pengirim pesan adalah admin
const isAdmin = meta.participants.some(
(p) => (p.id === msg.sender || p.lid === msg.sender) && (p.admin === 'admin' || p.admin === 'superadmin')
);3. Mengambil Tautan Undangan Grup (client.groupInviteCode)
const inviteCode = await client.groupInviteCode(groupJid);
console.log('Link Grup:', `https://chat.whatsapp.com/${inviteCode}`);4. Membalas Pesan di Dalam Grup (msg.reply)
Di dalam event client.on('message'), properti msg.isGroup bernilai true jika pesan berasal dari grup:
client.on('message', async (msg) => {
if (msg.fromMe) return;
// msg.chat = JID Grup (120363...g.us)
// msg.sender = JID Pengguna pengirim ([email protected] atau xxx@lid)
if (msg.command === 'ping') {
// Membalas langsung ke dalam grup dan mengutip pesan pengirim
await msg.reply('🏓 *Pong!*\nRespon cepat dari bot di dalam grup.');
}
});5. Mengirim Tombol Interaktif & List di Dalam Grup
Tombol Call-To-Action (URL, Salin Kode, Webview), Quick Reply, maupun Single-Select List Menu dapat dikirimkan langsung ke grup. Node <biz> native flow secara otomatis disematkan sehingga tombol tampil elegan di WhatsApp Android dan iOS:
// Kirim tombol Call-to-Action ke grup
await client.sendButton(groupJid, {
title: '⚡ PENGUMUMAN GRUP',
body: 'Halo semua anggota grup! Silakan akses tautan resmi atau salin kode promo di bawah:',
footer: 'Merajah Sockets • Group System',
buttons: [
{ type: 'url', text: '🌐 Kunjungi Website', url: 'https://example.com' },
{ type: 'copy', text: '📋 Salin Voucher', copy: 'MERAJAH-GROUP-2026' },
],
});
// Kirim Single-Select List Menu ke grup
await client.sendList(groupJid, {
title: '📋 DAFTAR MENU GRUP',
body: 'Pilih aksi atau bantuan dari daftar menu:',
buttonText: 'Buka Menu',
sections: [
{
title: 'Menu Utama',
rows: [
{ id: 'rules', title: '📜 Peraturan Grup', description: 'Tata tertib grup' },
{ id: 'admin', title: '👮 Panggil Admin', description: 'Hubungi pengurus grup' },
],
},
],
});6. Menangani Klik Tombol di Grup (button:click)
Saat anggota grup menekan tombol Quick Reply atau memilih opsi List:
client.on('button:click', async ({ buttonId, sender, chat, msg, reply }) => {
console.log(`[Button Click] ID: "${buttonId}" dari ${sender} di grup ${chat}`);
if (buttonId === 'rules') {
await reply('📜 *PERATURAN GRUP*\n1. Hormati sesama anggota\n2. Dilarang spam\n3. Patuhi arahan admin.');
} else if (buttonId === 'admin') {
await reply('👮 Notifikasi telah diteruskan kepada jajaran admin grup.');
}
});7. Pengelolaan Prefix di Grup
Agar bot tidak merespon setiap obrolan santai anggota grup, gunakan filter prefix yang disediakan oleh CreativeMessage:
client.on('message', async (msg) => {
if (msg.fromMe) return;
// Jika pesan di grup tidak memiliki prefix (! / . / # / $) dan bukan respon tombol, abaikan
const hasPrefix = Boolean(msg.prefix);
if (msg.isGroup && !hasPrefix && !msg.buttonResponse) {
return;
}
// Proses perintah resmi
if (msg.command === 'menu') {
await msg.reply('📋 Menampilkan menu perintah grup...');
}
});8. Membuat Grup Baru (client.groupCreate)
Membuat grup WhatsApp baru dengan subjek dan daftar peserta awal:
const newGroup = await client.groupCreate('Komunitas Pengembang Node.js', [
'[email protected]',
'[email protected]',
]);
console.log('Grup berhasil dibuat dengan ID:', newGroup.id);9. Mengelola Anggota Grup (client.groupParticipantsUpdate)
Menambah, menghapus, atau mengubah hak akses admin peserta grup:
const targetUser = '[email protected]';
// Menambahkan peserta baru
await client.groupParticipantsUpdate(groupJid, [targetUser], 'add');
// Menaikkan peserta menjadi Admin (Promote)
await client.groupParticipantsUpdate(groupJid, [targetUser], 'promote');
// Menurunkan Admin menjadi anggota biasa (Demote)
await client.groupParticipantsUpdate(groupJid, [targetUser], 'demote');
// Mengeluarkan peserta dari grup (Remove / Kick)
await client.groupParticipantsUpdate(groupJid, [targetUser], 'remove');10. Mengubah Nama & Deskripsi Grup
// Mengubah nama/subjek grup
await client.groupUpdateSubject(groupJid, 'Komunitas Merajah Sockets Indonesia');
// Mengubah atau menghapus deskripsi grup
await client.groupUpdateDescription(groupJid, 'Grup resmi diskusi implementasi WhatsApp Web Multi-Device protokol native WebSocket.');11. Pengaturan Izin & Pengumuman Grup (client.groupSettingUpdate)
Mengatur izin kirim pesan (hanya admin atau semua peserta) serta izin edit info grup:
// Mode Hanya Admin yang Boleh Mengirim Pesan (Tutup Grup)
await client.groupSettingUpdate(groupJid, 'announcement');
// Buka kembali grup agar semua anggota bisa mengirim pesan
await client.groupSettingUpdate(groupJid, 'not_announcement');
// Hanya Admin yang Boleh Mengedit Info Grup (Subjek, Foto, Deskripsi)
await client.groupSettingUpdate(groupJid, 'locked');
// Semua Anggota Boleh Mengedit Info Grup
await client.groupSettingUpdate(groupJid, 'unlocked');12. Pesan Sementara Grup (client.groupToggleEphemeral)
Mengatur masa kadaluwarsa pesan menghilang otomatis (disappearing messages):
// Aktifkan pesan sementara: 24 jam (86400 detik), 7 hari (604800 detik), atau 90 hari (7776000 detik)
await client.groupToggleEphemeral(groupJid, 86400);
// Nonaktifkan pesan sementara (0 detik)
await client.groupToggleEphemeral(groupJid, 0);13. Manajemen Tautan Undangan Grup
// Mengambil kode tautan undangan grup
const code = await client.groupInviteCode(groupJid);
console.log('Tautan Undangan:', `https://chat.whatsapp.com/${code}`);
// Mereset / mencabut kode undangan grup lama
const newCode = await client.groupRevokeInvite(groupJid);
console.log('Kode Undangan Baru:', newCode);
// Mengambil informasi grup dari kode undangan tanpa harus bergabung terlebih dahulu
const inviteInfo = await client.groupGetInviteInfo('KcFAwyGTo8RBhPv03LvoHZ');
console.log(`Grup: ${inviteInfo.subject}, Jumlah Anggota: ${inviteInfo.size}`);
// Bergabung ke grup menggunakan kode undangan
const joinedGroupJid = await client.groupAcceptInvite('KcFAwyGTo8RBhPv03LvoHZ');
console.log('Berhasil bergabung ke grup:', joinedGroupJid);14. Keluar dari Grup (client.groupLeave)
await client.groupLeave(groupJid);
console.log('Bot telah keluar dari grup.');📢 Saluran WhatsApp (Newsletter / Channels)
Merajah Sockets mendukung manajemen Saluran WhatsApp (WhatsApp Channels) secara penuh:
// 1. Membuat Saluran Baru
const channel = await client.newsletterCreate('Komunitas Merajah Sockets', 'Saluran informasi dan pembaruan');
console.log('Saluran dibuat:', channel);
// 2. Mengambil Metadata Saluran
const meta = await client.newsletterMetadata('123456789012345678@newsletter');
console.log('Nama Saluran:', meta);
// 3. Mengikuti (Follow) & Berhenti Mengikuti (Unfollow)
await client.newsletterFollow('123456789012345678@newsletter');
await client.newsletterUnfollow('123456789012345678@newsletter');
// 4. Membisukan (Mute) & Bunyikan (Unmute)
await client.newsletterMute('123456789012345678@newsletter');
await client.newsletterUnmute('123456789012345678@newsletter');
// 5. Mengubah Nama & Deskripsi Saluran
await client.newsletterUpdateName('123456789012345678@newsletter', 'Nama Saluran Baru');
await client.newsletterUpdateDescription('123456789012345678@newsletter', 'Deskripsi terbaru');📞 Pengendalian Panggilan Masuk (VoIP Calls)
Tangani panggilan suara dan video secara otomatis:
// Mendengarkan event panggilan masuk
client.on('call', async (calls) => {
for (const call of calls) {
console.log(`[Panggilan] Dari: ${call.from}, Tipe: ${call.isVideo ? 'Video' : 'Suara'}, Status: ${call.status}`);
// Tolak panggilan otomatis jika status = 'offer'
if (call.status === 'offer') {
await client.rejectCall(call.id, call.from);
await client.sendText(call.from, '⚠️ Maaf, bot tidak menerima panggilan suara/video.');
}
}
});🔐 Pengaturan Privasi & Pemblokiran Akun
Atur privasi akun WhatsApp secara terprogram:
// 1. Privasi Terakhir Dilihat (Last Seen)
// Nilai: 'all' | 'contacts' | 'contact_blacklist' | 'none'
await client.updateLastSeenPrivacy('contacts');
// 2. Privasi Status Online
// Nilai: 'all' | 'match_last_seen'
await client.updateOnlinePrivacy('match_last_seen');
// 3. Privasi Foto Profil
await client.updateProfilePicturePrivacy('contacts');
// 4. Privasi Laporan Dibaca (Read Receipts / Centang Biru)
// Nilai: 'all' | 'none'
await client.updateReadReceiptsPrivacy('all');
// 5. Blokir & Buka Blokir Pengguna
await client.updateBlockStatus('[email protected]', 'block');
await client.updateBlockStatus('[email protected]', 'unblock');
// 6. Mendapatkan Daftar Blokir
const blockedList = await client.fetchBlocklist();
console.log('Daftar JID yang diblokir:', blockedList);👤 Profil & Status Bio
// 1. Mengubah Foto Profil (Avatar)
await client.updateProfilePicture(client.user.id, fs.readFileSync('./avatar.jpg'));
// 2. Menghapus Foto Profil
await client.removeProfilePicture(client.user.id);
// 3. Mengubah Status Bio (About)
await client.updateProfileStatus('⚡ Powered by Merajah Sockets');
// 4. Mengambil Status Bio Pengguna Lain
const bio = await client.fetchStatus('[email protected]');
console.log('Status Bio:', bio?.status, 'Diperbarui pada:', bio?.setAt);🌐 Utiliti Versi WhatsApp Web Dinamis
Gunakan versi web dinamis agar selalu cocok dengan pelayan WhatsApp terbaru:
const { fetchLatestWaWebVersion, createMerajahClient, useFileSession } = require('merajah-sockets');
async function start() {
const { version, isLatest } = await fetchLatestWaWebVersion();
console.log(`Menggunakan WA Web Version: ${version.join('.')} (Terkini: ${isLatest})`);
const session = await useFileSession('./auth_info');
const client = createMerajahClient({
session,
version,
printQR: true,
});
}🧪 Uji Coba & Protokol
Merajah Sockets dilengkapi dengan rangkaian uji protokol mandiri:
# Menjalankan seluruh test suite
npm testHasil verifikasi 12 test suite:
- ✓ Protocol Framing (FrameCodec)
- ✓ Binary Node Codec & Fixtures
- ✓ Transport Layer & State Machine
- ✓ Auth State & Session Restoration
- ✓ JID Utilities & Normalization
- ✓ Media Cryptography (AES-CBC-256 & HMAC)
- ✓ Messaging Pipeline & Real ACK Generation
- ✓ Signal Protocol E2EE Cipher Bridge
- ✓ Privacy & Credential Redaction
- ✓ Native InMemoryStore & Message Cache
- ✓ Outbound Message Builders (Delete, Edit, ViewOnce)
- ✓ High-Level MerajahClient & CreativeMessage API
- ✅ ALL PROTOCOL & UNIT TESTS PASSED SUCCESSFULLY!
📄 Lisensi
Didistribusikan di bawah lisensi MIT. Bebas dikembangkan, dimodifikasi, dan digunakan untuk proyek komersial maupun personal.
