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-next

v7.1.0

Published

A WebSockets library for interacting with WhatsApp Web

Readme



🌟 Créditos Especiales

  • Nevi = Nevi-dev (Nose duarte me pidio que lo meta)
  • DuarteXV = DuarteXV (Gran Amigo Loco)
  • Ander = (Dueño de Alya Kujou y desarrollador de la api AlyaCORE API)

🆕 Novedades en v7.1.0 (Refactorización OOP y LIDs)

  • Modo Bajo Consumo (lowMemMode): Nuevo flag de configuración que disminuye agresivamente los cachés (hasta 10 veces) y optimiza el consumo, ideal para entornos con cientos de subbots.
  • Refactorización Orientada a Objetos (OOP): El núcleo de recepción de mensajes (messages-recv.ts) y la lectura de binarios (WABinary) dejaron de generar closures infinitos, salvando decenas de megas de RAM por cada nueva instancia de socket.
  • Protección contra LIDs (mapLidToPn): Olvídate de que tus comandos o base de datos se rompan porque WhatsApp empezó a enviar LIDs ocultos (@lid). Baileys-next ahora cuenta con una capa de abstracción que te permite forzar el ID tradicional numérico.
  • Correcciones Críticas del Núcleo:
    • Mitigado el Error 463 (Reachout Timelock) guardando correctamente los tcTokens entrantes y aplicándolos a mensajes salientes de manera secuencial (Mutex).
    • Solucionado el fallo generalizado (crash) al fallar el descifrado GCM en mensajes migrados a LID.
    • Fix de TypeScripts complejos de la versión upstream original de Baileys.

Tabla de Contenidos


🚀 Por que Baileys-next

La libreria original de Baileys es un motor brillante, pero fue disenada como una capa de bajo nivel. Cuando miles de desarrolladores la usaron para construir bots de produccion, aparecieron problemas repetidos:

| Problema | Baileys Original | Baileys-next | |---|---|---| | Consumo de RAM | Crece sin limite (in-memory store) | Constante (~15 MB) gracias a SQLite y lowMemMode | | Desconexiones | El desarrollador debe manejar la reconexion | Exponential Backoff automatico integrado | | Envio masivo | Sin proteccion, alto riesgo de ban | Rate Limiter con cola inteligente | | LIDs vs PNs | Estás forzado a operar usando LIDs rotos | Ajuste nativo mapLidToPn te devuelve tus IDs | | Multimedia | Requiere FFmpeg manual en el sistema | ffmpeg-static incluido, 0 instalacion extra | | Analiticas de grupo | No existe | StatsManager con deteccion de "fantasmas" | | Experiencia de desarrollo | Callbacks y eventos crudos | API de alto nivel con Bot, Context y Middlewares | | Logging | No estandarizado | Logger pino-compatible (structured JSON) | | Credenciales | Se pierden si registras listener en mal momento | bot.onCreds() garantiza el registro correcto | | Mensajes propios | El bot se responde a si mismo si no filtras | Filtrado automatico de msg.key.fromMe | | Encuestas | Imposible desencriptarlas facilmente | Evento bot.onPollVote nativo | | Recibos Lectura | Doble check azul dificil de capturar | Evento bot.onMessageReceiptUpdate nativo | | Helpers de Envío | Objetos complejos sendMessage | ctx.sendImage(), ctx.sendVideo(), ctx.readMessages() |


🔄 Antes vs Ahora

Responder a un Mensaje

Antes (Baileys original) — 15 lineas:

import makeWASocket, { useMultiFileAuthState, DisconnectReason } from '@whiskeysockets/baileys'
import { Boom } from '@hapi/boom'

async function start() {
    const { state, saveCreds } = await useMultiFileAuthState('auth')
    const sock = makeWASocket({ auth: state, printQRInTerminal: true })

    sock.ev.on('creds.update', saveCreds)
    sock.ev.on('connection.update', ({ connection, lastDisconnect }) => {
        if (connection === 'close') {
            const shouldReconnect = (lastDisconnect?.error as Boom)?.output?.statusCode !== DisconnectReason.loggedOut
            if (shouldReconnect) start()
        }
    })
    sock.ev.on('messages.upsert', async ({ messages, type }) => {
        if (type !== 'notify') return
        for (const msg of messages) {
            if (msg.key.fromMe) continue
            if (msg.message?.conversation === '!ping') {
                await sock.sendMessage(msg.key.remoteJid!, { text: 'Pong!' }, { quoted: msg })
            }
        }
    })
}
start()

