nostr-tools 2.19.4 → 2.21.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 (127) hide show
  1. package/lib/cjs/abstract-pool.js +32 -21
  2. package/lib/cjs/abstract-pool.js.map +2 -2
  3. package/lib/cjs/abstract-relay.js +22 -15
  4. package/lib/cjs/abstract-relay.js.map +2 -2
  5. package/lib/cjs/index.js +67 -56
  6. package/lib/cjs/index.js.map +3 -3
  7. package/lib/cjs/nip04.js +8 -8
  8. package/lib/cjs/nip04.js.map +2 -2
  9. package/lib/cjs/nip06.js +2 -2
  10. package/lib/cjs/nip06.js.map +1 -1
  11. package/lib/cjs/nip13.js +4 -4
  12. package/lib/cjs/nip13.js.map +2 -2
  13. package/lib/cjs/nip17.js +19 -19
  14. package/lib/cjs/nip17.js.map +3 -3
  15. package/lib/cjs/nip18.js +8 -8
  16. package/lib/cjs/nip18.js.map +2 -2
  17. package/lib/cjs/nip19.js +2 -2
  18. package/lib/cjs/nip19.js.map +2 -2
  19. package/lib/cjs/nip21.js +2 -2
  20. package/lib/cjs/nip21.js.map +2 -2
  21. package/lib/cjs/nip25.js +8 -8
  22. package/lib/cjs/nip25.js.map +2 -2
  23. package/lib/cjs/nip27.js +2 -2
  24. package/lib/cjs/nip27.js.map +2 -2
  25. package/lib/cjs/nip28.js +8 -8
  26. package/lib/cjs/nip28.js.map +2 -2
  27. package/lib/cjs/nip29.js +2 -2
  28. package/lib/cjs/nip29.js.map +2 -2
  29. package/lib/cjs/nip44.js +12 -12
  30. package/lib/cjs/nip44.js.map +2 -2
  31. package/lib/cjs/nip46.js +104 -115
  32. package/lib/cjs/nip46.js.map +3 -3
  33. package/lib/cjs/nip47.js +13 -13
  34. package/lib/cjs/nip47.js.map +2 -2
  35. package/lib/cjs/nip49.js +5 -5
  36. package/lib/cjs/nip49.js.map +3 -3
  37. package/lib/cjs/nip57.js +8 -8
  38. package/lib/cjs/nip57.js.map +2 -2
  39. package/lib/cjs/nip59.js +19 -19
  40. package/lib/cjs/nip59.js.map +3 -3
  41. package/lib/cjs/nip77.js +3 -3
  42. package/lib/cjs/nip77.js.map +2 -2
  43. package/lib/cjs/nip98.js +11 -11
  44. package/lib/cjs/nip98.js.map +3 -3
  45. package/lib/cjs/nipb7.js +3 -3
  46. package/lib/cjs/nipb7.js.map +2 -2
  47. package/lib/cjs/pool.js +39 -28
  48. package/lib/cjs/pool.js.map +2 -2
  49. package/lib/cjs/pure.js +8 -8
  50. package/lib/cjs/pure.js.map +2 -2
  51. package/lib/cjs/references.js +2 -2
  52. package/lib/cjs/references.js.map +2 -2
  53. package/lib/cjs/relay.js +29 -22
  54. package/lib/cjs/relay.js.map +2 -2
  55. package/lib/cjs/signer.js +8 -8
  56. package/lib/cjs/signer.js.map +2 -2
  57. package/lib/cjs/utils.js +1 -1
  58. package/lib/cjs/utils.js.map +1 -1
  59. package/lib/cjs/wasm.js +1 -1
  60. package/lib/cjs/wasm.js.map +1 -1
  61. package/lib/esm/abstract-pool.js +32 -21
  62. package/lib/esm/abstract-pool.js.map +2 -2
  63. package/lib/esm/abstract-relay.js +22 -15
  64. package/lib/esm/abstract-relay.js.map +2 -2
  65. package/lib/esm/index.js +77 -66
  66. package/lib/esm/index.js.map +3 -3
  67. package/lib/esm/nip04.js +8 -8
  68. package/lib/esm/nip04.js.map +3 -3
  69. package/lib/esm/nip06.js +2 -2
  70. package/lib/esm/nip06.js.map +1 -1
  71. package/lib/esm/nip13.js +3 -3
  72. package/lib/esm/nip13.js.map +1 -1
  73. package/lib/esm/nip17.js +16 -16
  74. package/lib/esm/nip17.js.map +3 -3
  75. package/lib/esm/nip18.js +7 -7
  76. package/lib/esm/nip18.js.map +3 -3
  77. package/lib/esm/nip19.js +2 -2
  78. package/lib/esm/nip19.js.map +2 -2
  79. package/lib/esm/nip21.js +2 -2
  80. package/lib/esm/nip21.js.map +2 -2
  81. package/lib/esm/nip25.js +7 -7
  82. package/lib/esm/nip25.js.map +3 -3
  83. package/lib/esm/nip27.js +2 -2
  84. package/lib/esm/nip27.js.map +2 -2
  85. package/lib/esm/nip28.js +7 -7
  86. package/lib/esm/nip28.js.map +3 -3
  87. package/lib/esm/nip29.js +2 -2
  88. package/lib/esm/nip29.js.map +2 -2
  89. package/lib/esm/nip44.js +10 -10
  90. package/lib/esm/nip44.js.map +3 -3
  91. package/lib/esm/nip46.js +101 -112
  92. package/lib/esm/nip46.js.map +3 -3
  93. package/lib/esm/nip47.js +12 -12
  94. package/lib/esm/nip47.js.map +3 -3
  95. package/lib/esm/nip49.js +5 -5
  96. package/lib/esm/nip49.js.map +3 -3
  97. package/lib/esm/nip57.js +7 -7
  98. package/lib/esm/nip57.js.map +3 -3
  99. package/lib/esm/nip59.js +16 -16
  100. package/lib/esm/nip59.js.map +3 -3
  101. package/lib/esm/nip77.js +2 -2
  102. package/lib/esm/nip77.js.map +1 -1
  103. package/lib/esm/nip98.js +9 -9
  104. package/lib/esm/nip98.js.map +3 -3
  105. package/lib/esm/nipb7.js +2 -2
  106. package/lib/esm/nipb7.js.map +1 -1
  107. package/lib/esm/pool.js +38 -27
  108. package/lib/esm/pool.js.map +3 -3
  109. package/lib/esm/pure.js +7 -7
  110. package/lib/esm/pure.js.map +3 -3
  111. package/lib/esm/references.js +2 -2
  112. package/lib/esm/references.js.map +2 -2
  113. package/lib/esm/relay.js +28 -21
  114. package/lib/esm/relay.js.map +3 -3
  115. package/lib/esm/signer.js +7 -7
  116. package/lib/esm/signer.js.map +3 -3
  117. package/lib/esm/utils.js +1 -1
  118. package/lib/esm/utils.js.map +1 -1
  119. package/lib/esm/wasm.js +1 -1
  120. package/lib/esm/wasm.js.map +1 -1
  121. package/lib/nostr.bundle.js +2864 -2379
  122. package/lib/nostr.bundle.js.map +4 -4
  123. package/lib/types/abstract-pool.d.ts +2 -0
  124. package/lib/types/abstract-relay.d.ts +6 -4
  125. package/lib/types/nip46.d.ts +2 -15
  126. package/lib/types/utils.d.ts +1 -1
  127. package/package.json +7 -7
