-
Detección de admins y resolución de JID/LID 100% nativa — Antes, cada bot tenía que reimplementar a mano la comparación de
jid,@lidy número de teléfono contragroupMetadatapara saber si alguien es admin. Ahora esa lógica vive directamente en el socket:isGroupAdmin(chatId, jid)—true/falsesi ese participante (venga como número o como@lid) es admin o superadmin del grupo.getGroupAdmins(chatId)— lista de admins del grupo, ya resueltos a su jid de número de teléfono real (nunca@lid).resolveParticipantJid(chatIdOrParticipants, jid)— convierte cualquier@lida su número real. Primero busca en los participantes del grupo; si no encuentra coincidencia, usa el mapeo LID↔PN nativo de WhatsApp (signalRepository.lidMapping) en vez de adivinar.groupMetadataCached(chatId)— igual quegroupMetadata, pero con cache de 30s que se invalida solo apenas hay un alta, baja, ascenso o descenso real de participantes (viagroup-participants.update), para no golpear a WhatsApp en cada mensaje.
Esto es lo mismo que antes hacían los bots "a mano" con
groupMetadata+ comparaciones manuales deid/lid/phoneNumber, pero ahora resuelto por la librería, con cache y con el mapeo oficial de WhatsApp como respaldo.
- Botones nativos reales — Se agregaron métodos directos en el socket para enviar botones interactivos de WhatsApp (native flow), reemplazando el viejo formato
buttons: [{text, id}]que ya no renderiza en WhatsApp:sendQuickReplyButtons— Botones de respuesta rápidasendUrlButton— Botón que abre un enlacesendCallButton— Botón para iniciar una llamadasendCopyButton— Botón que copia texto al portapapelessendReminderButton— Botón de recordatoriosendListButton— Menú desplegable con secciones y filassendMixedButtons— Combinación libre de varios tipos en un solo mensaje
- Previsualización automática de links —
sendLinkPreviewy todos los botones de arriba arman solos la tarjeta grande (imagen + título + descripción) de cualquier URL que detecten en el texto, con el mismo motor que usa WhatsApp para los links normales.
- Error en macOS — Se reparó un bug crítico que impedía iniciar sesión correctamente en dispositivos Mac. El proceso de pairing/QR ahora funciona de forma estable en macOS.
ꕤ Esta librería está basada en Baileys. No está afiliada ni aprobada oficialmente por WhatsApp.
@fer2809fl/baileys y su desarrollador no se hacen responsables por el mal uso de esta librería. Úsala de forma responsable — nada de spam ni actividades maliciosas.
Opción 1 — Desde npm (recomendado)
npm install @fer2809fl/baileys
yarn add @fer2809fl/baileysOpción 2 — Desde GitHub directamente
npm install github:Fer2809fl/Baileys
yarn add github:Fer2809fl/BaileysEn tu package.json
{
"dependencies": {
"@fer2809fl/baileys": "^1.9.0"
}
}Repositorio: github.com/Fer2809fl/Baileys Paquete npm: npmjs.com/package/@fer2809fl/baileys
const { makeWASocket, useMultiFileAuthState } = require('@fer2809fl/baileys')
async function startBot() {
const { state, saveCreds } = await useMultiFileAuthState('session-myfer')
const fer = makeWASocket({
auth: state,
printQRInTerminal: true,
generateHighQualityLinkPreview: true // recomendado para que las previews se vean mejor
})
fer.ev.on('connection.update', ({ connection }) => {
if (connection === 'open') console.log('✅ ¡Conectado con éxito!')
if (connection === 'close') console.log('❌ Conexión cerrada, reconectando...')
})
fer.ev.on('messages.upsert', async ({ messages }) => {
const m = messages[0]
if (!m.message) return
await fer.sendMessage(m.key.remoteJid, {
text: '¡Hola! Soy un bot de Fer!'
})
})
fer.ev.on('creds.update', saveCreds)
}
startBot()A diferencia de otras librerías, acá no se importan funciones sueltas: los botones son métodos que ya están directamente en el socket que devuelve makeWASocket. Solo llamalos desde sock (o como hayas nombrado tu conexión, fer en los ejemplos).
Todos aceptan al final un objeto extra opcional (footer, image, video, document, quoted) y uno de options para lo que ya soporta sendMessage normalmente.
await fer.sendQuickReplyButtons(
jid,
'🎮 *MENÚ DE OPCIONES*\n\n¿Qué deseas hacer?',
[
{ id: 'menu', text: '📋 Ver Menú' },
{ id: 'info', text: 'ℹ️ Información' },
{ id: 'owner', text: '👑 Owner' }
]
)Genera solo la tarjeta de previsualización (imagen, título, descripción) del link del botón.
await fer.sendUrlButton(
jid,
'🔗 *ENLACES IMPORTANTES*\n\nVisita nuestro repositorio oficial:',
'🌐 Ver GitHub', // etiqueta del botón
'https://github.com/Fer2809fl/Baileys' // URL de destino
)await fer.sendCallButton(
jid,
'📞 *SOPORTE TÉCNICO*\n\n¿Necesitas ayuda? Llámanos:',
'📞 Llamar Ahora', // etiqueta del botón
'+5214183357841' // número de teléfono
)await fer.sendCopyButton(
jid,
'📋 *CÓDIGO DE INSTALACIÓN*\n\nEjecuta este comando en tu terminal:',
'📋 Copiar Comando', // etiqueta del botón
'npm install asta-bot' // texto que se copiará
)await fer.sendReminderButton(
jid,
'⏰ *RECORDATORIO*\n\nActiva un aviso para no olvidarlo:',
'⏰ Recordarme'
)await fer.sendListButton(
jid,
'📋 *SELECCIONA UNA OPCIÓN*',
'Menú Principal', // título del botón que abre la lista
[
{
title: '📱 COMANDOS BÁSICOS',
rows: [
{ id: '#menu', title: '📋 Menú', description: 'Ver todos los comandos' },
{ id: '#ping', title: '🏓 Ping', description: 'Ver latencia del bot' },
{ id: '#owner', title: '👑 Owner', description: 'Info del creador' }
]
},
{
title: '🎮 COMANDOS DE GRUPO',
rows: [
{ id: '#add', title: '➕ Agregar', description: 'Agregar usuario al grupo' },
{ id: '#kick', title: '👢 Expulsar', description: 'Expulsar usuario del grupo' },
{ id: '#promote', title: '⭐ Promover', description: 'Dar admin a un usuario' }
]
}
]
)Para armar cualquier combinación libre de tipos (o alguno que no tenga método propio) en un solo mensaje.
await fer.sendMixedButtons(
jid,
'🎯 *PANEL DE CONTROL*\n\nSelecciona una acción rápida:',
[
{ name: 'cta_url', params: { display_text: '🌐 GitHub', url: 'https://github.com/Fer2809fl/Baileys', merchant_url: 'https://github.com/Fer2809fl/Baileys' } },
{ name: 'cta_copy', params: { display_text: '📋 Comando Inicio', copy_code: 'npm start' } },
{ name: 'quick_reply', params: { display_text: '📋 Ver Menú', id: 'menu' } }
]
)sendLinkPreview manda solo texto + una tarjeta grande y prolija con la imagen, título y descripción de cualquier URL — igual que un mensaje normal de WhatsApp con link, pero forzando renderLargerThumbnail para que se vea mejor. Sirve para links a fotos, artículos, redes sociales, lo que sea.
await fer.sendLinkPreview(
jid,
'¡Mirá esto! 👀',
'https://github.com/Fer2809fl/Baileys'
)Si el texto ya trae el link adentro, no hace falta pasarlo aparte:
await fer.sendLinkPreview(
jid,
'Repo oficial: https://github.com/Fer2809fl/Baileys'
)Esta misma previsualización se activa automáticamente en sendUrlButton y en cualquier otro botón si el texto trae un link. Para desactivarla en un envío puntual:
await fer.sendUrlButton(jid, texto, '🌐 Ver más', url, { preview: false })// plugins/botones.js
let handler = async (m, { conn, usedPrefix }) => {
if (m.text === `${usedPrefix}boton1`) {
await conn.sendCopyButton(m.chat,
'📋 *CÓDIGO DE INSTALACIÓN*\n\nEjecuta este comando en tu terminal:',
'📋 Copiar Comando',
'npm install asta-bot'
)
}
else if (m.text === `${usedPrefix}boton2`) {
await conn.sendUrlButton(m.chat,
'🔗 *ENLACES IMPORTANTES*\n\nVisita nuestro repositorio oficial:',
'🌐 Ver GitHub',
'https://github.com/Fer2809fl/Baileys'
)
}
else if (m.text === `${usedPrefix}boton3`) {
await conn.sendQuickReplyButtons(m.chat,
'🎮 *MENÚ DE OPCIONES*\n\n¿Qué deseas hacer?',
[
{ id: 'menu', text: '📋 Ver Menú' },
{ id: 'info', text: 'ℹ️ Información' },
{ id: 'owner', text: '👑 Owner' }
]
)
}
else if (m.text === `${usedPrefix}boton4`) {
await conn.sendCallButton(m.chat,
'📞 *SOPORTE TÉCNICO*\n\n¿Necesitas ayuda? Llámanos:',
'📞 Llamar Ahora',
'+5214183357841'
)
}
else if (m.text === `${usedPrefix}boton5`) {
await conn.sendListButton(m.chat,
'📋 *SELECCIONA UNA OPCIÓN*',
'Menú Principal',
[
{
title: '📱 COMANDOS BÁSICOS',
rows: [
{ id: '#menu', title: '📋 Menú', description: 'Ver todos los comandos' },
{ id: '#ping', title: '🏓 Ping', description: 'Ver latencia del bot' }
]
}
]
)
}
else if (m.text === `${usedPrefix}boton6`) {
await conn.sendLinkPreview(m.chat,
'¡Mirá el repo! 👀',
'https://github.com/Fer2809fl/Baileys'
)
}
}
handler.command = ['boton1', 'boton2', 'boton3', 'boton4', 'boton5', 'boton6']
export default handlerNo hace falta comparar jid/@lid/número a mano contra groupMetadata: usá estas funciones directo desde el socket.
// ¿Es admin del grupo? (acepta jid normal o @lid, resuelve solo)
const esAdmin = await fer.isGroupAdmin(m.chat, m.sender)
// Lista de admins ya resueltos a número (nunca @lid)
const admins = await fer.getGroupAdmins(m.chat)
// [{ jid: '521418xxxxxxx@s.whatsapp.net', admin: 'superadmin' }, ...]
// Resolver un @lid puntual (mención, quoted, etc.) a su número real
const numeroReal = await fer.resolveParticipantJid(m.chat, mentionedJid)
// groupMetadata con cache de 30s (se invalida solo con altas/bajas/promociones reales)
const meta = await fer.groupMetadataCached(m.chat)// plugins/admin-only.js
let handler = async (m, { conn }) => {
if (!(await conn.isGroupAdmin(m.chat, m.sender))) {
return conn.sendMessage(m.chat, { text: '🔒 Solo admins pueden usar este comando.' })
}
// ...
}
handler.command = ['ejemplo']
export default handler- 🚀 Optimizado para mayor velocidad y estabilidad
- 📸 Mensajes multimedia (imágenes, video, audio, documentos)
- 🔘 Botones nativos reales, sin imports sueltos (v1.9.0)
- 🖼️ Previsualización automática de links en botones y mensajes (v1.9.0)
- 👥 Soporte para grupos y chats privados
- ⚡ Sin Selenium — Conexión directa vía WebSocket
- 💾 Super eficiente — Bajo consumo de RAM
- 📱 Soporte multi-dispositivo — Compatible con WhatsApp Web
- 🔷 Totalmente tipado — TypeScript y JavaScript
- 🔄 Reconexión automática ante desconexiones
- 🔐 Sesiones persistentes guardadas localmente
- 🍎 Compatible con macOS
- Repositorio: https://github.com/Fer2809fl/Baileys
- Paquete npm: https://www.npmjs.com/package/@fer2809fl/baileys