Ahora (Baileys-next) — 8 lineas:

import { Bot, useMultiFileAuthState } from 'baileys-next'

async function start() {
    const { state, saveCreds } = await useMultiFileAuthState('auth')
    const bot = new Bot({ auth: state, printQRInTerminal: true })

    bot.onCreds(saveCreds) // Seguro antes de start()
    bot.command('!ping', async (ctx) => ctx.reply({ text: 'Pong!' }))
    await bot.start() // Reconexion automatica incluida
}
start()

Reconexion tras Caida

Antes — Debes gestionar manualmente:

sock.ev.on('connection.update', ({ connection, lastDisconnect }) => {
    if (connection === 'close') {
        const error = lastDisconnect?.error as Boom
        const statusCode = error?.output?.statusCode
        if (statusCode !== DisconnectReason.loggedOut) {
            // Reconectar... pero sin retardo. Si WhatsApp te bloquea
            // temporalmente, este loop infinito empeora todo.
            start()
        }
    }
})

Ahora — Automatico con Exponential Backoff:

const bot = new Bot({ auth: state })
await bot.start()
// Listo. Si se cae la conexion:
// Intento 1: espera 2s
// Intento 2: espera 4s
// Intento 3: espera 8s
// ... hasta maximo 60s
// Si es LoggedOut (sesion cerrada), NO reconecta.

Crear un Sticker

Antes — Instalar FFmpeg manualmente + 20 lineas de conversion:

// Requisito: apt install ffmpeg (o brew install ffmpeg)
import { exec } from 'child_process'
import fs from 'fs'

// Descargar el media...
const buffer = await downloadMediaMessage(msg, 'buffer', {})
fs.writeFileSync('/tmp/input.jpg', buffer)

// Convertir a WebP con shell
exec('ffmpeg -i /tmp/input.jpg -vcodec libwebp -vf scale=512:512 /tmp/output.webp', async () => {
    const sticker = fs.readFileSync('/tmp/output.webp')
    await sock.sendMessage(jid, { sticker }, { quoted: msg })
    // Y los metadatos EXIF? Otro paquete mas...
})

Ahora — 1 linea (FFmpeg incluido):

bot.command('!sticker', async (ctx) => {
    await ctx.replySticker(imageBuffer, { packname: 'MiBot', author: '@luis' })
    // FFmpeg + conversion + metadatos EXIF = todo incluido
})

Guardar Estado por Chat

Antes — Variable en memoria (se pierde al reiniciar):

const estados = new Map<string, any>() // Se pierde al reiniciar

sock.ev.on('messages.upsert', async ({ messages }) => {
    for (const msg of messages) {
        const jid = msg.key.remoteJid!
        if (msg.message?.conversation === '!recordar') {
            estados.set(jid, { nota: 'algo' })
        }
        if (msg.message?.conversation === '!nota') {
            const data = estados.get(jid)
            // Despues del reinicio: undefined
        }
    }
})

Ahora — Persistente en SQLite (sobrevive reinicios):

bot.command('!recordar', async (ctx) => {
    ctx.session.set({ nota: 'algo' }) // Guardado en disco
})

bot.command('!nota', async (ctx) => {
    const data = ctx.session.get<{ nota: string }>()
    await ctx.reply({ text: data?.nota ?? 'Sin notas' })
    // Despues del reinicio: la nota sigue ahi
})

Detectar Fantasmas de un Grupo

Antes — No existia:

// No habia forma de saber quien nunca habla.
// Tenias que construir tu propia base de datos,
// registrar cada mensaje manualmente, comparar
// con la lista de participantes...
// Facilmente +100 lineas de codigo.

Ahora — 3 lineas:

bot.command('!fantasmas', async (ctx) => {
    const ghosts = await bot.stats.getGhosts(ctx.remoteJid, 30)
    await ctx.reply({ text: `👻 ${ghosts.length} fantasmas encontrados` })
})

Enviar Multiples Mensajes sin ser Baneado

Antes — Sin proteccion:

// Enviar 50 mensajes en un loop = ban instantaneo
for (const jid of contactos) {
    await sock.sendMessage(jid, { text: 'Hola!' })
    // WhatsApp detecta envios a 0ms de intervalo
}

