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

nexawhats

v0.2.0

Published

Production-grade WhatsApp Web API for Node.js

Readme

NexaWhats

CI npm License TypeScript Node.js

Production-grade WhatsApp Web API for Node.js

NexaWhats is a complete rewrite of the WhatsApp Web API layer, built on top of battle-tested protocol code. It fixes the critical production issues in existing libraries while providing a modern, type-safe, and extensible API.

Status — v0.1.0 (alpha)

This release ships the infrastructure layer end-to-end, with the live protocol layer still in active development. You can use it today for:

  • Pluggable auth storageSQLiteAuthStore, FileAuthStore, MemoryAuthStore with atomic writes and a one-call migrateFromBaileys() utility.
  • Binary codec — full WhatsApp binary-XML encode/decode with token compression, JID packing, nibble/hex string encoding (188 tests).
  • Connection primitives — state machine + circuit breaker + retry helpers (Phase 2, fully tested).
  • Message queue — token-bucket rate limiter, priority queue, dead-letter queue, human-like timing (Phase 4).
  • Middleware pipeline — Koa-style use(), LID resolver, anti-ban logger (Phase 5).
  • Observability — Prometheus metrics + /health and /metrics endpoints (Phase 7).

Still in progress (0.2.0): full Noise handshake + Signal Protocol integration, sendMessage/recvMessage, group operations. Until those land, client.connect() sets up transport + health server but does not yet establish a live WhatsApp session — treat this release as a drop-in replacement for Baileys' useMultiFileAuthState plus a toolkit of reusable primitives. See examples/migrate-from-baileys/ for the recommended migration path.

Why NexaWhats?

  • Rock-solid connections — State machine + circuit breaker handles every WhatsApp disconnect (401/403/405/463/515) automatically
  • Production-ready auth — Pluggable stores (SQLite, Memory, File) with atomic writes. No more JSON file corruption.
  • Built-in rate limiting — Token bucket queue with human-like timing. Never get banned for sending too fast.
  • Middleware pipeline — Koa-style use() for message processing, LID resolution, logging, and anti-ban
  • Full type safety — Discriminated unions for message types, typed events, zero any in the public API

Quick Start

import { createClient, MemoryAuthStore } from 'nexawhats';

const store = new MemoryAuthStore();
const state = await store.loadState();

const client = createClient({
  auth: state ?? { creds: {}, keys: store },
  queue: { messagesPerMinute: 20, humanLikeTiming: true },
});

// Middleware
client.use(async (ctx, next) => {
  console.log(`Message from ${ctx.senderName}: ${ctx.text}`);
  await next();
});

// Event handling
client.on('messages.upsert', async ({ messages, type }) => {
  if (type !== 'notify') return;
  for (const msg of messages) {
    if (msg.key.fromMe) continue;
    await client.send(msg.key.remoteJid!, { text: 'Hello from NexaWhats!' });
  }
});

await client.connect();

Installation

npm install nexawhats
# or
pnpm add nexawhats
# or
yarn add nexawhats

For SQLite auth store (recommended for production):

npm install better-sqlite3

Features

Connection Management

  • Connection state machine (disconnected / connecting / connected / reconnecting)
  • Circuit breaker with auto-recovery (trips on rate limits, resets on success)
  • Exponential backoff with configurable delays
  • Auto version negotiation (fetches latest WhatsApp Web version)

Authentication

  • SQLiteAuthStore — Production default. Atomic writes, WAL mode, crash-safe.
  • MemoryAuthStore — For testing. No persistence.
  • FileAuthStore — Baileys-compatible. Same file format for easy migration.
  • Cacheable Signal key store with bounded LRU cache

Message Queue

  • Priority levels: urgent > high > normal > low
  • Token bucket rate limiter (default: 20/min)
  • Human-like timing with gaussian jitter
  • Dead-letter queue for permanently failed messages

Middleware

// LID resolver — auto-translates @lid JIDs to phone numbers
import { lidResolver, antiBan, messageLogger } from 'nexawhats';

client.use(lidResolver());
client.use(antiBan({ minDelay: 1000, maxDelay: 3000 }));
client.use(messageLogger());

Message Utilities

import { extractText, isGroupMessage, hasMedia, getMediaType } from 'nexawhats';

