@qntx/nostr 0.11.0 → 0.13.0

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 (164) hide show
  1. package/dist/{builder-GBddxj8i.d.mts → builder-C72nJITG.d.mts} +2 -2
  2. package/dist/{builder-BQbFDO6S.mjs → builder-CGgM_QHT.mjs} +5 -5
  3. package/dist/{builder-BQbFDO6S.mjs.map → builder-CGgM_QHT.mjs.map} +1 -1
  4. package/dist/{client-CTmp5w84.mjs → client-COkEihj_.mjs} +87 -79
  5. package/dist/client-COkEihj_.mjs.map +1 -0
  6. package/dist/client.d.mts +1 -1
  7. package/dist/client.mjs +1 -1
  8. package/dist/core.d.mts +7 -7
  9. package/dist/core.mjs +9 -9
  10. package/dist/{emitter-DkCY6NkU.mjs → emitter-u4kJqQDk.mjs} +2 -2
  11. package/dist/{emitter-DkCY6NkU.mjs.map → emitter-u4kJqQDk.mjs.map} +1 -1
  12. package/dist/{error-BquXDmIN.d.mts → error-BPqAU5RB.d.mts} +2 -6
  13. package/dist/{error-BD_0QFKT.d.mts → error-BjSUsx6M.d.mts} +2 -2
  14. package/dist/{error-UHkqzWL7.mjs → error-Dyb89ahb.mjs} +7 -3
  15. package/dist/error-Dyb89ahb.mjs.map +1 -0
  16. package/dist/{error-DH4guike.mjs → error-QyECUDIp.mjs} +2 -2
  17. package/dist/{error-DH4guike.mjs.map → error-QyECUDIp.mjs.map} +1 -1
  18. package/dist/{event-B3ua2_oL.mjs → event-DvM1f03b.mjs} +7 -3
  19. package/dist/event-DvM1f03b.mjs.map +1 -0
  20. package/dist/{filter-B16P33dz.mjs → filter-3jOh4uLN.mjs} +50 -20
  21. package/dist/filter-3jOh4uLN.mjs.map +1 -0
  22. package/dist/{filter-PG7r79rt.d.mts → filter-oYG2zjJ3.d.mts} +6 -2
  23. package/dist/{gossip-BTMdlUI7.d.mts → gossip-BvCItMVZ.d.mts} +3 -3
  24. package/dist/{gossip-K_JIexQs.mjs → gossip-CRyhK6E6.mjs} +4 -4
  25. package/dist/{gossip-K_JIexQs.mjs.map → gossip-CRyhK6E6.mjs.map} +1 -1
  26. package/dist/gossip.d.mts +1 -1
  27. package/dist/gossip.mjs +1 -1
  28. package/dist/http-CuazNRIP.mjs.map +1 -1
  29. package/dist/{index-DD0Ywpay.d.mts → index-B2JlP2Jf.d.mts} +9 -9
  30. package/dist/{index-BP94lABY.d.mts → index-DCobP2Jj.d.mts} +10 -10
  31. package/dist/{index-Hp26bgYG.d.mts → index-Dpj_MUxb.d.mts} +8 -5
  32. package/dist/{index-rKcmI6ex.d.mts → index-DzHmhHqD.d.mts} +3 -3
  33. package/dist/{index-N7HUGgwo.d.mts → index-YID-zPDF.d.mts} +58 -8
  34. package/dist/{index-CSsnE32i.d.mts → index-muydfuYD.d.mts} +21 -21
  35. package/dist/index.d.mts +19 -20
  36. package/dist/index.mjs +20 -20
  37. package/dist/{key-k8LDEPZh.mjs → key-D_oEutQ6.mjs} +32 -9
  38. package/dist/key-D_oEutQ6.mjs.map +1 -0
  39. package/dist/{key-CyKN1RTi.d.mts → key-DojW2QZl.d.mts} +14 -4
  40. package/dist/{kind-D8fENiiL.mjs → kind-I2Tvbe82.mjs} +6 -5
  41. package/dist/kind-I2Tvbe82.mjs.map +1 -0
  42. package/dist/{loaders-Dp2nXEFk.mjs → loaders-BRh2riV9.mjs} +17 -16
  43. package/dist/loaders-BRh2riV9.mjs.map +1 -0
  44. package/dist/loaders.d.mts +2 -2
  45. package/dist/loaders.mjs +1 -1
  46. package/dist/{memory-VyPnOBU3.mjs → memory-D_GdEQYG.mjs} +2 -2
  47. package/dist/memory-D_GdEQYG.mjs.map +1 -0
  48. package/dist/memory-index-3GSrPIWj.mjs +671 -0
  49. package/dist/memory-index-3GSrPIWj.mjs.map +1 -0
  50. package/dist/{message-pYfVKxPn.mjs → message-BMfreCQc.mjs} +6 -6
  51. package/dist/message-BMfreCQc.mjs.map +1 -0
  52. package/dist/{nip17-B7MI82Iq.d.mts → nip17-BZvFQLcs.d.mts} +5 -5
  53. package/dist/{nip19-DpPN17bY.d.mts → nip19-D4RKn6GC.d.mts} +2 -2
  54. package/dist/{nip46-BHaxC9TZ.d.mts → nip46-i8L8_nIm.d.mts} +2 -2
  55. package/dist/{nip51-O_vhOiK2.d.mts → nip51-C_kTYcud.d.mts} +2 -2
  56. package/dist/{nip59-CdDoJptA.d.mts → nip59-DfJ6Moeu.d.mts} +15 -7
  57. package/dist/{nip65-BL79HI8N.d.mts → nip65-CPNE0SV0.d.mts} +2 -2
  58. package/dist/{nip77-wHA_nEV5.d.mts → nip77-DhpoL7d8.d.mts} +2 -2
  59. package/dist/nips/blossom.d.mts +2 -2
  60. package/dist/nips/blossom.mjs +3 -3
  61. package/dist/nips/blossom.mjs.map +1 -1
  62. package/dist/nips/nip04.d.mts +11 -4
  63. package/dist/nips/nip04.mjs +44 -21
  64. package/dist/nips/nip04.mjs.map +1 -1
  65. package/dist/nips/nip05.d.mts +6 -3
  66. package/dist/nips/nip05.mjs +6 -3
  67. package/dist/nips/nip05.mjs.map +1 -1
  68. package/dist/nips/nip10.d.mts +2 -2
  69. package/dist/nips/nip10.mjs +4 -4
  70. package/dist/nips/nip11.d.mts +1 -1
  71. package/dist/nips/nip11.mjs +1 -1
  72. package/dist/nips/nip13.d.mts +1 -1
  73. package/dist/nips/nip13.mjs +1 -1
  74. package/dist/nips/nip13.mjs.map +1 -1
  75. package/dist/nips/nip17.d.mts +1 -1
  76. package/dist/nips/nip17.mjs +5 -5
  77. package/dist/nips/nip17.mjs.map +1 -1
  78. package/dist/nips/nip19.d.mts +1 -1
  79. package/dist/nips/nip19.mjs +2 -2
  80. package/dist/nips/nip19.mjs.map +1 -1
  81. package/dist/nips/nip21.d.mts +6 -3
  82. package/dist/nips/nip21.mjs +8 -5
  83. package/dist/nips/nip21.mjs.map +1 -1
  84. package/dist/nips/nip27.d.mts +1 -1
  85. package/dist/nips/nip27.mjs +15 -9
  86. package/dist/nips/nip27.mjs.map +1 -1
  87. package/dist/nips/nip42.mjs +2 -2
  88. package/dist/nips/nip44.d.mts +5 -0
  89. package/dist/nips/nip44.mjs +10 -3
  90. package/dist/nips/nip44.mjs.map +1 -1
  91. package/dist/nips/nip46.d.mts +1 -1
  92. package/dist/nips/nip46.mjs +9 -7
  93. package/dist/nips/nip46.mjs.map +1 -1
  94. package/dist/nips/nip49.d.mts +8 -2
  95. package/dist/nips/nip49.mjs +17 -3
  96. package/dist/nips/nip49.mjs.map +1 -1
  97. package/dist/nips/nip51.d.mts +1 -1
  98. package/dist/nips/nip51.mjs +5 -5
  99. package/dist/nips/nip51.mjs.map +1 -1
  100. package/dist/nips/nip57.mjs +6 -5
  101. package/dist/nips/nip57.mjs.map +1 -1
  102. package/dist/nips/nip59.d.mts +1 -1
  103. package/dist/nips/nip59.mjs +51 -23
  104. package/dist/nips/nip59.mjs.map +1 -1
  105. package/dist/nips/nip65.d.mts +1 -1
  106. package/dist/nips/nip65.mjs +3 -3
  107. package/dist/nips/nip77.d.mts +1 -1
  108. package/dist/nips/nip77.mjs +1 -1
  109. package/dist/nips/nip77.mjs.map +1 -1
  110. package/dist/nips/nip98.d.mts +1 -1
  111. package/dist/nips/nip98.mjs +18 -7
  112. package/dist/nips/nip98.mjs.map +1 -1
  113. package/dist/{pool-DUuYJ0x4.d.mts → pool-MehgIIzm.d.mts} +20 -16
  114. package/dist/{pool-BMUsw2un.mjs → pool-lMT_mvzn.mjs} +25 -25
  115. package/dist/pool-lMT_mvzn.mjs.map +1 -0
  116. package/dist/{put-DRmV1wHD.mjs → put-BEM5j8xK.mjs} +5 -5
  117. package/dist/{put-DRmV1wHD.mjs.map → put-BEM5j8xK.mjs.map} +1 -1
  118. package/dist/{reactive-jyKrA9ej.d.mts → reactive-B7lPFgTS.d.mts} +3 -3
  119. package/dist/{reactive--pDpLt2H.mjs → reactive-DFHY-f00.mjs} +24 -9
  120. package/dist/reactive-DFHY-f00.mjs.map +1 -0
  121. package/dist/{relay-DXtwUEdX.mjs → relay-DIR77xQ2.mjs} +102 -89
  122. package/dist/relay-DIR77xQ2.mjs.map +1 -0
  123. package/dist/relay.d.mts +5 -5
  124. package/dist/relay.mjs +3 -3
  125. package/dist/{report-CHld4uWj.mjs → report-D2BM5dgn.mjs} +2 -2
  126. package/dist/{report-CHld4uWj.mjs.map → report-D2BM5dgn.mjs.map} +1 -1
  127. package/dist/{signer-CWtxpOxc.mjs → signer-DJcmC4nA.mjs} +176 -17
  128. package/dist/signer-DJcmC4nA.mjs.map +1 -0
  129. package/dist/signer.d.mts +2 -2
  130. package/dist/signer.mjs +3 -3
  131. package/dist/{storage-B5Wdt_Mn.mjs → storage-n2BE1bdY.mjs} +108 -179
  132. package/dist/storage-n2BE1bdY.mjs.map +1 -0
  133. package/dist/storage.d.mts +3 -3
  134. package/dist/storage.mjs +4 -4
  135. package/dist/store.d.mts +1 -1
  136. package/dist/store.mjs +1 -1
  137. package/dist/testing.d.mts +4 -4
  138. package/dist/testing.mjs +35 -10
  139. package/dist/testing.mjs.map +1 -1
  140. package/dist/{types-CqhnT-Mx.d.mts → types-DiVVyf1e.d.mts} +2 -2
  141. package/dist/{util-DDpPkiED.mjs → util-DfsyJ9nz.mjs} +30 -10
  142. package/dist/util-DfsyJ9nz.mjs.map +1 -0
  143. package/dist/{verifier-CjH1vnP2.mjs → verifier-DEHUy4AD.mjs} +3 -3
  144. package/dist/{verifier-CjH1vnP2.mjs.map → verifier-DEHUy4AD.mjs.map} +1 -1
  145. package/dist/{verifier-Cl24c9ph.d.mts → verifier-DhAbqVJF.d.mts} +2 -2
  146. package/dist/{websocket-CmeqvAkp.d.mts → websocket-DaCvJkF9.d.mts} +2 -5
  147. package/package.json +4 -3
  148. package/dist/client-CTmp5w84.mjs.map +0 -1
  149. package/dist/error-UHkqzWL7.mjs.map +0 -1
  150. package/dist/event-B3ua2_oL.mjs.map +0 -1
  151. package/dist/filter-B16P33dz.mjs.map +0 -1
  152. package/dist/key-k8LDEPZh.mjs.map +0 -1
  153. package/dist/kind-D8fENiiL.mjs.map +0 -1
  154. package/dist/loaders-Dp2nXEFk.mjs.map +0 -1
  155. package/dist/memory-VyPnOBU3.mjs.map +0 -1
  156. package/dist/memory-index-Bhwe0ZdG.mjs +0 -374
  157. package/dist/memory-index-Bhwe0ZdG.mjs.map +0 -1
  158. package/dist/message-pYfVKxPn.mjs.map +0 -1
  159. package/dist/pool-BMUsw2un.mjs.map +0 -1
  160. package/dist/reactive--pDpLt2H.mjs.map +0 -1
  161. package/dist/relay-DXtwUEdX.mjs.map +0 -1
  162. package/dist/signer-CWtxpOxc.mjs.map +0 -1
  163. package/dist/storage-B5Wdt_Mn.mjs.map +0 -1
  164. package/dist/util-DDpPkiED.mjs.map +0 -1