Ahora — Rate Limiter automatico:

const bot = new Bot({ auth: state, rateLimitMs: 2000 })

// Mismo loop, pero internamente la libreria espera 2s entre cada envio
for (const jid of contactos) {
    await bot.sendMessage(jid, { text: 'Hola!' })
    // La cola interna los despacha a 2000ms de intervalo
}

Registrar Credenciales

Antes — Bug silencioso si lo haces antes de conectar:

const sock = makeWASocket({ auth: state })

// BUG: Si haces esto antes de que el socket conecte, funciona
// PERO si alguien hace bot.socket?.ev.on(...) antes de start(),
// como socket es undefined, el listener nunca se registra!
sock.ev.on('creds.update', saveCreds)

Ahora — Garantizado:

const bot = new Bot({ auth: state })
bot.onCreds(saveCreds) // Seguro. Se registra internamente y se ejecuta siempre.
await bot.start()

Ajuste Exclusivo: Odiamos los LIDs (mapLidToPn)

WhatsApp empezó a migrar los chats (especialmente de iOS) a identificadores opacos conocidos como LIDs (@lid), destruyendo la compatibilidad con bases de datos clásicas de números telefónicos (@s.whatsapp.net).

Antes (O en Baileys Original):

sock.ev.on('messages.upsert', async ({ messages }) => {
    // Si el usuario tiene un iPhone migrado, recibirás:
    console.log(messages[0].key.remoteJid) // "123456789012345@lid"
    // Tus regex se rompen, tu base de datos no lo encuentra, el bot no responde.
})

Ahora (Elige lo que prefieras):

// Si prefieres usar los IDs clásicos (Números de Teléfono / JIDs):
const bot = new Bot({ auth: state, mapLidToPn: true })

bot.use(async (ctx, next) => {
    // Baileys-next hace la traducción mágica de forma transparente
    console.log(ctx.remoteJid) // "[email protected]"
    await next()
})

La clase principal. Orquesta socket, middlewares, base de datos y todas las funciones.

const bot = new Bot(config: BotConfig)

| Metodo / Propiedad | Retorno | Descripcion | |---|---|---| | bot.start() | Promise<void> | Conecta a WhatsApp y empieza a escuchar | | bot.close() | void | Shutdown graceful: cierra DB, vacia colas | | bot.command(cmd, handler) | void | Registra handler para mensajes que empiecen con cmd | | bot.onText(handler) | void | Registra handler para todos los mensajes de texto | | bot.use(middleware) | void | Registra un middleware (ver seccion Middlewares) | | bot.onCreds(handler) | void | Registra handler para guardar credenciales (seguro antes de start) | | bot.onConnection(handler) | void | Registra handler para cambios de conexion (seguro antes de start) | | bot.sendMessage(jid, content, opts?) | Promise<unknown> | Envia mensaje (pasa por Rate Limiter si activo) | | bot.socket | WASocket \| undefined | Acceso directo al socket de Baileys (bajo nivel) | | bot.store | SQLiteStore | Instancia de la base de datos SQLite | | bot.stats | StatsManager \| undefined | Gestor de analiticas (si enableStats es true) | | bot.session | SessionManager | Gestor de sesiones persistentes por chat | | bot.isConnected | boolean | Estado actual de la conexion |


Clase Context (ctx)

Envuelve cada mensaje entrante con metodos convenientes. Se pasa como primer argumento a handlers y middlewares.

| Metodo / Propiedad | Retorno | Descripcion | |---|---|---| | ctx.message | WAMessage | Mensaje crudo original de WhatsApp | | ctx.remoteJid | string | JID del chat (grupo o privado) | | ctx.sender | string | JID del remitente (funciona en grupos y privados) | | ctx.isGroup | boolean | true si es un grupo (@g.us) | | ctx.text | string \| undefined | Texto del mensaje | | ctx.bot | Bot | Referencia al Bot padre | | ctx.reply(content, opts?) | Promise<unknown> | Responde al mensaje (con quote automatico) | | ctx.send(content, opts?) | Promise<unknown> | Envia al mismo chat sin citar | | ctx.react(emoji) | Promise<unknown> | Reacciona con un emoji | | ctx.replySticker(buffer, meta?) | Promise<unknown> | Envia sticker WebP (convierte automaticamente) | | ctx.replyVoiceNote(buffer) | Promise<unknown> | Envia nota de voz Opus/OGG | | ctx.read(delayMs?) | Promise<unknown> | Marca como leido con retardo opcional | | ctx.session.get<T>() | T \| undefined | Obtiene datos de sesion del chat | | ctx.session.set(data) | void | Guarda datos de sesion | | ctx.session.update(data) | void | Merge parcial de datos | | ctx.session.delete() | void | Elimina la sesion |


