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

lidsync

v5.0.3

Published

LID → JID Identity Resolver para Baileys. Cache LRU, índice invertido, resolución batch y auto-aprendizaje desde eventos.

Downloads

419

Readme


🔧 LidSync v5.0.2 — Parche de estabilidad

Esta actualización no añade características nuevas: corrige bugs de fondo que en la v5.0.0 causaban comportamientos silenciosos en producción. Métodos que existían en la API pública pero no estaban implementados, listeners que se quedaban vivos tras un destroy(), y un intervalo de limpieza que impedía que Node.js cerrara el proceso limpiamente.

¿Vienes de la v5.0.0? El API es 100% compatible. Solo actualiza la dependencia y opcionalmente adopta syncStore().


¿Qué es LidSync?

WhatsApp introdujo los LIDs (170360431460562@lid) como identificadores de privacidad que ocultan el número real del usuario. LidSync resuelve esos LIDs a JIDs reales ([email protected]) mediante un sistema de tres capas:

170360431460562@lid  →  [email protected]

🆕 ¿Qué se corrigió en la v5.0.2?

| Problema en v5.0.0 | Corrección en v5.0.2 | |---|---| | resolveBatch caía a loop secuencial | Concurrencia real controlada implementada | | preload() llamaba a método inexistente | precargarCache() implementado y funcional | | getStats() devolvía {} siempre | Métricas reales de caché e índice | | has() no existía en LidCache → error en runtime | Implementado | | destroy() dejaba el listener messages.upsert vivo | Los 3 listeners se remueven correctamente | | Limpieza de índice se ejecutaba después de insertar | Se ejecuta antes de insertar | | .unref() ausente → proceso zombi en Node.js | Restaurado en el intervalo de limpieza | | catch vacíos → errores desaparecían sin traza | console.warn en todos los casos | | sincronizarDesdeStore() solo era interno | syncStore() expuesto en la API pública |


🧠 Jerarquía de Resolución

LidSync utiliza una estrategia de tres capas para garantizar que el Owner y los usuarios siempre sean reconocidos:

| Nivel | Fuente | Lógica | |---|---|---| | 1 | Cache Dinámico | Persistencia de 24h con refresco automático (LRU). | | 2 | Índice Invertido | Map en memoria LID → JID, O(1). Se promueve al caché en cada consulta. | | 3 | Store & Signal | Fallback a la base de datos local y al repositorio interno de Baileys. |


⚠️ El problema de los LIDs opacos

Un LID solo puede resolverse si el usuario ya interactuó con el bot o está en la agenda del número vinculado.

Esto es una restricción de WhatsApp, no de LidSync. La librería soluciona esto detectando automáticamente el JID real cuando el usuario envía:

  • ❌ Eventos de bienvenida con LID puro → no resoluble hasta primera interacción
  • ✅ Un mensaje de texto
  • ✅ Un Sticker o Audio
  • ✅ Una Reacción (Emoji)

📦 Instalación

# En tu package.json
"npm i lidsync"
npm install

🛠️ Vinculación correcta

Para que LidSync funcione es imprescindible que el socket, el store y los eventos estén vinculados entre sí. Esta configuración va en tu archivo principal de conexión (connection.js o index.js), justo después de inicializar el socket y antes de empezar a escuchar mensajes.

import { makeWASocket, makeInMemoryStore } from "@whiskeysockets/baileys";
import { pluginLid } from "lidsync";

const store = makeInMemoryStore({});

async function connect() {
    let sock = makeWASocket({ /* tu config */ });

    // 1. Inyectar LidSync — pasar el store para que aprenda de tus contactos
    sock = pluginLid(sock, { store });

    // 2. Vincular el store a los eventos del socket
    store.bind(sock.ev);

    // 3. OPCIONAL: Si tu store carga desde un JSON, forzar sincronización
    //    una vez que la conexión ya esté abierta
    sock.ev.on('connection.update', (update) => {
        if (update.connection === 'open') {
            sock.lid.syncStore();
        }
    });

    return sock;
}

Nota: pluginLid debe llamarse antes de store.bind() para que el resolver ya esté suscrito cuando lleguen los primeros eventos de contactos.


🚀 Inicio Rápido

import { connectToWhatsApp } from './connection.js';
import { loadEvents } from './loader.js';
import { pluginLid } from 'lidsync';
import { makeInMemoryStore } from '@whiskeysockets/baileys';

const store = makeInMemoryStore({});

async function start() {
    let sock = await connectToWhatsApp();

    sock = pluginLid(sock, { store });
    store.bind(sock.ev);

    // sock.lid ya está disponible en todo el bot
    await loadEvents(sock);
}

start();

Resolución en mensajes

sock.ev.on('messages.upsert', async ({ messages }) => {
    const m = messages[0];
    if (!m.message || m.key.fromMe) return;

    const sender = m.key.participant || m.key.remoteJid;

    // resolve() devuelve el JID real o null si no es resoluble aún
    const realJid = await sock.lid.resolve(sender);
    console.log(`Mensaje de: ${realJid ?? sender}`);
});