@@ -1,12 +1,12 @@
1
- import { d as normalizeURL, f as nowSeconds, v as MessageError, x as WasmPoisonedError, y as NostrError } from "./util-DDpPkiED.mjs";
2
- import { n as verifyEvent } from "./verifier-CjH1vnP2.mjs";
3
- import { n as canonicalizeFilters, o as matchFilters, r as filterFingerprint, t as canonicalizeFilter } from "./filter-B16P33dz.mjs";
4
- import { n as createSubscriptionId, r as encodeClientMessage, s as parseRelayMessage, t as assertSubscriptionId } from "./message-pYfVKxPn.mjs";
5
- import { t as NoSignerError } from "./error-UHkqzWL7.mjs";
1
+ import { b as MessageError, f as normalizeURL, p as nowSeconds, w as toError, x as NostrError } from "./util-DfsyJ9nz.mjs";
2
+ import { n as verifyEvent } from "./verifier-DEHUy4AD.mjs";
3
+ import { n as canonicalizeFilters, r as filterFingerprint, s as matchFilters, t as canonicalizeFilter } from "./filter-3jOh4uLN.mjs";
4
+ import { n as createSubscriptionId, r as encodeClientMessage, s as parseRelayMessage, t as assertSubscriptionId } from "./message-BMfreCQc.mjs";
5
+ import { t as NoSignerError } from "./error-Dyb89ahb.mjs";
6
6
  import { i as throwIfAborted, n as onAbort, r as raceSignal, t as abortReason } from "./abort-DBq2STPj.mjs";
