Skip to content

Running WaSP in production — we have ~15 upstreamable commits, how would you like them? #8

Description

@Daggle24

Hi Kobus,

We build Biznder, an AI-agents platform for local businesses, and WhatsApp is our main customer channel. A few weeks ago we replaced the session engine of our multi-tenant WhatsApp sidecar with WaSP — the layered credential storage and the anti-ban queue were exactly the pieces we didn't want to keep hand-rolling on top of raw Baileys. It now runs behind a contract-test suite that drives both our old engine and WaSP through the same scenarios, so WaSP's provider got exercised pretty hard in the process.

Along the way we accumulated a fork with ~15 commits we believe belong upstream: Biznder/wasp#feat/biznder-ports. Every commit is self-contained, in your code style, with vitest coverage. Rather than carpet-bombing you with PRs, here's the inventory — tell us what you want and in what shape, and we'll feed them in whatever granularity works for you:

Fixes

  • main currently doesn't compile (phantom re-exports in index.ts) and CI has been red since June — just opened fix: repair the build, make lint pass, de-flake CI #7 alongside this issue, it also fixes the 3 lint errors and a flaky uptime assertion.
  • Layered auth can't read (or write) Baileys' on-disk state: JSON.stringify applies Buffer#toJSON before a v instanceof Buffer replacer ever runs, so credentials round-trip as number arrays Baileys' reviver doesn't decode → selectBestCreds scores them invalid → silent re-pair of every migrated session. Plus the Postgres layer queries tables no code creates, and signal-key filenames aren't sanitized the way Baileys does it. Three commits, backward-compatible with the old encoding.
  • disconnect() leaves the WebSocket (and its keepalive) alive when logout() rejects — the common case, since you usually disconnect because the network is bad.
  • Media messages with no caption travel with caption: "" attached.
  • Reaction messages are silently dropped by the normalizer (no raw-message either).

Features

  • LID identity resolution: formatJid() always addresses <digits>@s.whatsapp.net, which WhatsApp answers with ack 463 for LID-only contacts and which forks the conversation in two. We route outbound sends through signalRepository.lidMapping, return the actually-addressed JID as Message.resolvedJid, and expose getPNForLID()/getLIDForPN() for raw-message consumers. Complements the TC-token work (which expects LIDs anyway).
  • Pairing-code linking mode ("link with phone number") with rotation + a 15s cooldown — currently WaSP is QR-only.
  • close() — stop a session without unlinking the device. Right now the only teardown is disconnect() → logout(), so a rolling deploy or a graceful SIGTERM unlinks every session from its phone.
  • QR TTL metadata (60s first QR, 20s refreshes) so consumers can render an accurate expiry countdown.
  • Opt-in bound on reconnects for sessions that never connected — dead creds looping forever is a reconnect storm WhatsApp punishes.
  • Testability seams: socketFactory, authStateFactory and a version option — this is what let us write 60+ provider tests with a hand-driven fake instead of module mocks; the fake ships with the first feature PR.

We use all of this in production, and we're happy to keep maintaining what lands (Discord too, if that's easier for coordination).

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions