@iam4x/reconnecting-websocket 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,280 @@
1
+ # @iam4x/reconnecting-websocket
2
+
3
+ A robust, TypeScript-first WebSocket client with automatic reconnection, exponential backoff, and comprehensive event handling.
4
+
5
+ ## Features
6
+
7
+ - ✅ **Automatic Reconnection** - Automatically reconnects on connection loss with exponential backoff
8
+ - ✅ **Connection Timeout** - Configurable timeout to detect stalled connections
9
+ - ✅ **Event-Driven API** - Familiar event listener pattern matching WebSocket API
10
+ - ✅ **TypeScript Support** - Full TypeScript definitions included
11
+ - ✅ **Customizable** - Configurable retry delays, backoff factors, and WebSocket implementations
12
+ - ✅ **Reconnect Events** - Separate `reconnect` event for tracking reconnection attempts
13
+ - ✅ **Memory Safe** - Proper cleanup of timers and event listeners
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ bun add @iam4x/reconnecting-websocket
19
+ ```
20
+
21
+ or
22
+
23
+ ```bash
24
+ npm install @iam4x/reconnecting-websocket
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ```typescript
30
+ import { ReconnectingWebSocket } from "@iam4x/reconnecting-websocket";
31
+
32
+ const ws = new ReconnectingWebSocket("wss://echo.websocket.org");
33
+
34
+ ws.addEventListener("open", () => {
35
+ console.log("Connected!");
36
+ ws.send("Hello, Server!");
37
+ });
38
+
39
+ ws.addEventListener("message", (event: MessageEvent) => {
40
+ console.log("Received:", event.data);
41
+ });
42
+
43
+ ws.addEventListener("close", (event) => {
44
+ console.log("Connection closed:", event.code, event.reason);
45
+ });
46
+
47
+ ws.addEventListener("reconnect", () => {
48
+ console.log("Reconnected successfully!");
49
+ });
50
+
51
+ ws.addEventListener("error", (event: Event) => {
52
+ console.error("WebSocket error:", event);
53
+ });
54
+ ```
55
+
56
+ ## API Reference
57
+
58
+ ### Constructor
59
+
60
+ ```typescript
61
+ new ReconnectingWebSocket(url: string, options?: ReconnectOptions)
62
+ ```
63
+
64
+ Creates a new `ReconnectingWebSocket` instance and immediately attempts to connect.
65
+
66
+ #### Parameters
67
+
68
+ - `url` (string): The WebSocket server URL (e.g., `"wss://example.com"`)
69
+ - `options` (ReconnectOptions, optional): Configuration options (see below)
70
+
71
+ ### Options
72
+
73
+ ```typescript
74
+ interface ReconnectOptions {
75
+ retryDelay?: number; // Initial retry delay in ms (default: 1000)
76
+ maxRetryDelay?: number; // Maximum retry delay in ms (default: 30000)
77
+ connectionTimeout?: number; // Connection timeout in ms (default: 10000)
78
+ backoffFactor?: number; // Exponential backoff multiplier (default: 2)
79
+ WebSocketConstructor?: typeof WebSocket; // Custom WebSocket implementation
80
+ }
81
+ ```
82
+
83
+ #### Option Details
84
+
85
+ - **retryDelay**: The initial delay before the first reconnection attempt (in milliseconds)
86
+ - **maxRetryDelay**: The maximum delay between reconnection attempts. The delay will grow exponentially but won't exceed this value
87
+ - **connectionTimeout**: If a connection doesn't establish within this time, it will be aborted and retried
88
+ - **backoffFactor**: The multiplier for exponential backoff. Each retry delay is multiplied by this factor
89
+ - **WebSocketConstructor**: Allows you to provide a custom WebSocket implementation (useful for Node.js environments using libraries like `ws`)
90
+
91
+ ### Methods
92
+
93
+ #### `addEventListener(event, listener)`
94
+
95
+ Adds an event listener to the socket.
96
+
97
+ ```typescript
98
+ ws.addEventListener("open", (event: Event) => {
99
+ // Handle open event
100
+ });
101
+ ```
102
+
103
+ **Events:**
104
+ - `"open"` - Emitted when connection is established
105
+ - `"message"` - Emitted when a message is received (payload: `MessageEvent`)
106
+ - `"close"` - Emitted when connection closes (payload: `{ code: number, reason: string }`)
107
+ - `"reconnect"` - Emitted when successfully reconnected after a disconnection
108
+ - `"error"` - Emitted when an error occurs (payload: `Event`)
109
+
110
+ #### `removeEventListener(event, listener)`
111
+
112
+ Removes an event listener from the socket.
113
+
114
+ ```typescript
115
+ const handler = (event: Event) => console.log("Connected");
116
+ ws.addEventListener("open", handler);
117
+ ws.removeEventListener("open", handler);
118
+ ```
119
+
120
+ #### `send(data)`
121
+
122
+ Sends data through the WebSocket connection.
123
+
124
+ ```typescript
125
+ ws.send("Hello, Server!");
126
+ ws.send(JSON.stringify({ type: "ping" }));
127
+ ```
128
+
129
+ **Note:** This method will silently fail if the socket is not connected. Check `readyState` before sending if needed.
130
+
131
+ #### `close(code?, reason?)`
132
+
133
+ Closes the WebSocket connection and prevents automatic reconnection.
134
+
135
+ ```typescript
136
+ ws.close(); // Close with default code
137
+ ws.close(1000, "Normal closure"); // Close with code and reason
138
+ ```
139
+
140
+ After calling `close()`, the socket will not automatically reconnect. Create a new instance to reconnect.
141
+
142
+ ### Properties
143
+
144
+ #### `readyState`
145
+
146
+ Returns the current ready state of the WebSocket connection.
147
+
148
+ ```typescript
149
+ if (ws.readyState === WebSocket.OPEN) {
150
+ ws.send("Data");
151
+ }
152
+ ```
153
+
154
+ **Values:**
155
+ - `WebSocket.CONNECTING` (0) - Connection is being established
156
+ - `WebSocket.OPEN` (1) - Connection is open and ready
157
+ - `WebSocket.CLOSED` (3) - Connection is closed
158
+
159
+ #### `bufferedAmount`
160
+
161
+ Returns the number of bytes of data that have been queued using `send()` but not yet transmitted.
162
+
163
+ ```typescript
164
+ if (ws.bufferedAmount === 0) {
165
+ ws.send("Large message");
166
+ }
167
+ ```
168
+
169
+ **Note:** Returns `0` if the socket is not connected.
170
+
171
+ ## Examples
172
+
173
+ ### Custom Retry Configuration
174
+
175
+ ```typescript
176
+ const ws = new ReconnectingWebSocket("wss://api.example.com", {
177
+ retryDelay: 500, // Start with 500ms delay
178
+ maxRetryDelay: 60000, // Cap at 60 seconds
179
+ backoffFactor: 1.5, // Gentle backoff
180
+ connectionTimeout: 5000 // 5 second timeout
181
+ });
182
+ ```
183
+
184
+ ### Using with Node.js
185
+
186
+ ```typescript
187
+ import WebSocket from "ws";
188
+ import { ReconnectingWebSocket } from "@iam4x/reconnecting-websocket";
189
+
190
+ const ws = new ReconnectingWebSocket("wss://api.example.com", {
191
+ WebSocketConstructor: WebSocket as any,
192
+ });
193
+ ```
194
+
195
+ ### Handling Reconnections
196
+
197
+ ```typescript
198
+ let messageQueue: string[] = [];
199
+
200
+ ws.addEventListener("open", () => {
201
+ // Flush queued messages when reconnected
202
+ while (messageQueue.length > 0) {
203
+ ws.send(messageQueue.shift()!);
204
+ }
205
+ });
206
+
207
+ ws.addEventListener("reconnect", () => {
208
+ console.log("Reconnected! Resuming operations...");
209
+ });
210
+
211
+ // Queue messages when disconnected
212
+ function sendMessage(data: string) {
213
+ if (ws.readyState === WebSocket.OPEN) {
214
+ ws.send(data);
215
+ } else {
216
+ messageQueue.push(data);
217
+ }
218
+ }
219
+ ```
220
+
221
+ ### Error Handling
222
+
223
+ ```typescript
224
+ ws.addEventListener("error", (event: Event) => {
225
+ console.error("WebSocket error occurred:", event);
226
+ // Error events typically precede close events
227
+ // The socket will automatically attempt to reconnect
228
+ });
229
+
230
+ ws.addEventListener("close", (event) => {
231
+ if (event.code !== 1000) {
232
+ console.warn("Connection closed unexpectedly:", event.code, event.reason);
233
+ }
234
+ });
235
+ ```
236
+
237
+ ### Manual Connection Management
238
+
239
+ ```typescript
240
+ const ws = new ReconnectingWebSocket("wss://api.example.com");
241
+
242
+ // Later, close the connection
243
+ ws.close();
244
+
245
+ // To reconnect, create a new instance
246
+ const ws2 = new ReconnectingWebSocket("wss://api.example.com");
247
+ ```
248
+
249
+ ## Reconnection Behavior
250
+
251
+ The library uses exponential backoff for reconnection attempts:
252
+
253
+ 1. **First retry**: After `retryDelay` milliseconds
254
+ 2. **Second retry**: After `retryDelay * backoffFactor` milliseconds
255
+ 3. **Third retry**: After `retryDelay * backoffFactor²` milliseconds
256
+ 4. **And so on...** up to `maxRetryDelay`
257
+
258
+ Example with defaults (`retryDelay: 1000`, `backoffFactor: 2`, `maxRetryDelay: 30000`):
259
+ - Attempt 1: Wait 1 second
260
+ - Attempt 2: Wait 2 seconds
261
+ - Attempt 3: Wait 4 seconds
262
+ - Attempt 4: Wait 8 seconds
263
+ - Attempt 5: Wait 16 seconds
264
+ - Attempt 6+: Wait 30 seconds (max)
265
+
266
+ ## TypeScript Support
267
+
268
+ Full TypeScript definitions are included. The library is written in TypeScript and exports all necessary types.
269
+
270
+ ```typescript
271
+ import type { ReconnectingWebSocket } from "@iam4x/reconnecting-websocket";
272
+ ```
273
+
274
+ ## License
275
+
276
+ MIT
277
+
278
+ ## Contributing
279
+
280
+ Contributions are welcome! Please feel free to submit a Pull Request.
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ console.log("Hello via Bun!");
2
+ export {};
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@iam4x/reconnecting-websocket",
3
+ "module": "src/index.ts",
4
+ "type": "module",
5
+ "license": "MIT",
6
+ "version": "1.0.0",
7
+ "private": false,
8
+ "exports": {
9
+ ".": "./dist/index.js"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "build": "rm -rf dist && tsc -p tsconfig.build.json",
16
+ "test": "bun test",
17
+ "lint": "bun run lint:eslint && bun run lint:tsc",
18
+ "lint:eslint": "eslint src",
19
+ "lint:tsc": "tsc --noEmit",
20
+ "prepare": "husky"
21
+ },
22
+ "devDependencies": {
23
+ "@eslint/js": "^9.38.0",
24
+ "@typescript-eslint/parser": "^8.46.2",
25
+ "eslint": "^9.38.0",
26
+ "eslint-config-prettier": "10.1.1",
27
+ "eslint-import-resolver-typescript": "4.3.1",
28
+ "eslint-plugin-import": "^2.32.0",
29
+ "eslint-plugin-prettier": "^5.5.4",
30
+ "globals": "^16.4.0",
31
+ "husky": "^9.1.7",
32
+ "prettier": "^3.6.2",
33
+ "typescript-eslint": "^8.46.2"
34
+ },
35
+ "peerDependencies": {
36
+ "typescript": "^5.8.3"
37
+ }
38
+ }