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():
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:Uint8Arrayeverywhere for binary data (Bufferis 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 theWA_*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.