A robust, TypeScript-first WebSocket client with automatic reconnection, exponential backoff, and comprehensive event handling.
npm install @iam4x/reconnecting-websocketA robust, TypeScript-first WebSocket client with automatic reconnection, exponential backoff, and comprehensive event handling.
- ✅ Automatic Reconnection - Automatically reconnects on connection loss with exponential backoff
- ✅ Message Queueing - Messages sent while disconnected are queued and delivered on reconnection
- ✅ Connection Timeout - Configurable timeout to detect stalled connections
- ✅ Inactivity Detection - Optionally reconnect when no messages are received within a timeout
- ✅ Event-Driven API - Familiar event listener pattern matching WebSocket API
- ✅ TypeScript Support - Full TypeScript definitions included
- ✅ Customizable - Configurable retry delays, backoff factors, and WebSocket implementations
- ✅ Reconnect Events - Separate reconnect event for tracking reconnection attempts
- ✅ Memory Safe - Proper cleanup of timers and event listeners
``bash`
bun add @iam4x/reconnecting-websocket
or
`bash`
npm install @iam4x/reconnecting-websocket
`typescript
import { ReconnectingWebSocket } from "@iam4x/reconnecting-websocket";
const ws = new ReconnectingWebSocket("wss://echo.websocket.org");
ws.addEventListener("open", () => {
console.log("Connected!");
ws.send("Hello, Server!");
});
ws.addEventListener("message", (event: MessageEvent) => {
console.log("Received:", event.data);
});
ws.addEventListener("close", (event) => {
console.log("Connection closed:", event.code, event.reason);
});
ws.addEventListener("reconnect", () => {
console.log("Reconnected successfully!");
});
ws.addEventListener("error", (event: Event) => {
console.error("WebSocket error:", event);
});
`
`typescript`
new ReconnectingWebSocket(url: string, options?: ReconnectOptions)
Creates a new ReconnectingWebSocket instance and immediately attempts to connect.
#### Parameters
- url (string): The WebSocket server URL (e.g., "wss://example.com")options
- (ReconnectOptions, optional): Configuration options (see below)
`typescript`
interface ReconnectOptions {
retryDelay?: number; // Initial retry delay in ms (default: 1000)
maxRetryDelay?: number; // Maximum retry delay in ms (default: 30000)
connectionTimeout?: number; // Connection timeout in ms (default: 10000)
backoffFactor?: number; // Exponential backoff multiplier (default: 2)
healthCheckInterval?: number; // Health check interval in ms (default: 30000)
watchingInactivityTimeout?: number; // Inactivity timeout in ms (default: 0, disabled)
WebSocketConstructor?: typeof WebSocket; // Custom WebSocket implementation
}
#### Option Details
- retryDelay: The initial delay before the first reconnection attempt (in milliseconds)
- maxRetryDelay: The maximum delay between reconnection attempts. The delay will grow exponentially but won't exceed this value
- connectionTimeout: If a connection doesn't establish within this time, it will be aborted and retried
- backoffFactor: The multiplier for exponential backoff. Each retry delay is multiplied by this factor
- healthCheckInterval: Interval for checking if the socket is still healthy. Set to 0 to disable (default: 30000ms)0
- watchingInactivityTimeout: If no message is received within this timeout, the connection will be closed and a reconnection attempt will be made. Useful for detecting silent connection failures or keeping connections alive on servers that expect regular activity. Set to to disable (default: 0, disabled). A common value is 300000 (5 minutes)ws
- WebSocketConstructor: Allows you to provide a custom WebSocket implementation (useful for Node.js environments using libraries like )
#### addEventListener(event, listener)
Adds an event listener to the socket.
`typescript`
ws.addEventListener("open", (event: Event) => {
// Handle open event
});
Events:
- "open" - Emitted when connection is established"message"
- - Emitted when a message is received (payload: MessageEvent)"close"
- - Emitted when connection closes (payload: { code: number, reason: string })"reconnect"
- - Emitted when successfully reconnected after a disconnection"error"
- - Emitted when an error occurs (payload: Event)
#### removeEventListener(event, listener)
Removes an event listener from the socket.
`typescript`
const handler = (event: Event) => console.log("Connected");
ws.addEventListener("open", handler);
ws.removeEventListener("open", handler);
#### send(data)
Sends data through the WebSocket connection. If the socket is not open, messages are automatically queued and sent once the connection is established.
`typescript`
ws.send("Hello, Server!");
ws.send(JSON.stringify({ type: "ping" }));
Note: Messages sent while disconnected are queued and delivered in order when the socket opens. The queue is cleared if close() is called.
#### close(code?, reason?)
Closes the WebSocket connection and prevents automatic reconnection.
`typescript`
ws.close(); // Close with default code
ws.close(1000, "Normal closure"); // Close with code and reason
After calling close(), the socket will not automatically reconnect. Create a new instance to reconnect.
#### readyState
Returns the current ready state of the WebSocket connection.
`typescript`
if (ws.readyState === WebSocket.OPEN) {
ws.send("Data");
}
Values:
- WebSocket.CONNECTING (0) - Connection is being establishedWebSocket.OPEN
- (1) - Connection is open and readyWebSocket.CLOSED
- (3) - Connection is closed
#### bufferedAmount
Returns the number of bytes of data that have been queued using send() but not yet transmitted.
`typescript`
if (ws.bufferedAmount === 0) {
ws.send("Large message");
}
Note: Returns 0 if the socket is not connected.
`typescript`
const ws = new ReconnectingWebSocket("wss://api.example.com", {
retryDelay: 500, // Start with 500ms delay
maxRetryDelay: 60000, // Cap at 60 seconds
backoffFactor: 1.5, // Gentle backoff
connectionTimeout: 5000 // 5 second timeout
});
Use watchingInactivityTimeout to automatically reconnect when no messages are received for a period of time. This is useful for detecting silent connection failures or when the server expects regular activity:
`typescript
const ws = new ReconnectingWebSocket("wss://api.example.com", {
watchingInactivityTimeout: 300000, // Reconnect if no message received for 5 minutes
});
ws.addEventListener("message", (event: MessageEvent) => {
// Each message received resets the inactivity timer
console.log("Received:", event.data);
});
ws.addEventListener("close", (event) => {
// This will fire when inactivity timeout triggers a reconnect
console.log("Connection closed:", event.code, event.reason);
});
`
`typescript
import WebSocket from "ws";
import { ReconnectingWebSocket } from "@iam4x/reconnecting-websocket";
const ws = new ReconnectingWebSocket("wss://api.example.com", {
WebSocketConstructor: WebSocket as any,
});
`
Messages sent while disconnected are automatically queued and delivered when the connection is restored:
`typescript
const ws = new ReconnectingWebSocket("wss://api.example.com");
ws.addEventListener("reconnect", () => {
console.log("Reconnected! Resuming operations...");
});
// Safe to call anytime - messages are queued if disconnected
ws.send("message1");
ws.send("message2");
// When socket opens/reconnects, queued messages are sent automatically
`
Note: Calling close() clears the message queue. Messages queued before a forced close are discarded.
`typescript
ws.addEventListener("error", (event: Event) => {
console.error("WebSocket error occurred:", event);
// Error events typically precede close events
// The socket will automatically attempt to reconnect
});
ws.addEventListener("close", (event) => {
if (event.code !== 1000) {
console.warn("Connection closed unexpectedly:", event.code, event.reason);
}
});
`
`typescript
const ws = new ReconnectingWebSocket("wss://api.example.com");
// Later, close the connection
ws.close();
// To reconnect, create a new instance
const ws2 = new ReconnectingWebSocket("wss://api.example.com");
`
The library uses exponential backoff for reconnection attempts:
1. First retry: After retryDelay millisecondsretryDelay * backoffFactor
2. Second retry: After millisecondsretryDelay * backoffFactor²
3. Third retry: After millisecondsmaxRetryDelay
4. And so on... up to
Example with defaults (retryDelay: 1000, backoffFactor: 2, maxRetryDelay: 30000):
- Attempt 1: Wait 1 second
- Attempt 2: Wait 2 seconds
- Attempt 3: Wait 4 seconds
- Attempt 4: Wait 8 seconds
- Attempt 5: Wait 16 seconds
- Attempt 6+: Wait 30 seconds (max)
Full TypeScript definitions are included. The library is written in TypeScript and exports all necessary types.
`typescript``
import type { ReconnectingWebSocket } from "@iam4x/reconnecting-websocket";
MIT
Contributions are welcome! Please feel free to submit a Pull Request.