@hardlydifficult/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/dist/ReconnectingWebSocket.d.ts +68 -0
- package/dist/ReconnectingWebSocket.d.ts.map +1 -0
- package/dist/ReconnectingWebSocket.js +220 -0
- package/dist/ReconnectingWebSocket.js.map +1 -0
- package/dist/RequestTracker.d.ts +40 -0
- package/dist/RequestTracker.d.ts.map +1 -0
- package/dist/RequestTracker.js +85 -0
- package/dist/RequestTracker.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +54 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +29 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { BackoffOptions, WebSocketEvents, WebSocketOptions } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Calculate exponential backoff delay for a given attempt number.
|
|
4
|
+
*
|
|
5
|
+
* @param attempt - Zero-based attempt index
|
|
6
|
+
* @param options - Backoff configuration
|
|
7
|
+
* @returns Delay in milliseconds, capped at maxDelayMs
|
|
8
|
+
*/
|
|
9
|
+
export declare function getBackoffDelay(attempt: number, options: Required<BackoffOptions>): number;
|
|
10
|
+
/**
|
|
11
|
+
* A generic WebSocket client that automatically reconnects on disconnection,
|
|
12
|
+
* sends protocol-level pings for heartbeats, and parses JSON messages.
|
|
13
|
+
*
|
|
14
|
+
* @typeParam T - The shape of messages exchanged over the socket (JSON-serializable)
|
|
15
|
+
*/
|
|
16
|
+
export declare class ReconnectingWebSocket<T> {
|
|
17
|
+
private ws;
|
|
18
|
+
private readonly url;
|
|
19
|
+
private readonly backoff;
|
|
20
|
+
private readonly heartbeat;
|
|
21
|
+
private reconnectAttempt;
|
|
22
|
+
private shouldReconnect;
|
|
23
|
+
private heartbeatInterval;
|
|
24
|
+
private heartbeatTimeout;
|
|
25
|
+
private reconnectTimeout;
|
|
26
|
+
private readonly eventListeners;
|
|
27
|
+
constructor(options: WebSocketOptions);
|
|
28
|
+
/**
|
|
29
|
+
* Subscribe to a WebSocket lifecycle event.
|
|
30
|
+
* Multiple listeners per event are supported.
|
|
31
|
+
* Returns an unsubscribe function.
|
|
32
|
+
*/
|
|
33
|
+
on<K extends keyof WebSocketEvents<T>>(event: K, listener: WebSocketEvents<T>[K]): () => void;
|
|
34
|
+
/**
|
|
35
|
+
* Connect to the WebSocket server.
|
|
36
|
+
* Idempotent — no-op if already connected.
|
|
37
|
+
* If a reconnect timer is pending, cancels it and connects immediately,
|
|
38
|
+
* resetting the attempt counter.
|
|
39
|
+
*/
|
|
40
|
+
connect(): void;
|
|
41
|
+
/**
|
|
42
|
+
* Disconnect from the server and stop all reconnection attempts.
|
|
43
|
+
* Closes the socket with code 1000.
|
|
44
|
+
*/
|
|
45
|
+
disconnect(): void;
|
|
46
|
+
/**
|
|
47
|
+
* Send a message as JSON. No-op if not currently connected.
|
|
48
|
+
*/
|
|
49
|
+
send(message: T): void;
|
|
50
|
+
/**
|
|
51
|
+
* Prevent reconnection without closing the current connection.
|
|
52
|
+
* Useful for draining: deliver in-flight results but do not reconnect if the socket drops.
|
|
53
|
+
*/
|
|
54
|
+
stopReconnecting(): void;
|
|
55
|
+
/** Whether the socket is currently open */
|
|
56
|
+
get connected(): boolean;
|
|
57
|
+
private onOpen;
|
|
58
|
+
private onClose;
|
|
59
|
+
private onError;
|
|
60
|
+
private onPong;
|
|
61
|
+
private onMessage;
|
|
62
|
+
private sendHeartbeat;
|
|
63
|
+
private startHeartbeat;
|
|
64
|
+
private stopHeartbeat;
|
|
65
|
+
private scheduleReconnect;
|
|
66
|
+
private emit;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=ReconnectingWebSocket.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReconnectingWebSocket.d.ts","sourceRoot":"","sources":["../src/ReconnectingWebSocket.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,cAAc,EAEd,eAAe,EACf,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAapB;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,QAAQ,CAAC,cAAc,CAAC,GAChC,MAAM,CAGR;AAED;;;;;GAKG;AACH,qBAAa,qBAAqB,CAAC,CAAC;IAClC,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2B;IACnD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6B;IACvD,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,eAAe,CAAQ;IAC/B,OAAO,CAAC,iBAAiB,CAA+C;IACxE,OAAO,CAAC,gBAAgB,CAA8C;IACtE,OAAO,CAAC,gBAAgB,CAA8C;IAEtE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAG3B;gBAEQ,OAAO,EAAE,gBAAgB;IAMrC;;;;OAIG;IACH,EAAE,CAAC,CAAC,SAAS,MAAM,eAAe,CAAC,CAAC,CAAC,EACnC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAC9B,MAAM,IAAI;IAYb;;;;;OAKG;IACH,OAAO,IAAI,IAAI;IAmCf;;;OAGG;IACH,UAAU,IAAI,IAAI;IAelB;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI;IAMtB;;;OAGG;IACH,gBAAgB,IAAI,IAAI;IAIxB,2CAA2C;IAC3C,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,OAAO,CAAC,MAAM;IAMd,OAAO,CAAC,OAAO;IAUf,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,MAAM;IAOd,OAAO,CAAC,SAAS;IAiBjB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,IAAI;CAab"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ReconnectingWebSocket = void 0;
|
|
7
|
+
exports.getBackoffDelay = getBackoffDelay;
|
|
8
|
+
const ws_1 = __importDefault(require("ws"));
|
|
9
|
+
const BACKOFF_DEFAULTS = {
|
|
10
|
+
initialDelayMs: 1000,
|
|
11
|
+
maxDelayMs: 30000,
|
|
12
|
+
multiplier: 2,
|
|
13
|
+
};
|
|
14
|
+
const HEARTBEAT_DEFAULTS = {
|
|
15
|
+
intervalMs: 30000,
|
|
16
|
+
timeoutMs: 10000,
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Calculate exponential backoff delay for a given attempt number.
|
|
20
|
+
*
|
|
21
|
+
* @param attempt - Zero-based attempt index
|
|
22
|
+
* @param options - Backoff configuration
|
|
23
|
+
* @returns Delay in milliseconds, capped at maxDelayMs
|
|
24
|
+
*/
|
|
25
|
+
function getBackoffDelay(attempt, options) {
|
|
26
|
+
const delay = options.initialDelayMs * Math.pow(options.multiplier, attempt);
|
|
27
|
+
return Math.min(delay, options.maxDelayMs);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A generic WebSocket client that automatically reconnects on disconnection,
|
|
31
|
+
* sends protocol-level pings for heartbeats, and parses JSON messages.
|
|
32
|
+
*
|
|
33
|
+
* @typeParam T - The shape of messages exchanged over the socket (JSON-serializable)
|
|
34
|
+
*/
|
|
35
|
+
class ReconnectingWebSocket {
|
|
36
|
+
ws = null;
|
|
37
|
+
url;
|
|
38
|
+
backoff;
|
|
39
|
+
heartbeat;
|
|
40
|
+
reconnectAttempt = 0;
|
|
41
|
+
shouldReconnect = true;
|
|
42
|
+
heartbeatInterval = null;
|
|
43
|
+
heartbeatTimeout = null;
|
|
44
|
+
reconnectTimeout = null;
|
|
45
|
+
eventListeners = new Map();
|
|
46
|
+
constructor(options) {
|
|
47
|
+
this.url = options.url;
|
|
48
|
+
this.backoff = { ...BACKOFF_DEFAULTS, ...options.backoff };
|
|
49
|
+
this.heartbeat = { ...HEARTBEAT_DEFAULTS, ...options.heartbeat };
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Subscribe to a WebSocket lifecycle event.
|
|
53
|
+
* Multiple listeners per event are supported.
|
|
54
|
+
* Returns an unsubscribe function.
|
|
55
|
+
*/
|
|
56
|
+
on(event, listener) {
|
|
57
|
+
let set = this.eventListeners.get(event);
|
|
58
|
+
if (!set) {
|
|
59
|
+
set = new Set();
|
|
60
|
+
this.eventListeners.set(event, set);
|
|
61
|
+
}
|
|
62
|
+
set.add(listener);
|
|
63
|
+
return () => {
|
|
64
|
+
set.delete(listener);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Connect to the WebSocket server.
|
|
69
|
+
* Idempotent — no-op if already connected.
|
|
70
|
+
* If a reconnect timer is pending, cancels it and connects immediately,
|
|
71
|
+
* resetting the attempt counter.
|
|
72
|
+
*/
|
|
73
|
+
connect() {
|
|
74
|
+
if (this.ws) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (this.reconnectTimeout) {
|
|
78
|
+
clearTimeout(this.reconnectTimeout);
|
|
79
|
+
this.reconnectTimeout = null;
|
|
80
|
+
this.reconnectAttempt = 0;
|
|
81
|
+
}
|
|
82
|
+
this.shouldReconnect = true;
|
|
83
|
+
this.ws = new ws_1.default(this.url);
|
|
84
|
+
this.ws.on("open", () => {
|
|
85
|
+
this.onOpen();
|
|
86
|
+
});
|
|
87
|
+
this.ws.on("message", (data) => {
|
|
88
|
+
this.onMessage(data);
|
|
89
|
+
});
|
|
90
|
+
this.ws.on("close", (code, reason) => {
|
|
91
|
+
this.onClose(code, reason.toString());
|
|
92
|
+
});
|
|
93
|
+
this.ws.on("error", (error) => {
|
|
94
|
+
this.onError(error);
|
|
95
|
+
});
|
|
96
|
+
this.ws.on("pong", () => {
|
|
97
|
+
this.onPong();
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Disconnect from the server and stop all reconnection attempts.
|
|
102
|
+
* Closes the socket with code 1000.
|
|
103
|
+
*/
|
|
104
|
+
disconnect() {
|
|
105
|
+
this.shouldReconnect = false;
|
|
106
|
+
this.stopHeartbeat();
|
|
107
|
+
if (this.reconnectTimeout) {
|
|
108
|
+
clearTimeout(this.reconnectTimeout);
|
|
109
|
+
this.reconnectTimeout = null;
|
|
110
|
+
}
|
|
111
|
+
if (this.ws) {
|
|
112
|
+
this.ws.close(1000, "Client disconnecting");
|
|
113
|
+
this.ws = null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Send a message as JSON. No-op if not currently connected.
|
|
118
|
+
*/
|
|
119
|
+
send(message) {
|
|
120
|
+
if (this.ws?.readyState === ws_1.default.OPEN) {
|
|
121
|
+
this.ws.send(JSON.stringify(message));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Prevent reconnection without closing the current connection.
|
|
126
|
+
* Useful for draining: deliver in-flight results but do not reconnect if the socket drops.
|
|
127
|
+
*/
|
|
128
|
+
stopReconnecting() {
|
|
129
|
+
this.shouldReconnect = false;
|
|
130
|
+
}
|
|
131
|
+
/** Whether the socket is currently open */
|
|
132
|
+
get connected() {
|
|
133
|
+
return this.ws?.readyState === ws_1.default.OPEN;
|
|
134
|
+
}
|
|
135
|
+
onOpen() {
|
|
136
|
+
this.reconnectAttempt = 0;
|
|
137
|
+
this.startHeartbeat();
|
|
138
|
+
this.emit("open");
|
|
139
|
+
}
|
|
140
|
+
onClose(code, reason) {
|
|
141
|
+
this.ws = null;
|
|
142
|
+
this.stopHeartbeat();
|
|
143
|
+
this.emit("close", code, reason);
|
|
144
|
+
if (this.shouldReconnect) {
|
|
145
|
+
this.scheduleReconnect();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
onError(error) {
|
|
149
|
+
this.emit("error", error);
|
|
150
|
+
}
|
|
151
|
+
onPong() {
|
|
152
|
+
if (this.heartbeatTimeout) {
|
|
153
|
+
clearTimeout(this.heartbeatTimeout);
|
|
154
|
+
this.heartbeatTimeout = null;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
onMessage(data) {
|
|
158
|
+
try {
|
|
159
|
+
let raw;
|
|
160
|
+
if (Buffer.isBuffer(data)) {
|
|
161
|
+
raw = data.toString("utf8");
|
|
162
|
+
}
|
|
163
|
+
else if (Array.isArray(data)) {
|
|
164
|
+
raw = Buffer.concat(data).toString("utf8");
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
raw = Buffer.from(data).toString("utf8");
|
|
168
|
+
}
|
|
169
|
+
const parsed = JSON.parse(raw);
|
|
170
|
+
this.emit("message", parsed);
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
this.emit("error", err instanceof Error ? err : new Error(String(err)));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
sendHeartbeat() {
|
|
177
|
+
if (this.ws?.readyState === ws_1.default.OPEN) {
|
|
178
|
+
this.ws.ping();
|
|
179
|
+
this.heartbeatTimeout = setTimeout(() => {
|
|
180
|
+
this.ws?.terminate();
|
|
181
|
+
}, this.heartbeat.timeoutMs);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
startHeartbeat() {
|
|
185
|
+
this.stopHeartbeat();
|
|
186
|
+
this.heartbeatInterval = setInterval(() => {
|
|
187
|
+
this.sendHeartbeat();
|
|
188
|
+
}, this.heartbeat.intervalMs);
|
|
189
|
+
}
|
|
190
|
+
stopHeartbeat() {
|
|
191
|
+
if (this.heartbeatInterval) {
|
|
192
|
+
clearInterval(this.heartbeatInterval);
|
|
193
|
+
this.heartbeatInterval = null;
|
|
194
|
+
}
|
|
195
|
+
if (this.heartbeatTimeout) {
|
|
196
|
+
clearTimeout(this.heartbeatTimeout);
|
|
197
|
+
this.heartbeatTimeout = null;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
scheduleReconnect() {
|
|
201
|
+
const delay = getBackoffDelay(this.reconnectAttempt, this.backoff);
|
|
202
|
+
this.reconnectTimeout = setTimeout(() => {
|
|
203
|
+
this.reconnectAttempt++;
|
|
204
|
+
this.reconnectTimeout = null;
|
|
205
|
+
this.ws = null;
|
|
206
|
+
this.connect();
|
|
207
|
+
}, delay);
|
|
208
|
+
}
|
|
209
|
+
emit(event, ...args) {
|
|
210
|
+
const set = this.eventListeners.get(event);
|
|
211
|
+
if (!set) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
for (const listener of set) {
|
|
215
|
+
listener(...args);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
exports.ReconnectingWebSocket = ReconnectingWebSocket;
|
|
220
|
+
//# sourceMappingURL=ReconnectingWebSocket.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReconnectingWebSocket.js","sourceRoot":"","sources":["../src/ReconnectingWebSocket.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { RequestTrackerEvents } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Tracks active requests and manages draining state.
|
|
4
|
+
*
|
|
5
|
+
* Centralizes the pattern of rejecting new work during drain
|
|
6
|
+
* and notifying listeners when the last request completes.
|
|
7
|
+
*/
|
|
8
|
+
export declare class RequestTracker {
|
|
9
|
+
private _active;
|
|
10
|
+
private _draining;
|
|
11
|
+
private readonly listeners;
|
|
12
|
+
/**
|
|
13
|
+
* Subscribe to a RequestTracker event.
|
|
14
|
+
* Returns an unsubscribe function.
|
|
15
|
+
*/
|
|
16
|
+
on<K extends keyof RequestTrackerEvents>(event: K, listener: RequestTrackerEvents[K]): () => void;
|
|
17
|
+
/**
|
|
18
|
+
* Try to accept a new request.
|
|
19
|
+
* Returns false if draining — caller should send a rejection response.
|
|
20
|
+
*/
|
|
21
|
+
tryAccept(): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Mark a request as complete.
|
|
24
|
+
* Decrements the active count and emits drained when the last
|
|
25
|
+
* request finishes during a drain.
|
|
26
|
+
*/
|
|
27
|
+
complete(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Enter draining mode — no new requests will be accepted.
|
|
30
|
+
* Idempotent: subsequent calls are ignored.
|
|
31
|
+
* Emits draining immediately and drained when active reaches zero.
|
|
32
|
+
*/
|
|
33
|
+
startDraining(reason: string): void;
|
|
34
|
+
/** Whether the tracker is in draining mode */
|
|
35
|
+
get draining(): boolean;
|
|
36
|
+
/** Number of currently active requests */
|
|
37
|
+
get active(): number;
|
|
38
|
+
private emit;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=RequestTracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RequestTracker.d.ts","sourceRoot":"","sources":["../src/RequestTracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD;;;;;GAKG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAGtB;IAEJ;;;OAGG;IACH,EAAE,CAAC,CAAC,SAAS,MAAM,oBAAoB,EACrC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAChC,MAAM,IAAI;IAYb;;;OAGG;IACH,SAAS,IAAI,OAAO;IAQpB;;;;OAIG;IACH,QAAQ,IAAI,IAAI;IAOhB;;;;OAIG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAWnC,8CAA8C;IAC9C,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,0CAA0C;IAC1C,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,OAAO,CAAC,IAAI;CAWb"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RequestTracker = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Tracks active requests and manages draining state.
|
|
6
|
+
*
|
|
7
|
+
* Centralizes the pattern of rejecting new work during drain
|
|
8
|
+
* and notifying listeners when the last request completes.
|
|
9
|
+
*/
|
|
10
|
+
class RequestTracker {
|
|
11
|
+
_active = 0;
|
|
12
|
+
_draining = false;
|
|
13
|
+
listeners = new Map();
|
|
14
|
+
/**
|
|
15
|
+
* Subscribe to a RequestTracker event.
|
|
16
|
+
* Returns an unsubscribe function.
|
|
17
|
+
*/
|
|
18
|
+
on(event, listener) {
|
|
19
|
+
let set = this.listeners.get(event);
|
|
20
|
+
if (!set) {
|
|
21
|
+
set = new Set();
|
|
22
|
+
this.listeners.set(event, set);
|
|
23
|
+
}
|
|
24
|
+
set.add(listener);
|
|
25
|
+
return () => {
|
|
26
|
+
set.delete(listener);
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Try to accept a new request.
|
|
31
|
+
* Returns false if draining — caller should send a rejection response.
|
|
32
|
+
*/
|
|
33
|
+
tryAccept() {
|
|
34
|
+
if (this._draining) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
this._active++;
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Mark a request as complete.
|
|
42
|
+
* Decrements the active count and emits drained when the last
|
|
43
|
+
* request finishes during a drain.
|
|
44
|
+
*/
|
|
45
|
+
complete() {
|
|
46
|
+
this._active--;
|
|
47
|
+
if (this._draining && this._active === 0) {
|
|
48
|
+
this.emit("drained");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Enter draining mode — no new requests will be accepted.
|
|
53
|
+
* Idempotent: subsequent calls are ignored.
|
|
54
|
+
* Emits draining immediately and drained when active reaches zero.
|
|
55
|
+
*/
|
|
56
|
+
startDraining(reason) {
|
|
57
|
+
if (this._draining) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
this._draining = true;
|
|
61
|
+
this.emit("draining", reason);
|
|
62
|
+
if (this._active === 0) {
|
|
63
|
+
this.emit("drained");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** Whether the tracker is in draining mode */
|
|
67
|
+
get draining() {
|
|
68
|
+
return this._draining;
|
|
69
|
+
}
|
|
70
|
+
/** Number of currently active requests */
|
|
71
|
+
get active() {
|
|
72
|
+
return this._active;
|
|
73
|
+
}
|
|
74
|
+
emit(event, ...args) {
|
|
75
|
+
const set = this.listeners.get(event);
|
|
76
|
+
if (!set) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
for (const listener of set) {
|
|
80
|
+
listener(...args);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.RequestTracker = RequestTracker;
|
|
85
|
+
//# sourceMappingURL=RequestTracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RequestTracker.js","sourceRoot":"","sources":["../src/RequestTracker.ts"],"names":[],"mappings":";;;AAEA;;;;;GAKG;AACH,MAAa,cAAc;IACjB,OAAO,GAAG,CAAC,CAAC;IACZ,SAAS,GAAG,KAAK,CAAC;IACT,SAAS,GAAG,IAAI,GAAG,EAGjC,CAAC;IAEJ;;;OAGG;IACH,EAAE,CACA,KAAQ,EACR,QAAiC;QAEjC,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;YAChB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACjC,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAClB,OAAO,GAAG,EAAE;YACV,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACvB,CAAC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,SAAS;QACP,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;OAIG;IACH,QAAQ;QACN,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;YACzC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,aAAa,CAAC,MAAc;QAC1B,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAC9B,IAAI,IAAI,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;YACvB,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,8CAA8C;IAC9C,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,0CAA0C;IAC1C,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAIO,IAAI,CAAC,KAAiC,EAAE,GAAG,IAAe;QAChE,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO;QACT,CAAC;QACD,KAAK,MAAM,QAAQ,IAAI,GAAG,EAAE,CAAC;YAC1B,QAAsC,CAAC,GAAG,IAAI,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;CACF;AAxFD,wCAwFC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RequestTracker = exports.ReconnectingWebSocket = void 0;
|
|
4
|
+
var ReconnectingWebSocket_js_1 = require("./ReconnectingWebSocket.js");
|
|
5
|
+
Object.defineProperty(exports, "ReconnectingWebSocket", { enumerable: true, get: function () { return ReconnectingWebSocket_js_1.ReconnectingWebSocket; } });
|
|
6
|
+
var RequestTracker_js_1 = require("./RequestTracker.js");
|
|
7
|
+
Object.defineProperty(exports, "RequestTracker", { enumerable: true, get: function () { return RequestTracker_js_1.RequestTracker; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,uEAAmE;AAA1D,iIAAA,qBAAqB,OAAA;AAC9B,yDAAqD;AAA5C,mHAAA,cAAc,OAAA"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backoff configuration for reconnection delays.
|
|
3
|
+
*/
|
|
4
|
+
export interface BackoffOptions {
|
|
5
|
+
/** Initial delay in milliseconds. Default: 1000 */
|
|
6
|
+
initialDelayMs?: number;
|
|
7
|
+
/** Maximum delay in milliseconds. Default: 30000 */
|
|
8
|
+
maxDelayMs?: number;
|
|
9
|
+
/** Multiplier applied per attempt. Default: 2 */
|
|
10
|
+
multiplier?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Heartbeat configuration for detecting dead connections.
|
|
14
|
+
*/
|
|
15
|
+
export interface HeartbeatOptions {
|
|
16
|
+
/** Interval between pings in milliseconds. Default: 30000 */
|
|
17
|
+
intervalMs?: number;
|
|
18
|
+
/** Time to wait for pong before terminating. Default: 10000 */
|
|
19
|
+
timeoutMs?: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Configuration options for ReconnectingWebSocket.
|
|
23
|
+
*/
|
|
24
|
+
export interface WebSocketOptions {
|
|
25
|
+
/** WebSocket server URL */
|
|
26
|
+
url: string;
|
|
27
|
+
/** Backoff configuration for reconnection */
|
|
28
|
+
backoff?: BackoffOptions;
|
|
29
|
+
/** Heartbeat configuration */
|
|
30
|
+
heartbeat?: HeartbeatOptions;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Event callbacks for ReconnectingWebSocket.
|
|
34
|
+
*/
|
|
35
|
+
export interface WebSocketEvents<T> {
|
|
36
|
+
/** Fired when the connection is established */
|
|
37
|
+
open: () => void;
|
|
38
|
+
/** Fired when the connection is closed */
|
|
39
|
+
close: (code: number, reason: string) => void;
|
|
40
|
+
/** Fired on connection or parse errors */
|
|
41
|
+
error: (error: Error) => void;
|
|
42
|
+
/** Fired when a message is received and parsed */
|
|
43
|
+
message: (data: T) => void;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Event callbacks for RequestTracker.
|
|
47
|
+
*/
|
|
48
|
+
export interface RequestTrackerEvents {
|
|
49
|
+
/** Fired when draining mode is entered */
|
|
50
|
+
draining: (reason: string) => void;
|
|
51
|
+
/** Fired when all active requests complete during drain */
|
|
52
|
+
drained: () => void;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,mDAAmD;IACnD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,2BAA2B;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,6CAA6C;IAC7C,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,8BAA8B;IAC9B,SAAS,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,+CAA+C;IAC/C,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,0CAA0C;IAC1C,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,0CAA0C;IAC1C,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAC9B,kDAAkD;IAClD,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,0CAA0C;IAC1C,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,2DAA2D;IAC3D,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hardlydifficult/websocket",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "./dist/index.js",
|
|
5
|
+
"types": "./dist/index.d.ts",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"test": "vitest run",
|
|
12
|
+
"test:watch": "vitest",
|
|
13
|
+
"test:coverage": "vitest run --coverage",
|
|
14
|
+
"lint": "tsc --noEmit",
|
|
15
|
+
"clean": "rm -rf dist"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"ws": "8.19.0"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/node": "25.2.3",
|
|
22
|
+
"@types/ws": "8.18.1",
|
|
23
|
+
"typescript": "5.9.3",
|
|
24
|
+
"vitest": "4.0.18"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=18.0.0"
|
|
28
|
+
}
|
|
29
|
+
}
|