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
tcTokensentrantes 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.
- Mitigado el Error 463 (Reachout Timelock) guardando correctamente los
Tabla de Contenidos
- Por que Baileys-next
- Antes vs Ahora (Comparaciones)
- Arquitectura
- Instalacion
- Guia Rapida
- Referencia de la API
- Middlewares
- Persistencia SQLite
- Rate Limiter y Anti-Ban
- Analiticas y Fantasmas
- Multimedia (Stickers y Notas de Voz)
- Sesiones Persistentes
- Acceso a Bajo Nivel
- Evitar Problemas Comunes
- Migracion desde Baileys Original
- Contribuir
- Creditos y Reconocimientos
- Aviso Legal
🚀 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"]
endTablas 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-nextPaso 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.socketsigue exponiendo todas las funciones originales de Baileys.
🤝 Contribuir
Setup
git clone https://github.com/LuferOS/Baileys-next.git
cd Baileys-next
corepack enable
yarn installEstructura 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 principalValidacion
yarn lint # TypeScript + ESLint (0 errores)
yarn test # Tests unitarios
yarn build # Compilacion limpiaCommits
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 objetoctxdentro 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
Buffero 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'
)
})