StatsManager

Motor de analiticas silencioso. Almacena estadisticas en SQLite, indexadas por grupo.

| Metodo | Retorno | Descripcion | |---|---|---| | stats.getTopUsers(groupJid, limit?) | UserStats[] | Los limit usuarios mas activos | | stats.getTopStickers(groupJid, limit?) | UserStats[] | Los que mas stickers envian | | stats.getGhosts(groupJid, days?) | Promise<GhostEntry[]> | Miembros inactivos en days dias | | stats.getUserStats(groupJid, userJid) | UserStats \| undefined | Stats de un usuario especifico | | stats.observeMessage(groupJid, userJid, isSticker) | void | Registra mensaje (automatico) |

Interfaces:

interface UserStats {
    userJid: string
    messageCount: number
    stickerCount: number
    lastActive: number // timestamp
}

interface GhostEntry {
    jid: string
    isTotalGhost: boolean  // true = nunca ha enviado un mensaje
    lastActive?: number    // timestamp del ultimo mensaje
}

SessionManager

Estado persistente por chat. Util para flujos multi-paso, estados de conversacion, encuestas, etc.

| Metodo | Retorno | Descripcion | |---|---|---| | session.get<T>(jid) | T \| undefined | Obtiene datos | | session.set(jid, data) | void | Guarda (reemplaza todo) | | session.update(jid, data) | void | Merge parcial | | session.delete(jid) | void | Elimina | | session.has(jid) | boolean | Verifica existencia |


MediaManager

Utilidad estatica para conversion multimedia. No requiere instanciacion.

| Metodo | Retorno | Descripcion | |---|---|---| | MediaManager.convertToSticker(input, meta?) | Promise<Buffer> | Imagen/video a WebP (512x512) con EXIF | | MediaManager.convertToVoiceNote(input) | Promise<Buffer> | Audio a Opus/OGG mono 48kHz |


🔗 Middlewares

Pipeline inspirado en Koa/Express. Cada middleware recibe ctx y next().

graph LR
    MSG[Mensaje] --> MW1[Logger]
    MW1 -->|next| MW2[Auth]
    MW2 -->|next| MW3[Command]
    MW3 -->|next| END[Fin]
    MW2 -->|sin next| BLOCK[Bloqueado]

Ejemplo: Logger + Filtro de Admin

// Logger global
bot.use(async (ctx, next) => {
    const start = Date.now()
    await next()
    console.log(`[${Date.now() - start}ms] ${ctx.sender}: ${ctx.text}`)
})

// Filtro de admin (no llama next() si no es admin)
bot.use(async (ctx, next) => {
    if (ctx.text?.startsWith('!admin')) {
        const admins = ['[email protected]']
        if (!admins.includes(ctx.sender)) {
            await ctx.reply({ text: '⛔ Sin permisos.' })
            return
        }
    }
    await next()
})

// Solo admins llegan aqui
bot.command('!admin kick', async (ctx) => { /* ... */ })

Regla de oro: Si no llamas a await next(), la cadena se detiene.


💾 Persistencia SQLite

graph LR
    subgraph "Baileys Original"
        MEM["Map() en RAM"] --> CRASH["💥 OOM despues de horas"]
    end

    subgraph "Baileys-next"
        SQL["SQLite WAL en disco"] --> STABLE["✅ Estable por meses"]
    end

Tablas creadas automaticamente

| Tabla | Uso | |---|---| | kv_store | Contador de reintentos + sesiones (msgRetryCounterCache) | | group_stats | Contadores de mensajes, stickers, timestamps (indexado por group_jid) |

Configuracion

const bot = new Bot({
    auth: state,
    dbPath: './data/mi_bot.db' // Default: 'baileys_store.db'
})

La DB usa journal_mode = WAL (Write-Ahead Logging) para lecturas concurrentes sin bloqueo.


