nostr-tools 2.22.1 → 2.23.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 (78) hide show
  1. package/lib/cjs/abstract-pool.js +170 -235
  2. package/lib/cjs/abstract-pool.js.map +4 -4
  3. package/lib/cjs/abstract-relay.js +116 -199
  4. package/lib/cjs/abstract-relay.js.map +4 -4
  5. package/lib/cjs/index.js +235 -241
  6. package/lib/cjs/index.js.map +4 -4
  7. package/lib/cjs/nip04.js.map +1 -1
  8. package/lib/cjs/nip13.js +18 -8
  9. package/lib/cjs/nip13.js.map +2 -2
  10. package/lib/cjs/nip17.js.map +1 -1
  11. package/lib/cjs/nip18.js.map +1 -1
  12. package/lib/cjs/nip19.js.map +1 -1
  13. package/lib/cjs/nip21.js.map +1 -1
  14. package/lib/cjs/nip25.js.map +1 -1
  15. package/lib/cjs/nip27.js +1 -1
  16. package/lib/cjs/nip27.js.map +2 -2
  17. package/lib/cjs/nip28.js.map +1 -1
  18. package/lib/cjs/nip29.js.map +1 -1
  19. package/lib/cjs/nip44.js.map +1 -1
  20. package/lib/cjs/nip46.js +171 -236
  21. package/lib/cjs/nip46.js.map +4 -4
  22. package/lib/cjs/nip47.js.map +1 -1
  23. package/lib/cjs/nip57.js.map +1 -1
  24. package/lib/cjs/nip59.js.map +1 -1
  25. package/lib/cjs/nip98.js.map +1 -1
  26. package/lib/cjs/nipb7.js.map +1 -1
  27. package/lib/cjs/pool.js +171 -236
  28. package/lib/cjs/pool.js.map +4 -4
  29. package/lib/cjs/pure.js.map +1 -1
  30. package/lib/cjs/references.js.map +1 -1
  31. package/lib/cjs/relay.js +116 -199
  32. package/lib/cjs/relay.js.map +4 -4
  33. package/lib/cjs/signer.js.map +1 -1
  34. package/lib/cjs/utils.js +45 -44
  35. package/lib/cjs/utils.js.map +3 -3
  36. package/lib/esm/abstract-pool.js +170 -235
  37. package/lib/esm/abstract-pool.js.map +4 -4
  38. package/lib/esm/abstract-relay.js +116 -199
  39. package/lib/esm/abstract-relay.js.map +4 -4
  40. package/lib/esm/index.js +235 -241
  41. package/lib/esm/index.js.map +4 -4
  42. package/lib/esm/nip04.js.map +1 -1
  43. package/lib/esm/nip13.js +18 -8
  44. package/lib/esm/nip13.js.map +2 -2
  45. package/lib/esm/nip17.js.map +1 -1
  46. package/lib/esm/nip18.js.map +1 -1
  47. package/lib/esm/nip19.js.map +1 -1
  48. package/lib/esm/nip21.js.map +1 -1
  49. package/lib/esm/nip25.js.map +1 -1
  50. package/lib/esm/nip27.js +1 -1
  51. package/lib/esm/nip27.js.map +2 -2
  52. package/lib/esm/nip28.js.map +1 -1
  53. package/lib/esm/nip29.js.map +1 -1
  54. package/lib/esm/nip44.js.map +1 -1
  55. package/lib/esm/nip46.js +171 -236
  56. package/lib/esm/nip46.js.map +4 -4
  57. package/lib/esm/nip47.js.map +1 -1
  58. package/lib/esm/nip57.js.map +1 -1
  59. package/lib/esm/nip59.js.map +1 -1
  60. package/lib/esm/nip98.js.map +1 -1
  61. package/lib/esm/nipb7.js.map +1 -1
  62. package/lib/esm/pool.js +171 -236
  63. package/lib/esm/pool.js.map +4 -4
  64. package/lib/esm/pure.js.map +1 -1
  65. package/lib/esm/references.js.map +1 -1
  66. package/lib/esm/relay.js +116 -199
  67. package/lib/esm/relay.js.map +4 -4
  68. package/lib/esm/signer.js.map +1 -1
  69. package/lib/esm/utils.js +45 -44
  70. package/lib/esm/utils.js.map +3 -3
  71. package/lib/nostr.bundle.js +243 -249
  72. package/lib/nostr.bundle.js.map +4 -4
  73. package/lib/types/abstract-pool.d.ts +8 -1
  74. package/lib/types/abstract-relay.d.ts +3 -5
  75. package/lib/types/helpers.d.ts +0 -1
  76. package/lib/types/nip13.d.ts +0 -1
  77. package/lib/types/utils.d.ts +4 -16
  78. package/package.json +44 -1
