npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

baileys-joss

v1.0.3

Published

WhatsApp Web API with Interactive Buttons, List Messages, Albums, AI Messages, Polls, LID/SenderPn Plotting, Mini Games, Content Detection, Anti-Spam - A feature-rich Baileys fork

Readme


✨ Kenapa Baileys-Joss?


📦 Installation

# Menggunakan npm
npm install baileys-joss

# Menggunakan yarn
yarn add baileys-joss

# Menggunakan pnpm
pnpm add baileys-joss
// Untuk mengganti @whiskeysockets/baileys
{
  "dependencies": {
    "@whiskeysockets/baileys": "npm:baileys-joss"
  }
}

// Untuk mengganti @adiwajshing/baileys
{
  "dependencies": {
    "@adiwajshing/baileys": "npm:baileys-joss"
  }
}

🎯 Features

Fitur button interactive yang lebih lengkap dan mudah digunakan:

import { 
    generateInteractiveButtonMessage,
    generateInteractiveListMessage,
    generateTemplateMessage,
    generateCombinedButtons,
    generateCopyCodeButton,
    generateUrlButtonMessage,
    generateQuickReplyButtons
} from 'baileys-joss'

// Quick Reply Buttons
const quickButtons = generateQuickReplyButtons(
    'Pilih opsi di bawah ini:',
    [
        { id: 'btn-1', displayText: '✅ Setuju' },
        { id: 'btn-2', displayText: '❌ Tolak' },
        { id: 'btn-3', displayText: '📞 Hubungi CS' }
    ],
    { footer: 'Powered by Baileys-Joss' }
)

await sock.sendMessage(jid, quickButtons)

// URL Button
const urlButton = generateUrlButtonMessage(
    'Kunjungi website kami untuk info lebih lanjut',
    [{ displayText: '🌐 Buka Website', url: 'https://example.com' }],
    { title: 'Info Produk', footer: 'Click untuk membuka' }
)

await sock.sendMessage(jid, urlButton)

// Copy Code Button (untuk OTP, kode promo, dll)
const copyButton = generateCopyCodeButton(
    'Kode OTP Anda adalah:',
    '123456',
    '📋 Copy Kode'
)

await sock.sendMessage(jid, copyButton)

// Combined Buttons (mix URL, Reply, Copy, Call)
const combinedButtons = generateCombinedButtons(
    'Pilih aksi:',
    [
        { type: 'reply', displayText: '🛒 Pesan Sekarang', id: 'order' },
        { type: 'url', displayText: '🌐 Website', url: 'https://example.com' },
        { type: 'call', displayText: '📞 Telepon', phoneNumber: '+6281234567890' },
        { type: 'copy', displayText: '📋 Copy Promo', copyCode: 'PROMO2024' }
    ],
    { title: 'Menu Utama', footer: 'Baileys-Joss' }
)

await sock.sendMessage(jid, combinedButtons)

// List Message
const listMessage = generateInteractiveListMessage({
    title: '📋 Menu Produk',
    buttonText: 'Lihat Menu',
    description: 'Silahkan pilih produk yang diinginkan',
    footer: 'Ketik nomor untuk memesan',
    sections: [
        {
            title: 'Makanan',
            rows: [
                { rowId: 'nasi-goreng', title: 'Nasi Goreng', description: 'Rp 25.000' },
                { rowId: 'mie-goreng', title: 'Mie Goreng', description: 'Rp 22.000' }
            ]
        },
        {
            title: 'Minuman',
            rows: [
                { rowId: 'es-teh', title: 'Es Teh', description: 'Rp 5.000' },
                { rowId: 'kopi', title: 'Kopi', description: 'Rp 10.000' }
            ]
        }
    ]
})

await sock.sendMessage(jid, listMessage)

Kirim beberapa gambar/video sekaligus dalam format album:

// Send Album (grouped images/videos)
const albumMedia = [
    { image: { url: 'https://example.com/pic1.jpg' }, caption: 'Photo 1' },
    { image: { url: 'https://example.com/pic2.jpg' }, caption: 'Photo 2' },
    { video: { url: 'https://example.com/video.mp4' }, caption: 'Video' }
]

await sock.sendMessage(jid, { 
    album: albumMedia, 
    caption: 'My Album 📸' 
})

// Album dari file lokal
const localAlbum = [
    { image: fs.readFileSync('./image1.jpg') },
    { image: fs.readFileSync('./image2.jpg') },
    { video: fs.readFileSync('./video.mp4'), gifPlayback: true }
]

await sock.sendMessage(jid, { album: localAlbum })

Tambahkan ikon AI stylish pada pesan:

// Kirim pesan dengan AI icon
await sock.sendMessage(jid, { 
    text: 'Halo! Saya adalah asisten AI Anda 🤖',
    ai: true  // Menampilkan ikon AI pada pesan
})

// AI dengan media
await sock.sendMessage(jid, {
    image: { url: 'https://example.com/ai-generated.jpg' },
    caption: 'Generated by AI',
    ai: true
})

Kirim gambar dan video tanpa kompresi dalam kualitas HD:

// Kirim gambar HD (kualitas tinggi, tidak dikompres)
await sock.sendMessage(jid, {
    image: { url: './photo-hd.jpg' },
    caption: 'Foto HD 📸',
    hd: true  // Kirim tanpa kompresi
})

// Kirim video HD
await sock.sendMessage(jid, {
    video: { url: './video-4k.mp4' },
    caption: 'Video 4K 🎬',
    hd: true  // Kualitas asli
})

// HD dengan media dari URL
await sock.sendMessage(jid, {
    image: { url: 'https://example.com/high-res-photo.jpg' },
    hd: true,
    caption: 'High Resolution Photo'
})

Set foto profil panorama (wide) tanpa cropping:

// Set panorama profile picture (tidak di-crop square)
await sock.updatePanoramaProfilePicture(myJid, { url: './panorama.jpg' })

// Dengan opsi kustom
await sock.updatePanoramaProfilePicture(myJid, { url: './wide-photo.jpg' }, {
    maxWidth: 1080,  // Maximum width
    quality: 90      // JPEG quality (1-100)
})

// Set panorama untuk grup
await sock.updatePanoramaProfilePicture(groupJid, { url: './group-banner.jpg' })

// Atau gunakan profile picture biasa (square crop)
await sock.updateProfilePicture(myJid, { url: './square-photo.jpg' })

Buat polling dengan mudah:

// Create a Poll
const pollMessage = {
    name: '🎨 Warna Favorit?',
    values: ['🔴 Merah', '🔵 Biru', '🟢 Hijau', '🟡 Kuning'],
    selectableCount: 1  // Jumlah pilihan yang bisa dipilih
}

await sock.sendMessage(jid, { poll: pollMessage })

// Multi-select Poll
const multiPoll = {
    name: '🍕 Topping Pizza Favorit?',
    values: ['Pepperoni', 'Mushroom', 'Cheese', 'Olive', 'Bacon'],
    selectableCount: 3  // Bisa pilih hingga 3 opsi
}

await sock.sendMessage(jid, { poll: multiPoll })