const text = extractText(message);        // Handles all text types
const isGroup = isGroupMessage(message);  // true for @g.us
const media = hasMedia(message);          // image/video/audio/doc/sticker

JID Utilities

import { jidDecode, jidEncode, isLidUser, phoneFromJid } from 'nexawhats';

jidDecode('[email protected]');
// { user: '923124166950', server: 's.whatsapp.net' }

isLidUser('197151900590225@lid');  // true
phoneFromJid('[email protected]');  // '923124166950'

Stores

SQLite (Production)

// Coming in v0.2.0
import { SQLiteAuthStore } from 'nexawhats/store';
const store = new SQLiteAuthStore('./nexawhats.db');

Memory (Testing)

import { MemoryAuthStore } from 'nexawhats';
const store = new MemoryAuthStore();

Custom Store

import type { AuthStore } from 'nexawhats';

class MyRedisStore implements AuthStore {
  async loadState() { /* ... */ }
  async saveState(state) { /* ... */ }
  async saveCreds(creds) { /* ... */ }
  async getKeys(type, ids) { /* ... */ }
  async setKeys(data) { /* ... */ }
  async clear() { /* ... */ }
}

Events

| Event | Payload | Description | |-------|---------|-------------| | connection.update | Partial<ConnectionState> | Connection state changed | | creds.update | Partial<AuthenticationCreds> | Credentials updated (save them!) | | messages.upsert | { messages, type } | New messages received | | messages.update | WAMessageUpdate[] | Messages edited/deleted | | messages.reaction | { key, reaction }[] | Reaction added/removed | | groups.upsert | GroupMetadata[] | Joined a new group | | group-participants.update | { id, participants, action } | Member added/removed/promoted | | presence.update | { id, presences } | Typing/online status | | call | WACallEvent[] | Incoming call | | queue.drained | void | Message queue is empty | | queue.dead-letter | { jid, content, error } | Message permanently failed | | circuit-breaker.state-change | { from, to } | Circuit breaker state changed |

Error Handling

NexaWhats uses typed errors with recovery hints:

import { RateLimitError, BannedError, LoggedOutError } from 'nexawhats';

try {
  await client.connect();
} catch (error) {
  if (error instanceof RateLimitError) {
    console.log(`Rate limited — retry in ${error.retryAfterMs}ms`);
  } else if (error instanceof BannedError) {
    console.log('Number is banned by WhatsApp');
  } else if (error instanceof LoggedOutError) {
    console.log('Session expired — delete auth and re-scan QR');
  }
}

Comparison with Baileys

| Feature | Baileys | NexaWhats | |---------|---------|-----------| | Connection handling | Basic reconnect, manual 405 handling | State machine + circuit breaker | | Auth storage | JSON files (not production-ready) | Pluggable: SQLite / Memory / File | | Message sending | Raw sendMessage() | Queue with rate limiting + priority | | LID handling | Inconsistent | Auto-resolution middleware | | Testing | No mock server | Mock transport + fixtures | | Types | Deep optional nesting | Discriminated unions | | Middleware | Flat EventEmitter | Koa-style pipeline | | Anti-ban | Nothing built-in | Human-like timing + warm-up | | Observability | Pino logger only | Prometheus metrics + health endpoint | | Memory | Leaks ~0.1MB/message | Bounded caches + WeakRef | | v7 stability | Stuck in broken RCs | Stable releases |

Troubleshooting

405 Rate Limited NexaWhats handles this automatically via the circuit breaker. If persistent, try a different IP or wait 24-72 hours.

401 Logged Out Delete your auth store and re-authenticate. The LoggedOutError is emitted on connection.update.

Messages not sending Check client.queueDepth — if high, the rate limiter is throttling. Increase messagesPerMinute in config.

LID JID mismatch Use the lidResolver() middleware to automatically translate LID JIDs to phone-number format.

Memory growing Ensure you're not storing all messages in memory. Use the event listeners to process and discard.

Contributing

See CONTRIBUTING.md for development setup and guidelines.

Disclaimer

This project is not affiliated with, authorized by, or endorsed by WhatsApp LLC or Meta Platforms Inc. Using this library may violate WhatsApp's Terms of Service. See DISCLAIMER.md for full details.

For business-critical applications, use the official WhatsApp Business API.

License

Apache-2.0 — includes explicit patent grant for protocol implementations.