@@ -28,7 +28,7 @@ module.exports = __toCommonJS(abstract_pool_exports);
28
28
  var verifiedSymbol = Symbol("verified");
29
29
 
30
30
  // utils.ts
31
- var import_utils = require("@noble/hashes/utils");
31
+ var import_utils = require("@noble/hashes/utils.js");
32
32
  var utf8Decoder = new TextDecoder("utf-8");
33
33
  var utf8Encoder = new TextEncoder();
34
34
  function normalizeURL(url) {
@@ -220,7 +220,6 @@ var AbstractRelay = class {
220
220
  onnotice = (msg) => console.debug(`NOTICE from ${this.url}: ${msg}`);
221
221
  onauth;
222
222
  baseEoseTimeout = 4400;
223
- connectionTimeout = 4400;
224
223
  publishTimeout = 4400;
225
224
  pingFrequency = 29e3;
226
225
  pingTimeout = 2e4;
@@ -228,7 +227,6 @@ var AbstractRelay = class {
228
227
  openSubs = /* @__PURE__ */ new Map();
229
228
  enablePing;
230
229
  enableReconnect;
231
- connectionTimeoutHandle;
232
230
  reconnectTimeoutHandle;
233
231
  pingIntervalHandle;
234
232
  reconnectAttempts = 0;
@@ -253,7 +251,7 @@ var AbstractRelay = class {
253
251
  }
254
252
  static async connect(url, opts) {
255
253
  const relay = new AbstractRelay(url, opts);
256
- await relay.connect();
254
+ await relay.connect(opts);
257
255
  return relay;
258
256
  }
259
257
  closeAllSubscriptions(reason) {
@@ -299,22 +297,28 @@ var AbstractRelay = class {
299
297
  this.closeAllSubscriptions(reason);
300
298
  }
301
299
  }
302
- async connect() {
300
+ async connect(opts) {
301
+ let connectionTimeoutHandle;
303
302
  if (this.connectionPromise)
304
303
  return this.connectionPromise;
305
304
  this.challenge = void 0;
306
305
  this.authPromise = void 0;
307
306
  this.connectionPromise = new Promise((resolve, reject) => {
308
- this.connectionTimeoutHandle = setTimeout(() => {
309
- reject("connection timed out");
310
- this.connectionPromise = void 0;
311
- this.onclose?.();
312
- this.closeAllSubscriptions("relay connection timed out");
313
- }, this.connectionTimeout);
307
+ if (opts?.timeout) {
308
+ connectionTimeoutHandle = setTimeout(() => {
309
+ reject("connection timed out");
310
+ this.connectionPromise = void 0;
311
+ this.onclose?.();
312
+ this.closeAllSubscriptions("relay connection timed out");
313
+ }, opts.timeout);
314
+ }
315
+ if (opts?.abort) {
316
+ opts.abort.onabort = reject;
317
+ }
314
318
  try {
315
319
  this.ws = new this._WebSocket(this.url);
316
320
  } catch (err) {
317
- clearTimeout(this.connectionTimeoutHandle);
321
+ clearTimeout(connectionTimeoutHandle);
318
322
  reject(err);
319
323
  return;
320
324
  }
@@ -323,7 +327,7 @@ var AbstractRelay = class {
323
327
  clearTimeout(this.reconnectTimeoutHandle);
324
328
  this.reconnectTimeoutHandle = void 0;
325
329
  }
326
- clearTimeout(this.connectionTimeoutHandle);
330
+ clearTimeout(connectionTimeoutHandle);
327
331
  this._connected = true;
328
332
  const isReconnection = this.reconnectAttempts > 0;
329
333
  this.reconnectAttempts = 0;
@@ -344,12 +348,12 @@ var AbstractRelay = class {
344
348
  resolve();
345
349
  };
346
350
  this.ws.onerror = (ev) => {
347
- clearTimeout(this.connectionTimeoutHandle);
351
+ clearTimeout(connectionTimeoutHandle);
348
352
  reject(ev.message || "websocket error");
349
353
  this.handleHardClose("relay connection errored");
350
354
  };
351
355
  this.ws.onclose = (ev) => {
352
- clearTimeout(this.connectionTimeoutHandle);
356
+ clearTimeout(connectionTimeoutHandle);
353
357
  reject(ev.message || "websocket closed");
354
358
  this.handleHardClose("relay connection closed");
355
359
  };
@@ -561,6 +565,9 @@ var AbstractRelay = class {
561
565
  subscribe(filters, params) {
562
566
  const sub = this.prepareSubscription(filters, params);
563
567
  sub.fire();
568
+ if (params.abort) {
569
+ params.abort.onabort = () => sub.close(String(params.abort.reason || "<aborted>"));
570
+ }
564
571
  return sub;
565
572
  }
566
573
  prepareSubscription(filters, params) {
@@ -688,8 +695,6 @@ var AbstractSimplePool = class {
688
695
  this.relays.delete(url);
689
696
  }
690
697
  };
691
- if (params?.connectionTimeout)
692
- relay.connectionTimeout = params.connectionTimeout;
693
698
  this.relays.set(url, relay);
694
699
  }
695
700
  if (this.automaticallyAuth) {
@@ -698,7 +703,10 @@ var AbstractSimplePool = class {
698
703
  relay.onauth = authSignerFn;
699
704
  }
700
705
  }
701
- await relay.connect();
706
+ await relay.connect({
707
+ timeout: params?.connectionTimeout,
708
+ abort: params?.abort
709
+ });
702
710
  return relay;
703
711
  }
704
712
  close(relays) {
@@ -786,7 +794,8 @@ var AbstractSimplePool = class {
786
794
  let relay;
787
795
  try {
788
796
  relay = await this.ensureRelay(url, {
789
- connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1e3) : void 0
797
+ connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1e3) : void 0,
798
+ abort: params.abort
790
799
  });
791
800
  } catch (err) {
792
801
  handleClose(i, err?.message || String(err));
@@ -805,7 +814,8 @@ var AbstractSimplePool = class {
805
814
  handleClose(i, reason2);
806
815
  },
807
816
  alreadyHaveEvent: localAlreadyHaveEventHandler,
808
- eoseTimeout: params.maxWait
817
+ eoseTimeout: params.maxWait,
818
+ abort: params.abort
809
819
  });
810
820
  }).catch((err) => {
811
821
  handleClose(i, `auth was required and attempted, but failed with: ${err}`);
@@ -815,7 +825,8 @@ var AbstractSimplePool = class {
815
825
  }
816
826
  },
817
827
  alreadyHaveEvent: localAlreadyHaveEventHandler,
818
- eoseTimeout: params.maxWait
828
+ eoseTimeout: params.maxWait,
829
+ abort: params.abort
819
830
  });
820
831
  subs.push(subscription);
821
832
  })
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../abstract-pool.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts", "../../filter.ts", "../../fakejson.ts", "../../nip42.ts", "../../helpers.ts", "../../abstract-relay.ts"],
4
- "sourcesContent": ["/* global WebSocket */\n\nimport {\n AbstractRelay as AbstractRelay,\n SubscriptionParams,\n Subscription,\n type AbstractRelayConstructorOptions,\n} from './abstract-relay.ts'\nimport { normalizeURL } from './utils.ts'\n\nimport type { Event, EventTemplate, Nostr, VerifiedEvent } from './core.ts'\nimport { type Filter } from './filter.ts'\nimport { alwaysTrue } from './helpers.ts'\n\nexport type SubCloser = { close: (reason?: string) => void }\n\nexport type AbstractPoolConstructorOptions = AbstractRelayConstructorOptions & {\n // automaticallyAuth takes a relay URL and should return null\n // in case that relay shouldn't be authenticated against\n // or a function to sign the AUTH event template otherwise (that function may still throw in case of failure)\n automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n}\n\nexport type SubscribeManyParams = Omit<SubscriptionParams, 'onclose'> & {\n maxWait?: number\n onclose?: (reasons: string[]) => void\n onauth?: (event: EventTemplate) => Promise<VerifiedEvent>\n id?: string\n label?: string\n}\n\nexport class AbstractSimplePool {\n protected relays: Map<string, AbstractRelay> = new Map()\n public seenOn: Map<string, Set<AbstractRelay>> = new Map()\n public trackRelays: boolean = false\n\n public verifyEvent: Nostr['verifyEvent']\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n public automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n public trustedRelayURLs: Set<string> = new Set()\n\n private _WebSocket?: typeof WebSocket\n\n constructor(opts: AbstractPoolConstructorOptions) {\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n this.automaticallyAuth = opts.automaticallyAuth\n }\n\n async ensureRelay(url: string, params?: { connectionTimeout?: number }): Promise<AbstractRelay> {\n url = normalizeURL(url)\n\n let relay = this.relays.get(url)\n if (!relay) {\n relay = new AbstractRelay(url, {\n verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,\n websocketImplementation: this._WebSocket,\n enablePing: this.enablePing,\n enableReconnect: this.enableReconnect,\n })\n relay.onclose = () => {\n if (relay && !relay.enableReconnect) {\n this.relays.delete(url)\n }\n }\n if (params?.connectionTimeout) relay.connectionTimeout = params.connectionTimeout\n this.relays.set(url, relay)\n }\n\n if (this.automaticallyAuth) {\n const authSignerFn = this.automaticallyAuth(url)\n if (authSignerFn) {\n relay.onauth = authSignerFn\n }\n }\n\n await relay.connect()\n\n return relay\n }\n\n close(relays: string[]) {\n relays.map(normalizeURL).forEach(url => {\n this.relays.get(url)?.close()\n this.relays.delete(url)\n })\n }\n\n subscribe(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (!request.find(r => r.url === url)) {\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMany(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n const uniqUrls: string[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (uniqUrls.indexOf(url) === -1) {\n uniqUrls.push(url)\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMap(requests: { url: string; filter: Filter }[], params: SubscribeManyParams): SubCloser {\n const grouped = new Map<string, Filter[]>()\n for (const req of requests) {\n const { url, filter } = req\n if (!grouped.has(url)) grouped.set(url, [])\n grouped.get(url)!.push(filter)\n }\n const groupedRequests = Array.from(grouped.entries()).map(([url, filters]) => ({ url, filters }))\n\n if (this.trackRelays) {\n params.receivedEvent = (relay: AbstractRelay, id: string) => {\n let set = this.seenOn.get(id)\n if (!set) {\n set = new Set()\n this.seenOn.set(id, set)\n }\n set.add(relay)\n }\n }\n\n const _knownIds = new Set<string>()\n const subs: Subscription[] = []\n\n // batch all EOSEs into a single\n const eosesReceived: boolean[] = []\n let handleEose = (i: number) => {\n if (eosesReceived[i]) return // do not act twice for the same relay\n eosesReceived[i] = true\n if (eosesReceived.filter(a => a).length === groupedRequests.length) {\n params.oneose?.()\n handleEose = () => {}\n }\n }\n // batch all closes into a single\n const closesReceived: string[] = []\n let handleClose = (i: number, reason: string) => {\n if (closesReceived[i]) return // do not act twice for the same relay\n handleEose(i)\n closesReceived[i] = reason\n if (closesReceived.filter(a => a).length === groupedRequests.length) {\n params.onclose?.(closesReceived)\n handleClose = () => {}\n }\n }\n\n const localAlreadyHaveEventHandler = (id: string) => {\n if (params.alreadyHaveEvent?.(id)) {\n return true\n }\n const have = _knownIds.has(id)\n _knownIds.add(id)\n return have\n }\n\n // open a subscription in all given relays\n const allOpened = Promise.all(\n groupedRequests.map(async ({ url, filters }, i) => {\n let relay: AbstractRelay\n try {\n relay = await this.ensureRelay(url, {\n connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1000) : undefined,\n })\n } catch (err) {\n handleClose(i, (err as any)?.message || String(err))\n return\n }\n\n let subscription = relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n if (reason.startsWith('auth-required: ') && params.onauth) {\n relay\n .auth(params.onauth)\n .then(() => {\n relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n handleClose(i, reason) // the second time we won't try to auth anymore\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n })\n })\n .catch(err => {\n handleClose(i, `auth was required and attempted, but failed with: ${err}`)\n })\n } else {\n handleClose(i, reason)\n }\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n })\n\n subs.push(subscription)\n }),\n )\n\n return {\n async close(reason?: string) {\n await allOpened\n subs.forEach(sub => {\n sub.close(reason)\n })\n },\n }\n }\n\n subscribeEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribe(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n subscribeManyEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribeMany(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n async querySync(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event[]> {\n return new Promise(async resolve => {\n const events: Event[] = []\n this.subscribeEose(relays, filter, {\n ...params,\n onevent(event: Event) {\n events.push(event)\n },\n onclose(_: string[]) {\n resolve(events)\n },\n })\n })\n }\n\n async get(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event | null> {\n filter.limit = 1\n const events = await this.querySync(relays, filter, params)\n events.sort((a, b) => b.created_at - a.created_at)\n return events[0] || null\n }\n\n publish(\n relays: string[],\n event: Event,\n options?: { onauth?: (evt: EventTemplate) => Promise<VerifiedEvent> },\n ): Promise<string>[] {\n return relays.map(normalizeURL).map(async (url, i, arr) => {\n if (arr.indexOf(url) !== i) {\n // duplicate\n return Promise.reject('duplicate url')\n }\n\n let r = await this.ensureRelay(url)\n return r\n .publish(event)\n .catch(async err => {\n if (err instanceof Error && err.message.startsWith('auth-required: ') && options?.onauth) {\n await r.auth(options.onauth)\n return r.publish(event) // retry\n }\n throw err\n })\n .then(reason => {\n if (this.trackRelays) {\n let set = this.seenOn.get(event.id)\n if (!set) {\n set = new Set()\n this.seenOn.set(event.id, set)\n }\n set.add(r)\n }\n return reason\n })\n })\n }\n\n listConnectionStatus(): Map<string, boolean> {\n const map = new Map<string, boolean>()\n this.relays.forEach((relay, url) => map.set(url, relay.connected))\n\n return map\n }\n\n destroy(): void {\n this.relays.forEach(conn => conn.close())\n this.relays = new Map()\n }\n}\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public connectionTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(url: string, opts: AbstractRelayConstructorOptions): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect()\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(): Promise<void> {\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n this.connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, this.connectionTimeout)\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(this.connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(this.connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(this.connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(this.connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/* global WebSocket */\n\nimport {\n AbstractRelay as AbstractRelay,\n SubscriptionParams,\n Subscription,\n type AbstractRelayConstructorOptions,\n} from './abstract-relay.ts'\nimport { normalizeURL } from './utils.ts'\n\nimport type { Event, EventTemplate, Nostr, VerifiedEvent } from './core.ts'\nimport { type Filter } from './filter.ts'\nimport { alwaysTrue } from './helpers.ts'\n\nexport type SubCloser = { close: (reason?: string) => void }\n\nexport type AbstractPoolConstructorOptions = AbstractRelayConstructorOptions & {\n // automaticallyAuth takes a relay URL and should return null\n // in case that relay shouldn't be authenticated against\n // or a function to sign the AUTH event template otherwise (that function may still throw in case of failure)\n automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n}\n\nexport type SubscribeManyParams = Omit<SubscriptionParams, 'onclose'> & {\n maxWait?: number\n abort?: AbortSignal\n onclose?: (reasons: string[]) => void\n onauth?: (event: EventTemplate) => Promise<VerifiedEvent>\n id?: string\n label?: string\n}\n\nexport class AbstractSimplePool {\n protected relays: Map<string, AbstractRelay> = new Map()\n public seenOn: Map<string, Set<AbstractRelay>> = new Map()\n public trackRelays: boolean = false\n\n public verifyEvent: Nostr['verifyEvent']\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n public automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n public trustedRelayURLs: Set<string> = new Set()\n\n private _WebSocket?: typeof WebSocket\n\n constructor(opts: AbstractPoolConstructorOptions) {\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n this.automaticallyAuth = opts.automaticallyAuth\n }\n\n async ensureRelay(\n url: string,\n params?: {\n connectionTimeout?: number\n abort?: AbortSignal\n },\n ): Promise<AbstractRelay> {\n url = normalizeURL(url)\n\n let relay = this.relays.get(url)\n if (!relay) {\n relay = new AbstractRelay(url, {\n verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,\n websocketImplementation: this._WebSocket,\n enablePing: this.enablePing,\n enableReconnect: this.enableReconnect,\n })\n relay.onclose = () => {\n if (relay && !relay.enableReconnect) {\n this.relays.delete(url)\n }\n }\n this.relays.set(url, relay)\n }\n\n if (this.automaticallyAuth) {\n const authSignerFn = this.automaticallyAuth(url)\n if (authSignerFn) {\n relay.onauth = authSignerFn\n }\n }\n\n await relay.connect({\n timeout: params?.connectionTimeout,\n abort: params?.abort,\n })\n\n return relay\n }\n\n close(relays: string[]) {\n relays.map(normalizeURL).forEach(url => {\n this.relays.get(url)?.close()\n this.relays.delete(url)\n })\n }\n\n subscribe(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (!request.find(r => r.url === url)) {\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMany(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n const uniqUrls: string[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (uniqUrls.indexOf(url) === -1) {\n uniqUrls.push(url)\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMap(requests: { url: string; filter: Filter }[], params: SubscribeManyParams): SubCloser {\n const grouped = new Map<string, Filter[]>()\n for (const req of requests) {\n const { url, filter } = req\n if (!grouped.has(url)) grouped.set(url, [])\n grouped.get(url)!.push(filter)\n }\n const groupedRequests = Array.from(grouped.entries()).map(([url, filters]) => ({ url, filters }))\n\n if (this.trackRelays) {\n params.receivedEvent = (relay: AbstractRelay, id: string) => {\n let set = this.seenOn.get(id)\n if (!set) {\n set = new Set()\n this.seenOn.set(id, set)\n }\n set.add(relay)\n }\n }\n\n const _knownIds = new Set<string>()\n const subs: Subscription[] = []\n\n // batch all EOSEs into a single\n const eosesReceived: boolean[] = []\n let handleEose = (i: number) => {\n if (eosesReceived[i]) return // do not act twice for the same relay\n eosesReceived[i] = true\n if (eosesReceived.filter(a => a).length === groupedRequests.length) {\n params.oneose?.()\n handleEose = () => {}\n }\n }\n // batch all closes into a single\n const closesReceived: string[] = []\n let handleClose = (i: number, reason: string) => {\n if (closesReceived[i]) return // do not act twice for the same relay\n handleEose(i)\n closesReceived[i] = reason\n if (closesReceived.filter(a => a).length === groupedRequests.length) {\n params.onclose?.(closesReceived)\n handleClose = () => {}\n }\n }\n\n const localAlreadyHaveEventHandler = (id: string) => {\n if (params.alreadyHaveEvent?.(id)) {\n return true\n }\n const have = _knownIds.has(id)\n _knownIds.add(id)\n return have\n }\n\n // open a subscription in all given relays\n const allOpened = Promise.all(\n groupedRequests.map(async ({ url, filters }, i) => {\n let relay: AbstractRelay\n try {\n relay = await this.ensureRelay(url, {\n connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1000) : undefined,\n abort: params.abort,\n })\n } catch (err) {\n handleClose(i, (err as any)?.message || String(err))\n return\n }\n\n let subscription = relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n if (reason.startsWith('auth-required: ') && params.onauth) {\n relay\n .auth(params.onauth)\n .then(() => {\n relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n handleClose(i, reason) // the second time we won't try to auth anymore\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n })\n .catch(err => {\n handleClose(i, `auth was required and attempted, but failed with: ${err}`)\n })\n } else {\n handleClose(i, reason)\n }\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n\n subs.push(subscription)\n }),\n )\n\n return {\n async close(reason?: string) {\n await allOpened\n subs.forEach(sub => {\n sub.close(reason)\n })\n },\n }\n }\n\n subscribeEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribe(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n subscribeManyEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribeMany(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n async querySync(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event[]> {\n return new Promise(async resolve => {\n const events: Event[] = []\n this.subscribeEose(relays, filter, {\n ...params,\n onevent(event: Event) {\n events.push(event)\n },\n onclose(_: string[]) {\n resolve(events)\n },\n })\n })\n }\n\n async get(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event | null> {\n filter.limit = 1\n const events = await this.querySync(relays, filter, params)\n events.sort((a, b) => b.created_at - a.created_at)\n return events[0] || null\n }\n\n publish(\n relays: string[],\n event: Event,\n options?: { onauth?: (evt: EventTemplate) => Promise<VerifiedEvent> },\n ): Promise<string>[] {\n return relays.map(normalizeURL).map(async (url, i, arr) => {\n if (arr.indexOf(url) !== i) {\n // duplicate\n return Promise.reject('duplicate url')\n }\n\n let r = await this.ensureRelay(url)\n return r\n .publish(event)\n .catch(async err => {\n if (err instanceof Error && err.message.startsWith('auth-required: ') && options?.onauth) {\n await r.auth(options.onauth)\n return r.publish(event) // retry\n }\n throw err\n })\n .then(reason => {\n if (this.trackRelays) {\n let set = this.seenOn.get(event.id)\n if (!set) {\n set = new Set()\n this.seenOn.set(event.id, set)\n }\n set.add(r)\n }\n return reason\n })\n })\n }\n\n listConnectionStatus(): Map<string, boolean> {\n const map = new Map<string, boolean>()\n this.relays.forEach((relay, url) => map.set(url, relay.connected))\n\n return map\n }\n\n destroy(): void {\n this.relays.forEach(conn => conn.close())\n this.relays = new Map()\n }\n}\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["target", "reason"]
7
7
  }