Kelola WhatsApp Channel dengan lengkap:

// Create Newsletter/Channel
await sock.newsletterCreate('My Channel', 'Channel description')

// Update channel info
await sock.newsletterUpdateName(channelJid, 'New Channel Name')
await sock.newsletterUpdateDescription(channelJid, 'Updated description')
await sock.newsletterUpdatePicture(channelJid, { url: 'https://example.com/pic.jpg' })

// Follow/Unfollow
await sock.newsletterFollow(channelJid)
await sock.newsletterUnfollow(channelJid)

// Mute/Unmute
await sock.newsletterMute(channelJid)
await sock.newsletterUnmute(channelJid)

// Send reaction to channel message
await sock.newsletterReactMessage(channelJid, 'server_id', '🔥')

// Get channel metadata
const metadata = await sock.newsletterMetadata('jid', channelJid)
console.log('Subscribers:', metadata.subscribers)

// Admin operations
await sock.newsletterChangeOwner(channelJid, newOwnerLid)
await sock.newsletterDemote(channelJid, adminLid)
const adminCount = await sock.newsletterAdminCount(channelJid)

Generate custom alphanumeric pairing code:

// Standard pairing code
const code = await sock.requestPairingCode('6281234567890')
console.log('Your Pairing Code:', code)

// Custom alphanumeric pairing code
const customCode = await sock.requestPairingCode('6281234567890', 'MYCODE12')
console.log('Your Custom Code:', customCode)

Utilities untuk mengelola JID, LID (Linked ID), dan senderPn:

import { 
    parseJid,
    getSenderPn,
    getCurrentSenderInfo,
    isSelf,
    plotJid,
    normalizePhoneToJid,
    extractPhoneNumber,
    formatJidDisplay,
    isSameUser,
    getJidVariants,
    getRemoteJidFromMessage,
    createJidPlotter
} from 'baileys-joss'

// Get info tentang current session (senderPn)
const senderInfo = getCurrentSenderInfo(sock.authState)
console.log('Phone:', senderInfo.phoneNumber)
console.log('Phone JID:', senderInfo.phoneJid)
console.log('LID:', senderInfo.lid)
console.log('Device ID:', senderInfo.deviceId)
console.log('Name:', senderInfo.pushName)

// Parse JID untuk info lengkap
const jidInfo = parseJid('[email protected]')
console.log('User:', jidInfo.user)
console.log('Is LID:', jidInfo.isLid)
console.log('Is PN:', jidInfo.isPn)
console.log('Device:', jidInfo.device)

// Check apakah JID adalah diri sendiri
const isMe = isSelf(someJid, senderInfo)

// Normalize berbagai format nomor
const jid = normalizePhoneToJid('+62 812-3456-7890') // -> [email protected]

// Extract phone number dari JID
const phone = extractPhoneNumber('[email protected]') // -> 6281234567890

// Format untuk display
const display = formatJidDisplay('6281234567890:[email protected]', {
    showDevice: true,
    showType: true
}) // -> 6281234567890:1 (PN)

// Compare dua JID
const same = isSameUser('[email protected]', '6281234567890:[email protected]') // true

// Get sender dari message
sock.ev.on('messages.upsert', async ({ messages }) => {
    for (const msg of messages) {
        const { chatJid, senderJid } = getRemoteJidFromMessage(msg)
        console.log('Chat:', chatJid)
        console.log('Sender:', senderJid)
    }
})

// Advanced: Create plotter dengan LID mapping support
const plotter = createJidPlotter(
    sock.lidMapping.getLIDForPN.bind(sock.lidMapping),
    sock.lidMapping.getPNForLID.bind(sock.lidMapping)
)

const plotted = await plotter.plotBidirectional('[email protected]')
console.log('Phone:', plotted.pn)
console.log('LID:', plotted.lid)

Kirim lokasi dengan mudah:

// Send location
await sock.sendMessage(jid, {
    location: {
        degreesLatitude: -6.2088,
        degreesLongitude: 106.8456,
        name: 'Jakarta, Indonesia',
        address: 'Jl. Sudirman, Jakarta Pusat'
    }
})

Kelola grup dengan lengkap:

// Create group
const group = await sock.groupCreate('My Group', ['[email protected]'])

// Update group info
await sock.groupUpdateSubject(groupJid, 'New Group Name')
await sock.groupUpdateDescription(groupJid, 'New description')

// Manage participants
await sock.groupParticipantsUpdate(groupJid, ['[email protected]'], 'add')
await sock.groupParticipantsUpdate(groupJid, ['[email protected]'], 'remove')
await sock.groupParticipantsUpdate(groupJid, ['[email protected]'], 'promote')
await sock.groupParticipantsUpdate(groupJid, ['[email protected]'], 'demote')

// Get group metadata
const metadata = await sock.groupMetadata(groupJid)
console.log('Group Name:', metadata.subject)
console.log('Members:', metadata.participants.length)

// Group settings
await sock.groupSettingUpdate(groupJid, 'announcement') // Only admins can send
await sock.groupSettingUpdate(groupJid, 'not_announcement') // Everyone can send
await sock.groupSettingUpdate(groupJid, 'locked') // Only admins can edit info
await sock.groupSettingUpdate(groupJid, 'unlocked') // Everyone can edit info

// Leave group
await sock.groupLeave(groupJid)

🚀 Quick Start

import makeWASocket, { 
    useMultiFileAuthState,
    DisconnectReason,
    // Interactive Message features
    generateQuickReplyButtons,
    generateInteractiveListMessage,
    generateCombinedButtons,
    // JID Plotting features
    getCurrentSenderInfo,
    parseJid,
    isSelf
} from 'baileys-joss'

async function startBot() {
    const { state, saveCreds } = await useMultiFileAuthState('auth_session')
    
    const sock = makeWASocket({
        auth: state,
        printQRInTerminal: true
    })
    
    sock.ev.on('creds.update', saveCreds)
    
    sock.ev.on('connection.update', (update) => {
        const { connection, lastDisconnect } = update
        
        if (connection === 'close') {
            const shouldReconnect = lastDisconnect?.error?.output?.statusCode !== DisconnectReason.loggedOut
            if (shouldReconnect) {
                startBot()
            }
        } else if (connection === 'open') {
            console.log('✅ Connected!')
            
            // Get sender info
            const sender = getCurrentSenderInfo(sock.authState)
            console.log('📱 Logged in as:', sender?.phoneNumber)
        }
    })
    
    sock.ev.on('messages.upsert', async ({ messages }) => {
        const msg = messages[0]
        if (!msg.message || msg.key.fromMe) return
        
        const text = msg.message.conversation || 
                     msg.message.extendedTextMessage?.text || ''
        
        if (text === '/menu') {
            // Kirim interactive buttons
            const buttons = generateQuickReplyButtons(
                '🤖 Bot Menu\n\nPilih opsi:',
                [
                    { id: 'help', displayText: '❓ Bantuan' },
                    { id: 'info', displayText: 'ℹ️ Info' },
                    { id: 'order', displayText: '🛒 Order' }
                ],
                { footer: 'Baileys-Joss Bot' }
            )
            
            await sock.sendMessage(msg.key.remoteJid!, buttons)
        }
        
        if (text === '/poll') {
            // Kirim poll
            await sock.sendMessage(msg.key.remoteJid!, {
                poll: {
                    name: '🗳️ Vote sekarang!',
                    values: ['Option A', 'Option B', 'Option C'],
                    selectableCount: 1
                }
            })
        }
        
        if (text === '/ai') {
            // Kirim pesan dengan AI style
            await sock.sendMessage(msg.key.remoteJid!, {
                text: 'Halo! Saya asisten AI Anda 🤖',
                ai: true
            })
        }
    })
}