@@ -52,54 +52,6 @@ function normalizeURL(url) {
52
52
  throw new Error(`Invalid URL: ${url}`);
53
53
  }
54
54
  }
55
- var QueueNode = class {
56
- value;
57
- next = null;
58
- prev = null;
59
- constructor(message) {
60
- this.value = message;
61
- }
62
- };
63
- var Queue = class {
64
- first;
65
- last;
66
- constructor() {
67
- this.first = null;
68
- this.last = null;
69
- }
70
- enqueue(value) {
71
- const newNode = new QueueNode(value);
72
- if (!this.last) {
73
- this.first = newNode;
74
- this.last = newNode;
75
- } else if (this.last === this.first) {
76
- this.last = newNode;
77
- this.last.prev = this.first;
78
- this.first.next = newNode;
79
- } else {
80
- newNode.prev = this.last;
81
- this.last.next = newNode;
82
- this.last = newNode;
83
- }
84
- return true;
85
- }
86
- dequeue() {
87
- if (!this.first)
88
- return null;
89
- if (this.first === this.last) {
90
- const target2 = this.first;
91
- this.first = null;
92
- this.last = null;
93
- return target2.value;
94
- }
95
- const target = this.first;
96
- this.first = target.next;
97
- if (this.first) {
98
- this.first.prev = null;
99
- }
100
- return target.value;
101
- }
102
- };
103
55
 
104
56
  // kinds.ts
105
57
  var ClientAuth = 22242;
@@ -173,39 +125,6 @@ function makeAuthEvent(relayURL, challenge) {
173
125
  };
174
126
  }
175
127
 
176
- // helpers.ts
177
- async function yieldThread() {
178
- return new Promise((resolve, reject) => {
179
- try {
180
- if (typeof MessageChannel !== "undefined") {
181
- const ch = new MessageChannel();
182
- const handler = () => {
183
- ch.port1.removeEventListener("message", handler);
184
- resolve();
185
- };
186
- ch.port1.addEventListener("message", handler);
187
- ch.port2.postMessage(0);
188
- ch.port1.start();
189
- } else {
190
- if (typeof setImmediate !== "undefined") {
191
- setImmediate(resolve);
192
- } else if (typeof setTimeout !== "undefined") {
193
- setTimeout(resolve, 0);
194
- } else {
195
- resolve();
196
- }
197
- }
198
- } catch (e) {
199
- console.error("during yield: ", e);
200
- reject(e);
201
- }
202
- });
203
- }
204
- var alwaysTrue = (t) => {
205
- t[verifiedSymbol] = true;
206
- return true;
207
- };
208
-
209
128
  // abstract-relay.ts
