@ferrow/websocket-client
v2.0.0
Published
A reconnecting WebSocket wrapper with exponential backoff + jitter, heartbeat ping/pong, message queueing while disconnected, and an event emitter API. Bring your own WebSocket implementation.
Maintainers
Readme
websocket-client
A reconnecting WebSocket wrapper for TypeScript/JavaScript. Exponential backoff with jitter, heartbeat ping/pong, a bounded message queue for while you're disconnected, and a small event-emitter API — zero runtime dependencies.
It works with any W3C-compatible WebSocket constructor: the browser's
native WebSocket, or Node's ws
package. In Node you must bring your own WebSocket implementation —
this library does not bundle one, on purpose (see Design notes).
Install
npm install websocket-client
# Node also needs a WebSocket implementation, e.g.:

npm install wsQuickstart
Browser:
import { ReconnectingWebSocket } from "websocket-client";
const client = new ReconnectingWebSocket("wss://example.com/socket", {
WebSocket, // the browser's native global
});
client.on("open", () => console.log("connected"));
client.on("message", (ev) => console.log("received:", ev.data));
client.on("reconnect", () => console.log("reconnected after a drop"));
client.on("close", () => console.log("disconnected"));
client.send("hello"); // queued automatically if not yet openNode (using ws):
import { ReconnectingWebSocket } from "websocket-client";
import WebSocket from "ws";
const client = new ReconnectingWebSocket("wss://example.com/socket", {
WebSocket: WebSocket as any,
heartbeatInterval: 30_000,
});API
new ReconnectingWebSocket(url: string, options: ReconnectingWebSocketOptions)
| Option | Default | Description |
|---|---|---|
| WebSocket | required | A WebSocket constructor. |
| protocols | undefined | Passed through to the constructor. |
| minReconnectDelay | 1000 | Base backoff delay (ms). |
| maxReconnectDelay | 30000 | Backoff ceiling (ms). |
| reconnectDecay | 2 | Backoff multiplier per attempt. |
| jitter | 0.5 | Jitter fraction (0–1) randomized into each delay. |
| maxReconnectAttempts | Infinity | Stop retrying after this many attempts. |
| heartbeatInterval | 0 (off) | Interval (ms) between app-level pings. |
| heartbeatTimeout | 5000 | Force-close if no pong arrives within this window. |
| heartbeatMessage | "ping" | Payload sent as the heartbeat. |
| heartbeatPongMessage | "pong" | Payload expected back; matching messages are swallowed, not emitted as message. |
| maxQueueSize | 100 | Oldest queued messages are dropped past this. |
| autoConnect | true | Connect immediately on construction. |
Methods
connect()— (re)establish the connection.send(data)— send now if open, otherwise queue (FIFO, bounded bymaxQueueSize).close(code?, reason?)— close permanently; disables auto-reconnect.on(event, listener)/off(event, listener)readyState— the underlying socket'sreadyState, or-1before first connect.queuedMessageCount— messages currently queued.
Events
open, message, close, reconnect (fires alongside open specifically after a drop), error.
Design notes
The library takes the WebSocket constructor as an injected option instead
of depending on ws directly. That keeps it zero runtime dependencies
and framework-agnostic: it works unmodified in a browser, and in Node it
works with whatever WS client you already have installed (ws,
isomorphic-ws, a mock for tests) without version-pinning someone else's
package for them. The heartbeat is application-level (send/expect a
message) because the WebSocket protocol's native ping/pong frames aren't
exposed consistently across environments — if your server already speaks
protocol-level ping/pong, you can leave heartbeatInterval at 0 and let
the transport handle it.
Sponsored by Ferrow
Part of the ferrow-toolkit collection · Sponsored by Ferrow