🛡 Rate Limiter y Anti-Ban

sequenceDiagram
    participant DEV as Tu Codigo
    participant RL as Rate Limiter
    participant WA as WhatsApp

    DEV->>RL: sendMessage("Hola")
    RL->>WA: Envia "Hola"
    DEV->>RL: sendMessage("Mundo")
    Note over RL: Espera rateLimitMs...
    RL->>WA: Envia "Mundo"
    DEV->>RL: sendMessage("!")
    Note over RL: Espera rateLimitMs...
    RL->>WA: Envia "!"

Configuracion recomendada

| Escenario | rateLimitMs | autoReadMs | |---|---|---| | Bot personal | 500 | 1000 | | Bot de grupo (< 50) | 1500 | 2000 | | Bot de servicio (100+) | 2000 - 3000 | 2000 - 3000 | | Quitar Antibaneo (Velocidad pura) | 0 (o no lo definas) | N/A |

¿Cómo Quitar el Antibaneo (Deshabilitar Cola de Mensajes)?

Si estás diseñando un sistema interno o necesitas máxima velocidad (0 milisegundos de retardo entre mensajes) y no te importan los bloqueos de WhatsApp, tienes dos opciones:

Opción A: Globalmente (Apagar Rate Limiter) Simplemente configura rateLimitMs: 0 (o no envíes este parámetro al crear el Bot):

const bot = new Bot({
    // rateLimitMs: 1500 // Bórralo o pon 0
})

Opción B: Por mensaje (Bypass del Rate Limiter) Si quieres mantener el anti-baneo encendido para el 99% de tus mensajes, pero necesitas enviar una alerta urgente sin esperar en la cola:

await bot.sendMessage(
    ctx.remoteJid, 
    { text: '¡ALERTA MÁXIMA!' }, 
    { ignoreRateLimit: true } // Se envía instantáneamente sin importar la cola
)

Auto-Read manual

bot.command('!test', async (ctx) => {
    await ctx.read(1500) // Clava el visto con 1.5s de retardo
    await ctx.reply({ text: 'Listo!' })
})

👻 Analiticas y Fantasmas

// Fantasmas (inactivos 30+ dias)
const ghosts = await bot.stats.getGhosts(ctx.remoteJid, 30)

// Top 10 activos
const top = bot.stats.getTopUsers(ctx.remoteJid, 10)

// Top stickereros
const stickers = bot.stats.getTopStickers(ctx.remoteJid, 5)

// Stats de un usuario especifico
const user = bot.stats.getUserStats(ctx.remoteJid, '[email protected]')

🎨 Multimedia (Stickers y Notas de Voz)

// Sticker con metadatos
await ctx.replySticker(imageBuffer, { packname: 'MiBot', author: '@luis' })

// Nota de voz nativa
await ctx.replyVoiceNote(audioBuffer)

// Tambien acepta rutas de archivo
await ctx.replySticker('/tmp/imagen.png')
await ctx.replyVoiceNote('/tmp/audio.mp3')

Especificaciones tecnicas:

  • Stickers: WebP, 512x512, con transparencia, metadatos EXIF inyectados
  • Notas de voz: Opus/OGG, mono, 48kHz (formato nativo PTT de WhatsApp)
  • FFmpeg incluido via ffmpeg-static (0 instalacion manual)

📋 Sesiones Persistentes

Flujos multi-paso que sobreviven reinicios:

// Flujo de encuesta con estados
bot.command('!encuesta', async (ctx) => {
    ctx.session.set({ paso: 1, pregunta: '¿Color favorito?' })
    await ctx.reply({ text: '¿Cual es tu color favorito?' })
})

bot.onText(async (ctx, next) => {
    const state = ctx.session.get<{ paso: number, pregunta: string }>()
    if (state?.paso === 1) {
        ctx.session.update({ paso: 2, respuesta: ctx.text })
        await ctx.reply({ text: `Guardado: ${ctx.text}. ¿Tu comida favorita?` })
        return // No propagar
    }
    if (state?.paso === 2) {
        ctx.session.delete() // Limpiar
        await ctx.reply({ text: `Encuesta completa!` })
        return
    }
    await next()
})

🔧 Acceso a Bajo Nivel

bot.socket expone el socket original de Baileys:

