wireweave 0.3.26 → 0.3.27

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 +48 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wireweave",
3
- "version": "0.3.26",
3
+ "version": "0.3.27",
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
@@ -38,8 +38,10 @@ export class RelayPool extends EventTarget {
38
38
  this.relays = new Map();
39
39
  this.subs = new Map();
40
40
  this.pending = [];
41
+ this._pendingIds = new Set();
41
42
  this.seen = new Map();
42
43
  this._reconnectTimers = new Map();
44
+ this._acks = new Map();
43
45
  this._closed = false;
44
46
  this.verifyEvent = verifyEvent;
45
47
  this.WS = WebSocketImpl || (typeof WebSocket !== 'undefined' ? WebSocket : null);
@@ -55,6 +57,8 @@ export class RelayPool extends EventTarget {
55
57
  this._closed = true;
56
58
  for (const [, t] of this._reconnectTimers) clearTimeout(t);
57
59
  this._reconnectTimers.clear();
60
+ for (const [, rec] of this._acks) { clearTimeout(rec.timer); rec.resolve(false); }
61
+ this._acks.clear();
58
62
  for (const [, r] of this.relays) {
59
63
  if (r.ws) {
60
64
  r.ws.onclose = null; r.ws.onerror = null; r.ws.onopen = null; r.ws.onmessage = null;
@@ -132,8 +136,12 @@ export class RelayPool extends EventTarget {
132
136
  this._emit('eose', { subId });
133
137
  } else if (type === 'NOTICE') {
134
138
  this._emit('notice', { url, message: msg[1] });
135
- } else if (type === 'OK' && !msg[2]) {
136
- this._emit('reject', { id: msg[1], reason: msg[3] || '' });
139
+ } else if (type === 'OK') {
140
+ const accepted = msg[2] === true;
141
+ const id = msg[1], reason = msg[3] || '';
142
+ if (accepted) this._emit('ok', { url, id });
143
+ else this._emit('reject', { url, id, reason });
144
+ this._settleAck(id, accepted, reason);
137
145
  }
138
146
  }
139
147
 
@@ -169,16 +177,51 @@ export class RelayPool extends EventTarget {
169
177
  sent = true;
170
178
  }
171
179
  }
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);
180
+ if (sent) {
181
+ if (event?.id) this._pendingIds.delete(event.id);
182
+ } else {
183
+ this._queuePending(event);
175
184
  }
176
185
  return sent;
177
186
  }
178
187
 
188
+ _queuePending(event) {
189
+ if (event?.id && this._pendingIds.has(event.id)) return;
190
+ if (event?.id) this._pendingIds.add(event.id);
191
+ this.pending.push({ event, ts: Date.now() });
192
+ while (this.pending.length > PENDING_MAX) {
193
+ const dropped = this.pending.shift();
194
+ if (dropped.event?.id) this._pendingIds.delete(dropped.event.id);
195
+ }
196
+ }
197
+
198
+ // Resolves true once any relay sends OK accepted, false on relay reject,
199
+ // or false on timeout. Gives callers delivery confidence beyond fire-and-forget.
200
+ publishAndWait(event, { timeoutMs = 8000 } = {}) {
201
+ const sent = this.publish(event);
202
+ if (!event?.id) return Promise.resolve(sent);
203
+ return new Promise((resolve) => {
204
+ const prior = this._acks.get(event.id);
205
+ if (prior) clearTimeout(prior.timer);
206
+ const settle = (ok) => {
207
+ const rec = this._acks.get(event.id);
208
+ if (rec) { clearTimeout(rec.timer); this._acks.delete(event.id); }
209
+ resolve(ok);
210
+ };
211
+ const timer = setTimeout(() => settle(false), timeoutMs);
212
+ this._acks.set(event.id, { resolve: settle, timer });
213
+ });
214
+ }
215
+
216
+ _settleAck(id, accepted) {
217
+ const rec = this._acks.get(id);
218
+ if (rec) rec.resolve(accepted);
219
+ }
220
+
179
221
  _drainPending() {
180
222
  const cutoff = Date.now() - PENDING_TTL_MS;
181
223
  const pending = this.pending.splice(0);
224
+ this._pendingIds.clear();
182
225
  for (const p of pending) { if (p.ts >= cutoff) this.publish(p.event); }
183
226
  }
184
227