wireweave 0.3.23 → 0.3.26

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/package.json +1 -1
  2. package/src/relay-pool.js +20 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wireweave",
3
- "version": "0.3.23",
3
+ "version": "0.3.26",
4
4
  "description": "nostr + webrtc voice + data SDK. networking layer for 247420 projects.",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
package/src/relay-pool.js CHANGED
@@ -12,6 +12,9 @@ const DEFAULT_RELAYS = [
12
12
  ];
13
13
 
14
14
  const SEEN_MAX = 10000;
15
+ const PENDING_MAX = 500;
16
+ const PENDING_TTL_MS = 120000;
17
+ const jitter = (ms) => Math.round(ms * (0.75 + Math.random() * 0.5));
15
18
 
16
19
  const lruTouch = (map, key) => {
17
20
  if (map.has(key)) { map.delete(key); map.set(key, 1); return false; }
@@ -36,16 +39,22 @@ export class RelayPool extends EventTarget {
36
39
  this.subs = new Map();
37
40
  this.pending = [];
38
41
  this.seen = new Map();
42
+ this._reconnectTimers = new Map();
43
+ this._closed = false;
39
44
  this.verifyEvent = verifyEvent;
40
45
  this.WS = WebSocketImpl || (typeof WebSocket !== 'undefined' ? WebSocket : null);
41
46
  if (!this.WS) throw new Error('No WebSocket implementation available');
42
47
  }
43
48
 
44
49
  connect() {
50
+ this._closed = false;
45
51
  for (const url of this.urls) this._open(url);
46
52
  }
47
53
 
48
54
  disconnect() {
55
+ this._closed = true;
56
+ for (const [, t] of this._reconnectTimers) clearTimeout(t);
57
+ this._reconnectTimers.clear();
49
58
  for (const [, r] of this.relays) {
50
59
  if (r.ws) {
51
60
  r.ws.onclose = null; r.ws.onerror = null; r.ws.onopen = null; r.ws.onmessage = null;
@@ -58,6 +67,8 @@ export class RelayPool extends EventTarget {
58
67
  }
59
68
 
60
69
  _open(url) {
70
+ if (this._closed) return;
71
+ this._reconnectTimers.delete(url);
61
72
  const existing = this.relays.get(url);
62
73
  if (existing?.ws && (existing.ws.readyState === 0 || existing.ws.readyState === 1)) return;
63
74
  const relay = existing || { ws: null, status: 'connecting', subIds: new Set(), latencyMs: null, failCount: 0, reconnectDelay: 1000, _reqSentAt: null, _openedAt: null };
@@ -94,7 +105,9 @@ export class RelayPool extends EventTarget {
94
105
  if (sustained) { relay.failCount = 0; relay.reconnectDelay = 1000; }
95
106
  else { relay.failCount++; relay.reconnectDelay = Math.min(relay.reconnectDelay * 2, 30000); }
96
107
  relay._openedAt = null;
97
- setTimeout(() => this._open(url), relay.reconnectDelay);
108
+ if (this._closed) return;
109
+ const t = setTimeout(() => this._open(url), jitter(relay.reconnectDelay));
110
+ this._reconnectTimers.set(url, t);
98
111
  };
99
112
  }
100
113
 
@@ -156,13 +169,17 @@ export class RelayPool extends EventTarget {
156
169
  sent = true;
157
170
  }
158
171
  }
159
- if (!sent) this.pending.push(event);
172
+ if (!sent) {
173
+ this.pending.push({ event, ts: Date.now() });
174
+ if (this.pending.length > PENDING_MAX) this.pending.splice(0, this.pending.length - PENDING_MAX);
175
+ }
160
176
  return sent;
161
177
  }
162
178
 
163
179
  _drainPending() {
180
+ const cutoff = Date.now() - PENDING_TTL_MS;
164
181
  const pending = this.pending.splice(0);
165
- for (const e of pending) this.publish(e);
182
+ for (const p of pending) { if (p.ts >= cutoff) this.publish(p.event); }
166
183
  }
167
184
 
168
185
  isConnected() {