@@ -27,7 +27,7 @@ __export(abstract_relay_exports, {
27
27
  module.exports = __toCommonJS(abstract_relay_exports);
28
28
 
29
29
  // utils.ts
30
- var import_utils = require("@noble/hashes/utils");
30
+ var import_utils = require("@noble/hashes/utils.js");
31
31
  var utf8Decoder = new TextDecoder("utf-8");
32
32
  var utf8Encoder = new TextEncoder();
33
33
  function normalizeURL(url) {
@@ -215,7 +215,6 @@ var AbstractRelay = class {
215
215
  onnotice = (msg) => console.debug(`NOTICE from ${this.url}: ${msg}`);
216
216
  onauth;
217
217
  baseEoseTimeout = 4400;
218
- connectionTimeout = 4400;
219
218
  publishTimeout = 4400;
220
219
  pingFrequency = 29e3;
221
220
  pingTimeout = 2e4;
@@ -223,7 +222,6 @@ var AbstractRelay = class {
223
222
  openSubs = /* @__PURE__ */ new Map();
224
223
  enablePing;
225
224
  enableReconnect;
226
- connectionTimeoutHandle;
227
225
  reconnectTimeoutHandle;
228
226
  pingIntervalHandle;
229
227
  reconnectAttempts = 0;
@@ -248,7 +246,7 @@ var AbstractRelay = class {
248
246
  }
249
247
  static async connect(url, opts) {
250
248
  const relay = new AbstractRelay(url, opts);
251
- await relay.connect();
249
+ await relay.connect(opts);
252
250
  return relay;
253
251
  }
254
252
  closeAllSubscriptions(reason) {
@@ -294,22 +292,28 @@ var AbstractRelay = class {
294
292
  this.closeAllSubscriptions(reason);
295
293
  }
296
294
  }
297
- async connect() {
295
+ async connect(opts) {
296
+ let connectionTimeoutHandle;
298
297
  if (this.connectionPromise)
299
298
  return this.connectionPromise;
300
299
  this.challenge = void 0;
301
300
  this.authPromise = void 0;
302
301
  this.connectionPromise = new Promise((resolve, reject) => {
303
- this.connectionTimeoutHandle = setTimeout(() => {
304
- reject("connection timed out");
305
- this.connectionPromise = void 0;
306
- this.onclose?.();
307
- this.closeAllSubscriptions("relay connection timed out");
308
- }, this.connectionTimeout);
302
+ if (opts?.timeout) {
303
+ connectionTimeoutHandle = setTimeout(() => {
304
+ reject("connection timed out");
305
+ this.connectionPromise = void 0;
306
+ this.onclose?.();
307
+ this.closeAllSubscriptions("relay connection timed out");
308
+ }, opts.timeout);
309
+ }
310
+ if (opts?.abort) {
311
+ opts.abort.onabort = reject;
312
+ }
309
313
  try {
310
314
  this.ws = new this._WebSocket(this.url);
311
315
  } catch (err) {
312
- clearTimeout(this.connectionTimeoutHandle);
316
+ clearTimeout(connectionTimeoutHandle);
313
317
  reject(err);
314
318
  return;
315
319
  }
@@ -318,7 +322,7 @@ var AbstractRelay = class {
318
322
  clearTimeout(this.reconnectTimeoutHandle);
319
323
  this.reconnectTimeoutHandle = void 0;
320
324
  }
321
- clearTimeout(this.connectionTimeoutHandle);
325
+ clearTimeout(connectionTimeoutHandle);
322
326
  this._connected = true;
323
327
  const isReconnection = this.reconnectAttempts > 0;
324
328
  this.reconnectAttempts = 0;
@@ -339,12 +343,12 @@ var AbstractRelay = class {
339
343
  resolve();
340
344
  };
341
345
  this.ws.onerror = (ev) => {
342
- clearTimeout(this.connectionTimeoutHandle);
346
+ clearTimeout(connectionTimeoutHandle);
343
347
  reject(ev.message || "websocket error");
344
348
  this.handleHardClose("relay connection errored");
345
349
  };
346
350
  this.ws.onclose = (ev) => {
347
- clearTimeout(this.connectionTimeoutHandle);
351
+ clearTimeout(connectionTimeoutHandle);
348
352
  reject(ev.message || "websocket closed");
349
353
  this.handleHardClose("relay connection closed");
350
354
  };
@@ -556,6 +560,9 @@ var AbstractRelay = class {
556
560
  subscribe(filters, params) {
557
561
  const sub = this.prepareSubscription(filters, params);
558
562
  sub.fire();
563
+ if (params.abort) {
564
+ params.abort.onabort = () => sub.close(String(params.abort.reason || "<aborted>"));
565
+ }
559
566
  return sub;
560
567
  }
561
568
  prepareSubscription(filters, params) {