Skip to main content
zapo is organized around a thin client that delegates every feature to a focused coordinator. The client owns the connection, authentication, and event emitter; coordinators own the domain logic.

The client

WaClient is the single entry point. You construct it with options and an optional logger, then call connect():
The client itself exposes only a small surface: connection lifecycle (connect, disconnect, logout), state queries (getState, getCredentials), and the typed event emitter (on, once, off). Everything else lives behind a coordinator getter.

Coordinators

Each coordinator is reached through a getter on the client. They are lazily wired at construction and are safe to hold references to. Because the coordinator types are exported from the package root, you can annotate them in TypeScript:

Data flow

  • Incoming: frames are decoded into binary nodes, parsed and normalized into typed event payloads, then emitted (message, receipt, group, …).
  • Outgoing: your call to a coordinator (e.g. client.message.send) is built into a protocol node, encrypted, and written to the socket; the coordinator resolves once the server acks.

Engineering conventions

If you read the source, these conventions are pervasive and explain a lot of the API shape:
  • Uint8Array everywhere for binary data (Buffer is avoided), with zero-copy views in hot paths.
  • Named exports only — there are no default exports.
  • No enums — constants use Object.freeze({ ... } as const), surfaced as the WA_* objects.
  • Bounded in-memory structures to prevent unbounded growth in long-lived processes.

Next

Authentication

Pairing with QR or an 8-character code, and credential lifecycle.

Events

The full event map and how to listen.

Stores

Providers, domains, and backends.

Configuration

Every WaClientOptions field explained.
Last modified on May 28, 2026