7
- import { t as invokeSafely } from "./report-CHld4uWj.mjs";
7
+ import { t as invokeSafely } from "./report-D2BM5dgn.mjs";
8
8
  import { isAuthRequired, makeAuthEvent } from "./nips/nip42.mjs";
9
- import { t as Emitter } from "./emitter-DkCY6NkU.mjs";
9
+ import { t as Emitter } from "./emitter-u4kJqQDk.mjs";
10
10
  import { Nip77Error, runNegSession } from "./nips/nip77.mjs";
11
11
  //#region src/relay/error.ts
12
12
  /** Base class for relay errors; carries the relay URL when known. */
@@ -49,20 +49,6 @@ var RelaySuspendedError = class extends RelayError {
49
49
  }
50
50
  };
51
51
  //#endregion
52
- //#region src/relay/websocket.ts
53
- let impl;
54
- try {
55
- if (globalThis.WebSocket !== void 0) impl = globalThis.WebSocket;
56
- } catch {}
57
- /** Inject a WebSocket implementation (required on Node unless undici/global is present). */
58
- function useWebSocketImplementation(websocketImplementation) {
59
- impl = websocketImplementation;
60
- }
61
- function getWebSocketImplementation() {
62
- if (!impl) throw new RelayConnectionError("No WebSocket implementation available; call useWebSocketImplementation() or run in a browser");
63
- return impl;
64
- }
65
- //#endregion
66
52
  //#region src/relay/auth.ts
