reachlo 1.3.1 → 1.4.1
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/index.js +42 -4
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
class Reachlo {
|
|
3
3
|
constructor(apiKey, options = {}) {
|
|
4
4
|
this.apiKey = apiKey;
|
|
5
|
-
this.url = options.url || 'wss://
|
|
5
|
+
this.url = options.url || 'wss://edge.reachlo.space/';
|
|
6
6
|
this.socket = null;
|
|
7
7
|
this.channels = new Map();
|
|
8
8
|
this.pendingSubs = new Set();
|
|
@@ -12,7 +12,13 @@ class Reachlo {
|
|
|
12
12
|
this.debug = options.debug || false; // Default: false (silent)
|
|
13
13
|
this.bufferPublish = options.bufferPublish ?? false; // Drop by default for AI
|
|
14
14
|
this.heartbeatInterval = options.heartbeatInterval || 20000;
|
|
15
|
-
this.
|
|
15
|
+
this.reconnectBaseDelay = options.reconnectBaseDelay || 1000;
|
|
16
|
+
this.reconnectMaxDelay = options.reconnectMaxDelay || 30000;
|
|
17
|
+
this.batchInterval = options.batchInterval || 0; // 0 = disabled
|
|
18
|
+
|
|
19
|
+
// Batch state
|
|
20
|
+
this._batchQueue = [];
|
|
21
|
+
this._batchTimer = null;
|
|
16
22
|
|
|
17
23
|
// State
|
|
18
24
|
this.heartbeatTimer = null;
|
|
@@ -20,6 +26,7 @@ class Reachlo {
|
|
|
20
26
|
this.shouldReconnect = true;
|
|
21
27
|
this.lastPong = Date.now();
|
|
22
28
|
this.reconnecting = false; // Prevent duplicate events
|
|
29
|
+
this._reconnectAttempt = 0;
|
|
23
30
|
|
|
24
31
|
// Protocol v2 State
|
|
25
32
|
this.msgId = 0;
|
|
@@ -90,6 +97,7 @@ class Reachlo {
|
|
|
90
97
|
this.socket.onopen = () => {
|
|
91
98
|
this._log("Reachlo: Connected");
|
|
92
99
|
this.reconnecting = false;
|
|
100
|
+
this._reconnectAttempt = 0; // Reset backoff on successful connect
|
|
93
101
|
this.lastPong = Date.now();
|
|
94
102
|
this._startHeartbeat();
|
|
95
103
|
this._emitLifecycle('connect');
|
|
@@ -135,8 +143,16 @@ class Reachlo {
|
|
|
135
143
|
this.reconnecting = true;
|
|
136
144
|
this._emitLifecycle('reconnecting');
|
|
137
145
|
}
|
|
138
|
-
|
|
139
|
-
|
|
146
|
+
// Exponential backoff + jitter to prevent reconnection storms
|
|
147
|
+
const baseDelay = Math.min(
|
|
148
|
+
this.reconnectBaseDelay * Math.pow(2, this._reconnectAttempt),
|
|
149
|
+
this.reconnectMaxDelay
|
|
150
|
+
);
|
|
151
|
+
const jitter = Math.random() * 1000; // 0–1s random jitter
|
|
152
|
+
const delay = baseDelay + jitter;
|
|
153
|
+
this._reconnectAttempt++;
|
|
154
|
+
this._log(`Reachlo: Retrying in ${(delay / 1000).toFixed(1)}s (attempt ${this._reconnectAttempt})...`);
|
|
155
|
+
this.reconnectTimer = setTimeout(() => this.connect(), delay);
|
|
140
156
|
}
|
|
141
157
|
};
|
|
142
158
|
|
|
@@ -204,6 +220,8 @@ class Reachlo {
|
|
|
204
220
|
disconnect() {
|
|
205
221
|
this.shouldReconnect = false;
|
|
206
222
|
if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
|
|
223
|
+
if (this._batchTimer) clearTimeout(this._batchTimer);
|
|
224
|
+
this._batchQueue = [];
|
|
207
225
|
this._stopHeartbeat();
|
|
208
226
|
|
|
209
227
|
|
|
@@ -232,6 +250,14 @@ class Reachlo {
|
|
|
232
250
|
|
|
233
251
|
_send(payload) {
|
|
234
252
|
if (this.socket && this.socket.readyState === 1) {
|
|
253
|
+
// If batching is enabled, queue instead of sending immediately
|
|
254
|
+
if (this.batchInterval > 0 && payload.type === 'publish') {
|
|
255
|
+
this._batchQueue.push(payload);
|
|
256
|
+
if (!this._batchTimer) {
|
|
257
|
+
this._batchTimer = setTimeout(() => this._flushBatch(), this.batchInterval);
|
|
258
|
+
}
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
235
261
|
this.socket.send(JSON.stringify(payload));
|
|
236
262
|
return true;
|
|
237
263
|
} else {
|
|
@@ -242,6 +268,18 @@ class Reachlo {
|
|
|
242
268
|
return false; // Dropped
|
|
243
269
|
}
|
|
244
270
|
}
|
|
271
|
+
|
|
272
|
+
_flushBatch() {
|
|
273
|
+
this._batchTimer = null;
|
|
274
|
+
if (this._batchQueue.length === 0) return;
|
|
275
|
+
if (this.socket && this.socket.readyState === 1) {
|
|
276
|
+
this.socket.send(JSON.stringify({
|
|
277
|
+
type: 'batch',
|
|
278
|
+
messages: this._batchQueue
|
|
279
|
+
}));
|
|
280
|
+
}
|
|
281
|
+
this._batchQueue = [];
|
|
282
|
+
}
|
|
245
283
|
}
|
|
246
284
|
|
|
247
285
|
class ReachloChannel {
|
package/package.json
CHANGED