await bot.socket?.sendPresenceUpdate('composing', jid)
await bot.socket?.profilePictureUrl(jid)
await bot.socket?.groupMetadata(groupJid)
await bot.socket?.updateProfilePicture(jid, buffer)

bot.socket?.ev.on('group-participants.update', handler)
bot.socket?.ev.on('presence.update', handler)

⚠️ Evitar Problemas Comunes

| Problema | Causa | Solucion | |---|---|---| | better-sqlite3 no compila | Node.js v24+ rompe compilacion C++ | Usar Node 22 LTS: nvm use 22 | | ECONNRESET frecuente | Red inestable | No hacer nada (Exponential Backoff integrado) | | LoggedOut (401) | Sesion cerrada por WA | Eliminar carpeta auth y re-escanear QR | | Stickers no visibles en iOS | WebP > 100 KB | Recortar video antes de convertir | | Error 463 / Baneos por LID | Faltaba tctoken o LID caducado | Resuelto en v7.0.7 (escucha ev.on('lid-migration.update') si guardas LIDs) | | Mensajes fuera de orden | Sin Rate Limiter | Activar rateLimitMs | | Bot se responde a si mismo | Version vieja del fork | Actualizar (filtro fromMe incluido) | | Credenciales no se guardan | onCreds despues de start() | Usar bot.onCreds() antes de start() |


🔄 Migracion desde Baileys Original

Paso 1: Cambiar dependencia

npm uninstall @whiskeysockets/baileys
npm install baileys-next

Paso 2: Actualizar imports

- import makeWASocket from '@whiskeysockets/baileys'
+ import { Bot, useMultiFileAuthState } from 'baileys-next'

Paso 3: Reemplazar patron de socket

- const sock = makeWASocket({ auth: state })
- sock.ev.on('messages.upsert', ({ messages }) => { ... })
+ const bot = new Bot({ auth: state })
+ bot.command('!cmd', async (ctx) => { ... })
+ await bot.start()

Paso 4: Eliminar makeInMemoryStore

- import { makeInMemoryStore } from '@whiskeysockets/baileys'
- const store = makeInMemoryStore({})
- store.bind(sock.ev)
// Ya no es necesario. SQLiteStore se inicializa automaticamente.

Compatibilidad: bot.socket sigue exponiendo todas las funciones originales de Baileys.


🤝 Contribuir

Setup

git clone https://github.com/LuferOS/Baileys-next.git
cd Baileys-next
corepack enable
yarn install

Estructura del Proyecto

src/
├── Framework/           ← Codigo del fork (alto nivel)
│   ├── Bot.ts           ← Clase principal, middlewares, rate limiter, reconexion
│   ├── Context.ts       ← Wrapper de mensaje con helpers (reply, react, sticker...)
│   ├── MediaManager.ts  ← Conversion de stickers y notas de voz (ffmpeg-static)
│   ├── SessionManager.ts← Sesiones persistentes por chat
│   ├── StatsManager.ts  ← Analiticas y deteccion de fantasmas
│   ├── Store/
│   │   └── SQLiteStore.ts ← Motor de persistencia SQLite (WAL mode)
│   └── index.ts         ← Re-exports del framework
├── Socket/              ← Core de Baileys (WebSocket, Noise Protocol)
├── Signal/              ← Protocolo Signal (criptografia E2E)
├── Utils/               ← Utilidades del core
├── Types/               ← Tipos TypeScript publicos
├── WABinary/            ← Codificacion binaria de stanzas
└── index.ts             ← Export principal

Validacion

yarn lint      # TypeScript + ESLint (0 errores)
yarn test      # Tests unitarios
yarn build     # Compilacion limpia

Commits

git commit -m "feat(framework): add cooldown per user"
git commit -m "fix(media): handle webp conversion on linux"

Que NO contribuir

  • Herramientas de spam o mensajeria masiva
  • Scrapers de datos sin consentimiento
  • Mecanismos para evadir bans legitimos

💖 Creditos y Reconocimientos

Este proyecto es un Fork construido sobre el trabajo excepcional de la comunidad original:

| Contribuidor | Rol | |---|---| | WhiskeySockets / Rajeh | Creadores y mantenedores actuales del core | | @pokearaujo | Observaciones sobre WhatsApp Multi-Device | | @Sigalor | Ingenieria inversa del protocolo de WA Web | | @Rhymen | Primera implementacion en Go |