startBot()

💡 Use Case Examples

// Create a newsletter  
await sock.newsletterCreate('My Updates Channel', 'Stay updated!')

// Update description  
await sock.newsletterUpdateDescription(channelJid, 'Fresh updates weekly 🔥')

// Send reaction to channel message  
await sock.newsletterReactMessage(channelJid, 'server_id', '❤️')

// Fetch channel messages
const messages = await sock.newsletterFetchMessages('jid', channelJid, 10)
// Native Flow Buttons
const buttons = generateCombinedButtons(
    'Welcome to our service! 🎉',
    [
        { type: 'reply', displayText: '📋 View Menu', id: 'menu' },
        { type: 'url', displayText: '🌐 Visit Website', url: 'https://example.com' },
        { type: 'call', displayText: '📞 Call Us', phoneNumber: '+1234567890' },
        { type: 'copy', displayText: '📋 Copy Promo', copyCode: 'SAVE20' }
    ],
    { title: 'Welcome!', footer: 'Powered by Baileys-Joss' }
)

await sock.sendMessage(jid, buttons)
const media = [
    { image: { url: 'https://example.com/pic1.jpg' }, caption: 'Photo 1 📸' },
    { image: { url: 'https://example.com/pic2.jpg' }, caption: 'Photo 2 📸' },
    { video: { url: 'https://example.com/clip.mp4' }, caption: 'Video 🎬' }
]

await sock.sendMessage(jid, { 
    album: media, 
    caption: 'My Vacation Memories 🌴' 
})
// Request standard pairing code
const code = await sock.requestPairingCode('6281234567890')
console.log('Your Pairing Code:', code)

// Request custom pairing code
const customCode = await sock.requestPairingCode('6281234567890', 'BAILEYS1')
console.log('Your Custom Code:', customCode)
const pollMessage = {
    name: '🎬 Film Favorit Weekend Ini?',
    values: [
        '🦸 Superhero Movie',
        '😂 Comedy',
        '😱 Horror',
        '💑 Romance'
    ],
    selectableCount: 1
}

await sock.sendMessage(jid, { poll: pollMessage })
await sock.sendMessage(jid, {
    location: {
        degreesLatitude: -6.2088,
        degreesLongitude: 106.8456,
        name: 'Monas Jakarta',
        address: 'Jalan Medan Merdeka, Jakarta Pusat'
    }
})
// Create group
const group = await sock.groupCreate('My Awesome Group', [
    '[email protected]',
    '[email protected]'
])

console.log('Group created:', group.id)

// Update group settings
await sock.groupUpdateSubject(group.id, 'Updated Group Name')
await sock.groupSettingUpdate(group.id, 'announcement')

// Add members
await sock.groupParticipantsUpdate(group.id, [
    '[email protected]'
], 'add')

🆕 Baileys-Joss v1.0.3 New Features

Jadwalkan pesan untuk dikirim otomatis di waktu tertentu:

import { createMessageScheduler } from 'baileys-joss'

// Buat scheduler
const scheduler = createMessageScheduler(
    (jid, content) => sock.sendMessage(jid, content),
    {
        onSent: (scheduled, message) => {
            console.log(`Pesan terkirim ke ${scheduled.jid}`)
        },
        onFailed: (scheduled, error) => {
            console.log(`Gagal kirim: ${error.message}`)
        }
    }
)

// Jadwalkan pesan untuk waktu tertentu
const scheduled = scheduler.schedule(
    '[email protected]',
    { text: 'Selamat Ulang Tahun! 🎂' },
    new Date('2024-12-25 09:00:00')
)

// Jadwalkan dengan delay (30 menit dari sekarang)
scheduler.scheduleDelay(jid, { text: 'Reminder!' }, 30 * 60 * 1000)

// Cancel scheduled message
scheduler.cancel(scheduled.id)

// Get all pending messages
const pending = scheduler.getPending()

// Stop scheduler
scheduler.stop()

Kirim pesan massal ke banyak kontak dengan rate limiting:

import { createBulkSender, sendBulkMessages } from 'baileys-joss'

// Method 1: Create bulk sender instance
const bulkSender = createBulkSender(
    (jid, content) => sock.sendMessage(jid, content),
    {
        delayBetweenMessages: 2000, // 2 detik delay
        randomDelay: 1000, // Random 0-1 detik tambahan
        maxRetries: 2,
        onProgress: (progress) => {
            console.log(`Progress: ${progress.sent}/${progress.total} (${progress.percentage}%)`)
        },
        onComplete: (results) => {
            const success = results.filter(r => r.success).length
            console.log(`Selesai: ${success}/${results.length} berhasil`)
        }
    }
)

// Kirim pesan yang sama ke banyak JID
const jids = [
    '[email protected]',
    '[email protected]',
    '[email protected]'
]

const results = await bulkSender.sendToMany(jids, { text: 'Hello everyone!' })

// Kirim pesan berbeda ke JID berbeda
const messages = [
    { jid: '[email protected]', content: { text: 'Hi John!' } },
    { jid: '[email protected]', content: { text: 'Hi Jane!' } }
]
await bulkSender.send(messages)

// Method 2: Quick helper
await sendBulkMessages(
    (jid, content) => sock.sendMessage(jid, content),
    jids,
    { text: 'Broadcast message' }
)

Sistem balasan otomatis berdasarkan keyword/pattern:

import { createAutoReply } from 'baileys-joss'

// Buat auto-reply handler
const autoReply = createAutoReply(
    (jid, content, options) => sock.sendMessage(jid, content, options),
    (jid, presence) => sock.sendPresenceUpdate(presence, jid),
    {
        simulateTyping: true,
        typingDuration: 1500,
        globalCooldown: 1000
    }
)

// Tambah rule berdasarkan keywords
autoReply.addRule({
    keywords: ['harga', 'price', 'biaya'],
    response: { text: 'Silakan cek katalog kami di example.com' },
    cooldown: 60000, // 1 menit cooldown per user
    quoted: true // Reply dengan quote
})

// Rule dengan regex pattern
autoReply.addRule({
    pattern: /^(hi|hello|halo|hay)/i,
    response: { text: 'Hai! Ada yang bisa dibantu? 😊' },
    privateOnly: true // Hanya di private chat
})

// Rule dengan dynamic response
autoReply.addRule({
    keywords: ['order'],
    response: async (message, match) => {
        const sender = message.key.remoteJid
        return { text: `Terima kasih sudah order! ID: ${Date.now()}` }
    }
})

