WebSocket with auto-reconnection — a drop-in replacement for the standard WebSocket.
npm i @nktkas/rews
pnpm add @nktkas/rews
yarn add @nktkas/rews
deno add jsr:@nktkas/rews
Simply replace WebSocket with ReconnectingWebSocket:
import { ReconnectingWebSocket } from "@nktkas/rews";
// const ws = new WebSocket("wss://...");
const ws = new ReconnectingWebSocket("wss://...", {
// optional reconnection options
});
ws.addEventListener("message", (e) => console.log(e.data));
ws.send("data");interface ReconnectingWebSocketOptions {
/**
* Custom WebSocket constructor.
* @default globalThis.WebSocket
*/
WebSocket?: new (url: string | URL, protocols?: string | string[]) => WebSocket;
/**
* Maximum number of reconnection attempts.
* @default 3
*/
maxRetries?: number;
/**
* Maximum time in ms to wait for a connection to open.
* Set to `null` to disable.
* @default 10_000
*/
connectionTimeout?: number | null;
/**
* Delay before reconnection in ms.
* May be a number or a function that returns a number.
* @param attempt - The current attempt number.
* @default (attempt) => Math.min(~~(1 << attempt) * 150, 10_000); // Exponential backoff (max 10s)
*/
reconnectionDelay?: number | ((attempt: number) => number);
}ReconnectingWebSocket will automatically attempt to reconnect when the connection is lost, up to a configurable number
of retries.
Messages sent while the connection is closed are buffered and sent once the connection is re-established.
All event listeners added to the ReconnectingWebSocket instance are preserved across reconnections.
The url and protocols parameters accept functions that return their respective values. These functions are invoked
on each reconnection attempt, enabling dynamic endpoint resolution or authentication token refresh.
const ws = new ReconnectingWebSocket(
() => `wss://example.com?token=${getAuthToken()}`,
() => ["protocol-v1"],
);The terminate event fires when the WebSocket permanently closes.
Error Codes:
RECONNECTION_LIMIT- Maximum reconnection attempts reachedTERMINATED_BY_USER- Closed viaclose()methodUNKNOWN_ERROR- An unknown error occurred during reconnection
Usage:
ws.addEventListener("terminate", (event) => {
const error = event.detail; // ReconnectingWebSocketError
console.log(error.code); // Error code
console.log(error.cause); // Original error if available
});
// Check termination status manually
if (ws.isTerminated) {
const error = ws.terminationReason!; // ReconnectingWebSocketError
console.log(error.code); // Error code
console.log(error.cause); // Original error if available
}Before:
// Requires manual reconnection logic, listener re-attachment, and message buffering
let ws: WebSocket;
let attempts = 0;
const messageHandler = (e) => console.log(e.data);
const messageQueue: string[] = [];
function connect() {
ws = new WebSocket("wss://example.com");
// Re-attach listener on each reconnection
ws.addEventListener("message", messageHandler);
ws.onopen = () => {
attempts = 0;
// Send queued messages
while (messageQueue.length > 0) {
ws.send(messageQueue.shift()!);
}
};
ws.onclose = () => {
// Attempt reconnection
if (attempts++ < 3) {
setTimeout(connect, 1000);
}
};
ws.onerror = () => {
ws.close();
};
}
function send(data: string) {
if (ws.readyState === WebSocket.OPEN) {
ws.send(data);
} else {
messageQueue.push(data); // Buffer message if not connected
}
}
connect();
send("data");After:
// Original WebSocket API remains unchanged despite reconnection logic
const ws = new ReconnectingWebSocket("wss://example.com");
ws.addEventListener("message", (e) => console.log(e.data)); // listener persists across reconnections
ws.send("data"); // buffered if disconnected