67
53
  var RelayAuth = class {
68
54
  #challenge;
@@ -266,7 +252,7 @@ var CountTracker = class {
266
252
  }
267
253
  #finish(waiter) {
268
254
  this.clearTimer(waiter);
269
- this.#entries.delete(waiter.id);
255
+ if (this.#entries.get(waiter.id) === waiter) this.#entries.delete(waiter.id);
270
256
  }
271
257
  };
272
258
  //#endregion
@@ -298,11 +284,11 @@ var Subscription = class {
298
284
  this.filters = filters;
299
285
  this.closeOnEose = opts.closeOnEose === true;
300
286
  this.#handlers = {
301
- onevent: opts.onevent,
302
- oneose: opts.oneose,
303
- onclose: opts.onclose,
287
+ onEvent: opts.onEvent,
288
+ onEose: opts.onEose,
289
+ onClose: opts.onClose,
304
290
  alreadyHaveEvent: opts.alreadyHaveEvent,
305
- receivedEvent: opts.receivedEvent
291
+ onEventSeen: opts.onEventSeen
306
292
  };
307
293
  if (opts.eoseTimeoutMs !== void 0) this.#eoseTimer = setTimeout(() => {
308
294
  this.#eoseTimer = void 0;
@@ -327,21 +313,21 @@ var Subscription = class {
327
313
  }
