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.1

Published

WhatsApp Web API with Interactive Buttons, List Messages, Albums, AI Messages, Polls, LID/SenderPn Plotting - 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
})

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')

📋 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 | | video | Kirim video | | 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 |


🔄 Changelog

  • ✨ Added Album Messages support (carousel format)
  • ✨ Added AI Message Style (ai: true) - shows AI indicator on messages
  • ✨ Added Custom Pairing Code support
  • ✨ Enhanced Newsletter/Channel control
  • ✨ Enhanced Poll creation
  • 🔧 Fixed Interactive Buttons - Added biz node for proper button rendering
  • 🔧 Fixed List Messages delivery
  • 🎨 Improved documentation with collapsible sections
  • 🐛 Bug fixes and stability improvements
  • 🎉 Initial release
  • ✨ Interactive Buttons support
  • ✨ List Messages support
  • ✨ Copy Code Button
  • ✨ URL Buttons
  • ✨ Combined Button Types
  • ✨ Native Flow Messages
  • ✨ LID/SenderPn Plotting utilities

🤝 Contributing

Kontribusi sangat diterima! Silahkan:

  1. 🍴 Fork repository ini
  2. 🌿 Buat branch fitur (git checkout -b feature/AmazingFeature)
  3. 💾 Commit changes (git commit -m 'Add some AmazingFeature')
  4. 📤 Push ke branch (git push origin feature/AmazingFeature)
  5. 🔃 Buka Pull Request

💖 Support

Jika project ini membantu, berikan ⭐ di GitHub!


⚠️ Disclaimer

Peringatan: Proyek ini tidak berafiliasi dengan WhatsApp atau Meta. Gunakan dengan tanggung jawab dan sesuai dengan Terms of Service WhatsApp.

Jangan spam!
Jangan abuse API!
Gunakan untuk keperluan yang baik!


📄 License

MIT License - Lihat file LICENSE untuk detail.


🙏 Credits