Built and signed on GitHub ActionsBuilt and signed on GitHub Actions
WebSocket with auto-reconnection — a drop-in replacement for the standard WebSocket.
@nktkas/rews
WebSocket with auto-reconnection — a drop-in replacement for the standard WebSocket.
Installation
Node.js (choose your package manager)
npm i @nktkas/rews pnpm add @nktkas/rews yarn add @nktkas/rews
Deno
deno add jsr:@nktkas/rews
Usage
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");
Options
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); }
Differences from standard WebSocket
Automatic Reconnection
ReconnectingWebSocket will automatically attempt to reconnect when the connection is lost, up to a configurable number
of retries.
Message Buffering
Messages sent while the connection is closed are buffered and sent once the connection is re-established.
Preserved Event Listeners
All event listeners added to the ReconnectingWebSocket instance are preserved across reconnections.
Dynamic URL and Protocol Providers
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"], );
Terminate Event
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 }
Why Use This
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
Add Package
deno add jsr:@nktkas/rews
Import symbol
import * as rews from "@nktkas/rews";
Import directly with a jsr specifier
import * as rews from "jsr:@nktkas/rews";
Add Package
pnpm i jsr:@nktkas/rews
pnpm dlx jsr add @nktkas/rews
Import symbol
import * as rews from "@nktkas/rews";
Add Package
yarn add jsr:@nktkas/rews
yarn dlx jsr add @nktkas/rews
Import symbol
import * as rews from "@nktkas/rews";
Add Package
vlt install jsr:@nktkas/rews
Import symbol
import * as rews from "@nktkas/rews";
Add Package
npx jsr add @nktkas/rews
Import symbol
import * as rews from "@nktkas/rews";
Add Package
bunx jsr add @nktkas/rews
Import symbol
import * as rews from "@nktkas/rews";