// Rule untuk grup saja
autoReply.addRule({
    exactMatch: '/menu',
    response: { text: 'Menu:\n1. Help\n2. Info\n3. Contact' },
    groupsOnly: true
})

// Proses pesan masuk
sock.ev.on('messages.upsert', async ({ messages }) => {
    for (const msg of messages) {
        if (!msg.key.fromMe) {
            await autoReply.processMessage(msg)
        }
    }
})

Kirim kartu kontak lengkap dengan detail:

import { 
    createContactCard, 
    createContactCards, 
    quickContact,
    generateVCard 
} from 'baileys-joss'

// Quick contact (simple)
const simple = quickContact('John Doe', '+628123456789', {
    organization: 'PT Example',
    email: '[email protected]'
})
await sock.sendMessage(jid, createContactCard(simple))

// Full vCard with all details
const fullContact = {
    fullName: 'Dr. John Doe',
    displayName: 'John D.',
    organization: 'Hospital ABC',
    title: 'Senior Doctor',
    phones: [
        { number: '+628123456789', type: 'CELL' },
        { number: '+622112345678', type: 'WORK' }
    ],
    emails: [
        { email: '[email protected]', type: 'WORK' },
        { email: '[email protected]', type: 'HOME' }
    ],
    urls: [
        { url: 'https://linkedin.com/in/johndoe', type: 'WORK' }
    ],
    addresses: [{
        street: 'Jl. Sudirman No. 123',
        city: 'Jakarta',
        state: 'DKI Jakarta',
        postalCode: '12345',
        country: 'Indonesia',
        type: 'WORK'
    }],
    birthday: '1990-05-15',
    note: 'Met at conference 2024'
}

await sock.sendMessage(jid, createContactCard(fullContact))

// Send multiple contacts
const contacts = [
    quickContact('Alice', '+628111111111'),
    quickContact('Bob', '+628222222222'),
    quickContact('Charlie', '+628333333333')
]
await sock.sendMessage(jid, createContactCards(contacts))

// Generate raw vCard string
const vcardString = generateVCard(fullContact)
console.log(vcardString)

Posting status WhatsApp (foto, video, text):

import { 
    StatusHelper, 
    STATUS_BROADCAST_JID,
    STATUS_BACKGROUNDS,
    STATUS_FONTS
} from 'baileys-joss'

const statusJid = STATUS_BROADCAST_JID // 'status@broadcast'

// Post text status
await sock.sendMessage(statusJid, StatusHelper.text(
    'Hello World! 🌍',
    STATUS_BACKGROUNDS.solid.green
))

// Post image status
const imageBuffer = fs.readFileSync('./my-photo.jpg')
await sock.sendMessage(statusJid, StatusHelper.image(
    imageBuffer,
    'Beautiful day! ☀️'
))

// Post video status
const videoBuffer = fs.readFileSync('./my-video.mp4')
await sock.sendMessage(statusJid, StatusHelper.video(
    videoBuffer,
    'Check this out! 🎬'
))

// Post GIF status
await sock.sendMessage(statusJid, StatusHelper.gif(
    gifBuffer,
    'Animated! 🎭'
))

// Custom text status with font
import { createTextStatus } from 'baileys-joss'

await sock.sendMessage(statusJid, createTextStatus({
    text: 'Custom styled status!',
    backgroundColor: STATUS_BACKGROUNDS.solid.purple,
    font: STATUS_FONTS.DANCING,
    textColor: '#FFFFFF'
}))

Template pesan siap pakai untuk berbagai keperluan:

import { createTemplateManager, renderTemplate, PRESET_TEMPLATES } from 'baileys-joss'

// Create manager with preset templates
const templates = createTemplateManager(true)

// Render preset template
const orderConfirmation = templates.render('order_confirmation', {
    orderId: 'ORD-12345',
    customerName: 'John Doe',
    orderDate: '2024-01-15',
    items: '1x Product A\n2x Product B',
    total: '150,000'
})

await sock.sendMessage(jid, { text: orderConfirmation })

// Create custom template
templates.create({
    name: 'Welcome Message',
    content: `Halo {{name}}! 👋

Selamat datang di {{company}}!

Berikut layanan kami:
{{services}}

Contact: {{phone:021-12345678}}`,
    category: 'greeting'
})

// Render custom template
const welcome = templates.render('welcome_message', {
    name: 'Budi',
    company: 'PT Example',
    services: '- Layanan A\n- Layanan B\n- Layanan C'
})

// Quick template rendering (tanpa manager)
const quick = renderTemplate(
    'Hi {{name}}, your order #{{orderId}} is {{status:processing}}',
    { name: 'Alice', orderId: '123' }
)

// List available templates
const allTemplates = templates.getAll()
const invoiceTemplates = templates.getByCategory('invoice')

// Export/Import templates
const exportJson = templates.export()
templates.import(exportJson, true) // true = overwrite existing

Kelola dan kirim ke broadcast list:

import { createBroadcastManager } from 'baileys-joss'

const broadcast = createBroadcastManager(
    (jid, content) => sock.sendMessage(jid, content)
)

// Create broadcast list
const customerList = broadcast.create({
    name: 'VIP Customers',
    description: 'Premium customers for promo',
    recipients: [
        '[email protected]',
        '[email protected]'
    ]
})

// Add more recipients
broadcast.addRecipients(customerList.id, [
    '[email protected]'
])

// Send to broadcast list
const result = await broadcast.broadcast(
    customerList.id,
    { text: '🎉 Special promo for VIP customers!' },
    {
        delay: 2000,
        onProgress: (sent, total, jid) => {
            console.log(`Sending ${sent}/${total}: ${jid}`)
        }
    }
)

console.log(`Sent: ${result.sent}, Failed: ${result.failed}`)

// Get statistics
const stats = broadcast.getStats()
console.log(`Total lists: ${stats.totalLists}, Recipients: ${stats.totalRecipients}`)

// Export/Import lists
const json = broadcast.export()
broadcast.import(json)

Simulasi sedang mengetik:

import { createTypingIndicator } from 'baileys-joss'

const typing = createTypingIndicator(
    (jid, presence) => sock.sendPresenceUpdate(presence, jid)
)

// Start typing
await typing.startTyping(jid, { 
    duration: 5000,  // Auto pause after 5 seconds
    autoPause: true 
})

// Start recording (for voice notes)
await typing.startRecording(jid, { duration: 3000 })

// Stop typing
await typing.stopTyping(jid)

// Simulate typing then send
await typing.simulateTyping(jid, 2000, async () => {
    return sock.sendMessage(jid, { text: 'Hello!' })
})

// Stop all typing indicators
await typing.stopAll()

Kontrol centang biru:

import { createReadReceiptController } from 'baileys-joss'

const readReceipts = createReadReceiptController(
    (jid, participant, messageIds) => sock.readMessages([{ remoteJid: jid, id: messageIds[0] }]),
    {
        enabled: true,
        readDelay: 1000, // 1 second delay
        excludeJids: ['[email protected]']
    }
)