210
129
  var SendingOnClosedConnection = class extends Error {
211
130
  constructor(message, relay) {
@@ -227,16 +146,16 @@ var AbstractRelay = class {
227
146
  openSubs = /* @__PURE__ */ new Map();
228
147
  enablePing;
229
148
  enableReconnect;
149
+ idleSince = Date.now();
150
+ ongoingOperations = 0;
230
151
  reconnectTimeoutHandle;
231
152
  pingIntervalHandle;
232
153
  reconnectAttempts = 0;
233
- closedIntentionally = false;
154
+ skipReconnection = false;
234
155
  connectionPromise;
235
156
  openCountRequests = /* @__PURE__ */ new Map();
236
157
  openEventPublishes = /* @__PURE__ */ new Map();
237
158
  ws;
238
- incomingMessageQueue = new Queue();
239
- queueRunning = false;
240
159
  challenge;
241
160
  authPromise;
242
161
  serial = 0;
@@ -288,12 +207,11 @@ var AbstractRelay = class {
288
207
  }
289
208
  this._connected = false;
290
209
  this.connectionPromise = void 0;
291
- const wasIntentional = this.closedIntentionally;
292
- this.closedIntentionally = false;
293
- this.onclose?.();
294
- if (this.enableReconnect && !wasIntentional) {
210
+ this.idleSince = void 0;
211
+ if (this.enableReconnect && !this.skipReconnection) {
295
212
  this.reconnect();
296
213
  } else {
214
+ this.onclose?.();
297
215
  this.closeAllSubscriptions(reason);
298
216
  }
299
217
  }
@@ -303,11 +221,13 @@ var AbstractRelay = class {
303
221
  return this.connectionPromise;
304
222
  this.challenge = void 0;
305
223
  this.authPromise = void 0;
224
+ this.skipReconnection = false;
306
225
  this.connectionPromise = new Promise((resolve, reject) => {
307
226
  if (opts?.timeout) {
308
227
  connectionTimeoutHandle = setTimeout(() => {
309
228
  reject("connection timed out");
310
229
  this.connectionPromise = void 0;
230
+ this.skipReconnection = true;
311
231
  this.onclose?.();
312
232
  this.handleHardClose("relay connection timed out");
313
233
  }, opts.timeout);
@@ -315,23 +235,14 @@ var AbstractRelay = class {
315
235
  if (opts?.abort) {
316
236
  opts.abort.onabort = reject;
317
237
  }
318
- const connectionFailed = () => {
319
- clearTimeout(connectionTimeoutHandle);
320
- reject("connection failed");
321
- this.connectionPromise = void 0;
322
- this.onclose?.();
323
- this.handleHardClose("relay connection failed");
324
- };
325
238
  try {
326
239
  this.ws = new this._WebSocket(this.url);
327
- this.ws.addEventListener("error", connectionFailed);
328
240
  } catch (err) {
329
241
  clearTimeout(connectionTimeoutHandle);
330
242
  reject(err);
331
243
  return;
332
244
  }
333
245
  this.ws.onopen = () => {
334
- this.ws?.removeEventListener("error", connectionFailed);
335
246
  if (this.reconnectTimeoutHandle) {
336
247
  clearTimeout(this.reconnectTimeoutHandle);
337
248
  this.reconnectTimeoutHandle = void 0;
@@ -356,10 +267,13 @@ var AbstractRelay = class {
356
267
  }
357
268
  resolve();
358
269
  };
359
- this.ws.onerror = (ev) => {
270
+ this.ws.onerror = () => {
360
271
  clearTimeout(connectionTimeoutHandle);
361
- reject(ev.message || "websocket error");
362
- this.handleHardClose("relay connection errored");
272
+ reject("connection failed");
273
+ this.connectionPromise = void 0;
274
+ this.skipReconnection = true;
275
+ this.onclose?.();
276
+ this.handleHardClose("relay connection failed");
363
277
  };
364
278
  this.ws.onclose = (ev) => {
365
279
  clearTimeout(connectionTimeoutHandle);
@@ -385,7 +299,7 @@ var AbstractRelay = class {
385
299
  const sub = this.subscribe(
386
300
  [{ ids: ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"], limit: 0 }],
387
301
  {
388
- label: "forced-ping",
302
+ label: "<forced-ping>",
389
303
  oneose: () => {
390
304
  resolve(true);
391
305
  sub.close();
@@ -414,20 +328,106 @@ var AbstractRelay = class {
414
328
  }
415
329
  }
416
330
  }
417
- async runQueue() {
418
- this.queueRunning = true;
419
- while (true) {
420
- if (false === this.handleNext()) {
421
- break;
331
+ async send(message) {
332
+ if (!this.connectionPromise)
333
+ throw new SendingOnClosedConnection(message, this.url);
334
+ this.connectionPromise.then(() => {
335
+ this.ws?.send(message);
336
+ });
337
+ }
338
+ async auth(signAuthEvent) {
339
+ const challenge = this.challenge;
340
+ if (!challenge)
341
+ throw new Error("can't perform auth, no challenge was received");
342
+ if (this.authPromise)
343
+ return this.authPromise;
344
+ this.authPromise = new Promise(async (resolve, reject) => {
345
+ try {
346
+ let evt = await signAuthEvent(makeAuthEvent(this.url, challenge));
347
+ let timeout = setTimeout(() => {
348
+ let ep = this.openEventPublishes.get(evt.id);
349
+ if (ep) {
350
+ ep.reject(new Error("auth timed out"));
351
+ this.openEventPublishes.delete(evt.id);
352
+ }
353
+ }, this.publishTimeout);
354
+ this.openEventPublishes.set(evt.id, { resolve, reject, timeout });
355
+ this.send('["AUTH",' + JSON.stringify(evt) + "]");
356
+ } catch (err) {
357
+ console.warn("subscribe auth function failed:", err);
422
358
  }
423
- await yieldThread();
359
+ });
360
+ return this.authPromise;
361
+ }
362
+ async publish(event) {
363
+ this.idleSince = void 0;
364
+ this.ongoingOperations++;
365
+ const ret = new Promise((resolve, reject) => {
366
+ const timeout = setTimeout(() => {
367
+ const ep = this.openEventPublishes.get(event.id);
368
+ if (ep) {
369
+ ep.reject(new Error("publish timed out"));
370
+ this.openEventPublishes.delete(event.id);
371
+ }
372
+ }, this.publishTimeout);
373
+ this.openEventPublishes.set(event.id, { resolve, reject, timeout });
374
+ });
375
+ this.send('["EVENT",' + JSON.stringify(event) + "]");
376
+ this.ongoingOperations--;
377
+ if (this.ongoingOperations === 0)
378
+ this.idleSince = Date.now();
379
+ return ret;
380
+ }
381
+ async count(filters, params) {
382
+ this.serial++;
383
+ const id = params?.id || "count:" + this.serial;
384
+ const ret = new Promise((resolve, reject) => {
385
+ this.openCountRequests.set(id, { resolve, reject });
386
+ });
387
+ this.send('["COUNT","' + id + '",' + JSON.stringify(filters).substring(1));
388
+ return ret;
389
+ }
390
+ subscribe(filters, params) {
391
+ if (params.label !== "<forced-ping>") {
392
+ this.idleSince = void 0;
393
+ this.ongoingOperations++;
394
+ }
395
+ const sub = this.prepareSubscription(filters, params);
396
+ sub.fire();
397
+ if (params.abort) {
398
+ params.abort.onabort = () => sub.close(String(params.abort.reason || "<aborted>"));
424
399
  }
425
- this.queueRunning = false;
400
+ return sub;
426
401
  }
427
- handleNext() {
428
- const json = this.incomingMessageQueue.dequeue();
402
+ prepareSubscription(filters, params) {
403
+ this.serial++;
404
+ const id = params.id || (params.label ? params.label + ":" : "sub:") + this.serial;
405
+ const sub = new Subscription(this, id, filters, params);
406
+ this.openSubs.set(id, sub);
407
+ return sub;
408
+ }
409
+ close() {
410
+ this.skipReconnection = true;
411
+ if (this.reconnectTimeoutHandle) {
412
+ clearTimeout(this.reconnectTimeoutHandle);
413
+ this.reconnectTimeoutHandle = void 0;
414
+ }
415
+ if (this.pingIntervalHandle) {
416
+ clearInterval(this.pingIntervalHandle);
417
+ this.pingIntervalHandle = void 0;
418
+ }
419
+ this.closeAllSubscriptions("relay connection closed by us");
420
+ this._connected = false;
421
+ this.idleSince = void 0;
422
+ this.onclose?.();
423
+ if (this.ws?.readyState === this._WebSocket.OPEN) {
424
+ this.ws?.close();
425
+ }
426
+ }
427
+ _onmessage(ev) {
428
+ const json = ev.data;
429
429
  if (!json) {
430
- return false;
430
+ return;
431
431
  }
432
432
  const subid = getSubscriptionId(json);
433
433
  if (subid) {
@@ -514,101 +514,11 @@ var AbstractRelay = class {
514
514
  }
515
515
  }
516
516
  } catch (err) {
517
+ const [_, __, event] = JSON.parse(json);
518
+ window.printer.maybe(event.pubkey, ":: caught err", event, this.url, err);
517
519
  return;
518
520
  }
519
521
  }
520
- async send(message) {
521
- if (!this.connectionPromise)
522
- throw new SendingOnClosedConnection(message, this.url);
523
- this.connectionPromise.then(() => {
524
- this.ws?.send(message);
525
- });
526
- }
527
- async auth(signAuthEvent) {
528
- const challenge = this.challenge;
529
- if (!challenge)
530
- throw new Error("can't perform auth, no challenge was received");
531
- if (this.authPromise)
532
- return this.authPromise;
533
- this.authPromise = new Promise(async (resolve, reject) => {
534
- try {
535
- let evt = await signAuthEvent(makeAuthEvent(this.url, challenge));
536
- let timeout = setTimeout(() => {
537
- let ep = this.openEventPublishes.get(evt.id);
538
- if (ep) {
539
- ep.reject(new Error("auth timed out"));
540
- this.openEventPublishes.delete(evt.id);
541
- }
542
- }, this.publishTimeout);
543
- this.openEventPublishes.set(evt.id, { resolve, reject, timeout });
544
- this.send('["AUTH",' + JSON.stringify(evt) + "]");
545
- } catch (err) {
546
- console.warn("subscribe auth function failed:", err);
547
- }
548
- });
549
- return this.authPromise;
550
- }
551
- async publish(event) {
552
- const ret = new Promise((resolve, reject) => {
553
- const timeout = setTimeout(() => {
554
- const ep = this.openEventPublishes.get(event.id);
555
- if (ep) {
556
- ep.reject(new Error("publish timed out"));
557
- this.openEventPublishes.delete(event.id);
558
- }
559
- }, this.publishTimeout);
560
- this.openEventPublishes.set(event.id, { resolve, reject, timeout });
561
- });
562
- this.send('["EVENT",' + JSON.stringify(event) + "]");
563
- return ret;
564
- }
565
- async count(filters, params) {
566
- this.serial++;
567
- const id = params?.id || "count:" + this.serial;
568
- const ret = new Promise((resolve, reject) => {
569
- this.openCountRequests.set(id, { resolve, reject });
570
- });
571
- this.send('["COUNT","' + id + '",' + JSON.stringify(filters).substring(1));
572
- return ret;
573
- }
574
- subscribe(filters, params) {
575
- const sub = this.prepareSubscription(filters, params);
576
- sub.fire();
577
- if (params.abort) {
578
- params.abort.onabort = () => sub.close(String(params.abort.reason || "<aborted>"));
579
- }
580
- return sub;
581
- }
582
- prepareSubscription(filters, params) {
583
- this.serial++;
584
- const id = params.id || (params.label ? params.label + ":" : "sub:") + this.serial;
585
- const subscription = new Subscription(this, id, filters, params);
586
- this.openSubs.set(id, subscription);
587
- return subscription;
588
- }
589
- close() {
590
- this.closedIntentionally = true;
591
- if (this.reconnectTimeoutHandle) {
592
- clearTimeout(this.reconnectTimeoutHandle);
593
- this.reconnectTimeoutHandle = void 0;
594
- }
595
- if (this.pingIntervalHandle) {
596
- clearInterval(this.pingIntervalHandle);
597
- this.pingIntervalHandle = void 0;
598
- }
599
- this.closeAllSubscriptions("relay connection closed by us");
600
- this._connected = false;
601
- this.onclose?.();
602
- if (this.ws?.readyState === this._WebSocket.OPEN) {
603
- this.ws?.close();
604
- }
605
- }
606
- _onmessage(ev) {
607
- this.incomingMessageQueue.enqueue(ev.data);
608
- if (!this.queueRunning) {
609
- this.runQueue();
610
- }
611
- }
612
522
  };
613
523
  var Subscription = class {
614
524
  relay;
@@ -667,10 +577,19 @@ var Subscription = class {
667
577
  this.closed = true;
668
578
  }
669
579
  this.relay.openSubs.delete(this.id);
580
+ this.relay.ongoingOperations--;
581
+ if (this.relay.ongoingOperations === 0)
582
+ this.relay.idleSince = Date.now();
670
583
  this.onclose?.(reason);
671
584
  }
672
585
  };
673
586
 
587
+ // helpers.ts
588
+ var alwaysTrue = (t) => {
589
+ t[verifiedSymbol] = true;
590
+ return true;
591
+ };
592
+
674
593
  // abstract-pool.ts
675
594
  var AbstractSimplePool = class {
676
595
  relays = /* @__PURE__ */ new Map();
@@ -682,7 +601,9 @@ var AbstractSimplePool = class {
682
601
  automaticallyAuth;
683
602
  trustedRelayURLs = /* @__PURE__ */ new Set();
684
603
  onRelayConnectionFailure;
604
+ onRelayConnectionSuccess;
685
605
  allowConnectingToRelay;
606
+ maxWaitForConnection;
686
607
  _WebSocket;
687
608
  constructor(opts) {
688
609
  this.verifyEvent = opts.verifyEvent;
@@ -691,7 +612,9 @@ var AbstractSimplePool = class {
691
612
  this.enableReconnect = opts.enableReconnect || false;
692
613
  this.automaticallyAuth = opts.automaticallyAuth;
693
614
  this.onRelayConnectionFailure = opts.onRelayConnectionFailure;
615
+ this.onRelayConnectionSuccess = opts.onRelayConnectionSuccess;
694
616
  this.allowConnectingToRelay = opts.allowConnectingToRelay;
617
+ this.maxWaitForConnection = opts.maxWaitForConnection || 3e3;
695
618
  }
696
619
  async ensureRelay(url, params) {
697
620
  url = normalizeURL(url);
@@ -704,9 +627,7 @@ var AbstractSimplePool = class {
704
627
  enableReconnect: this.enableReconnect
705
628
  });
706
629
  relay.onclose = () => {
707
- if (relay && !relay.enableReconnect) {
708
- this.relays.delete(url);
709
- }
630
+ this.relays.delete(url);
710
631
  };
711
632
  this.relays.set(url, relay);
712
633
  }
@@ -716,10 +637,15 @@ var AbstractSimplePool = class {
716
637
  relay.onauth = authSignerFn;
717
638
  }
718
639
  }
719
- await relay.connect({
720
- timeout: params?.connectionTimeout,
721
- abort: params?.abort
722
- });
640
+ try {
641
+ await relay.connect({
642
+ timeout: params?.connectionTimeout,
643
+ abort: params?.abort
644
+ });
645
+ } catch (err) {
646
+ this.relays.delete(url);
647
+ throw err;
648
+ }
723
649
  return relay;
724
650
  }
725
651
  close(relays) {
@@ -730,25 +656,20 @@ var AbstractSimplePool = class {
730
656
  }
731
657
  subscribe(relays, filter, params) {
732
658
  const request = [];
659
+ const uniqUrls = [];
733
660
  for (let i = 0; i < relays.length; i++) {
734
661
  const url = normalizeURL(relays[i]);
735
662
  if (!request.find((r) => r.url === url)) {
736
- request.push({ url, filter });
663
+ if (uniqUrls.indexOf(url) === -1) {
664
+ uniqUrls.push(url);
665
+ request.push({ url, filter });
666
+ }
737
667
  }
738
668
  }
739
669
  return this.subscribeMap(request, params);
740
670
  }
741
671
  subscribeMany(relays, filter, params) {
742
- const request = [];
743
- const uniqUrls = [];
744
- for (let i = 0; i < relays.length; i++) {
745
- const url = normalizeURL(relays[i]);
746
- if (uniqUrls.indexOf(url) === -1) {
747
- uniqUrls.push(url);
748
- request.push({ url, filter });
749
- }
750
- }
751
- return this.subscribeMap(request, params);
672
+ return this.subscribe(relays, filter, params);
752
673
  }
753
674
  subscribeMap(requests, params) {
754
675
  const grouped = /* @__PURE__ */ new Map();
@@ -811,7 +732,7 @@ var AbstractSimplePool = class {
811
732
  let relay;
812
733
  try {
813
734
  relay = await this.ensureRelay(url, {
814
- connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1e3) : void 0,
735
+ connectionTimeout: this.maxWaitForConnection < (params.maxWait || 0) ? Math.max(params.maxWait * 0.8, params.maxWait - 1e3) : this.maxWaitForConnection,
815
736
  abort: params.abort
816
737
  });
817
738
  } catch (err) {
@@ -819,6 +740,7 @@ var AbstractSimplePool = class {
819
740
  handleClose(i, err?.message || String(err));
820
741
  return;
821
742
  }
743
+ this.onRelayConnectionSuccess?.(url);
822
744
  let subscription = relay.subscribe(filters, {
823
745
  ...params,
824
746
  oneose: () => handleEose(i),
@@ -859,22 +781,21 @@ var AbstractSimplePool = class {
859
781
  };
860
782
  }
861
783
  subscribeEose(relays, filter, params) {
862
- const subcloser = this.subscribe(relays, filter, {
784
+ let subcloser;
785
+ subcloser = this.subscribe(relays, filter, {
863
786
  ...params,
864
787
  oneose() {
865
- subcloser.close("closed automatically on eose");
788
+ const reason = "closed automatically on eose";
789
+ if (subcloser)
790
+ subcloser.close(reason);
791
+ else
792
+ params.onclose?.(relays.map((_) => reason));
866
793
  }
867
794
  });
868
795
  return subcloser;
869
796
  }
870
797
  subscribeManyEose(relays, filter, params) {
871
- const subcloser = this.subscribeMany(relays, filter, {
872
- ...params,
873
- oneose() {
874
- subcloser.close("closed automatically on eose");
875
- }
876
- });
877
- return subcloser;
798
+ return this.subscribeEose(relays, filter, params);
878
799
  }
879
800
  async querySync(relays, filter, params) {
880
801
  return new Promise(async (resolve) => {
@@ -896,7 +817,7 @@ var AbstractSimplePool = class {
896
817
  events.sort((a, b) => b.created_at - a.created_at);
897
818
  return events[0] || null;
898
819
  }
899
- publish(relays, event, options) {
820
+ publish(relays, event, params) {
900
821
  return relays.map(normalizeURL).map(async (url, i, arr) => {
901
822
  if (arr.indexOf(url) !== i) {
902
823
  return Promise.reject("duplicate url");
@@ -906,14 +827,17 @@ var AbstractSimplePool = class {
906
827
  }
907
828
  let r;
908
829
  try {
909
- r = await this.ensureRelay(url);
830
+ r = await this.ensureRelay(url, {
831
+ connectionTimeout: this.maxWaitForConnection < (params?.maxWait || 0) ? Math.max(params.maxWait * 0.8, params.maxWait - 1e3) : this.maxWaitForConnection,
832
+ abort: params?.abort
833
+ });
910
834
  } catch (err) {
911
835
  this.onRelayConnectionFailure?.(url);
912
836
  return String("connection failure: " + String(err));
913
837
  }
914
838
  return r.publish(event).catch(async (err) => {
915
- if (err instanceof Error && err.message.startsWith("auth-required: ") && options?.onauth) {
916
- await r.auth(options.onauth);
839
+ if (err instanceof Error && err.message.startsWith("auth-required: ") && params?.onauth) {
840
+ await r.auth(params.onauth);
917
841
  return r.publish(event);
918
842
  }
919
843
  throw err;
@@ -939,4 +863,15 @@ var AbstractSimplePool = class {
939
863
  this.relays.forEach((conn) => conn.close());
940
864
  this.relays = /* @__PURE__ */ new Map();
941
865
  }
866
+ pruneIdleRelays(idleThresholdMs = 1e4) {
867
+ const prunedUrls = [];
868
+ for (const [url, relay] of this.relays) {
869
+ if (relay.idleSince && Date.now() - relay.idleSince >= idleThresholdMs) {
870
+ this.relays.delete(url);
871
+ prunedUrls.push(url);
872
+ relay.close();
873
+ }
874
+ }
875
+ return prunedUrls;
876
+ }
942
877
  };