🔎 API

sock.lid.resolve(id)

Resuelve un LID a su JID real. Si el input ya es un JID (@s.whatsapp.net), lo devuelve directamente normalizado. Normaliza sufijos de dispositivo (:1, :2) automáticamente.

const jid = await sock.lid.resolve('170360431460562@lid');
// → '[email protected]' | null

Retorna: string | null

  • string — JID limpio, sin sufijos de dispositivo (:0, :1)
  • null — LID no resoluble (usuario sin interacción previa)

sock.lid.resolveBatch(ids, opciones?)

Resuelve múltiples LIDs con concurrencia controlada. Los que ya están en caché se resuelven de inmediato sin consultas adicionales.

const ids = ['id1@lid', 'id2@lid', 'id3@lid'];

const resultados = await sock.lid.resolveBatch(ids, { concurrency: 5 });

for (const [lid, jid] of resultados) {
    console.log(`${lid} → ${jid}`);
}

Retorna: Map<string, string> — solo incluye los LIDs que pudieron resolverse.


sock.lid.syncStore(forzar?)

Sincroniza manualmente el índice desde el store. Útil cuando el store carga sus datos desde un archivo JSON después de que pluginLid fue inicializado.

// Sincronización normal (solo si no se ha hecho antes)
sock.lid.syncStore();

// Forzar re-sincronización aunque ya se haya hecho antes
sock.lid.syncStore(true);

sock.lid.isResolvable(id)

Verifica si un LID tiene mapeo conocido en el índice o caché sin hacer consultas de red.

if (sock.lid.isResolvable('170360431460562@lid')) {
    // Resolución inmediata garantizada
    const jid = await sock.lid.resolve('170360431460562@lid');
}

Retorna: boolean


sock.lid.preload(pares)

Pre-carga mapeos conocidos (por ejemplo, desde tu base de datos) al caché e índice en memoria.

// Acepta Array de tuplas o Map
sock.lid.preload([
    ['123456789@lid', '[email protected]'],
    ['987654321@lid', '[email protected]']
]);

sock.lid.getStats()

Devuelve estadísticas reales del caché LRU e índice invertido.

const stats = sock.lid.getStats();
console.log(stats);
/*
{
    cache: {
        size: 1250,
        maxSize: 7500,
        hits: 4821,
        misses: 302,
        evictions: 0,
        expirations: 14,
        hitRate: "94.10%",
        memoryEstimate: "305.18 KB"
    },
    index: {
        size: 1250,
        maxSize: 50000
    },
    sincronizado: true
}
*/

sock.lid.destroy()

Limpia el caché, vacía el índice y remueve los 3 listeners del socket. Llamar siempre antes de una reconexión para evitar listeners duplicados.

// En tu lógica de reconexión:
sock.lid.destroy();
sock = await reconnect();
sock = pluginLid(sock, { store });

📊 Monitoreo y Limpieza

LidSync gestiona la memoria de forma automática. Verás estos mensajes en consola cuando el sistema realice mantenimiento preventivo:

[LidSync] Limpieza: 14 entradas caducadas eliminadas.

Esto ocurre automáticamente cuando el caché supera el 85% de su capacidad. El intervalo usa .unref() para no impedir que Node.js cierre el proceso cuando sea necesario.


⚠️ Importante

La librería aprende de forma pasiva. Cuanto más tiempo esté el bot encendido y más mensajes/contactos reciba, más precisa será la base de datos de identidades. La vinculación correcta del store es lo que permite que el bot no "olvide" a los usuarios tras un reinicio.


🧠 Arquitectura interna

pluginLid(sock, { store })
│
├── LidResolver
│   ├── LidCache (LRU, TTL 24h, máx 7500 entradas)
│   ├── #reverseIndex (Map<LID, JID> — índice O(1), máx 50000)
│   ├── Auto-Aprendizaje (contacts.upsert, contacts.update, messages.upsert)
│   └── sock.signalRepository (Baileys interno — fallback)
│
└── sock.lid
    ├── resolve(id)
    ├── resolveBatch(ids, opts?)
    ├── syncStore(forzar?)
    ├── isResolvable(id)
    ├── preload(pares)
    ├── getStats()
    └── destroy()

Normalización automática: todos los JIDs que salen de LidSync están limpios de sufijos de dispositivo.

// Entrada interna:  521234567890:[email protected]
// Salida garantizada: [email protected]

⚙️ Compatibilidad

  • Baileys: @whiskeysockets/baileys >=6.7.0
  • Node.js: 18 o superior
  • Entornos: Termux, Render, Pterodactyl / Pelican

🧪 Bot de prueba

Repositorio de referencia con implementación completa:

🔗 LidSync-CoreBot


👨‍💻 Creador


🤝 Agradecimientos