328
314
  /**
329
315
  * Local close: idempotent; clears the EOSE timer and abort listener, detaches via `onLocalClose`
330
- * (sends CLOSE / leaves the live group), then fires `onclose`.
316
+ * (sends CLOSE / leaves the live group), then fires `onClose`.
331
317
  */
332
318
  close(reason = "closed by client") {
333
319
  if (this.#closed) return;
334
320
  this.#closed = true;
335
321
  this.#teardown();
336
322
  this.#onLocalClose(this);
337
- invokeSafely(() => this.#handlers.onclose?.(reason));
323
+ invokeSafely(() => this.#handlers.onClose?.(reason));
338
324
  }
339
325
  /** Remote/transport termination: like {@link close} but `onLocalClose` is not called. */
340
326
  end(reason) {
341
327
  if (this.#closed) return;
342
328
  this.#closed = true;
343
329
  this.#teardown();
344
- invokeSafely(() => this.#handlers.onclose?.(reason));
330
+ invokeSafely(() => this.#handlers.onClose?.(reason));
345
331
  }
346
332
  #teardown() {
347
333
  if (this.#eoseTimer !== void 0) {
@@ -351,7 +337,7 @@ var Subscription = class {
351
337
  this.#abortDispose?.();
352
338
  this.#abortDispose = void 0;
353
339
  }
354
- /** Mark EOSE: fires `oneose`, then closes when `closeOnEose`. No-op when closed or EOSE'd. */
340
+ /** Mark EOSE: fires `onEose`, then closes when `closeOnEose`. No-op when closed or EOSE'd. */
355
341
  markEose() {
356
342
  if (this.#closed || this.#eosed) return;
357
343
  this.#eosed = true;
@@ -359,7 +345,7 @@ var Subscription = class {
359
345
  clearTimeout(this.#eoseTimer);
360
346
  this.#eoseTimer = void 0;
361
347
  }
362
- invokeSafely(() => this.#handlers.oneose?.());
348
+ invokeSafely(() => this.#handlers.onEose?.());
363
349
  if (this.closeOnEose) this.close("eose");
364
350
  }
365
351
  /** Clear `eosed` for a replayed REQ (AUTH retry / reconnect). */
@@ -375,9 +361,9 @@ var Subscription = class {
375
361
  resetAuthRetry() {
376
362
  this.#authRetried = false;
377
363
  }
378
- /** `receivedEvent` for every EVENT id, before watermark/alreadyHaveEvent/verify. */
364
+ /** `onEventSeen` for every EVENT id, before watermark/alreadyHaveEvent/verify. */
379
365
  notifyReceived(id) {
380
- invokeSafely(() => this.#handlers.receivedEvent?.(id));
366
+ invokeSafely(() => this.#handlers.onEventSeen?.(id));
381
367
  }
382
368
  alreadyHas(id) {
383
369
  let have = false;
@@ -389,10 +375,10 @@ var Subscription = class {
389
375
  isAtWatermark(id) {
390
376
  return this.#idsAtWatermark.has(id);
391
377
  }
392
- /** Verified event: advance the watermark, then fire `onevent`. */
378
+ /** Verified event: advance the watermark, then fire `onEvent`. */
393
379
  deliver(event) {
394
380
  this.noteVerified(event);
395
- invokeSafely(() => this.#handlers.onevent?.(event));
381
+ invokeSafely(() => this.#handlers.onEvent?.(event));
396
382
  }
397
383
  /**
398
384
  * Advance the reconnect watermark after a verified EVENT. A far-future `created_at` (buggy or
@@ -429,16 +415,17 @@ function subscriptionToAsyncIterable(start, opts) {
429
415
  let head = 0;
430
416
  let done = false;
431
417
  let error;
432
- let wake;
418
+ let waiters = [];
433
419
  let closer;
434
420
  let localClose = false;
435
421
  let disposeAbort;
436
422
  const notify = () => {
437
- wake?.();
438
- wake = void 0;
423
+ const pending = waiters;
424
+ waiters = [];
425
+ for (const wake of pending) wake();
439
426
  };
440
427
  const waitForWake = async () => new Promise((resolve) => {
441
- wake = resolve;
428
+ waiters.push(resolve);
442
429
  });
443
430
  const closeLocal = (reason) => {
444
431
  localClose = true;
@@ -448,14 +435,11 @@ function subscriptionToAsyncIterable(start, opts) {
448
435
  notify();
449
436
  };
450
437
  closer = start({
451
- onevent(event) {
438
+ onEvent(event) {
452
439
  queue.push(event);
453
440
  notify();
454
441
  },
455
- oneose() {
456
- if (opts?.includeEose === false) closeLocal("eose");
457
- },
458
- onclose(reason) {
442
+ onClose(reason) {
459
443
  if (opts?.signal?.aborted === true) localClose = true;
460
444
  if (!localClose && reason) error = new RelayClosedError(reason);
461
445
  done = true;
@@ -524,6 +508,9 @@ async function fetchFilters(subscribe, filters, opts) {
524
508
  let end = { type: "timeout" };
525
509
  await new Promise((resolve, reject) => {
526
510
  let settled = false;
511
+ let timer;
512
+ let sub;
513
+ let pendingCloseReason = "fetch complete";
527
514
  const done = (err) => {
528
515
  if (settled) return;
529
516
  settled = true;
@@ -532,43 +519,54 @@ async function fetchFilters(subscribe, filters, opts) {
532
519
  let reason = "aborted";
533
520
  if (err instanceof Error) reason = err.message;
534
521
  else if (err === void 0) reason = "fetch complete";
535
- sub.close(reason);
522
+ pendingCloseReason = reason;
523
+ sub?.close(reason);
536
524
  if (err === void 0) resolve();
537
525
  else reject(err);
538
526
  };
539
527
  const disposeAbort = onAbort(opts.signal, () => {
540
528
  if (opts.signal !== void 0) done(abortReason(opts.signal));
541
529
  });
542
- const timer = setTimeout(() => {
530
+ try {
531
+ sub = subscribe(filters, {
532
+ id: opts.id,
533
+ signal: opts.signal,
534
+ closeOnEose: true,
535
+ onEvent(event) {
536
+ if (seen.has(event.id)) return;
537
+ seen.add(event.id);
538
+ events.push(event);
539
+ },
540
+ onEose() {
541
+ end = { type: "eose" };
542
+ done();
543
+ },
544
+ onClose(reason) {
545
+ if (settled) return;
546
+ if (opts.signal?.aborted === true) {
547
+ done(abortReason(opts.signal));
548
+ return;
549
+ }
550
+ end = {
551
+ type: "closed",
552
+ reason
553
+ };
554
+ done();
555
+ }
556
+ });
557
+ } catch (error) {
558
+ disposeAbort();
559
+ reject(error);
560
+ return;
561
+ }
562
+ if (settled) {
563
+ sub.close(pendingCloseReason);
564
+ return;
565
+ }
566
+ timer = setTimeout(() => {
543
567
  end = { type: "timeout" };
544
568
  done();
545
569
  }, opts.timeoutMs);
546
- const sub = subscribe(filters, {
547
- id: opts.id,
548
- signal: opts.signal,
549
- closeOnEose: true,
550
- onevent(event) {
551
- if (seen.has(event.id)) return;
552
- seen.add(event.id);
553
- events.push(event);
554
- },
555
- oneose() {
556
- end = { type: "eose" };
557
- done();
558
- },
559
- onclose(reason) {
560
- if (settled) return;
561
- if (opts.signal?.aborted === true) {
562
- done(abortReason(opts.signal));
563
- return;
564
- }
565
- end = {
566
- type: "closed",
567
- reason
568
- };
569
- done();
570
- }
571
- });
572
570
  });
573
571
  return {
574
572
  events,
@@ -1086,25 +1084,32 @@ var SubscriptionRegistry = class {
1086
1084
  return true;
1087
1085
  }
1088
1086
  closeAll(reason) {
1089
- const groups = [...this.#liveBySubId.values()];
1087
+ const subs = [...this.#subs.values()];
1088
+ const groups = /* @__PURE__ */ new Set();
1089
+ for (const sub of subs) {
1090
+ const group = this.#liveBySubId.get(sub.id);
1091
+ if (group !== void 0) groups.add(group);
1092
+ }
1090
1093
  for (const group of groups) invokeSafely(() => {
1091
1094
  this.#endLiveGroup(group, {
1092
1095
  sendClose: false,
1093
1096
  reason
1094
1097
  });
1095
1098
  });
1096
- for (const sub of this.#subs.values()) sub.end(reason);
1097
- this.#subs.clear();
1098
- this.#liveByFp.clear();
1099
- this.#liveBySubId.clear();
1099
+ for (const sub of subs) {
1100
+ if (this.#subs.get(sub.id) === sub) this.#subs.delete(sub.id);
1101
+ sub.end(reason);
1102
+ }
1100
1103
  }
1101
1104
  #openExclusive(filters, opts) {
1102
1105
  const sub = new Subscription(filters, opts, (closed) => {
1106
+ if (this.#subs.get(closed.id) !== closed) return;
1103
1107
  this.#subs.delete(closed.id);
1104
1108
  try {
1105
1109
  if (this.#isOpen()) this.#send(["CLOSE", closed.id]);
1106
1110
  } catch {}
1107
1111
  });
1112
+ if (sub.closed) return sub;
1108
1113
  this.#subs.set(sub.id, sub);
1109
1114
  if (this.#isOpen()) this.#send([
1110
1115
  "REQ",
@@ -1167,8 +1172,8 @@ var SubscriptionRegistry = class {
1167
1172
  }
1168
1173
  #forgetLiveGroup(group, reason) {
1169
1174
  if (this.#liveByFp.get(group.fp) === group) this.#liveByFp.delete(group.fp);
1170
- this.#liveBySubId.delete(group.sub.id);
1171
- this.#subs.delete(group.sub.id);
1175
+ if (this.#liveBySubId.get(group.sub.id) === group) this.#liveBySubId.delete(group.sub.id);
1176
+ if (this.#subs.get(group.sub.id) === group.sub) this.#subs.delete(group.sub.id);
1172
1177
  group.sub.end(reason);
1173
1178
  }
1174
1179
  #detachLive(group, handle) {
@@ -1194,7 +1199,10 @@ var SubscriptionRegistry = class {
1194
1199
  #deliverLiveEvent(group, event) {
1195
1200
  const { sub } = group;
1196
1201
  const attachments = [...group.attachments];
1197
- for (const att of attachments) att.notifyReceived(event.id);
1202
+ for (const att of attachments) {
1203
+ if (att.closed) continue;
1204
+ att.notifyReceived(event.id);
1205
+ }
1198
1206
  if (sub.isAtWatermark(event.id)) return;
1199
1207
  const recipients = [];
1200
1208
  for (const att of attachments) {
@@ -1280,7 +1288,9 @@ var Relay = class Relay {
1280
1288
  #events = new Emitter();
1281
1289
  constructor(url, opts = {}) {
1282
1290
  this.url = normalizeURL(url);
1283
- this.#WS = opts.websocketImplementation ?? getWebSocketImplementation();
1291
+ const wsImpl = opts.websocketImplementation ?? globalThis.WebSocket;
1292
+ if (wsImpl === void 0) throw new RelayConnectionError("no WebSocket implementation; pass websocketImplementation");
1293
+ this.#WS = wsImpl;
1284
1294
  this.#verify = opts.verifyEvent ?? verifyEvent;
1285
1295
  this.#publishTimeoutMs = opts.publishTimeoutMs ?? 4400;
1286
1296
  this.#connectTimeoutMs = opts.connectTimeoutMs ?? 5e3;
@@ -1694,9 +1704,14 @@ var Relay = class Relay {
1694
1704
  subscribe(filters, opts = {}) {
1695
1705
  if (filters.length === 0) throw new MessageError("REQ requires at least one filter");
1696
1706
  if (!this.#isOpen() && !this.#enableReconnect) throw new RelayClosedError("not connected", this.url);
1707
+ if (opts.id !== void 0) this.#assertWireIdFree(assertSubscriptionId(opts.id));
1697
1708
  const canonical = canonicalizeFilters(filters);
1698
1709
  return this.#subscriptions.open(canonical, opts);
1699
1710
  }
1711
+ /** Caller-chosen ids must not shadow an in-flight REQ or COUNT on this relay. */
1712
+ #assertWireIdFree(id) {
1713
+ if (this.#subscriptions.get(id) !== void 0 || this.#countRequests.get(id) !== void 0) throw new MessageError(`duplicate subscription id: ${id}`);
1714
+ }
1700
1715
  #acceptEvent(event) {
1701
1716
  if (this.#verifyDead) return false;
1702
1717
  try {
@@ -1704,12 +1719,9 @@ var Relay = class Relay {
1704
1719
  if (!ok) this.#events.emit("invalidevent", void 0);
1705
1720
  return ok;
1706
1721
  } catch (error) {
1707
- if (error instanceof WasmPoisonedError) {
1708
- this.#verifyDead = true;
1709
- this.#events.emit("notice", "wasm-poisoned: instance aborted");
1710
- return false;
1711
- }
1712
- throw error;
1722
+ this.#verifyDead = true;
1723
+ this.#events.emit("verifiererror", toError(error));
1724
+ return false;
1713
1725
  }
1714
1726
  }
1715
1727
  /** AsyncIterable of events for filters until the subscription is closed. */
@@ -1758,6 +1770,7 @@ var Relay = class Relay {
1758
1770
  throwIfAborted(opts?.signal);
1759
1771
  const canonical = canonicalizeFilters(filters);
1760
1772
  const id = opts?.id === void 0 ? this.nextSubId("count") : createSubscriptionId(opts.id);
1773
+ if (opts?.id !== void 0) this.#assertWireIdFree(id);
1761
1774
  const timeoutMs = opts?.timeoutMs ?? this.#publishTimeoutMs;
1762
1775
  return this.#countRequests.track(id, {
1763
1776
  timeoutMs,
@@ -1814,6 +1827,6 @@ var Relay = class Relay {
1814
1827
  }
1815
1828
  };
1816
1829
  //#endregion
1817
- export { getWebSocketImplementation as a, RelayConnectionError as c, RelaySuspendedError as d, RelayTimeoutError as f, subscriptionToAsyncIterable as i, RelayError as l, Relay as n, useWebSocketImplementation as o, RelayStatus as r, RelayClosedError as s, DEFAULT_REQUEST_TIMEOUT_MS as t, RelayPublishError as u };
1830
+ export { RelayClosedError as a, RelayPublishError as c, subscriptionToAsyncIterable as i, RelaySuspendedError as l, Relay as n, RelayConnectionError as o, RelayStatus as r, RelayError as s, DEFAULT_REQUEST_TIMEOUT_MS as t, RelayTimeoutError as u };
1818
1831
 
1819
- //# sourceMappingURL=relay-DXtwUEdX.mjs.map
1832
+ //# sourceMappingURL=relay-DIR77xQ2.mjs.map