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.
Files changed (2) hide show
  1. package/index.js +42 -4
  2. 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://friendly-octo-barnacle.fly.dev';
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.reconnectInterval = options.reconnectInterval || 3000;
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
- console.log(`Reachlo: Retrying in ${this.reconnectInterval / 1000}s...`);
139
- this.reconnectTimer = setTimeout(() => this.connect(), this.reconnectInterval);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reachlo",
3
- "version": "1.3.1",
3
+ "version": "1.4.1",
4
4
  "description": "Streaming-native real-time infrastructure. Ordered channels, durable replay, presence, backpressure, and ACK delivery.",
5
5
  "main": "index.js",
6
6
  "type": "module",