nostr-tools 2.23.2 → 2.23.4

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 (138) hide show
  1. package/lib/cjs/abstract-pool.js +6 -2
  2. package/lib/cjs/abstract-pool.js.map +2 -2
  3. package/lib/cjs/abstract-relay.js +6 -2
  4. package/lib/cjs/abstract-relay.js.map +2 -2
  5. package/lib/cjs/index.js +181 -17
  6. package/lib/cjs/index.js.map +4 -4
  7. package/lib/cjs/nip17.js +31 -9
  8. package/lib/cjs/nip17.js.map +2 -2
  9. package/lib/cjs/nip22.js +154 -0
  10. package/lib/cjs/nip22.js.map +7 -0
  11. package/lib/cjs/nip44.js +34 -10
  12. package/lib/cjs/nip44.js.map +2 -2
  13. package/lib/cjs/nip46.js +40 -12
  14. package/lib/cjs/nip46.js.map +2 -2
  15. package/lib/cjs/nip47.js +3 -3
  16. package/lib/cjs/nip47.js.map +2 -2
  17. package/lib/cjs/nip59.js +31 -9
  18. package/lib/cjs/nip59.js.map +2 -2
  19. package/lib/cjs/pool.js +6 -2
  20. package/lib/cjs/pool.js.map +2 -2
  21. package/lib/cjs/relay.js +6 -2
  22. package/lib/cjs/relay.js.map +2 -2
  23. package/lib/esm/abstract-pool.js +6 -2
  24. package/lib/esm/abstract-pool.js.map +2 -2
  25. package/lib/esm/abstract-relay.js +6 -2
  26. package/lib/esm/abstract-relay.js.map +2 -2
  27. package/lib/esm/index.js +181 -17
  28. package/lib/esm/index.js.map +4 -4
  29. package/lib/esm/nip17.js +31 -9
  30. package/lib/esm/nip17.js.map +2 -2
  31. package/lib/esm/nip22.js +133 -0
  32. package/lib/esm/nip22.js.map +7 -0
  33. package/lib/esm/nip44.js +34 -10
  34. package/lib/esm/nip44.js.map +2 -2
  35. package/lib/esm/nip46.js +40 -12
  36. package/lib/esm/nip46.js.map +2 -2
  37. package/lib/esm/nip47.js +3 -3
  38. package/lib/esm/nip47.js.map +2 -2
  39. package/lib/esm/nip59.js +31 -9
  40. package/lib/esm/nip59.js.map +2 -2
  41. package/lib/esm/pool.js +6 -2
  42. package/lib/esm/pool.js.map +2 -2
  43. package/lib/esm/relay.js +6 -2
  44. package/lib/esm/relay.js.map +2 -2
  45. package/lib/nostr.bundle.js +189 -25
  46. package/lib/nostr.bundle.js.map +4 -4
  47. package/package.json +8 -2
  48. package/lib/types/abstract-pool.d.ts +0 -60
  49. package/lib/types/abstract-relay.d.ts +0 -110
  50. package/lib/types/benchmarks.d.ts +0 -1
  51. package/lib/types/core.d.ts +0 -32
  52. package/lib/types/core.test.d.ts +0 -1
  53. package/lib/types/fakejson.d.ts +0 -6
  54. package/lib/types/fakejson.test.d.ts +0 -1
  55. package/lib/types/filter.d.ts +0 -19
  56. package/lib/types/filter.test.d.ts +0 -1
  57. package/lib/types/helpers.d.ts +0 -2
  58. package/lib/types/index.d.ts +0 -30
  59. package/lib/types/kinds.d.ts +0 -200
  60. package/lib/types/kinds.test.d.ts +0 -1
  61. package/lib/types/nip04.d.ts +0 -2
  62. package/lib/types/nip04.test.d.ts +0 -1
  63. package/lib/types/nip05.d.ts +0 -17
  64. package/lib/types/nip05.test.d.ts +0 -1
  65. package/lib/types/nip06.d.ts +0 -15
  66. package/lib/types/nip06.test.d.ts +0 -1
  67. package/lib/types/nip07.d.ts +0 -13
  68. package/lib/types/nip10.d.ts +0 -24
  69. package/lib/types/nip10.test.d.ts +0 -1
  70. package/lib/types/nip11.d.ts +0 -266
  71. package/lib/types/nip11.test.d.ts +0 -1
  72. package/lib/types/nip13.d.ts +0 -8
  73. package/lib/types/nip13.test.d.ts +0 -1
  74. package/lib/types/nip17.d.ts +0 -15
  75. package/lib/types/nip17.test.d.ts +0 -1
  76. package/lib/types/nip18.d.ts +0 -22
  77. package/lib/types/nip18.test.d.ts +0 -1
  78. package/lib/types/nip19.d.ts +0 -81
  79. package/lib/types/nip19.test.d.ts +0 -1
  80. package/lib/types/nip21.d.ts +0 -34
  81. package/lib/types/nip21.test.d.ts +0 -1
  82. package/lib/types/nip25.d.ts +0 -15
  83. package/lib/types/nip25.test.d.ts +0 -1
  84. package/lib/types/nip27.d.ts +0 -32
  85. package/lib/types/nip27.test.d.ts +0 -1
  86. package/lib/types/nip28.d.ts +0 -46
  87. package/lib/types/nip28.test.d.ts +0 -1
  88. package/lib/types/nip29.d.ts +0 -265
  89. package/lib/types/nip30.d.ts +0 -22
  90. package/lib/types/nip30.test.d.ts +0 -1
  91. package/lib/types/nip39.d.ts +0 -2
  92. package/lib/types/nip39.test.d.ts +0 -1
  93. package/lib/types/nip40.d.ts +0 -10
  94. package/lib/types/nip40.test.d.ts +0 -1
  95. package/lib/types/nip42.d.ts +0 -5
  96. package/lib/types/nip42.test.d.ts +0 -1
  97. package/lib/types/nip44.d.ts +0 -13
  98. package/lib/types/nip44.test.d.ts +0 -1
  99. package/lib/types/nip46.d.ts +0 -117
  100. package/lib/types/nip47.d.ts +0 -9
  101. package/lib/types/nip47.test.d.ts +0 -1
  102. package/lib/types/nip49.d.ts +0 -3
  103. package/lib/types/nip49.test.d.ts +0 -1
  104. package/lib/types/nip54.d.ts +0 -1
  105. package/lib/types/nip54.test.d.ts +0 -1
  106. package/lib/types/nip55.d.ts +0 -30
  107. package/lib/types/nip55.test.d.ts +0 -1
  108. package/lib/types/nip57.d.ts +0 -25
  109. package/lib/types/nip57.test.d.ts +0 -1
  110. package/lib/types/nip58.d.ts +0 -134
  111. package/lib/types/nip58.test.d.ts +0 -1
  112. package/lib/types/nip59.d.ts +0 -12
  113. package/lib/types/nip59.test.d.ts +0 -1
  114. package/lib/types/nip75.d.ts +0 -61
  115. package/lib/types/nip75.test.d.ts +0 -1
  116. package/lib/types/nip77.d.ts +0 -102
  117. package/lib/types/nip77.test.d.ts +0 -1
  118. package/lib/types/nip94.d.ts +0 -87
  119. package/lib/types/nip94.test.d.ts +0 -1
  120. package/lib/types/nip98.d.ts +0 -74
  121. package/lib/types/nip98.test.d.ts +0 -1
  122. package/lib/types/nip99.d.ts +0 -92
  123. package/lib/types/nip99.test.d.ts +0 -1
  124. package/lib/types/nipb7.d.ts +0 -23
  125. package/lib/types/nipb7.test.d.ts +0 -1
  126. package/lib/types/pool.d.ts +0 -6
  127. package/lib/types/pool.test.d.ts +0 -1
  128. package/lib/types/pure.d.ts +0 -8
  129. package/lib/types/pure.test.d.ts +0 -1
  130. package/lib/types/references.d.ts +0 -10
  131. package/lib/types/references.test.d.ts +0 -1
  132. package/lib/types/relay.d.ts +0 -11
  133. package/lib/types/relay.test.d.ts +0 -1
  134. package/lib/types/signer.d.ts +0 -11
  135. package/lib/types/test-helpers.d.ts +0 -14
  136. package/lib/types/utils.d.ts +0 -9
  137. package/lib/types/utils.test.d.ts +0 -1
  138. package/lib/types/wasm.d.ts +0 -8
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../abstract-relay.ts", "../../utils.ts", "../../kinds.ts", "../../filter.ts", "../../fakejson.ts", "../../nip42.ts"],
4
- "sourcesContent": ["/* 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 { normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.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 public idleSince: number | undefined = Date.now() // when undefined that means it isn't idle\n public ongoingOperations: number = 0 // used to compute idleness\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private skipReconnection: 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 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 this.idleSince = undefined\n\n if (this.enableReconnect && !this.skipReconnection) {\n this.reconnect()\n } else {\n this.onclose?.()\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.skipReconnection = false\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.skipReconnection = true\n this.onclose?.()\n this.handleHardClose('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 = () => {\n clearTimeout(connectionTimeoutHandle)\n reject('connection failed')\n this.connectionPromise = undefined\n this.skipReconnection = true\n this.onclose?.()\n this.handleHardClose('relay connection failed')\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 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 this.idleSince = undefined\n this.ongoingOperations++\n\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\n // compute idleness state\n this.ongoingOperations--\n if (this.ongoingOperations === 0) this.idleSince = Date.now()\n\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 if (params.label !== '<forced-ping>') {\n this.idleSince = undefined\n this.ongoingOperations++\n }\n\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 sub = new Subscription(this, id, filters, params)\n this.openSubs.set(id, sub)\n return sub\n }\n\n public close() {\n this.skipReconnection = 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.idleSince = undefined\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>): void {\n const json = ev.data\n if (!json) {\n return\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 } else {\n so.oninvalidevent?.(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 const [_, __, event] = JSON.parse(json)\n ;(window as any).printer.maybe(event.pubkey, ':: caught err', event, this.url, err)\n return\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 oninvalidevent: ((evt: unknown) => void) | undefined\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.oninvalidevent = params.oninvalidevent\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\n // compute idleness state\n this.relay.ongoingOperations--\n if (this.relay.ongoingOperations === 0) this.relay.idleSince = Date.now()\n\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oninvalidevent?: (evt: unknown) => 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", "import type { NostrEvent } 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: NostrEvent[], event: NostrEvent): NostrEvent[] {\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: NostrEvent[], event: NostrEvent): NostrEvent[] {\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 function mergeReverseSortedLists(list1: NostrEvent[], list2: NostrEvent[]): NostrEvent[] {\n const result: NostrEvent[] = new Array(list1.length + list2.length)\n result.length = 0\n let i1 = 0\n let i2 = 0\n let sameTimestampIds: string[] = []\n\n while (i1 < list1.length && i2 < list2.length) {\n let next: NostrEvent\n if (list1[i1]?.created_at > list2[i2]?.created_at) {\n next = list1[i1]\n i1++\n } else {\n next = list2[i2]\n i2++\n }\n\n if (result.length > 0 && result[result.length - 1].created_at === next.created_at) {\n if (sameTimestampIds.includes(next.id)) continue\n } else {\n sameTimestampIds.length = 0\n }\n\n result.push(next)\n sameTimestampIds.push(next.id)\n }\n\n while (i1 < list1.length) {\n const next = list1[i1]\n i1++\n\n if (result.length > 0 && result[result.length - 1].created_at === next.created_at) {\n if (sameTimestampIds.includes(next.id)) continue\n } else {\n sameTimestampIds.length = 0\n }\n result.push(next)\n sameTimestampIds.push(next.id)\n }\n\n while (i2 < list2.length) {\n const next = list2[i2]\n i2++\n\n if (result.length > 0 && result[result.length - 1].created_at === next.created_at) {\n if (sameTimestampIds.includes(next.id)) continue\n } else {\n sameTimestampIds.length = 0\n }\n result.push(next)\n sameTimestampIds.push(next.id)\n }\n\n return result\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"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/* 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 { normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.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 public idleSince: number | undefined = Date.now() // when undefined that means it isn't idle\n public ongoingOperations: number = 0 // used to compute idleness\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private skipReconnection: 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 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 this.idleSince = undefined\n\n if (this.enableReconnect && !this.skipReconnection) {\n this.reconnect()\n } else {\n this.onclose?.()\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.skipReconnection = false\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.skipReconnection = true\n this.onclose?.()\n this.handleHardClose('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 = () => {\n clearTimeout(connectionTimeoutHandle)\n reject('connection failed')\n this.connectionPromise = undefined\n this.skipReconnection = true\n this.onclose?.()\n this.handleHardClose('relay connection failed')\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 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 this.idleSince = undefined\n this.ongoingOperations++\n\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\n // compute idleness state\n this.ongoingOperations--\n if (this.ongoingOperations === 0) this.idleSince = Date.now()\n\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 if (params.label !== '<forced-ping>') {\n this.idleSince = undefined\n this.ongoingOperations++\n }\n\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 sub = new Subscription(this, id, filters, params)\n this.openSubs.set(id, sub)\n return sub\n }\n\n public close() {\n this.skipReconnection = 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.idleSince = undefined\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>): void {\n const json = ev.data\n if (!json) {\n return\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 } else {\n so.oninvalidevent?.(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 try {\n const [_, __, event] = JSON.parse(json)\n console.warn(`[nostr] relay ${this.url} error processing message:`, err, event)\n } catch (_) {\n console.warn(`[nostr] relay ${this.url} error processing message:`, err)\n }\n return\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 oninvalidevent: ((evt: unknown) => void) | undefined\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.oninvalidevent = params.oninvalidevent\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\n // compute idleness state\n this.relay.ongoingOperations--\n if (this.relay.ongoingOperations === 0) this.relay.idleSince = Date.now()\n\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oninvalidevent?: (evt: unknown) => 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", "import type { NostrEvent } 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: NostrEvent[], event: NostrEvent): NostrEvent[] {\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: NostrEvent[], event: NostrEvent): NostrEvent[] {\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 function mergeReverseSortedLists(list1: NostrEvent[], list2: NostrEvent[]): NostrEvent[] {\n const result: NostrEvent[] = new Array(list1.length + list2.length)\n result.length = 0\n let i1 = 0\n let i2 = 0\n let sameTimestampIds: string[] = []\n\n while (i1 < list1.length && i2 < list2.length) {\n let next: NostrEvent\n if (list1[i1]?.created_at > list2[i2]?.created_at) {\n next = list1[i1]\n i1++\n } else {\n next = list2[i2]\n i2++\n }\n\n if (result.length > 0 && result[result.length - 1].created_at === next.created_at) {\n if (sameTimestampIds.includes(next.id)) continue\n } else {\n sameTimestampIds.length = 0\n }\n\n result.push(next)\n sameTimestampIds.push(next.id)\n }\n\n while (i1 < list1.length) {\n const next = list1[i1]\n i1++\n\n if (result.length > 0 && result[result.length - 1].created_at === next.created_at) {\n if (sameTimestampIds.includes(next.id)) continue\n } else {\n sameTimestampIds.length = 0\n }\n result.push(next)\n sameTimestampIds.push(next.id)\n }\n\n while (i2 < list2.length) {\n const next = list2[i2]\n i2++\n\n if (result.length > 0 && result[result.length - 1].created_at === next.created_at) {\n if (sameTimestampIds.includes(next.id)) continue\n } else {\n sameTimestampIds.length = 0\n }\n result.push(next)\n sameTimestampIds.push(next.id)\n }\n\n return result\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"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/lib/cjs/index.js CHANGED
@@ -41,6 +41,7 @@ __export(nostr_tools_exports, {
41
41
  nip18: () => nip18_exports,
42
42
  nip19: () => nip19_exports,
43
43
  nip21: () => nip21_exports,
44
+ nip22: () => nip22_exports,
44
45
  nip25: () => nip25_exports,
45
46
  nip27: () => nip27_exports,
46
47
  nip28: () => nip28_exports,
@@ -1041,8 +1042,12 @@ var AbstractRelay = class {
1041
1042
  }
1042
1043
  }
1043
1044
  } catch (err) {
1044
- const [_, __, event] = JSON.parse(json);
1045
- window.printer.maybe(event.pubkey, ":: caught err", event, this.url, err);
1045
+ try {
1046
+ const [_, __, event] = JSON.parse(json);
1047
+ console.warn(`[nostr] relay ${this.url} error processing message:`, err, event);
1048
+ } catch (_) {
1049
+ console.warn(`[nostr] relay ${this.url} error processing message:`, err);
1050
+ }
1046
1051
  return;
1047
1052
  }
1048
1053
  }
@@ -2026,7 +2031,8 @@ var import_sha23 = require("@noble/hashes/sha2.js");
2026
2031
  var import_utils13 = require("@noble/hashes/utils.js");
2027
2032
  var import_base3 = require("@scure/base");
2028
2033
  var minPlaintextSize = 1;
2029
- var maxPlaintextSize = 65535;
2034
+ var maxPlaintextSize = 4294967295;
2035
+ var extendedPrefixThreshold = 65536;
2030
2036
  function getConversationKey(privkeyA, pubkeyB) {
2031
2037
  const sharedX = import_secp256k13.secp256k1.getSharedSecret(privkeyA, (0, import_utils13.hexToBytes)("02" + pubkeyB)).subarray(1, 33);
2032
2038
  return (0, import_hkdf.extract)(import_sha23.sha256, sharedX, utf8Encoder.encode("nip44-v2"));
@@ -2044,28 +2050,49 @@ function calcPaddedLen(len) {
2044
2050
  throw new Error("expected positive integer");
2045
2051
  if (len <= 32)
2046
2052
  return 32;
2047
- const nextPower = 1 << Math.floor(Math.log2(len - 1)) + 1;
2053
+ const nextPower = 2 ** (Math.floor(Math.log2(len - 1)) + 1);
2048
2054
  const chunk = nextPower <= 256 ? 32 : nextPower / 8;
2049
2055
  return chunk * (Math.floor((len - 1) / chunk) + 1);
2050
2056
  }
2051
2057
  function writeU16BE(num) {
2052
- if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > maxPlaintextSize)
2058
+ if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > 65535)
2053
2059
  throw new Error("invalid plaintext size: must be between 1 and 65535 bytes");
2054
2060
  const arr = new Uint8Array(2);
2055
2061
  new DataView(arr.buffer).setUint16(0, num, false);
2056
2062
  return arr;
2057
2063
  }
2064
+ function writeU32BE(num) {
2065
+ if (!Number.isSafeInteger(num) || num < extendedPrefixThreshold || num > maxPlaintextSize)
2066
+ throw new Error("invalid plaintext size: must be between 65536 and 4294967295 bytes");
2067
+ const arr = new Uint8Array(4);
2068
+ new DataView(arr.buffer).setUint32(0, num, false);
2069
+ return arr;
2070
+ }
2058
2071
  function pad(plaintext) {
2059
2072
  const unpadded = utf8Encoder.encode(plaintext);
2060
2073
  const unpaddedLen = unpadded.length;
2061
- const prefix = writeU16BE(unpaddedLen);
2074
+ if (unpaddedLen < minPlaintextSize || unpaddedLen > maxPlaintextSize)
2075
+ throw new Error("invalid plaintext size: must be between 1 and 4294967295 bytes");
2076
+ const prefix = unpaddedLen >= extendedPrefixThreshold ? (0, import_utils13.concatBytes)(new Uint8Array([0, 0]), writeU32BE(unpaddedLen)) : writeU16BE(unpaddedLen);
2062
2077
  const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen);
2063
2078
  return (0, import_utils13.concatBytes)(prefix, unpadded, suffix);
2064
2079
  }
2065
2080
  function unpad(padded) {
2066
- const unpaddedLen = new DataView(padded.buffer).getUint16(0);
2067
- const unpadded = padded.subarray(2, 2 + unpaddedLen);
2068
- if (unpaddedLen < minPlaintextSize || unpaddedLen > maxPlaintextSize || unpadded.length !== unpaddedLen || padded.length !== 2 + calcPaddedLen(unpaddedLen))
2081
+ const dv = new DataView(padded.buffer, padded.byteOffset, padded.byteLength);
2082
+ const firstTwo = dv.getUint16(0);
2083
+ let unpaddedLen;
2084
+ let prefixLen;
2085
+ if (firstTwo === 0) {
2086
+ unpaddedLen = dv.getUint32(2);
2087
+ if (unpaddedLen < extendedPrefixThreshold)
2088
+ throw new Error("invalid padding");
2089
+ prefixLen = 6;
2090
+ } else {
2091
+ unpaddedLen = firstTwo;
2092
+ prefixLen = 2;
2093
+ }
2094
+ const unpadded = padded.subarray(prefixLen, prefixLen + unpaddedLen);
2095
+ if (unpaddedLen < minPlaintextSize || unpaddedLen > maxPlaintextSize || unpadded.length !== unpaddedLen || padded.length !== prefixLen + calcPaddedLen(unpaddedLen))
2069
2096
  throw new Error("invalid padding");
2070
2097
  return utf8Decoder.decode(unpadded);
2071
2098
  }
@@ -2079,7 +2106,7 @@ function decodePayload(payload) {
2079
2106
  if (typeof payload !== "string")
2080
2107
  throw new Error("payload must be a valid string");
2081
2108
  const plen = payload.length;
2082
- if (plen < 132 || plen > 87472)
2109
+ if (plen < 132)
2083
2110
  throw new Error("invalid payload length: " + plen);
2084
2111
  if (payload[0] === "#")
2085
2112
  throw new Error("unknown encryption version");
@@ -2090,7 +2117,7 @@ function decodePayload(payload) {
2090
2117
  throw new Error("invalid base64: " + error.message);
2091
2118
  }
2092
2119
  const dlen = data.length;
2093
- if (dlen < 99 || dlen > 65603)
2120
+ if (dlen < 99)
2094
2121
  throw new Error("invalid data length: " + dlen);
2095
2122
  const vers = data[0];
2096
2123
  if (vers !== 2)
@@ -2120,7 +2147,9 @@ function decrypt2(payload, conversationKey) {
2120
2147
  var v2 = {
2121
2148
  utils: {
2122
2149
  getConversationKey,
2123
- calcPaddedLen
2150
+ calcPaddedLen,
2151
+ pad,
2152
+ unpad
2124
2153
  },
2125
2154
  encrypt: encrypt2,
2126
2155
  decrypt: decrypt2
@@ -2325,6 +2354,141 @@ function parse2(uri) {
2325
2354
  };
2326
2355
  }
2327
2356
 
2357
+ // nip22.ts
2358
+ var nip22_exports = {};
2359
+ __export(nip22_exports, {
2360
+ parse: () => parse3
2361
+ });
2362
+ function parseKind(kind) {
2363
+ if (!kind)
2364
+ return void 0;
2365
+ return /^\d+$/.test(kind) ? parseInt(kind, 10) : kind;
2366
+ }
2367
+ function parseAddressPointer(value, relayUrl) {
2368
+ const idx = value.indexOf(":");
2369
+ const idx2 = value.indexOf(":", idx + 1);
2370
+ if (idx === -1 || idx2 === -1)
2371
+ return void 0;
2372
+ const kind = parseInt(value.slice(0, idx), 10);
2373
+ if (Number.isNaN(kind))
2374
+ return void 0;
2375
+ return {
2376
+ kind,
2377
+ pubkey: value.slice(idx + 1, idx2),
2378
+ identifier: value.slice(idx2 + 1),
2379
+ relays: relayUrl ? [relayUrl] : []
2380
+ };
2381
+ }
2382
+ function parsePointer(tag) {
2383
+ switch (tag[0]) {
2384
+ case "E":
2385
+ case "e":
2386
+ if (!tag[1])
2387
+ return void 0;
2388
+ return {
2389
+ id: tag[1],
2390
+ relays: tag[2] ? [tag[2]] : [],
2391
+ author: tag[3]
2392
+ };
2393
+ case "A":
2394
+ case "a":
2395
+ if (!tag[1])
2396
+ return void 0;
2397
+ return parseAddressPointer(tag[1], tag[2]);
2398
+ case "I":
2399
+ case "i":
2400
+ if (!tag[1])
2401
+ return void 0;
2402
+ return {
2403
+ value: tag[1],
2404
+ hint: tag[2]
2405
+ };
2406
+ }
2407
+ }
2408
+ function parseQuote(tag) {
2409
+ if (!tag[1])
2410
+ return void 0;
2411
+ if (tag[1].includes(":")) {
2412
+ return parseAddressPointer(tag[1], tag[2]);
2413
+ }
2414
+ return {
2415
+ id: tag[1],
2416
+ relays: tag[2] ? [tag[2]] : [],
2417
+ author: tag[3]
2418
+ };
2419
+ }
2420
+ function choosePointer(candidates) {
2421
+ return candidates.findLast((candidate) => candidate.tagName === "A" || candidate.tagName === "a")?.pointer || candidates.findLast((candidate) => candidate.tagName === "I" || candidate.tagName === "i")?.pointer || candidates.findLast((candidate) => candidate.tagName === "E" || candidate.tagName === "e")?.pointer;
2422
+ }
2423
+ function inheritRelayHints(pointer, profiles) {
2424
+ if (!pointer || !("id" in pointer) || !pointer.author)
2425
+ return;
2426
+ const author = profiles.find((profile) => profile.pubkey === pointer.author);
2427
+ if (!author || !author.relays)
2428
+ return;
2429
+ if (!pointer.relays) {
2430
+ pointer.relays = [];
2431
+ }
2432
+ author.relays.forEach((url) => {
2433
+ if (pointer.relays.indexOf(url) === -1)
2434
+ pointer.relays.push(url);
2435
+ });
2436
+ author.relays = pointer.relays;
2437
+ }
2438
+ function parse3(event) {
2439
+ const result = {
2440
+ root: void 0,
2441
+ rootKind: void 0,
2442
+ reply: void 0,
2443
+ replyKind: void 0,
2444
+ mentions: [],
2445
+ quotes: [],
2446
+ profiles: []
2447
+ };
2448
+ const rootCandidates = [];
2449
+ const replyCandidates = [];
2450
+ for (const tag of event.tags) {
2451
+ if ((tag[0] === "E" || tag[0] === "A" || tag[0] === "I") && tag[1]) {
2452
+ const pointer = parsePointer(tag);
2453
+ if (pointer)
2454
+ rootCandidates.push({ tagName: tag[0], pointer });
2455
+ continue;
2456
+ }
2457
+ if ((tag[0] === "e" || tag[0] === "a" || tag[0] === "i") && tag[1]) {
2458
+ const pointer = parsePointer(tag);
2459
+ if (pointer)
2460
+ replyCandidates.push({ tagName: tag[0], pointer });
2461
+ continue;
2462
+ }
2463
+ if (tag[0] === "K") {
2464
+ result.rootKind = parseKind(tag[1]);
2465
+ continue;
2466
+ }
2467
+ if (tag[0] === "k") {
2468
+ result.replyKind = parseKind(tag[1]);
2469
+ continue;
2470
+ }
2471
+ if (tag[0] === "q") {
2472
+ const pointer = parseQuote(tag);
2473
+ if (pointer)
2474
+ result.quotes.push(pointer);
2475
+ continue;
2476
+ }
2477
+ if ((tag[0] === "P" || tag[0] === "p") && tag[1]) {
2478
+ result.profiles.push({
2479
+ pubkey: tag[1],
2480
+ relays: tag[2] ? [tag[2]] : []
2481
+ });
2482
+ }
2483
+ }
2484
+ result.root = choosePointer(rootCandidates);
2485
+ result.reply = choosePointer(replyCandidates);
2486
+ inheritRelayHints(result.root, result.profiles);
2487
+ inheritRelayHints(result.reply, result.profiles);
2488
+ result.quotes.forEach((pointer) => inheritRelayHints(pointer, result.profiles));
2489
+ return result;
2490
+ }
2491
+
2328
2492
  // nip25.ts
2329
2493
  var nip25_exports = {};
2330
2494
  __export(nip25_exports, {
@@ -2372,12 +2536,12 @@ function getReactedEventPointer(event) {
2372
2536
  // nip27.ts
2373
2537
  var nip27_exports = {};
2374
2538
  __export(nip27_exports, {
2375
- parse: () => parse3
2539
+ parse: () => parse4
2376
2540
  });
2377
2541
  var noCharacter = /\W/m;
2378
2542
  var noURLCharacter = /[^\w\/] |[^\w\/]$|$|,| /m;
2379
2543
  var MAX_HASHTAG_LENGTH = 42;
2380
- function* parse3(content) {
2544
+ function* parse4(content) {
2381
2545
  let emojis = [];
2382
2546
  if (typeof content !== "string") {
2383
2547
  for (let i2 = 0; i2 < content.tags.length; i2++) {
@@ -2688,12 +2852,12 @@ __export(nip47_exports, {
2688
2852
  function parseConnectionString(connectionString) {
2689
2853
  const { host, pathname, searchParams } = new URL(connectionString);
2690
2854
  const pubkey = pathname || host;
2691
- const relay = searchParams.get("relay");
2855
+ const relays = searchParams.getAll("relay");
2692
2856
  const secret = searchParams.get("secret");
2693
- if (!pubkey || !relay || !secret) {
2857
+ if (!pubkey || relays.length === 0 || !secret) {
2694
2858
  throw new Error("invalid connection string");
2695
2859
  }
2696
- return { pubkey, relay, secret };
2860
+ return { pubkey, relay: relays[0], relays, secret };
2697
2861
  }
2698
2862
  async function makeNwcRequestEvent(pubkey, secretKey, invoice) {
2699
2863
  const content = {