Apoya al mantenedor original: Sponsor Page


⚖️ Aviso Legal

Este proyecto NO esta afiliado, asociado, autorizado, respaldado por, ni conectado de ninguna manera oficial con WhatsApp o cualquiera de sus filiales.

Los mantenedores no aprueban el uso en practicas que violen los Terminos de Servicio de WhatsApp (spam, mensajeria masiva no deseada, extraccion de datos sin consentimiento).



✉️ Guía de Mensajería (Estilo Baileys-next)

Nota: Puedes usar bot.socket?.sendMessage(jid, ...) para enviar mensajes crudos, o usar el objeto ctx dentro de un comando si quieres enviar respuestas más fáciles. Aquí te mostramos cómo enviar mensajes usando la instancia de Socket de Baileys-next.

🔠 Texto y Enlaces

// --- Texto normal
await bot.socket?.sendMessage(jid, {
   text: '👋🏻 Hola'
})

// --- Texto con Vista Previa de Enlace (Link Preview)
const urlA = 'https://www.npmjs.com/package/baileys-next'
await bot.socket?.sendMessage(jid, {
   text: urlA + ' 👆🏻 ¡Echa un vistazo!',
   linkPreview: {
      'matched-text': urlA,
      title: '🌱 baileys-next',
      description: 'Librería de WhatsApp reimaginada',
      previewType: 0, 
      jpegThumbnail: fs.readFileSync('./path/to/image.jpg')
   }
})

🔔 Menciones

// --- Mencionar a alguien específico
await bot.socket?.sendMessage(jid, {
   text: '👋🏻 Hola @628123456789',
   mentions: ['[email protected]']
})

// --- Mencionar a todos
await bot.socket?.sendMessage(jid, {
   text: '👋🏻 Hola @all',
   mentionAll: true
})

😁 Reacciones

// O puedes usar ctx.react('✨')
await bot.socket?.sendMessage(jid, {
   react: {
      key: message.key,
      text: '✨'
   }
})

📌 Fijar Mensajes

await bot.socket?.sendMessage(jid, {
   pin: message.key,
   time: 86400, // Segundos: 86400 (1d), 604800 (7d), 2592000 (30d)
   type: 1 // 1 para fijar, 2 para quitar
})

➡️ Reenviar

await bot.socket?.sendMessage(jid, {
   forward: message,
   force: true 
})

👤 Contactos (VCard)

const vcard = 'BEGIN:VCARD\n'
            + 'VERSION:3.0\n'
            + 'FN:Lia Wynn\n'
            + 'TEL;type=CELL;type=VOICE;waid=628123456789:+62 8123 4567 89\n'
            + 'END:VCARD'

await bot.socket?.sendMessage(jid, {
   contacts: {
      displayName: 'Lia Wynn',
      contacts: [{ vcard }]
   }
})

📍 Ubicación

await bot.socket?.sendMessage(jid, {
   location: {
      degreesLatitude: 24.121231,
      degreesLongitude: 55.1121221,
      name: '👋🏻 ¡Estoy aquí!'
   }
})

📊 Encuestas

await bot.socket?.sendMessage(jid, {
   poll: {
      name: '🔥 Votación',
      values: ['Sí', 'No'],
      selectableCount: 1
   }
})

📁 Multimedia (Imágenes, Videos, Stickers, Audio)

Nota: Puedes pasar un Buffer o la ruta/URL en el campo { url: '...' }.

// --- Imagen
await bot.socket?.sendMessage(jid, {
   image: { url: './path/to/image.jpg' },
   caption: '🔥 Genial'
})

// --- Video (Opcional: gifPlayback para enviarlo como GIF)
await bot.socket?.sendMessage(jid, {
   video: { url: './path/to/video.mp4' },
   gifPlayback: false, 
   caption: '🎥 Mira esto'
})

// --- Sticker (Baileys-next convierte imagen/video a sticker por ti usando MediaManager si usas ctx.replySticker)
await bot.socket?.sendMessage(jid, {
   sticker: { url: './path/to/sticker.webp' }
})

// --- Audio (ptt: true para enviarlo como Nota de Voz)
await bot.socket?.sendMessage(jid, {
   audio: { url: './path/to/audio.mp3' },
   ptt: true 
})