// Toggle read receipts
readReceipts.disable() // Stop sending read receipts
readReceipts.enable()  // Resume

// Check status
console.log(readReceipts.isEnabled())

// Manual read (respects config)
await readReceipts.markRead(jid, participant, ['messageId123'])

// Force read (ignores config)
await readReceipts.forceMarkRead(jid, participant, ['messageId123'])

// Update config
readReceipts.setConfig({
    enabled: true,
    readDelay: 2000
})

Cari pesan dalam chat:

import { createMessageSearch, searchMessages } from 'baileys-joss'

// Create search manager
const search = createMessageSearch()

// Add messages to index
search.addMessages(chatMessages)

// Search by text
const results = search.search('harga produk', {
    caseSensitive: false,
    limit: 20,
    messageTypes: ['text', 'image'], // Include captions
    fromDate: new Date('2024-01-01')
})

for (const result of results) {
    console.log(`Found: "${result.matchedText}"`)
    console.log(`Score: ${result.relevanceScore}`)
    console.log(`Message ID: ${result.message.key.id}`)
}

// Search with regex
const regexResults = search.searchRegex(/order\s*#?\d+/i)

// Get messages by type
const images = search.getByType('image')
const videos = search.getByType('video')

// Get messages by sender
const fromSender = search.getBySender('[email protected]')

// Quick search (without manager)
const quickResults = searchMessages(messages, 'keyword', {
    jid: specificChatJid,
    fromMe: false
})

Statistik dan analitik chat:

import { createChatAnalytics } from 'baileys-joss'

const analytics = createChatAnalytics()

// Add messages for analysis
analytics.addMessages(allMessages)

// Get stats for specific chat
const chatStats = analytics.getChatStats('[email protected]')

console.log(`Total messages: ${chatStats.totalMessages}`)
console.log(`From me: ${chatStats.messagesFromMe}`)
console.log(`Media count: ${chatStats.mediaCount}`)
console.log(`Links shared: ${chatStats.linkCount}`)
console.log(`Emojis used: ${chatStats.emojiCount}`)
console.log(`Most active hour: ${chatStats.mostActiveHour}:00`)
console.log(`Most active day: ${chatStats.mostActiveDay}`)
console.log(`Avg messages/day: ${chatStats.averageMessagesPerDay}`)

// Message breakdown by type
console.log('Messages by type:', chatStats.messagesByType)
// { text: 150, image: 45, video: 12, audio: 8, ... }

// Global stats across all chats
const globalStats = analytics.getGlobalStats()
console.log(`Total chats: ${globalStats.totalChats}`)
console.log(`Total messages: ${globalStats.totalMessages}`)
console.log(`Most active chat: ${globalStats.mostActiveChat?.jid}`)

// Activity analysis
const hourlyActivity = analytics.getActivityByHour(jid) // Array[24]
const dailyActivity = analytics.getActivityByDay(jid) // { Sunday: 10, Monday: 25, ... }

// Top participants in group
const topParticipants = analytics.getTopParticipants(groupJid, 5)
for (const p of topParticipants) {
    console.log(`${p.participant}: ${p.count} messages`)
}

Export chat ke JSON, HTML, TXT, atau CSV:

import { createChatExporter, exportChat } from 'baileys-joss'

const exporter = createChatExporter()

// Add messages
exporter.addMessages(jid, chatMessages)

// Export to JSON
const jsonExport = exporter.export(jid, {
    format: 'json',
    includeMediaInfo: true,
    includeMetadata: true
})

fs.writeFileSync(jsonExport.filename, jsonExport.content)

// Export to HTML (readable format)
const htmlExport = exporter.export(jid, {
    format: 'html',
    title: 'Chat dengan John',
    dateFormat: 'YYYY-MM-DD HH:mm'
})

fs.writeFileSync(htmlExport.filename, htmlExport.content)

// Export to TXT (simple text)
const txtExport = exporter.export(jid, {
    format: 'txt',
    dateRange: {
        start: new Date('2024-01-01'),
        end: new Date('2024-12-31')
    }
})

// Export to CSV (for spreadsheet)
const csvExport = exporter.export(jid, {
    format: 'csv',
    includeMetadata: true
})

// Quick export (without manager)
const result = exportChat(messages, jid, { format: 'json' })
console.log(`Exported ${result.messageCount} messages`)

// Export all chats
const allExports = exporter.exportAll({ format: 'json' })

Game sederhana untuk chat interaktif:

import { 
    MiniGamesManager,
    createTicTacToeGame,
    createQuiz 
} from 'baileys-joss'

// Create games manager
const games = new MiniGamesManager()

// 🎯 Guess Number Game
const guessSession = games.startGuessNumber('[email protected]', {
    minNumber: 1,
    maxNumber: 100,
    maxAttempts: 7
})

// Handle guess
const result = games.handleGuess(guessSession.id, 50)
if (result.correct) {
    await sock.sendMessage(jid, { text: `🎉 Correct! The number was ${result.answer}` })
} else {
    await sock.sendMessage(jid, { text: `${result.hint} (${result.remaining} attempts left)` })
}

// 🧠 Quiz Game
const quizSession = games.startQuiz(jid, {
    questions: [
        {
            question: 'Apa ibukota Indonesia?',
            options: ['Jakarta', 'Bandung', 'Surabaya', 'Medan'],
            correctIndex: 0,
            explanation: 'Jakarta adalah ibukota Indonesia sejak 1945'
        }
    ],
    category: 'geography'
})
await sock.sendMessage(jid, { 
    text: `📝 Quiz:\n${quizSession.data.currentQuestion}\n\n${quizSession.data.options.map((o, i) => `${i+1}. ${o}`).join('\n')}` 
})

// ❌⭕ TicTacToe Game  
const tttSession = games.startTicTacToe(jid, player1Jid, player2Jid)
const moveResult = games.handleMove(tttSession.id, player1Jid, 4) // Center position

await sock.sendMessage(jid, { 
    text: `${games.renderBoard(tttSession)}\n\n${moveResult.message}` 
})

// 🎲 Quick Games
const dice = games.rollDice() // { value: 1-6, emoji: '🎲' }
const coin = games.flipCoin() // { result: 'heads'|'tails', emoji: '🪙' }
const rps = games.playRockPaperScissors('rock', 'scissors') // { winner: 'player1', ... }

// 🏆 Leaderboard
const leaderboard = games.getLeaderboard(10)

Deteksi otomatis berbagai jenis konten dalam pesan:

import { 
    ContentDetector, 
    ContentFilter,
    hasLinks,
    hasPhoneNumbers,
    hasEmails,
    hasMediaContent 
} from 'baileys-joss'

// Create detector
const detector = new ContentDetector()

// Full analysis
const result = detector.analyze(message)
console.log('Has media:', result.hasMedia)
console.log('Media type:', result.mediaType)
console.log('Links found:', result.links)
console.log('Phone numbers:', result.phoneNumbers)
console.log('Emails:', result.emails)
console.log('Mentions:', result.mentions)
console.log('Hashtags:', result.hashtags)
console.log('Word count:', result.wordCount)

// Quick checks
if (hasLinks(message)) {
    console.log('Message contains links!')
}
if (hasPhoneNumbers(message)) {
    console.log('Message contains phone numbers!')
}
if (hasMediaContent(message)) {
    console.log('Message has media attachment!')
}

// Content filtering
const filter = new ContentFilter({
    blockLinks: true,
    blockedDomains: ['spam.com', 'malware.xyz'],
    blockPhoneNumbers: false,
    sensitiveKeywords: ['spam', 'promo', 'click here'],
    maxMessageLength: 1000
})

const filterResult = filter.check(message)
if (!filterResult.allowed) {
    await sock.sendMessage(jid, { 
        text: `⚠️ Message blocked: ${filterResult.blockedReason}` 
    })
}

Sistem untuk mendeteksi dan mencegah spam:

import { AntiSpamManager } from 'baileys-joss'

// Create anti-spam manager
const antispam = new AntiSpamManager({
    maxMessagesPerMinute: 15,
    maxDuplicates: 3,
    duplicateWindow: 60000, // 1 minute
    minMessageDelay: 500,
    whitelist: ['[email protected]'],
    onSpamDetected: async (jid, message, result) => {
        console.log(`Spam detected from ${jid}: ${result.reason}`)
        if (result.action === 'mute') {
            await sock.sendMessage(jid, { text: '⚠️ You are muted for spamming!' })
        }
    }
})

// Add custom spam pattern
antispam.addRule({
    id: 'promo_spam',
    name: 'Promotional Spam',
    type: 'pattern',
    enabled: true,
    config: { patterns: [/FREE\s+\d+\s+TOKEN/i, /CLICK\s+HERE.*WIN/i] },
    action: 'delete'
})

// Check incoming messages
sock.ev.on('messages.upsert', async ({ messages }) => {
    for (const msg of messages) {
        const result = await antispam.checkMessage(msg)
        
        if (result.isSpam) {
            console.log(`🛡️ Spam blocked! Score: ${result.score}, Reason: ${result.reason}`)
            
            // Handle based on action
            if (result.action === 'delete') {
                await sock.sendMessage(msg.key.remoteJid, { delete: msg.key })
            } else if (result.action === 'warn') {
                await sock.sendMessage(msg.key.remoteJid, { 
                    text: `⚠️ Warning: ${result.reason}` 
                })
            }
            continue
        }
        
        // Process non-spam message...
    }
})

// Whitelist trusted users
antispam.whitelist('[email protected]')

// Mute spammer temporarily
antispam.muteUser('[email protected]', 3600) // 1 hour

// Ban repeat offender
antispam.banUser('[email protected]')

// Get spam statistics
const stats = antispam.getStats()
console.log('Total spam blocked:', stats.totalBlocked)

Scan dan validasi URL untuk keamanan:

import { LinkScanner, scanUrls, isUrlSafe } from 'baileys-joss'

// Create scanner
const scanner = new LinkScanner({
    followRedirects: true,
    maxRedirects: 5,
    timeout: 5000,
    enablePhishingDetection: true
})

// Scan single URL
const result = await scanner.scanUrl('https://suspicious-link.xyz/login')
console.log('Safe:', result.safe)
console.log('Risk level:', result.riskLevel) // 'safe' | 'low' | 'medium' | 'high' | 'critical'
console.log('Threats:', result.threats)
console.log('Details:', result.details)

// Scan all URLs in a message
const messageResults = await scanner.scanMessage(message)
for (const urlResult of messageResults) {
    if (!urlResult.safe) {
        await sock.sendMessage(jid, { 
            text: `⚠️ Warning! Suspicious link detected:\n${urlResult.url}\n\nRisk: ${urlResult.riskLevel}\nThreats: ${urlResult.threats.join(', ')}` 
        })
    }
}

// Quick safety check
const isSafe = await scanner.isUrlSafe('https://example.com')

// Add custom patterns
scanner.addPhishingPattern(/banking.*verify.*account/i)
scanner.addTrustedDomain('mytrusted.com')
scanner.addMaliciousDomain('known-scam.xyz')

// Auto-scan in message handler
sock.ev.on('messages.upsert', async ({ messages }) => {
    for (const msg of messages) {
        const scanResults = await scanner.scanMessage(msg)
        const dangerous = scanResults.filter(r => r.riskLevel === 'high' || r.riskLevel === 'critical')
        
        if (dangerous.length > 0) {
            await sock.sendMessage(msg.key.remoteJid, { 
                text: `🚨 Dangerous link(s) detected! ${dangerous.length} threat(s) found.`
            }, { quoted: msg })
        }
    }
})

Logging aktivitas untuk audit trail:

import { ActivityLogger } from 'baileys-joss'

// Create logger
const logger = new ActivityLogger({
    fileLogging: true,
    logFilePath: './logs/bot-activity.log',
    maxMemoryEntries: 1000,
    maxFileSize: 10 * 1024 * 1024, // 10MB
    minLevel: 'info',
    categories: ['message', 'user', 'group', 'bot'],
    onLog: (entry) => {
        if (entry.level === 'error') {
            // Send alert to admin
            console.error(`[ALERT] ${entry.action}: ${entry.details.message}`)
        }
    }
})

// Log message activity
logger.logMessage(message, 'received', {
    processed: true,
    responseTime: 150
})

// Log user action
logger.logUserAction('[email protected]', 'command_executed', {
    command: '/help',
    success: true
})

// Log group action
logger.logGroupAction('[email protected]', 'member_added', {
    addedBy: '[email protected]',
    newMember: '[email protected]'
})

// Log custom activity
logger.log({
    level: 'info',
    category: 'bot',
    action: 'scheduled_task',
    actor: 'system',
    details: { task: 'daily_backup', status: 'completed' }
})

// Query logs
const recentErrors = logger.query({
    level: 'error',
    fromDate: new Date(Date.now() - 24 * 60 * 60 * 1000), // Last 24 hours
    limit: 50
})

// Get statistics
const stats = logger.getStats()
console.log('Total entries:', stats.totalEntries)
console.log('By level:', stats.byLevel)
console.log('Top actors:', stats.topActors)

// Export logs
const jsonLogs = logger.export('json')
const csvLogs = logger.export('csv')

Generate meme sederhana dengan text overlay:

import { 
    MemeGenerator, 
    MEME_TEMPLATES,
    drakeMeme,
    expandingBrainMeme,
    thisIsFineMeme 
} from 'baileys-joss'

// Create generator
const meme = new MemeGenerator()

// List available templates
const templates = meme.getTemplates()
console.log('Available templates:', templates.map(t => t.name))

// Generate Drake meme (quick helper)
const drake = drakeMeme(
    'Debugging code manually',      // Rejected
    'Using console.log everywhere'  // Approved
)
await sock.sendMessage(jid, { text: drake.htmlContent })

// Generate Expanding Brain meme
const brain = expandingBrainMeme([
    'Using var',
    'Using let',
    'Using const',
    'Using TypeScript'
])
await sock.sendMessage(jid, { text: brain.htmlContent })

// Generate "This is Fine" meme
const fine = thisIsFineMeme('Production is on fire but it\'s fine')
await sock.sendMessage(jid, { text: fine.htmlContent })

// Custom meme with template
const custom = meme.generateTextMeme({
    template: 'distracted',
    texts: {
        boyfriend: 'Me',
        girlfriend: 'My deadlines',
        other: 'New side project'
    },
    fontSize: 24,
    fontColor: '#ffffff'
})

// Generate SVG meme (for advanced use)
const svgMeme = meme.generateSvgMeme({
    template: 'two_buttons',
    texts: {
        button1: 'Sleep early',
        button2: 'One more episode'
    }
})

// Send as formatted text meme
await sock.sendMessage(jid, { 
    text: `🎭 *MEME*\n\n${custom.htmlContent}` 
})

Timer produktivitas dengan teknik Pomodoro:

import { PomodoroManager, DEFAULT_POMODORO_CONFIG } from 'baileys-joss'

// Create pomodoro manager
const pomodoro = new PomodoroManager()

// Register event handler
pomodoro.onEvent(async (event) => {
    const jid = event.session.jid
    
    switch (event.type) {
        case 'work_start':
            await sock.sendMessage(jid, { 
                text: `🍅 *WORK SESSION STARTED*\n\n⏱️ Duration: 25 minutes\n🎯 Session: ${event.session.currentSession}/${event.session.totalSessions}\n\n💪 Stay focused!` 
            })
            break
        case 'work_end':
            await sock.sendMessage(jid, { 
                text: `✅ *WORK SESSION COMPLETE!*\n\n🎉 Great job! Time for a break.\n\nType /break to start break timer.` 
            })
            break
        case 'break_start':
            await sock.sendMessage(jid, { 
                text: `☕ *BREAK TIME*\n\n⏱️ Duration: 5 minutes\n\n🧘 Relax and recharge!` 
            })
            break
        case 'break_end':
            await sock.sendMessage(jid, { 
                text: `⏰ *BREAK OVER!*\n\nReady for next session?\nType /work to continue.` 
            })
            break
    }
})

// Start work session
const session = pomodoro.start('[email protected]', {
    workDuration: 25,      // 25 minutes
    shortBreakDuration: 5, // 5 minutes
    longBreakDuration: 15, // 15 minutes
    sessionsBeforeLongBreak: 4,
    autoStartBreaks: true
})

// Pause/Resume
pomodoro.pause(jid)
pomodoro.resume(jid)

// Start break manually
pomodoro.startBreak(jid)

// Get current status
const status = pomodoro.status(jid)
console.log('Status:', status.status) // 'work' | 'short_break' | 'long_break' | 'paused'
console.log('Time remaining:', status.remainingTime)
console.log('Current session:', status.currentSession)

// Stop and reset
pomodoro.stop(jid)

// Get statistics
const stats = pomodoro.stats(jid)
console.log('Total work sessions:', stats.totalWorkSessions)
console.log('Total work minutes:', stats.totalWorkMinutes)
console.log('Current streak:', stats.currentStreak)

Random quotes dan quotes harian:

import { 
    QuoteManager,
    getRandomQuote,
    getQuoteOfTheDay,
    getMotivationalQuote,
    getIslamicQuote,
    getFunnyQuote,
    quoteCommand,
    QUOTES 
} from 'baileys-joss'

// Quick helpers
const random = getRandomQuote()
await sock.sendMessage(jid, { 
    text: `💬 *Quote*\n\n"${random.text}"\n\n— ${random.author}` 
})

// Quote of the day (same quote all day)
const qotd = getQuoteOfTheDay()
await sock.sendMessage(jid, { 
    text: `📅 *Quote of the Day*\n\n"${qotd.quote.text}"\n\n— ${qotd.quote.author}` 
})

// Category-specific quotes
const motivational = getMotivationalQuote()
const islamic = getIslamicQuote()
const funny = getFunnyQuote()

// Using QuoteManager for more control
const quoteManager = new QuoteManager()

// Get quote by category
const loveQuote = quoteManager.getByCategory('love')
const wisdomQuote = quoteManager.getByCategory('wisdom')

// Get quote by language
const indonesianQuote = quoteManager.getByLanguage('id')
const englishQuote = quoteManager.getByLanguage('en')

// Search quotes
const searchResults = quoteManager.search('success')

// Add custom quote
quoteManager.addQuote({
    id: 'custom1',
    text: 'My custom inspirational quote',
    author: 'Me',
    category: 'inspirational',
    language: 'en'
})

// Parse command (for bot integration)
// Supported: /quote, /quote motivational, /quote islamic, /quote funny
const commandResult = quoteCommand('/quote motivational')
await sock.sendMessage(jid, { text: commandResult })

// Send random quote with formatting
const formatted = quoteManager.format(getRandomQuote(), {
    style: 'fancy', // 'simple' | 'fancy' | 'minimal'
    includeCategory: true
})
await sock.sendMessage(jid, { text: formatted })

Informasi cuaca dengan integrasi OpenWeatherMap:

import { 
    WeatherBot, 
    getWeather, 
    getSimpleWeather,
    weatherCommand 
} from 'baileys-joss'

// Create weather bot (with API key for full features)
const weather = new WeatherBot({
    apiKey: 'YOUR_OPENWEATHERMAP_API_KEY', // Optional: enables API mode
    units: 'metric', // 'metric' | 'imperial'
    language: 'id',
    defaultCity: 'Jakarta'
})

// Get weather for a city
const data = await weather.getWeather('Jakarta')
await sock.sendMessage(jid, { 
    text: `🌤️ *Weather in ${data.city}, ${data.country}*\n\n🌡️ Temperature: ${data.temperature}°C\n🤒 Feels like: ${data.feelsLike}°C\n💧 Humidity: ${data.humidity}%\n💨 Wind: ${data.windSpeed} m/s\n☁️ Condition: ${data.description}\n\n🌅 Sunrise: ${new Date(data.sunrise * 1000).toLocaleTimeString()}\n🌇 Sunset: ${new Date(data.sunset * 1000).toLocaleTimeString()}` 
})

// Quick helper (uses sample data if no API key)
const simpleWeather = await getSimpleWeather('Tokyo')
await sock.sendMessage(jid, { text: simpleWeather })

// Get 5-day forecast
const forecast = await weather.getForecast('Singapore')
let forecastText = `📅 *5-Day Forecast for ${forecast.city}*\n\n`
for (const day of forecast.forecasts.slice(0, 5)) {
    forecastText += `${day.date}: ${day.temperature}°C, ${day.description}\n`
}
await sock.sendMessage(jid, { text: forecastText })

// Weather alerts
const alerts = await weather.getAlerts('Miami')
if (alerts.length > 0) {
    for (const alert of alerts) {
        await sock.sendMessage(jid, { 
            text: `⚠️ *Weather Alert*\n\n${alert.event}\n\nSeverity: ${alert.severity}\n${alert.description}` 
        })
    }
}

// Parse weather command (for bot integration)
// Supported: /weather Jakarta, /cuaca Bandung
const result = await weatherCommand('/weather Singapore', weather)
await sock.sendMessage(jid, { text: result })

// Format with emoji
const formatted = weather.formatWeather(data, {
    includeEmoji: true,
    includeDetails: true,
    language: 'id'
})
await sock.sendMessage(jid, { text: formatted })

Generate QR code custom untuk pairing:

import { 
    createQRGenerator, 
    QRHelper,
    createQRHandler,
    createWhatsAppQR 
} from 'baileys-joss'

// Quick QR generation
const terminalQR = await QRHelper.terminal(pairingCode)
console.log(terminalQR)

// Generate SVG QR
const svgQR = await QRHelper.svg(pairingCode, {
    size: 300,
    foregroundColor: '#128C7E', // WhatsApp green
    backgroundColor: '#FFFFFF'
})

// Generate base64 QR (for web)
const base64QR = await QRHelper.base64(pairingCode)

// Generate PNG buffer
const pngBuffer = await QRHelper.buffer(pairingCode)
fs.writeFileSync('qr.png', pngBuffer)

// Custom generator
const generator = createQRGenerator({
    size: 256,
    errorCorrectionLevel: 'H',
    foregroundColor: '#000000',
    margin: 4
})

const qr = await generator.generate(data)

// WhatsApp-styled QR
const waQR = await createWhatsAppQR(pairingCode)

// Use as QR event handler
const sock = makeWASocket({
    // ...
    printQRInTerminal: false
})

sock.ev.on('connection.update', async ({ qr }) => {
    if (qr) {
        const qrHandler = createQRHandler({
            maxAttempts: 5,
            onQR: (rendered, raw, attempt) => {
                console.log(`\nScan QR (${attempt}/5):\n`)
                console.log(rendered)
            }
        })
        await qrHandler(qr)
    }
})

Download semua media dari chat:

import { createMediaDownloader, downloadAllMedia } from 'baileys-joss'

const downloader = createMediaDownloader(
    async (key) => store.loadMessage(key.remoteJid, key.id)
)

// Download all media from chat
const summary = await downloader.downloadFromChat(
    '[email protected]',
    chatMessages,
    {
        outputDir: './downloads/john-doe',
        types: ['image', 'video', 'document'], // or ['all']
        createSubfolders: true, // images/, videos/, etc.
        skipExisting: true,
        maxFileSize: 50 * 1024 * 1024, // 50MB limit
        delay: 500, // Delay between downloads
        onProgress: (current, total, filename) => {
            console.log(`Downloading ${current}/${total}: ${filename}`)
        },
        onError: (msg, error) => {
            console.log(`Failed: ${error.message}`)
        }
    }
)

console.log(`Downloaded: ${summary.successful}/${summary.total}`)
console.log(`Total size: ${(summary.totalSize / 1024 / 1024).toFixed(2)} MB`)
console.log(`Failed: ${summary.failed}`)

// Download single media
const singleResult = await downloader.downloadSingle(
    mediaMessage,
    './downloads',
    { filenameTemplate: '{type}_{date}_{id}{ext}' }
)

// Quick download all (without manager)
await downloadAllMedia(messages, './downloads/all-media', {
    types: ['image'],
    onProgress: (curr, total) => console.log(`${curr}/${total}`)
})

📋 API Reference

| Function | Description | |----------|-------------| | generateInteractiveButtonMessage() | Buat button message dengan media header | | generateInteractiveListMessage() | Buat list message dengan sections | | generateTemplateMessage() | Buat template message (Quick Reply, URL, Call) | | generateNativeFlowMessage() | Buat native flow message (format terbaru) | | generateCopyCodeButton() | Button untuk copy code | | generateUrlButtonMessage() | Button dengan URL | | generateQuickReplyButtons() | Quick reply buttons | | generateCombinedButtons() | Gabungan berbagai jenis button |

| Function | Description | |----------|-------------| | parseJid() | Parse JID dan extract info lengkap | | getSenderPn() | Get senderPn dari AuthenticationCreds | | getCurrentSenderInfo() | Get current sender info dari authState | | isSelf() | Check apakah JID adalah diri sendiri | | plotJid() | Plot JID (basic, tanpa LID mapping) | | normalizePhoneToJid() | Normalize nomor ke JID | | extractPhoneNumber() | Extract phone number dari JID | | formatJidDisplay() | Format JID untuk display | | isSameUser() | Compare dua JID | | getJidVariants() | Get semua variant JID dari nomor | | constructJidWithDevice() | Construct JID dengan device ID | | getRemoteJidFromMessage() | Get remoteJid dari message | | createJidPlotter() | Create plotter dengan LID mapping support |

| Function | Description | |----------|-------------| | newsletterCreate() | Buat channel baru | | newsletterUpdateName() | Update nama channel | | newsletterUpdateDescription() | Update deskripsi channel | | newsletterUpdatePicture() | Update foto channel | | newsletterFollow() | Follow channel | | newsletterUnfollow() | Unfollow channel | | newsletterMute() | Mute notifikasi channel | | newsletterUnmute() | Unmute notifikasi channel | | newsletterReactMessage() | React ke pesan channel | | newsletterMetadata() | Get metadata channel | | newsletterAdminCount() | Get jumlah admin | | newsletterChangeOwner() | Ganti owner channel | | newsletterDemote() | Demote admin channel | | newsletterDelete() | Hapus channel |

| Function | Description | |----------|-------------| | groupCreate() | Buat grup baru | | groupUpdateSubject() | Update nama grup | | groupUpdateDescription() | Update deskripsi grup | | groupParticipantsUpdate() | Add/remove/promote/demote member | | groupSettingUpdate() | Update pengaturan grup | | groupMetadata() | Get metadata grup | | groupLeave() | Keluar dari grup | | groupInviteCode() | Get kode invite grup | | groupAcceptInvite() | Join grup via invite code |

| Type | Description | |------|-------------| | text | Pesan teks biasa | | image | Kirim gambar (dengan opsi hd: true untuk kualitas HD) | | video | Kirim video (dengan opsi hd: true untuk kualitas HD) | | audio | Kirim audio | | document | Kirim dokumen | | sticker | Kirim sticker | | location | Kirim lokasi | | contacts | Kirim kontak | | poll | Buat polling | | album | Kirim album (multiple media) | | react | React ke pesan | | edit | Edit pesan | | delete | Hapus pesan |

| Function | Description | |----------|-------------| | updateProfilePicture() | Update foto profil (square crop) | | updatePanoramaProfilePicture() | Update foto profil panorama (wide, tidak di-crop) | | removeProfilePicture() | Hapus foto profil | | profilePictureUrl() | Get URL foto profil |

| Function | Description | |----------|-------------| | MiniGamesManager | Main class untuk manage semua games | | games.startGuessNumber() | Start guess number game | | games.startQuiz() | Start quiz game | | games.startTicTacToe() | Start TicTacToe (vs bot/player) | | games.playRockPaperScissors() | Play RPS game | | games.rollDice() | Roll dice (1-6) | | games.flipCoin() | Flip a coin | | `games.handleGues