👉🏻 Mensajes Interactivos (Botones, Listas, Carrusel)

// --- Botones (Native Flow)
await bot.socket?.sendMessage(jid, {
   image: { url: './path/to/image.jpg' },
   caption: '👆🏻 ¡Botones con Native Flow!',
   footer: 'Baileys-next',
   buttons: [
      { text: '👋🏻 Calificar', id: '#Rating' }, 
      { 
         text: '📋 Seleccionar', 
         sections: [{
            title: '✨ Opciones',
            rows: [{ title: '🏷️ Cupón', id: '#CouponCode' }]
         }]
      }
   ]
})

🕒 Mensajes Temporales (Efímeros)

await bot.socket?.sendMessage(jid, {
   text: '👁️ Este mensaje desaparecerá pronto',
   ephemeral: true
})

👁️ Ver una Vez (View Once)

await bot.socket?.sendMessage(jid, {
   image: { url: './path/to/image.jpg' },
   caption: '👁️ Solo podrás ver esto una vez',
   viewOnce: true // O viewOnceV2: true
})

✏️ Editar y 🗑️ Eliminar Mensajes

// --- Editar
await bot.socket?.sendMessage(jid, {
   text: '✨ Texto corregido!',
   edit: message.key
})

// --- Eliminar
await bot.socket?.sendMessage(jid, {
   delete: message.key
})

🏷️ Buscar ID de WhatsApp (JID o LID)

// Buscar si un número o LID tiene cuenta de WA
const ids = await bot.socket?.findUserId('[email protected]')
console.log('🏷️ IDs Encontrados:', ids)

👥 Gestión de Grupos y Comunidades

// --- Crear Grupo
const group = await bot.socket?.groupCreate('Mi Grupo', ['[email protected]'])

// --- Agregar, Expulsar, Promover
await bot.socket?.groupParticipantsUpdate(jid, ['[email protected]'], 'add') // 'remove', 'promote', 'demote'

// --- Cambiar Configuración (Sólo Admins hablan)
await bot.socket?.groupSettingUpdate(jid, 'announcement')

👤 Gestión del Perfil del Bot

// --- Cambiar Nombre
await bot.socket?.updateProfileName('Mi Bot')

// --- Cambiar Bio/Estado
await bot.socket?.updateProfileStatus('Disponible')

// --- Cambiar Foto de Perfil
await bot.socket?.updateProfilePicture(bot.socket.user.id, buffer)

⚡ Helpers de Contexto (Novedad v7.0.8)

Para hacer que Baileys-next sea aún más fácil de usar, hemos integrado ayudantes de alto nivel en la clase Context (ctx). Ya no necesitas recordar la estructura interna de Baileys para enviar mensajes interactivos complejos.

1. Mensajes Interactivos (Native Flow / Botones)

bot.command('!opciones', async (ctx) => {
    await ctx.replyButtons(
        { text: 'Elige una opción:', footer: 'Baileys-next' },
        [
            { text: '👋🏻 Saludar', id: '#Saludar' },
            { text: '🌐 Visitar Web', url: 'https://github.com' }
        ]
    )
})

También disponible ctx.sendButtons(...) (sin citar) y ctx.replyInteractive(...) para Carruseles.

2. Edición y Eliminación

bot.command('!magia', async (ctx) => {
    // Si el usuario invoca el comando, puedes borrar su mensaje:
    await ctx.delete()
    
    // O editar un mensaje que tú (el bot) hayas enviado:
    const sent = await ctx.reply('Esperando...')
    // (Luego de un proceso asíncrono largo...)
    // await sent.edit('¡Listo!') // Proximamente en v7.1!
    // Por ahora, ctx.edit() editará el mensaje original si fue enviado por el bot.
})

3. Compartir Contactos (VCard)

bot.command('!contacto', async (ctx) => {
    await ctx.replyContacts([{
        displayName: 'LuferOS',
        vcard: 'BEGIN:VCARD\nVERSION:3.0\nFN:LuferOS\nTEL:+628123456789\nEND:VCARD'
    }])
})

4. Vistas Previas de Enlaces (Link Previews)

bot.command('!repo', async (ctx) => {
    await ctx.replyWithLinkPreview(
        '¡Mira esto!', 
        'https://github.com/LuferOS/Baileys-next', 
        'Baileys-next Repository'
    )
})