@openclaw/buzz 2026.9.1 → 2026.9.3

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 (33) hide show
  1. package/dist/api.js +1 -1
  2. package/dist/{channel-B50upNWy.js → channel-C6rro-f7.js} +30 -13
  3. package/dist/channel-plugin-api.js +1 -1
  4. package/node_modules/nostr-tools/README.md +23 -0
  5. package/node_modules/nostr-tools/lib/cjs/index.js +25 -15
  6. package/node_modules/nostr-tools/lib/cjs/index.js.map +2 -2
  7. package/node_modules/nostr-tools/lib/cjs/nip27.js +24 -14
  8. package/node_modules/nostr-tools/lib/cjs/nip27.js.map +2 -2
  9. package/node_modules/nostr-tools/lib/cjs/nipb7.js +1003 -98
  10. package/node_modules/nostr-tools/lib/cjs/nipb7.js.map +4 -4
  11. package/node_modules/nostr-tools/lib/cjs/relay.js +1 -1
  12. package/node_modules/nostr-tools/lib/cjs/relay.js.map +2 -2
  13. package/node_modules/nostr-tools/lib/esm/index.js +25 -15
  14. package/node_modules/nostr-tools/lib/esm/index.js.map +2 -2
  15. package/node_modules/nostr-tools/lib/esm/nip27.js +24 -14
  16. package/node_modules/nostr-tools/lib/esm/nip27.js.map +2 -2
  17. package/node_modules/nostr-tools/lib/esm/nipb7.js +1009 -98
  18. package/node_modules/nostr-tools/lib/esm/nipb7.js.map +4 -4
  19. package/node_modules/nostr-tools/lib/esm/relay.js +1 -1
  20. package/node_modules/nostr-tools/lib/esm/relay.js.map +2 -2
  21. package/node_modules/nostr-tools/lib/nostr.bundle.js +25 -15
  22. package/node_modules/nostr-tools/lib/nostr.bundle.js.map +2 -2
  23. package/node_modules/nostr-tools/lib/types/nip27.d.ts +18 -0
  24. package/node_modules/nostr-tools/lib/types/nipb7.d.ts +112 -5
  25. package/node_modules/nostr-tools/lib/types/relay.d.ts +1 -1
  26. package/node_modules/nostr-tools/package.json +1 -7
  27. package/package.json +5 -5
  28. package/node_modules/nostr-tools/lib/cjs/nipb0.js +0 -1087
  29. package/node_modules/nostr-tools/lib/cjs/nipb0.js.map +0 -7
  30. package/node_modules/nostr-tools/lib/esm/nipb0.js +0 -1072
  31. package/node_modules/nostr-tools/lib/esm/nipb0.js.map +0 -7
  32. package/node_modules/nostr-tools/lib/types/nipb0.d.ts +0 -128
  33. package/node_modules/nostr-tools/lib/types/nipb0.test.d.ts +0 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../nipb7.ts", "../../utils.ts"],
4
- "sourcesContent": ["import { sha256 } from '@noble/hashes/sha2.js'\nimport { EventTemplate } from './core.ts'\nimport { Signer } from './signer.ts'\nimport { bytesToHex, isHex32 } from './utils.ts'\n\nexport type BlobDescriptor = {\n url: string\n sha256: string\n size: number\n type: string\n uploaded: number\n}\n\nexport class BlossomClient {\n private mediaserver: string\n private signer: Signer\n\n constructor(mediaserver: string, signer: Signer) {\n if (!mediaserver.startsWith('http')) {\n mediaserver = 'https://' + mediaserver\n }\n this.mediaserver = mediaserver.replace(/\\/$/, '') + '/'\n this.signer = signer\n }\n\n private async httpCall(\n method: string,\n url: string,\n contentType?: string,\n addAuthorization?: () => Promise<string>,\n body?: File | Blob,\n result?: any,\n ): Promise<any> {\n const headers: { [_: string]: string } = {}\n\n if (contentType) {\n headers['Content-Type'] = contentType\n }\n\n if (addAuthorization) {\n const auth = await addAuthorization()\n if (auth) {\n headers['Authorization'] = auth\n }\n }\n\n const response = await fetch(this.mediaserver + url, {\n method,\n headers,\n body,\n })\n\n if (response.status >= 300) {\n const reason = response.headers.get('X-Reason') || response.statusText\n throw new Error(`${url} returned an error (${response.status}): ${reason}`)\n }\n\n if (result !== null && response.headers.get('content-type')?.includes('application/json')) {\n return await response.json()\n }\n\n return response\n }\n\n private async authorizationHeader(modify?: (event: EventTemplate) => void): Promise<string> {\n const now = Math.floor(Date.now() / 1000)\n const event: EventTemplate = {\n created_at: now,\n kind: 24242,\n content: 'blossom stuff',\n tags: [['expiration', String(now + 60)]],\n }\n\n if (modify) {\n modify(event)\n }\n\n try {\n const signedEvent = await this.signer.signEvent(event)\n const eventJson = JSON.stringify(signedEvent)\n return 'Nostr ' + btoa(eventJson)\n } catch (error) {\n return ''\n }\n }\n\n async check(hash: string): Promise<void> {\n if (!isHex32(hash)) {\n throw new Error(`${hash} is not a valid 32-byte hex string`)\n }\n\n try {\n await this.httpCall('HEAD', hash)\n } catch (error) {\n throw new Error(`failed to check for ${hash}: ${error}`)\n }\n }\n\n async uploadBlob(file: File | Blob, contentType?: string): Promise<BlobDescriptor> {\n const hash = bytesToHex(sha256(new Uint8Array(await file.arrayBuffer())))\n const actualContentType = contentType || file.type || 'application/octet-stream'\n\n const bd = await this.httpCall(\n 'PUT',\n 'upload',\n actualContentType,\n () =>\n this.authorizationHeader(evt => {\n evt.tags.push(['t', 'upload'])\n evt.tags.push(['x', hash])\n }),\n file,\n {},\n )\n\n return bd\n }\n\n async uploadFile(file: File): Promise<BlobDescriptor> {\n return this.uploadBlob(file, file.type)\n }\n\n async download(hash: string): Promise<ArrayBuffer> {\n if (!isHex32(hash)) {\n throw new Error(`${hash} is not a valid 32-byte hex string`)\n }\n\n const authHeader = await this.authorizationHeader(evt => {\n evt.tags.push(['t', 'get'])\n evt.tags.push(['x', hash])\n })\n\n const response = await fetch(this.mediaserver + hash, {\n method: 'GET',\n headers: {\n Authorization: authHeader,\n },\n })\n\n if (response.status >= 300) {\n throw new Error(`${hash} is not present in ${this.mediaserver}: ${response.status}`)\n }\n\n return await response.arrayBuffer()\n }\n\n async downloadAsBlob(hash: string): Promise<Blob> {\n const arrayBuffer = await this.download(hash)\n return new Blob([arrayBuffer])\n }\n\n async list(): Promise<BlobDescriptor[]> {\n const pubkey = await this.signer.getPublicKey()\n\n if (!isHex32(pubkey)) {\n throw new Error(`pubkey ${pubkey} is not valid`)\n }\n\n try {\n const bds = await this.httpCall(\n 'GET',\n `list/${pubkey}`,\n undefined,\n () =>\n this.authorizationHeader(evt => {\n evt.tags.push(['t', 'list'])\n }),\n undefined,\n [],\n )\n return bds\n } catch (error) {\n throw new Error(`failed to list blobs: ${error}`)\n }\n }\n\n async delete(hash: string): Promise<void> {\n if (!isHex32(hash)) {\n throw new Error(`${hash} is not a valid 32-byte hex string`)\n }\n\n try {\n await this.httpCall(\n 'DELETE',\n hash,\n undefined,\n () =>\n this.authorizationHeader(evt => {\n evt.tags.push(['t', 'delete'])\n evt.tags.push(['x', hash])\n }),\n undefined,\n null,\n )\n } catch (error) {\n throw new Error(`failed to delete ${hash}: ${error}`)\n }\n }\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\n/**\n * Checks if a string is a 64-char lowercase hex string as most Nostr ids and pubkeys.\n */\nexport function isHex32(input: string): boolean {\n if (input.length !== 64) return false\n for (let i = 0; i < 64; i++) {\n let cc = input.charCodeAt(i)\n if (isNaN(cc) || cc < 48 || cc > 102 || (cc > 57 && cc < 97)) {\n return false\n }\n }\n return true\n}\n"],
5
- "mappings": "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",
6
- "names": []
3
+ "sources": ["../../nipb7.ts", "../../utils.ts", "../../core.ts", "../../kinds.ts"],
4
+ "sourcesContent": ["import { sha256 } from '@noble/hashes/sha2.js'\nimport { bytesToHex } from '@noble/hashes/utils.js'\nimport type { EventTemplate } from './core.ts'\nimport type { Signer } from './signer.ts'\nimport { kinds } from './index.ts'\nimport { isHex32 } from './utils.ts'\n\nexport type BlobDescriptor = {\n url: string\n sha256: string\n size: number\n type: string\n uploaded: number\n}\n\nexport type UploadType = Blob | File | Buffer\n\nexport type SignedEvent = EventTemplate & {\n id: string\n sig: string\n pubkey: string\n}\n\nexport type AuthEventOptions = {\n blobs?: string | string[]\n servers?: string | string[]\n message?: string\n expiration?: number\n}\n\nexport function getBlobSize(blob: UploadType): number {\n if ((typeof File !== 'undefined' && blob instanceof File) || blob instanceof Blob) {\n return blob.size\n }\n return (blob as Buffer).length\n}\n\nexport function getBlobType(blob: UploadType): string | undefined {\n if ((typeof File !== 'undefined' && blob instanceof File) || blob instanceof Blob) {\n return blob.type || undefined\n }\n return undefined\n}\n\nexport async function computeBlobSha256(blob: UploadType): Promise<string> {\n let buffer: ArrayBuffer | Uint8Array\n\n if ((typeof File !== 'undefined' && blob instanceof File) || blob instanceof Blob) {\n buffer = await blob.arrayBuffer()\n } else {\n buffer = blob\n }\n\n const hash = sha256.create().update(new Uint8Array(buffer)).digest()\n return bytesToHex(hash)\n}\n\n// auth\n\nexport function encodeAuthorizationHeader(event: SignedEvent): string {\n const json = JSON.stringify(event)\n const bytes = new TextEncoder().encode(json)\n let binary = ''\n for (const byte of bytes) binary += String.fromCharCode(byte)\n return 'Nostr ' + btoa(binary)\n}\n\nexport function now(): number {\n return Math.floor(Date.now() / 1000)\n}\n\nexport function oneHour(): number {\n return now() + 3600\n}\n\nexport function getAuthTagValues(auth: SignedEvent, tagName: string): string[] {\n return auth.tags.filter(tag => tag[0] === tagName).map(tag => tag[1])\n}\n\nexport function getAuthExpiration(auth: SignedEvent): number | undefined {\n const expiration = auth.tags.find(tag => tag[0] === 'expiration')?.[1]\n if (!expiration) return undefined\n const timestamp = Number(expiration)\n if (!Number.isFinite(timestamp)) return undefined\n return timestamp\n}\n\nexport function isAuthExpired(auth: SignedEvent, timestamp: number = now()): boolean {\n const expiration = getAuthExpiration(auth)\n return expiration !== undefined && expiration <= timestamp\n}\n\nexport function normalizeServerTag(server: string | URL): string {\n if (server instanceof URL) return server.hostname.toLowerCase()\n if (URL.canParse(server)) return new URL(server).hostname.toLowerCase()\n return server.toLowerCase()\n}\n\nexport function areServersEqual(a: string | URL, b: string | URL): boolean {\n return normalizeServerTag(a) === normalizeServerTag(b)\n}\n\nfunction normalizeServers(servers: string | string[]): string[] {\n const values = Array.isArray(servers) ? servers : [servers]\n return [...new Set(values.map(normalizeServerTag))]\n}\n\nexport async function createAuthEvent(\n signer: (draft: EventTemplate) => Promise<SignedEvent>,\n type: 'upload' | 'list' | 'delete' | 'get' | 'media',\n options?: AuthEventOptions,\n): Promise<SignedEvent> {\n const draft: EventTemplate = {\n created_at: now(),\n kind: kinds.BlobsAuth,\n content: options?.message ?? '',\n tags: [\n ['t', type],\n ['expiration', String(options?.expiration ?? oneHour())],\n ],\n }\n\n if (options?.blobs) {\n const blobList = Array.isArray(options.blobs) ? options.blobs : [options.blobs]\n const seen = new Set<string>()\n for (const blob of blobList) {\n const hash = typeof blob === 'string' ? blob : await computeBlobSha256(blob)\n if (!seen.has(hash)) {\n draft.tags.push(['x', hash])\n seen.add(hash)\n }\n }\n }\n\n if (options?.servers) {\n for (const server of normalizeServers(options.servers)) {\n draft.tags.push(['server', server])\n }\n }\n\n return signer(draft)\n}\n\nexport type UploadAuthOptions = Omit<AuthEventOptions, 'blobs'> & { type?: 'upload' | 'media' }\n\nexport async function createUploadAuth(\n signer: (draft: EventTemplate) => Promise<SignedEvent>,\n blobs: string | string[],\n options?: UploadAuthOptions,\n): Promise<SignedEvent> {\n return createAuthEvent(signer, options?.type ?? 'upload', { message: 'Upload Blob', ...options, blobs })\n}\n\nexport type DownloadAuthOptions = Omit<AuthEventOptions, 'blobs' | 'servers'>\n\nexport async function createDownloadAuth(\n signer: (draft: EventTemplate) => Promise<SignedEvent>,\n hash: string,\n options?: DownloadAuthOptions,\n): Promise<SignedEvent> {\n return createAuthEvent(signer, 'get', { message: 'Download Blob', ...options, blobs: [hash] })\n}\n\nexport type MirrorAuthOptions = Omit<AuthEventOptions, 'blobs'>\n\nexport async function createMirrorAuth(\n signer: (draft: EventTemplate) => Promise<SignedEvent>,\n hash: string,\n options?: MirrorAuthOptions,\n): Promise<SignedEvent> {\n return createAuthEvent(signer, 'upload', { message: 'Mirror Blob', ...options, blobs: [hash] })\n}\n\nexport type ListAuthOptions = Omit<AuthEventOptions, 'blobs'>\n\nexport async function createListAuth(\n signer: (draft: EventTemplate) => Promise<SignedEvent>,\n options?: ListAuthOptions,\n): Promise<SignedEvent> {\n return createAuthEvent(signer, 'list', { message: 'List Blobs', ...options })\n}\n\nexport type DeleteAuthOptions = Omit<AuthEventOptions, 'blobs'>\n\nexport async function createDeleteAuth(\n signer: (draft: EventTemplate) => Promise<SignedEvent>,\n hash: string,\n options?: DeleteAuthOptions,\n): Promise<SignedEvent> {\n return createAuthEvent(signer, 'delete', { message: 'Delete Blob', ...options, blobs: [hash] })\n}\n\n// blossom URI\n\nexport type BlossomURI = {\n sha256: string\n ext: string\n servers: string[]\n authors: string[]\n size?: number\n}\n\nexport function parseBlossomURI(uri: string): BlossomURI {\n if (!uri.startsWith('blossom:')) throw new Error('Invalid blossom URI: missing blossom: scheme')\n const body = uri.slice('blossom:'.length)\n const queryIndex = body.indexOf('?')\n const path = queryIndex === -1 ? body : body.slice(0, queryIndex)\n const query = queryIndex === -1 ? '' : body.slice(queryIndex + 1)\n const dotIndex = path.indexOf('.')\n if (dotIndex === -1) throw new Error('Invalid blossom URI: missing file extension')\n const sha256 = path.slice(0, dotIndex)\n const ext = path.slice(dotIndex + 1)\n if (!isHex32(sha256)) throw new Error('Invalid blossom URI: invalid sha256 hash')\n if (!ext) throw new Error('Invalid blossom URI: empty file extension')\n const params = new URLSearchParams(query)\n const servers = params.getAll('xs')\n const authors = params.getAll('as')\n const szValue = params.get('sz')\n let size: number | undefined\n if (szValue !== null) {\n size = Number(szValue)\n if (!Number.isFinite(size) || size <= 0 || Math.floor(size) !== size) {\n throw new Error('Invalid blossom URI: sz must be a positive integer')\n }\n }\n return { sha256, ext, servers, authors, size }\n}\n\nexport function buildBlossomURI(options: BlossomURI): string {\n const params = new URLSearchParams()\n for (const server of options.servers) params.append('xs', server)\n for (const author of options.authors) params.append('as', author)\n if (options.size !== undefined) params.append('sz', String(options.size))\n const query = params.toString()\n return `blossom:${options.sha256}.${options.ext}${query ? '?' + query : ''}`\n}\n\nexport function blossomURIToURL(uri: string | BlossomURI): URL {\n const str = typeof uri === 'string' ? uri : buildBlossomURI(uri)\n return new URL(str)\n}\n\nexport function blossomURIFromURL(url: URL): BlossomURI {\n if (url.protocol !== 'blossom:') throw new Error('Invalid blossom URL: expected blossom: protocol')\n const path = url.pathname\n const dotIndex = path.indexOf('.')\n if (dotIndex === -1) throw new Error('Invalid blossom URL: missing file extension')\n const sha256 = path.slice(0, dotIndex)\n const ext = path.slice(dotIndex + 1)\n if (!isHex32(sha256)) throw new Error('Invalid blossom URL: invalid sha256 hash')\n if (!ext) throw new Error('Invalid blossom URL: empty file extension')\n const servers = url.searchParams.getAll('xs')\n const authors = url.searchParams.getAll('as')\n const szValue = url.searchParams.get('sz')\n let size: number | undefined\n if (szValue !== null) {\n size = Number(szValue)\n if (!Number.isFinite(size) || size <= 0 || Math.floor(size) !== size) {\n throw new Error('Invalid blossom URL: sz must be a positive integer')\n }\n }\n return { sha256, ext, servers, authors, size }\n}\n\nconst commonMimeExtensions: Record<string, string> = {\n 'application/json': '.json',\n 'application/pdf': '.pdf',\n 'application/vnd.android.package-archive': '.apk',\n 'application/vnd.sqlite3': '.sqlite3',\n 'application/xml': '.xml',\n 'audio/aac': '.aac',\n 'audio/flac': '.flac',\n 'audio/midi': '.midi',\n 'audio/mp3': '.mp3',\n 'audio/mpeg': '.mp3',\n 'audio/mp4': '.m4a',\n 'audio/ogg': '.ogg',\n 'audio/wav': '.wav',\n 'audio/webm': '.weba',\n 'audio/x-aiff': '.aiff',\n 'audio/x-m4a': '.m4a',\n 'image/avif': '.avif',\n 'image/gif': '.gif',\n 'image/jpeg': '.jpg',\n 'image/png': '.png',\n 'image/svg+xml': '.svg',\n 'image/webp': '.webp',\n 'text/css': '.css',\n 'text/csv': '.csv',\n 'text/html': '.html',\n 'text/javascript': '.js',\n 'text/markdown': '.md',\n 'text/plain': '.txt',\n 'text/xml': '.xml',\n 'video/mp2t': '.ts',\n 'video/mp4': '.mp4',\n 'video/ogg': '.ogv',\n 'video/quicktime': '.mov',\n 'video/webm': '.webm',\n 'video/x-matroska': '.mkv',\n}\n\nconst commonExtensionMimes: Record<string, string> = {\n '.aac': 'audio/aac',\n '.aiff': 'audio/x-aiff',\n '.apk': 'application/vnd.android.package-archive',\n '.avif': 'image/avif',\n '.css': 'text/css; charset=utf-8',\n '.csv': 'text/csv; charset=utf-8',\n '.flac': 'audio/flac',\n '.gif': 'image/gif',\n '.html': 'text/html; charset=utf-8',\n '.jpeg': 'image/jpeg',\n '.jpg': 'image/jpeg',\n '.js': 'text/javascript; charset=utf-8',\n '.json': 'application/json',\n '.m4a': 'audio/mp4',\n '.md': 'text/markdown; charset=utf-8',\n '.midi': 'audio/midi',\n '.mkv': 'video/x-matroska',\n '.mov': 'video/quicktime',\n '.mp3': 'audio/mpeg',\n '.mp4': 'video/mp4',\n '.oga': 'audio/ogg',\n '.ogg': 'audio/ogg',\n '.ogv': 'video/ogg',\n '.pdf': 'application/pdf',\n '.png': 'image/png',\n '.sqlite3': 'application/vnd.sqlite3',\n '.svg': 'image/svg+xml',\n '.ts': 'video/mp2t',\n '.txt': 'text/plain; charset=utf-8',\n '.wav': 'audio/wav',\n '.weba': 'audio/webm',\n '.webm': 'video/webm',\n '.webp': 'image/webp',\n '.xml': 'application/xml',\n}\n\nfunction normalizeMIMEType(mimetype: string): string {\n const idx = mimetype.indexOf(';')\n return idx >= 0 ? mimetype.slice(0, idx).trim().toLowerCase() : mimetype.trim().toLowerCase()\n}\n\nexport function getExtension(mimetype: string): string {\n const normalized = normalizeMIMEType(mimetype)\n if (!normalized) return ''\n return commonMimeExtensions[normalized] ?? ''\n}\n\nexport function getMIMEType(ext: string): string {\n if (!ext) return ''\n ext = ext.trim().toLowerCase()\n if (ext[0] !== '.') ext = '.' + ext\n return commonExtensionMimes[ext] ?? ''\n}\n\nexport function getServersFromServerListEvent(event: { tags: string[][] }): URL[] {\n const servers: URL[] = []\n for (const tag of event.tags) {\n if (tag[0] === 'server' && tag[1]) {\n try {\n const url = new URL(tag[1])\n url.pathname = '/'\n servers.push(url)\n } catch {}\n }\n }\n return servers\n}\n\nexport function getHashFromURL(url: string | URL): string | null {\n // strip fragment, then query string\n const path = typeof url === 'string' ? url.split('#', 1)[0].split('?', 1)[0] : url.pathname\n\n // get the last path segment\n const lastSlash = path.lastIndexOf('/')\n let segment = lastSlash === -1 ? path : path.slice(lastSlash + 1)\n\n // if there is an extension it should start at exactly the 64th character\n const dotIndex = segment.indexOf('.')\n if (dotIndex !== -1 && dotIndex !== 64) return null\n\n // the first 64 characters must be all lowercase hex\n for (let i = 0; i < 64; i++) {\n const c = segment.charCodeAt(i)\n const isDigit = c >= 48 && c <= 57 // '0'-'9'\n const isLowerHex = c >= 97 && c <= 102 // 'a'-'f'\n if (!isDigit && !isLowerHex) return null\n }\n\n return segment.slice(0, 64)\n}\n\nexport type UploadOptions = {\n signal?: AbortSignal\n auth?: SignedEvent | boolean\n timeout?: number\n onAuth?: (server: string, sha256: string) => Promise<SignedEvent>\n}\n\nexport async function uploadBlob(server: string, blob: Blob | File, opts?: UploadOptions): Promise<BlobDescriptor> {\n const url = new URL('/upload', server).toString()\n const sha256 = await computeBlobSha256(blob)\n\n const headers: Record<string, string> = {\n 'X-SHA-256': sha256,\n 'Content-Type': getBlobType(blob) || 'application/octet-stream',\n }\n\n if (opts?.auth) {\n const authEvent = typeof opts.auth === 'boolean' ? await opts.onAuth?.(server, sha256) : opts.auth\n if (authEvent) headers['Authorization'] = encodeAuthorizationHeader(authEvent)\n }\n\n const res = await fetch(url, {\n method: 'PUT',\n body: blob,\n headers,\n signal: opts?.signal,\n })\n\n if (res.status >= 300) {\n const reason = res.headers.get('X-Reason') || res.statusText\n throw new Error(`upload returned error (${res.status}): ${reason}`)\n }\n\n return res.json()\n}\n\nexport type DownloadOptions = {\n signal?: AbortSignal\n auth?: SignedEvent | boolean\n timeout?: number\n onAuth?: (server: string, sha256: string) => Promise<SignedEvent>\n}\n\nexport async function downloadBlob(server: string, hash: string, opts?: DownloadOptions): Promise<Response> {\n const url = new URL('/' + hash, server).toString()\n const headers: Record<string, string> = {}\n\n if (opts?.auth) {\n const authEvent = typeof opts.auth === 'boolean' ? await opts.onAuth?.(server, hash) : opts.auth\n if (authEvent) headers['Authorization'] = encodeAuthorizationHeader(authEvent)\n }\n\n const res = await fetch(url, { headers, signal: opts?.signal })\n\n if (res.status >= 300) {\n const reason = res.headers.get('X-Reason') || res.statusText\n throw new Error(`${hash} download error (${res.status}): ${reason}`)\n }\n\n return res\n}\n\nexport type ListOptions = {\n signal?: AbortSignal\n auth?: SignedEvent | boolean\n timeout?: number\n onAuth?: (server: string) => Promise<SignedEvent>\n cursor?: string\n limit?: number\n since?: number\n until?: number\n}\n\nexport async function listBlobs(server: string, pubkey: string, opts?: ListOptions): Promise<BlobDescriptor[]> {\n const url = new URL('/list/' + pubkey, server)\n if (opts?.cursor) url.searchParams.append('cursor', opts.cursor)\n if (opts?.limit) url.searchParams.append('limit', String(opts.limit))\n if (opts?.since) url.searchParams.append('since', String(opts.since))\n if (opts?.until) url.searchParams.append('until', String(opts.until))\n\n const headers: Record<string, string> = {}\n\n if (opts?.auth) {\n const authEvent = typeof opts.auth === 'boolean' ? await opts.onAuth?.(server) : opts.auth\n if (authEvent) headers['Authorization'] = encodeAuthorizationHeader(authEvent)\n }\n\n const res = await fetch(url.toString(), { headers, signal: opts?.signal })\n\n if (res.status >= 300) {\n const reason = res.headers.get('X-Reason') || res.statusText\n throw new Error(`list error (${res.status}): ${reason}`)\n }\n\n return res.json()\n}\n\nexport async function* iterateBlobs(\n server: string,\n pubkey: string,\n opts?: ListOptions,\n): AsyncGenerator<BlobDescriptor[], void, void> {\n let cursor = opts?.cursor\n while (true) {\n const page = await listBlobs(server, pubkey, { ...opts, cursor })\n if (page.length === 0) return\n yield page\n if (opts?.limit && page.length < opts.limit) return\n cursor = page[page.length - 1]?.sha256\n if (!cursor) return\n }\n}\n\nexport type DeleteOptions = {\n signal?: AbortSignal\n auth?: SignedEvent | boolean\n timeout?: number\n onAuth?: (server: string, sha256: string) => Promise<SignedEvent>\n}\n\nexport async function deleteBlob(server: string, hash: string, opts?: DeleteOptions): Promise<boolean> {\n const url = new URL('/' + hash, server).toString()\n const headers: Record<string, string> = {}\n\n if (opts?.auth) {\n const authEvent = typeof opts.auth === 'boolean' ? await opts.onAuth?.(server, hash) : opts.auth\n if (authEvent) headers['Authorization'] = encodeAuthorizationHeader(authEvent)\n }\n\n const res = await fetch(url, { method: 'DELETE', headers, signal: opts?.signal })\n\n if (res.status >= 300) {\n const reason = res.headers.get('X-Reason') || res.statusText\n throw new Error(`delete error (${res.status}): ${reason}`)\n }\n\n return res.ok\n}\n\nexport type HasBlobOptions = {\n signal?: AbortSignal\n timeout?: number\n}\n\nexport async function hasBlob(server: string, hash: string, opts?: HasBlobOptions): Promise<boolean> {\n const url = new URL('/' + hash, server)\n try {\n const res = await fetch(url.toString(), { method: 'HEAD', signal: opts?.signal })\n return res.status !== 404\n } catch {\n return false\n }\n}\n\nexport type MirrorOptions = {\n signal?: AbortSignal\n auth?: SignedEvent | boolean\n timeout?: number\n onAuth?: (server: string, sha256: string) => Promise<SignedEvent>\n}\n\nexport async function mirrorBlob(server: string, blob: BlobDescriptor, opts?: MirrorOptions): Promise<BlobDescriptor> {\n const url = new URL('/mirror', server).toString()\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-SHA-256': blob.sha256,\n }\n\n if (opts?.auth) {\n const authEvent = typeof opts.auth === 'boolean' ? await opts.onAuth?.(server, blob.sha256) : opts.auth\n if (authEvent) headers['Authorization'] = encodeAuthorizationHeader(authEvent)\n }\n\n const res = await fetch(url, {\n method: 'PUT',\n body: JSON.stringify({ url: blob.url }),\n headers,\n signal: opts?.signal,\n })\n\n if (res.status >= 300) {\n const reason = res.headers.get('X-Reason') || res.statusText\n throw new Error(`mirror error (${res.status}): ${reason}`)\n }\n\n return res.json()\n}\n\nexport type ReportOptions = {\n signal?: AbortSignal\n timeout?: number\n onError?: (server: string, error: Error) => void\n}\n\nexport async function reportBlobs(\n servers: Iterable<string>,\n report: SignedEvent,\n opts?: ReportOptions,\n): Promise<Map<string, boolean>> {\n if (report.kind !== 1984 || !report.tags.some(tag => tag[0] === 'x' && !!tag[1])) {\n throw new Error('Invalid blob report event: must be kind 1984 with x tag')\n }\n\n const results = new Map<string, boolean>()\n const body = JSON.stringify(report)\n\n for (const server of servers) {\n try {\n const res = await fetch(new URL('/report', server).toString(), {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body,\n signal: opts?.signal,\n })\n if (res.status >= 300) {\n const reason = res.headers.get('X-Reason') || res.statusText\n throw new Error(`report error (${res.status}): ${reason}`)\n }\n results.set(server, true)\n } catch (error) {\n if (opts?.onError && error instanceof Error) opts.onError(server, error)\n }\n }\n\n return results\n}\n\nexport class BlossomClient {\n private mediaserver: string\n\n constructor(\n mediaserver: string,\n private signer: Signer,\n ) {\n if (!mediaserver.startsWith('http')) {\n mediaserver = 'https://' + mediaserver\n }\n this.mediaserver = mediaserver.replace(/\\/$/, '') + '/'\n }\n\n getMediaServer(): string {\n return this.mediaserver\n }\n\n private async authorizationHeader(modify?: (event: EventTemplate) => void): Promise<string> {\n const event = {\n created_at: now(),\n kind: kinds.BlobsAuth,\n content: 'blossom stuff',\n tags: [['expiration', String(now() + 60)]],\n }\n\n modify?.(event)\n\n try {\n const signedEvent = await this.signer.signEvent(event)\n const json = JSON.stringify(signedEvent)\n return 'Nostr ' + btoa(json)\n } catch {\n return ''\n }\n }\n\n private async httpCall(\n method: string,\n url: string,\n contentType?: string,\n addAuthorization?: () => Promise<string>,\n body?: File | Blob | string,\n ): Promise<any> {\n const headers: Record<string, string> = {}\n\n if (contentType) headers['Content-Type'] = contentType\n if (addAuthorization) {\n const auth = await addAuthorization()\n if (auth) headers['Authorization'] = auth\n }\n\n const res = await fetch(this.mediaserver + url, { method, headers, body })\n\n if (res.status >= 300) {\n const reason = res.headers.get('X-Reason') || res.statusText\n throw new Error(`${url} returned error (${res.status}): ${reason}`)\n }\n\n if (res.headers.get('content-type')?.includes('application/json')) {\n return res.json()\n }\n\n return res\n }\n\n async uploadBlob(file: Blob | File, contentType?: string): Promise<BlobDescriptor> {\n const hash = bytesToHex(sha256(new Uint8Array(await file.arrayBuffer())))\n const actualContentType = contentType || getBlobType(file) || 'application/octet-stream'\n\n return this.httpCall(\n 'PUT',\n 'upload',\n actualContentType,\n () =>\n this.authorizationHeader(evt => {\n evt.tags.push(['t', 'upload'], ['x', hash])\n }),\n file,\n )\n }\n\n async uploadFile(file: File): Promise<BlobDescriptor> {\n return this.uploadBlob(file, file.type)\n }\n\n async download(hash: string): Promise<ArrayBuffer> {\n if (!isHex32(hash)) throw new Error(`${hash} is not a valid 32-byte hex string`)\n\n const authHeader = await this.authorizationHeader(evt => {\n evt.tags.push(['t', 'get'], ['x', hash])\n })\n\n const res = await fetch(this.mediaserver + hash, {\n method: 'GET',\n headers: { Authorization: authHeader },\n })\n\n if (res.status >= 300) {\n throw new Error(`${hash} not present on ${this.mediaserver}: ${res.status}`)\n }\n\n return res.arrayBuffer()\n }\n\n async downloadAsBlob(hash: string): Promise<Blob> {\n return new Blob([await this.download(hash)])\n }\n\n async list(): Promise<BlobDescriptor[]> {\n const pubkey = await this.signer.getPublicKey()\n\n if (!isHex32(pubkey)) {\n throw new Error(`pubkey ${pubkey} is not valid`)\n }\n\n return this.httpCall('GET', `list/${pubkey}`, undefined, () =>\n this.authorizationHeader(evt => {\n evt.tags.push(['t', 'list'])\n }),\n )\n }\n\n async delete(hash: string): Promise<void> {\n if (!isHex32(hash)) throw new Error(`${hash} is not a valid 32-byte hex string`)\n\n await this.httpCall('DELETE', hash, undefined, () =>\n this.authorizationHeader(evt => {\n evt.tags.push(['t', 'delete'], ['x', hash])\n }),\n )\n }\n\n async check(hash: string): Promise<void> {\n if (!isHex32(hash)) throw new Error(`${hash} is not valid 32-byte hex`)\n await this.httpCall('HEAD', hash)\n }\n\n async mirror(remoteBlobURL: string): Promise<BlobDescriptor> {\n const hash = remoteBlobURL.split('/').pop()?.split('.')[0] || ''\n return this.httpCall(\n 'PUT',\n 'mirror',\n 'application/json',\n () =>\n this.authorizationHeader(evt => {\n evt.tags.push(['t', 'upload'], ['x', hash])\n }),\n JSON.stringify({ url: remoteBlobURL }),\n )\n }\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\n/**\n * Checks if a string is a 64-char lowercase hex string as most Nostr ids and pubkeys.\n */\nexport function isHex32(input: string): boolean {\n if (input.length !== 64) return false\n for (let i = 0; i < 64; i++) {\n let cc = input.charCodeAt(i)\n if (isNaN(cc) || cc < 48 || cc > 102 || (cc > 57 && cc < 97)) {\n return false\n }\n }\n return true\n}\n", "import { isHex32 } from './utils.ts'\n\nexport 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 (!isHex32(event.pubkey)) 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 * Compare events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n */\nexport function compareEvents(a: Event, b: Event): 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/**\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(compareEvents)\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 SimpleGroupThreadedReply = 10\nexport type SimpleGroupThreadedReply = typeof SimpleGroupThreadedReply\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const SimpleGroupReply = 12\nexport type SimpleGroupReply = typeof SimpleGroupReply\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 ReactionToWebsite = 17\nexport type ReactionToWebsite = typeof ReactionToWebsite\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 PublicMessage = 24\nexport type PublicMessage = typeof PublicMessage\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 PodcastEpisode = 54\nexport type PodcastEpisode = typeof PodcastEpisode\nexport const Chess = 64\nexport type Chess = typeof Chess\nexport const MergeRequests = 818\nexport type MergeRequests = typeof MergeRequests\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Bid = 1021\nexport type Bid = typeof Bid\nexport const BidConfirmation = 1022\nexport type BidConfirmation = typeof BidConfirmation\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const Scroll = 1227\nexport type Scroll = typeof Scroll\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const CodeSnippet = 1337\nexport type CodeSnippet = typeof CodeSnippet\nexport const Patch = 1617\nexport type Patch = typeof Patch\nexport const GitPullRequest = 1618\nexport type GitPullRequest = typeof GitPullRequest\nexport const GitPullRequestUpdate = 1619\nexport type GitPullRequestUpdate = typeof GitPullRequestUpdate\nexport const Issue = 1621\nexport type Issue = typeof Issue\nexport const Reply = 1622\nexport type Reply = typeof Reply\nexport const StatusOpen = 1630\nexport type StatusOpen = typeof StatusOpen\nexport const StatusApplied = 1631\nexport type StatusApplied = typeof StatusApplied\nexport const StatusClosed = 1632\nexport type StatusClosed = typeof StatusClosed\nexport const StatusDraft = 1633\nexport type StatusDraft = typeof StatusDraft\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 RelayReviews = 1986\nexport type RelayReviews = typeof RelayReviews\nexport const AIEmbeddings = 1987\nexport type AIEmbeddings = typeof AIEmbeddings\nexport const Torrent = 2003\nexport type Torrent = typeof Torrent\nexport const TorrentComment = 2004\nexport type TorrentComment = typeof TorrentComment\nexport const CoinjoinPool = 2022\nexport type CoinjoinPool = typeof CoinjoinPool\nexport const DecoupledKeyClientAnnouncement = 4454\nexport type DecoupledKeyClientAnnouncement = typeof DecoupledKeyClientAnnouncement\nexport const DecoupledEncryptionKeyDistribution = 4455\nexport type DecoupledEncryptionKeyDistribution = typeof DecoupledEncryptionKeyDistribution\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 ReservedCashuWalletTokens = 7374\nexport type ReservedCashuWalletTokens = typeof ReservedCashuWalletTokens\nexport const CashuWalletTokens = 7375\nexport type CashuWalletTokens = typeof CashuWalletTokens\nexport const CashuWalletHistory = 7376\nexport type CashuWalletHistory = typeof CashuWalletHistory\nexport const GeocacheLog = 7516\nexport type GeocacheLog = typeof GeocacheLog\nexport const GeocacheProofOfFind = 7517\nexport type GeocacheProofOfFind = typeof GeocacheProofOfFind\nexport const SimpleGroupPutUser = 9000\nexport type SimpleGroupPutUser = typeof SimpleGroupPutUser\nexport const SimpleGroupRemoveUser = 9001\nexport type SimpleGroupRemoveUser = typeof SimpleGroupRemoveUser\nexport const SimpleGroupEditMetadata = 9002\nexport type SimpleGroupEditMetadata = typeof SimpleGroupEditMetadata\nexport const SimpleGroupDeleteEvent = 9005\nexport type SimpleGroupDeleteEvent = typeof SimpleGroupDeleteEvent\nexport const SimpleGroupCreateGroup = 9007\nexport type SimpleGroupCreateGroup = typeof SimpleGroupCreateGroup\nexport const SimpleGroupDeleteGroup = 9008\nexport type SimpleGroupDeleteGroup = typeof SimpleGroupDeleteGroup\nexport const SimpleGroupCreateInvite = 9009\nexport type SimpleGroupCreateInvite = typeof SimpleGroupCreateInvite\nexport const SimpleGroupJoinRequest = 9021\nexport type SimpleGroupJoinRequest = typeof SimpleGroupJoinRequest\nexport const SimpleGroupLeaveRequest = 9022\nexport type SimpleGroupLeaveRequest = typeof SimpleGroupLeaveRequest\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const NutZap = 9321\nexport type NutZap = typeof NutZap\nexport const TidalLogin = 9467\nexport type TidalLogin = typeof TidalLogin\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 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 SimpleGroupList = 10009\nexport type SimpleGroupList = typeof SimpleGroupList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const PrivateEventRelayList = 10013\nexport type PrivateEventRelayList = typeof PrivateEventRelayList\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const NutZapInfo = 10019\nexport type NutZapInfo = typeof NutZapInfo\nexport const MediaFollows = 10020\nexport type MediaFollows = typeof MediaFollows\nexport const FavoriteFollowSets = 10021\nexport type FavoriteFollowSets = typeof FavoriteFollowSets\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DecoupledKeyAnnouncement = 10044\nexport type DecoupledKeyAnnouncement = typeof DecoupledKeyAnnouncement\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FavoritePodcasts = 10054\nexport type FavoritePodcasts = typeof FavoritePodcasts\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const GoodWikiAuthorList = 10101\nexport type GoodWikiAuthorList = typeof GoodWikiAuthorList\nexport const GoodWikiRelayList = 10102\nexport type GoodWikiRelayList = typeof GoodWikiRelayList\nexport const PodcastMetadata = 10154\nexport type PodcastMetadata = typeof PodcastMetadata\nexport const AuthoredPodcasts = 10164\nexport type AuthoredPodcasts = typeof AuthoredPodcasts\nexport const RelayMonitorAnnouncement = 10166\nexport type RelayMonitorAnnouncement = typeof RelayMonitorAnnouncement\nexport const RoomPresence = 10312\nexport type RoomPresence = typeof RoomPresence\nexport const UserGraspList = 10317\nexport type UserGraspList = typeof UserGraspList\nexport const ProxyAnnouncement = 10377\nexport type ProxyAnnouncement = typeof ProxyAnnouncement\nexport const TransportMethodAnnouncement = 11111\nexport type TransportMethodAnnouncement = typeof TransportMethodAnnouncement\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const NsiteRoot = 15128\nexport type NsiteRoot = typeof NsiteRoot\nexport const CashuWalletEvent = 17375\nexport type CashuWalletEvent = typeof CashuWalletEvent\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 BlobsAuth = 24242\nexport type BlobsAuth = typeof BlobsAuth\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 CuratedVideoSets = 30005\nexport type CuratedVideoSets = typeof CuratedVideoSets\nexport const MuteSets = 30007\nexport type MuteSets = typeof MuteSets\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 MarketplaceUI = 30019\nexport type MarketplaceUI = typeof MarketplaceUI\nexport const ProductSoldAsAuction = 30020\nexport type ProductSoldAsAuction = typeof ProductSoldAsAuction\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 ModularArticleHeader = 30040\nexport type ModularArticleHeader = typeof ModularArticleHeader\nexport const ModularArticleContent = 30041\nexport type ModularArticleContent = typeof ModularArticleContent\nexport const ReleaseArtifactSets = 30063\nexport type ReleaseArtifactSets = typeof ReleaseArtifactSets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const RelayDiscovery = 30166\nexport type RelayDiscovery = typeof RelayDiscovery\nexport const AppCurationSet = 30267\nexport type AppCurationSet = typeof AppCurationSet\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const InteractiveRoom = 30312\nexport type InteractiveRoom = typeof InteractiveRoom\nexport const ConferenceEvent = 30313\nexport type ConferenceEvent = typeof ConferenceEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const SlideSet = 30388\nexport type SlideSet = typeof SlideSet\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const RepositoryAnnouncement = 30617\nexport type RepositoryAnnouncement = typeof RepositoryAnnouncement\nexport const RepositoryState = 30618\nexport type RepositoryState = typeof RepositoryState\nexport const WikiArticle = 30818\nexport type WikiArticle = typeof WikiArticle\nexport const Redirects = 30819\nexport type Redirects = typeof Redirects\nexport const DraftEvent = 31234\nexport type DraftEvent = typeof DraftEvent\nexport const LinkSet = 31388\nexport type LinkSet = typeof LinkSet\nexport const Feed = 31890\nexport type Feed = typeof Feed\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 SoftwareApplication = 32267\nexport type SoftwareApplication = typeof SoftwareApplication\nexport const LegacyNsiteFile = 34128\nexport type LegacyNsiteFile = typeof LegacyNsiteFile\nexport const VideoViewEvent = 34237\nexport type VideoViewEvent = typeof VideoViewEvent\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const NsiteNamed = 35128\nexport type NsiteNamed = typeof NsiteNamed\nexport const GeocacheListing = 37515\nexport type GeocacheListing = typeof GeocacheListing\nexport const GeocacheLogEntry = 37516\nexport type GeocacheLogEntry = typeof GeocacheLogEntry\nexport const CashuMintAnnouncement = 38172\nexport type CashuMintAnnouncement = typeof CashuMintAnnouncement\nexport const FedimintAnnouncement = 38173\nexport type FedimintAnnouncement = typeof FedimintAnnouncement\nexport const PeerToPeerOrderEvents = 38383\nexport type PeerToPeerOrderEvents = typeof PeerToPeerOrderEvents\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\nexport const SimpleGroupAdmins = 39001\nexport type SimpleGroupAdmins = typeof SimpleGroupAdmins\nexport const SimpleGroupMembers = 39002\nexport type SimpleGroupMembers = typeof SimpleGroupMembers\nexport const SimpleGroupRoles = 39003\nexport type SimpleGroupRoles = typeof SimpleGroupRoles\nexport const SimpleGroupLiveKitParticipants = 39004\nexport type SimpleGroupLiveKitParticipants = typeof SimpleGroupLiveKitParticipants\nexport const StarterPacks = 39089\nexport type StarterPacks = typeof StarterPacks\nexport const MediaStarterPacks = 39092\nexport type MediaStarterPacks = typeof MediaStarterPacks\nexport const WebBookmarks = 39701\nexport type WebBookmarks = typeof WebBookmarks\n"],
5
+ "mappings": "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",
6
+ "names": ["import_utils", "Date", "Date", "sha256"]
7
7
  }
@@ -775,7 +775,7 @@ var Relay = class extends AbstractRelay {
775
775
  }
776
776
  static async connect(url, options) {
777
777
  const relay = new Relay(url, options);
778
- await relay.connect();
778
+ await relay.connect(options);
779
779
  return relay;
780
780
  }
781
781
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../relay.ts", "../../pure.ts", "../../utils.ts", "../../core.ts", "../../kinds.ts", "../../filter.ts", "../../fakejson.ts", "../../nip42.ts", "../../abstract-relay.ts"],
4
- "sourcesContent": ["/* global WebSocket */\n\nimport { verifyEvent } from './pure.ts'\nimport { AbstractRelay, type AbstractRelayConstructorOptions } from './abstract-relay.ts'\n\nvar _WebSocket: typeof WebSocket\n\ntry {\n _WebSocket = WebSocket\n} catch {}\n\nexport function useWebSocketImplementation(websocketImplementation: any) {\n _WebSocket = websocketImplementation\n}\n\nexport class Relay extends AbstractRelay {\n constructor(\n url: string,\n options?: Pick<AbstractRelayConstructorOptions, 'enablePing' | 'enableReconnect' | 'idleTimeout'>,\n ) {\n super(url, { verifyEvent, websocketImplementation: _WebSocket, ...options })\n }\n\n static async connect(\n url: string,\n options?: Pick<AbstractRelayConstructorOptions, 'enablePing' | 'enableReconnect' | 'idleTimeout'>,\n ): Promise<Relay> {\n const relay = new Relay(url, options)\n await relay.connect()\n return relay\n }\n}\n\nexport type RelayRecord = Record<string, { read: boolean; write: boolean }>\n\nexport * from './abstract-relay.ts'\n", "import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n try {\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\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\n/**\n * Checks if a string is a 64-char lowercase hex string as most Nostr ids and pubkeys.\n */\nexport function isHex32(input: string): boolean {\n if (input.length !== 64) return false\n for (let i = 0; i < 64; i++) {\n let cc = input.charCodeAt(i)\n if (isNaN(cc) || cc < 48 || cc > 102 || (cc > 57 && cc < 97)) {\n return false\n }\n }\n return true\n}\n", "import { isHex32 } from './utils.ts'\n\nexport 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 (!isHex32(event.pubkey)) 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 * Compare events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n */\nexport function compareEvents(a: Event, b: Event): 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/**\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(compareEvents)\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 SimpleGroupThreadedReply = 10\nexport type SimpleGroupThreadedReply = typeof SimpleGroupThreadedReply\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const SimpleGroupReply = 12\nexport type SimpleGroupReply = typeof SimpleGroupReply\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 ReactionToWebsite = 17\nexport type ReactionToWebsite = typeof ReactionToWebsite\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 PublicMessage = 24\nexport type PublicMessage = typeof PublicMessage\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 PodcastEpisode = 54\nexport type PodcastEpisode = typeof PodcastEpisode\nexport const Chess = 64\nexport type Chess = typeof Chess\nexport const MergeRequests = 818\nexport type MergeRequests = typeof MergeRequests\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Bid = 1021\nexport type Bid = typeof Bid\nexport const BidConfirmation = 1022\nexport type BidConfirmation = typeof BidConfirmation\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const Scroll = 1227\nexport type Scroll = typeof Scroll\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const CodeSnippet = 1337\nexport type CodeSnippet = typeof CodeSnippet\nexport const Patch = 1617\nexport type Patch = typeof Patch\nexport const GitPullRequest = 1618\nexport type GitPullRequest = typeof GitPullRequest\nexport const GitPullRequestUpdate = 1619\nexport type GitPullRequestUpdate = typeof GitPullRequestUpdate\nexport const Issue = 1621\nexport type Issue = typeof Issue\nexport const Reply = 1622\nexport type Reply = typeof Reply\nexport const StatusOpen = 1630\nexport type StatusOpen = typeof StatusOpen\nexport const StatusApplied = 1631\nexport type StatusApplied = typeof StatusApplied\nexport const StatusClosed = 1632\nexport type StatusClosed = typeof StatusClosed\nexport const StatusDraft = 1633\nexport type StatusDraft = typeof StatusDraft\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 RelayReviews = 1986\nexport type RelayReviews = typeof RelayReviews\nexport const AIEmbeddings = 1987\nexport type AIEmbeddings = typeof AIEmbeddings\nexport const Torrent = 2003\nexport type Torrent = typeof Torrent\nexport const TorrentComment = 2004\nexport type TorrentComment = typeof TorrentComment\nexport const CoinjoinPool = 2022\nexport type CoinjoinPool = typeof CoinjoinPool\nexport const DecoupledKeyClientAnnouncement = 4454\nexport type DecoupledKeyClientAnnouncement = typeof DecoupledKeyClientAnnouncement\nexport const DecoupledEncryptionKeyDistribution = 4455\nexport type DecoupledEncryptionKeyDistribution = typeof DecoupledEncryptionKeyDistribution\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 ReservedCashuWalletTokens = 7374\nexport type ReservedCashuWalletTokens = typeof ReservedCashuWalletTokens\nexport const CashuWalletTokens = 7375\nexport type CashuWalletTokens = typeof CashuWalletTokens\nexport const CashuWalletHistory = 7376\nexport type CashuWalletHistory = typeof CashuWalletHistory\nexport const GeocacheLog = 7516\nexport type GeocacheLog = typeof GeocacheLog\nexport const GeocacheProofOfFind = 7517\nexport type GeocacheProofOfFind = typeof GeocacheProofOfFind\nexport const SimpleGroupPutUser = 9000\nexport type SimpleGroupPutUser = typeof SimpleGroupPutUser\nexport const SimpleGroupRemoveUser = 9001\nexport type SimpleGroupRemoveUser = typeof SimpleGroupRemoveUser\nexport const SimpleGroupEditMetadata = 9002\nexport type SimpleGroupEditMetadata = typeof SimpleGroupEditMetadata\nexport const SimpleGroupDeleteEvent = 9005\nexport type SimpleGroupDeleteEvent = typeof SimpleGroupDeleteEvent\nexport const SimpleGroupCreateGroup = 9007\nexport type SimpleGroupCreateGroup = typeof SimpleGroupCreateGroup\nexport const SimpleGroupDeleteGroup = 9008\nexport type SimpleGroupDeleteGroup = typeof SimpleGroupDeleteGroup\nexport const SimpleGroupCreateInvite = 9009\nexport type SimpleGroupCreateInvite = typeof SimpleGroupCreateInvite\nexport const SimpleGroupJoinRequest = 9021\nexport type SimpleGroupJoinRequest = typeof SimpleGroupJoinRequest\nexport const SimpleGroupLeaveRequest = 9022\nexport type SimpleGroupLeaveRequest = typeof SimpleGroupLeaveRequest\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const NutZap = 9321\nexport type NutZap = typeof NutZap\nexport const TidalLogin = 9467\nexport type TidalLogin = typeof TidalLogin\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 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 SimpleGroupList = 10009\nexport type SimpleGroupList = typeof SimpleGroupList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const PrivateEventRelayList = 10013\nexport type PrivateEventRelayList = typeof PrivateEventRelayList\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const NutZapInfo = 10019\nexport type NutZapInfo = typeof NutZapInfo\nexport const MediaFollows = 10020\nexport type MediaFollows = typeof MediaFollows\nexport const FavoriteFollowSets = 10021\nexport type FavoriteFollowSets = typeof FavoriteFollowSets\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DecoupledKeyAnnouncement = 10044\nexport type DecoupledKeyAnnouncement = typeof DecoupledKeyAnnouncement\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FavoritePodcasts = 10054\nexport type FavoritePodcasts = typeof FavoritePodcasts\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const GoodWikiAuthorList = 10101\nexport type GoodWikiAuthorList = typeof GoodWikiAuthorList\nexport const GoodWikiRelayList = 10102\nexport type GoodWikiRelayList = typeof GoodWikiRelayList\nexport const PodcastMetadata = 10154\nexport type PodcastMetadata = typeof PodcastMetadata\nexport const AuthoredPodcasts = 10164\nexport type AuthoredPodcasts = typeof AuthoredPodcasts\nexport const RelayMonitorAnnouncement = 10166\nexport type RelayMonitorAnnouncement = typeof RelayMonitorAnnouncement\nexport const RoomPresence = 10312\nexport type RoomPresence = typeof RoomPresence\nexport const UserGraspList = 10317\nexport type UserGraspList = typeof UserGraspList\nexport const ProxyAnnouncement = 10377\nexport type ProxyAnnouncement = typeof ProxyAnnouncement\nexport const TransportMethodAnnouncement = 11111\nexport type TransportMethodAnnouncement = typeof TransportMethodAnnouncement\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const NsiteRoot = 15128\nexport type NsiteRoot = typeof NsiteRoot\nexport const CashuWalletEvent = 17375\nexport type CashuWalletEvent = typeof CashuWalletEvent\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 BlobsAuth = 24242\nexport type BlobsAuth = typeof BlobsAuth\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 CuratedVideoSets = 30005\nexport type CuratedVideoSets = typeof CuratedVideoSets\nexport const MuteSets = 30007\nexport type MuteSets = typeof MuteSets\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 MarketplaceUI = 30019\nexport type MarketplaceUI = typeof MarketplaceUI\nexport const ProductSoldAsAuction = 30020\nexport type ProductSoldAsAuction = typeof ProductSoldAsAuction\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 ModularArticleHeader = 30040\nexport type ModularArticleHeader = typeof ModularArticleHeader\nexport const ModularArticleContent = 30041\nexport type ModularArticleContent = typeof ModularArticleContent\nexport const ReleaseArtifactSets = 30063\nexport type ReleaseArtifactSets = typeof ReleaseArtifactSets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const RelayDiscovery = 30166\nexport type RelayDiscovery = typeof RelayDiscovery\nexport const AppCurationSet = 30267\nexport type AppCurationSet = typeof AppCurationSet\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const InteractiveRoom = 30312\nexport type InteractiveRoom = typeof InteractiveRoom\nexport const ConferenceEvent = 30313\nexport type ConferenceEvent = typeof ConferenceEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const SlideSet = 30388\nexport type SlideSet = typeof SlideSet\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const RepositoryAnnouncement = 30617\nexport type RepositoryAnnouncement = typeof RepositoryAnnouncement\nexport const RepositoryState = 30618\nexport type RepositoryState = typeof RepositoryState\nexport const WikiArticle = 30818\nexport type WikiArticle = typeof WikiArticle\nexport const Redirects = 30819\nexport type Redirects = typeof Redirects\nexport const DraftEvent = 31234\nexport type DraftEvent = typeof DraftEvent\nexport const LinkSet = 31388\nexport type LinkSet = typeof LinkSet\nexport const Feed = 31890\nexport type Feed = typeof Feed\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 SoftwareApplication = 32267\nexport type SoftwareApplication = typeof SoftwareApplication\nexport const LegacyNsiteFile = 34128\nexport type LegacyNsiteFile = typeof LegacyNsiteFile\nexport const VideoViewEvent = 34237\nexport type VideoViewEvent = typeof VideoViewEvent\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const NsiteNamed = 35128\nexport type NsiteNamed = typeof NsiteNamed\nexport const GeocacheListing = 37515\nexport type GeocacheListing = typeof GeocacheListing\nexport const GeocacheLogEntry = 37516\nexport type GeocacheLogEntry = typeof GeocacheLogEntry\nexport const CashuMintAnnouncement = 38172\nexport type CashuMintAnnouncement = typeof CashuMintAnnouncement\nexport const FedimintAnnouncement = 38173\nexport type FedimintAnnouncement = typeof FedimintAnnouncement\nexport const PeerToPeerOrderEvents = 38383\nexport type PeerToPeerOrderEvents = typeof PeerToPeerOrderEvents\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\nexport const SimpleGroupAdmins = 39001\nexport type SimpleGroupAdmins = typeof SimpleGroupAdmins\nexport const SimpleGroupMembers = 39002\nexport type SimpleGroupMembers = typeof SimpleGroupMembers\nexport const SimpleGroupRoles = 39003\nexport type SimpleGroupRoles = typeof SimpleGroupRoles\nexport const SimpleGroupLiveKitParticipants = 39004\nexport type SimpleGroupLiveKitParticipants = typeof SimpleGroupLiveKitParticipants\nexport const StarterPacks = 39089\nexport type StarterPacks = typeof StarterPacks\nexport const MediaStarterPacks = 39092\nexport type MediaStarterPacks = typeof MediaStarterPacks\nexport const WebBookmarks = 39701\nexport type WebBookmarks = typeof WebBookmarks\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", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, 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: (event: Event, url: string) => boolean\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n idleTimeout?: number\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 idleTimeout: number = 0 // auto-close after ms of inactivity, 0 = disabled\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 private idleTimeoutHandle: ReturnType<typeof setTimeout> | undefined\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: (event: Event, url: string) => boolean\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 if (opts.idleTimeout) this.idleTimeout = opts.idleTimeout\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 clearIdleTimeout() {\n if (this.idleTimeoutHandle) {\n clearTimeout(this.idleTimeoutHandle)\n this.idleTimeoutHandle = undefined\n }\n }\n\n public scheduleIdleClose() {\n this.clearIdleTimeout()\n if (this.idleTimeout > 0) {\n this.idleTimeoutHandle = setTimeout(() => {\n if (this.ongoingOperations === 0 && this.idleSince) {\n this.close()\n }\n }, this.idleTimeout)\n }\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 // browsers and the node `ws` library fire BOTH onerror and onclose on a\n // failed/abnormal socket. detach the handlers on the first invocation so the\n // error->close pair collapses into a single terminal action -- otherwise\n // onclose would fire twice (terminal paths) and reconnect() would be\n // scheduled twice (reconnect paths, skipping a backoff slot).\n if (this.ws) {\n this.ws.onopen = null\n this.ws.onerror = null\n this.ws.onclose = null\n }\n\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 this.clearIdleTimeout()\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 // only give up on the initial connect; a slow reconnect\n // should fall through to the next backoff slot.\n if (this.reconnectAttempts === 0) {\n this.skipReconnection = true\n }\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 // only give up on the initial connect. a failed reconnect\n // attempt must fall through so the next backoff slot fires;\n // otherwise one failed retry tears down every subscription.\n if (this.reconnectAttempts === 0) {\n this.skipReconnection = true\n }\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.clearIdleTimeout()\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 try {\n await this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n } catch (err) {\n const ep = this.openEventPublishes.get(event.id)\n if (ep) {\n ep.reject(err as Error)\n this.openEventPublishes.delete(event.id)\n }\n }\n\n // compute idleness state\n this.ongoingOperations--\n if (this.ongoingOperations === 0) {\n this.idleSince = Date.now()\n this.scheduleIdleClose()\n }\n\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n return (await this.countWithHLL(filters, params)).count\n }\n\n public async countWithHLL(\n filters: Filter[],\n params: { id?: string | null },\n ): Promise<{ count: number; hll?: string }> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<{ count: number; hll?: string }>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n try {\n await this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n } catch (err) {\n const cr = this.openCountRequests.get(id)\n if (cr) {\n cr.reject(err as Error)\n this.openCountRequests.delete(id)\n }\n }\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.clearIdleTimeout()\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.connectionPromise = undefined\n this.idleSince = undefined\n this.clearIdleTimeout()\n this.onclose?.()\n if (this.ws) {\n // detach the handlers before closing so the resulting ws.onclose doesn't\n // route into handleHardClose and fire onclose / closeAllSubscriptions a\n // second time -- this user-initiated close() is the single owner of that.\n this.ws.onopen = null\n this.ws.onerror = null\n this.ws.onclose = null\n // close the socket unless it's already closing/closed; this also aborts a\n // still-CONNECTING socket so it can't open and linger untracked.\n if (this.ws.readyState !== this._WebSocket.CLOSING && this.ws.readyState !== this._WebSocket.CLOSED) {\n this.ws.close()\n }\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 (matchFilters(so.filters, event) && this.verifyEvent(event, this.url)) {\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; hll?: string }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload)\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) {\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.reject(new Error(data[2] as string))\n this.openCountRequests.delete(id)\n }\n return\n }\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).catch(err => {\n // If the connection closed before auth could be sent, just ignore it.\n // This is a race condition when relays close connections quickly\n // (e.g., WoT-enforced relays that reject unknown pubkeys).\n if (!(err instanceof SendingOnClosedConnection)) {\n throw err // re-throw other errors\n }\n })\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 if (!this.id.startsWith('<forced-ping>')) {\n this.relay.ongoingOperations--\n if (this.relay.ongoingOperations === 0) {\n this.relay.idleSince = Date.now()\n this.relay.scheduleIdleClose()\n }\n }\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: (payload: { count: number; hll?: string }) => 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 { verifyEvent } from './pure.ts'\nimport { AbstractRelay, type AbstractRelayConstructorOptions } from './abstract-relay.ts'\n\nvar _WebSocket: typeof WebSocket\n\ntry {\n _WebSocket = WebSocket\n} catch {}\n\nexport function useWebSocketImplementation(websocketImplementation: any) {\n _WebSocket = websocketImplementation\n}\n\nexport class Relay extends AbstractRelay {\n constructor(\n url: string,\n options?: Pick<AbstractRelayConstructorOptions, 'enablePing' | 'enableReconnect' | 'idleTimeout'>,\n ) {\n super(url, { verifyEvent, websocketImplementation: _WebSocket, ...options })\n }\n\n static async connect(\n url: string,\n options?: Pick<AbstractRelayConstructorOptions, 'enablePing' | 'enableReconnect' | 'idleTimeout'> &\n Parameters<AbstractRelay['connect']>[0],\n ): Promise<Relay> {\n const relay = new Relay(url, options)\n await relay.connect(options)\n return relay\n }\n}\n\nexport type RelayRecord = Record<string, { read: boolean; write: boolean }>\n\nexport * from './abstract-relay.ts'\n", "import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n try {\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\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\n/**\n * Checks if a string is a 64-char lowercase hex string as most Nostr ids and pubkeys.\n */\nexport function isHex32(input: string): boolean {\n if (input.length !== 64) return false\n for (let i = 0; i < 64; i++) {\n let cc = input.charCodeAt(i)\n if (isNaN(cc) || cc < 48 || cc > 102 || (cc > 57 && cc < 97)) {\n return false\n }\n }\n return true\n}\n", "import { isHex32 } from './utils.ts'\n\nexport 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 (!isHex32(event.pubkey)) 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 * Compare events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n */\nexport function compareEvents(a: Event, b: Event): 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/**\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(compareEvents)\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 SimpleGroupThreadedReply = 10\nexport type SimpleGroupThreadedReply = typeof SimpleGroupThreadedReply\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const SimpleGroupReply = 12\nexport type SimpleGroupReply = typeof SimpleGroupReply\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 ReactionToWebsite = 17\nexport type ReactionToWebsite = typeof ReactionToWebsite\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 PublicMessage = 24\nexport type PublicMessage = typeof PublicMessage\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 PodcastEpisode = 54\nexport type PodcastEpisode = typeof PodcastEpisode\nexport const Chess = 64\nexport type Chess = typeof Chess\nexport const MergeRequests = 818\nexport type MergeRequests = typeof MergeRequests\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Bid = 1021\nexport type Bid = typeof Bid\nexport const BidConfirmation = 1022\nexport type BidConfirmation = typeof BidConfirmation\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const Scroll = 1227\nexport type Scroll = typeof Scroll\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const CodeSnippet = 1337\nexport type CodeSnippet = typeof CodeSnippet\nexport const Patch = 1617\nexport type Patch = typeof Patch\nexport const GitPullRequest = 1618\nexport type GitPullRequest = typeof GitPullRequest\nexport const GitPullRequestUpdate = 1619\nexport type GitPullRequestUpdate = typeof GitPullRequestUpdate\nexport const Issue = 1621\nexport type Issue = typeof Issue\nexport const Reply = 1622\nexport type Reply = typeof Reply\nexport const StatusOpen = 1630\nexport type StatusOpen = typeof StatusOpen\nexport const StatusApplied = 1631\nexport type StatusApplied = typeof StatusApplied\nexport const StatusClosed = 1632\nexport type StatusClosed = typeof StatusClosed\nexport const StatusDraft = 1633\nexport type StatusDraft = typeof StatusDraft\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 RelayReviews = 1986\nexport type RelayReviews = typeof RelayReviews\nexport const AIEmbeddings = 1987\nexport type AIEmbeddings = typeof AIEmbeddings\nexport const Torrent = 2003\nexport type Torrent = typeof Torrent\nexport const TorrentComment = 2004\nexport type TorrentComment = typeof TorrentComment\nexport const CoinjoinPool = 2022\nexport type CoinjoinPool = typeof CoinjoinPool\nexport const DecoupledKeyClientAnnouncement = 4454\nexport type DecoupledKeyClientAnnouncement = typeof DecoupledKeyClientAnnouncement\nexport const DecoupledEncryptionKeyDistribution = 4455\nexport type DecoupledEncryptionKeyDistribution = typeof DecoupledEncryptionKeyDistribution\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 ReservedCashuWalletTokens = 7374\nexport type ReservedCashuWalletTokens = typeof ReservedCashuWalletTokens\nexport const CashuWalletTokens = 7375\nexport type CashuWalletTokens = typeof CashuWalletTokens\nexport const CashuWalletHistory = 7376\nexport type CashuWalletHistory = typeof CashuWalletHistory\nexport const GeocacheLog = 7516\nexport type GeocacheLog = typeof GeocacheLog\nexport const GeocacheProofOfFind = 7517\nexport type GeocacheProofOfFind = typeof GeocacheProofOfFind\nexport const SimpleGroupPutUser = 9000\nexport type SimpleGroupPutUser = typeof SimpleGroupPutUser\nexport const SimpleGroupRemoveUser = 9001\nexport type SimpleGroupRemoveUser = typeof SimpleGroupRemoveUser\nexport const SimpleGroupEditMetadata = 9002\nexport type SimpleGroupEditMetadata = typeof SimpleGroupEditMetadata\nexport const SimpleGroupDeleteEvent = 9005\nexport type SimpleGroupDeleteEvent = typeof SimpleGroupDeleteEvent\nexport const SimpleGroupCreateGroup = 9007\nexport type SimpleGroupCreateGroup = typeof SimpleGroupCreateGroup\nexport const SimpleGroupDeleteGroup = 9008\nexport type SimpleGroupDeleteGroup = typeof SimpleGroupDeleteGroup\nexport const SimpleGroupCreateInvite = 9009\nexport type SimpleGroupCreateInvite = typeof SimpleGroupCreateInvite\nexport const SimpleGroupJoinRequest = 9021\nexport type SimpleGroupJoinRequest = typeof SimpleGroupJoinRequest\nexport const SimpleGroupLeaveRequest = 9022\nexport type SimpleGroupLeaveRequest = typeof SimpleGroupLeaveRequest\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const NutZap = 9321\nexport type NutZap = typeof NutZap\nexport const TidalLogin = 9467\nexport type TidalLogin = typeof TidalLogin\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 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 SimpleGroupList = 10009\nexport type SimpleGroupList = typeof SimpleGroupList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const PrivateEventRelayList = 10013\nexport type PrivateEventRelayList = typeof PrivateEventRelayList\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const NutZapInfo = 10019\nexport type NutZapInfo = typeof NutZapInfo\nexport const MediaFollows = 10020\nexport type MediaFollows = typeof MediaFollows\nexport const FavoriteFollowSets = 10021\nexport type FavoriteFollowSets = typeof FavoriteFollowSets\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DecoupledKeyAnnouncement = 10044\nexport type DecoupledKeyAnnouncement = typeof DecoupledKeyAnnouncement\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FavoritePodcasts = 10054\nexport type FavoritePodcasts = typeof FavoritePodcasts\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const GoodWikiAuthorList = 10101\nexport type GoodWikiAuthorList = typeof GoodWikiAuthorList\nexport const GoodWikiRelayList = 10102\nexport type GoodWikiRelayList = typeof GoodWikiRelayList\nexport const PodcastMetadata = 10154\nexport type PodcastMetadata = typeof PodcastMetadata\nexport const AuthoredPodcasts = 10164\nexport type AuthoredPodcasts = typeof AuthoredPodcasts\nexport const RelayMonitorAnnouncement = 10166\nexport type RelayMonitorAnnouncement = typeof RelayMonitorAnnouncement\nexport const RoomPresence = 10312\nexport type RoomPresence = typeof RoomPresence\nexport const UserGraspList = 10317\nexport type UserGraspList = typeof UserGraspList\nexport const ProxyAnnouncement = 10377\nexport type ProxyAnnouncement = typeof ProxyAnnouncement\nexport const TransportMethodAnnouncement = 11111\nexport type TransportMethodAnnouncement = typeof TransportMethodAnnouncement\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const NsiteRoot = 15128\nexport type NsiteRoot = typeof NsiteRoot\nexport const CashuWalletEvent = 17375\nexport type CashuWalletEvent = typeof CashuWalletEvent\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 BlobsAuth = 24242\nexport type BlobsAuth = typeof BlobsAuth\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 CuratedVideoSets = 30005\nexport type CuratedVideoSets = typeof CuratedVideoSets\nexport const MuteSets = 30007\nexport type MuteSets = typeof MuteSets\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 MarketplaceUI = 30019\nexport type MarketplaceUI = typeof MarketplaceUI\nexport const ProductSoldAsAuction = 30020\nexport type ProductSoldAsAuction = typeof ProductSoldAsAuction\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 ModularArticleHeader = 30040\nexport type ModularArticleHeader = typeof ModularArticleHeader\nexport const ModularArticleContent = 30041\nexport type ModularArticleContent = typeof ModularArticleContent\nexport const ReleaseArtifactSets = 30063\nexport type ReleaseArtifactSets = typeof ReleaseArtifactSets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const RelayDiscovery = 30166\nexport type RelayDiscovery = typeof RelayDiscovery\nexport const AppCurationSet = 30267\nexport type AppCurationSet = typeof AppCurationSet\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const InteractiveRoom = 30312\nexport type InteractiveRoom = typeof InteractiveRoom\nexport const ConferenceEvent = 30313\nexport type ConferenceEvent = typeof ConferenceEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const SlideSet = 30388\nexport type SlideSet = typeof SlideSet\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const RepositoryAnnouncement = 30617\nexport type RepositoryAnnouncement = typeof RepositoryAnnouncement\nexport const RepositoryState = 30618\nexport type RepositoryState = typeof RepositoryState\nexport const WikiArticle = 30818\nexport type WikiArticle = typeof WikiArticle\nexport const Redirects = 30819\nexport type Redirects = typeof Redirects\nexport const DraftEvent = 31234\nexport type DraftEvent = typeof DraftEvent\nexport const LinkSet = 31388\nexport type LinkSet = typeof LinkSet\nexport const Feed = 31890\nexport type Feed = typeof Feed\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 SoftwareApplication = 32267\nexport type SoftwareApplication = typeof SoftwareApplication\nexport const LegacyNsiteFile = 34128\nexport type LegacyNsiteFile = typeof LegacyNsiteFile\nexport const VideoViewEvent = 34237\nexport type VideoViewEvent = typeof VideoViewEvent\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const NsiteNamed = 35128\nexport type NsiteNamed = typeof NsiteNamed\nexport const GeocacheListing = 37515\nexport type GeocacheListing = typeof GeocacheListing\nexport const GeocacheLogEntry = 37516\nexport type GeocacheLogEntry = typeof GeocacheLogEntry\nexport const CashuMintAnnouncement = 38172\nexport type CashuMintAnnouncement = typeof CashuMintAnnouncement\nexport const FedimintAnnouncement = 38173\nexport type FedimintAnnouncement = typeof FedimintAnnouncement\nexport const PeerToPeerOrderEvents = 38383\nexport type PeerToPeerOrderEvents = typeof PeerToPeerOrderEvents\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\nexport const SimpleGroupAdmins = 39001\nexport type SimpleGroupAdmins = typeof SimpleGroupAdmins\nexport const SimpleGroupMembers = 39002\nexport type SimpleGroupMembers = typeof SimpleGroupMembers\nexport const SimpleGroupRoles = 39003\nexport type SimpleGroupRoles = typeof SimpleGroupRoles\nexport const SimpleGroupLiveKitParticipants = 39004\nexport type SimpleGroupLiveKitParticipants = typeof SimpleGroupLiveKitParticipants\nexport const StarterPacks = 39089\nexport type StarterPacks = typeof StarterPacks\nexport const MediaStarterPacks = 39092\nexport type MediaStarterPacks = typeof MediaStarterPacks\nexport const WebBookmarks = 39701\nexport type WebBookmarks = typeof WebBookmarks\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", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, 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: (event: Event, url: string) => boolean\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n idleTimeout?: number\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 idleTimeout: number = 0 // auto-close after ms of inactivity, 0 = disabled\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 private idleTimeoutHandle: ReturnType<typeof setTimeout> | undefined\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: (event: Event, url: string) => boolean\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 if (opts.idleTimeout) this.idleTimeout = opts.idleTimeout\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 clearIdleTimeout() {\n if (this.idleTimeoutHandle) {\n clearTimeout(this.idleTimeoutHandle)\n this.idleTimeoutHandle = undefined\n }\n }\n\n public scheduleIdleClose() {\n this.clearIdleTimeout()\n if (this.idleTimeout > 0) {\n this.idleTimeoutHandle = setTimeout(() => {\n if (this.ongoingOperations === 0 && this.idleSince) {\n this.close()\n }\n }, this.idleTimeout)\n }\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 // browsers and the node `ws` library fire BOTH onerror and onclose on a\n // failed/abnormal socket. detach the handlers on the first invocation so the\n // error->close pair collapses into a single terminal action -- otherwise\n // onclose would fire twice (terminal paths) and reconnect() would be\n // scheduled twice (reconnect paths, skipping a backoff slot).\n if (this.ws) {\n this.ws.onopen = null\n this.ws.onerror = null\n this.ws.onclose = null\n }\n\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 this.clearIdleTimeout()\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 // only give up on the initial connect; a slow reconnect\n // should fall through to the next backoff slot.\n if (this.reconnectAttempts === 0) {\n this.skipReconnection = true\n }\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 // only give up on the initial connect. a failed reconnect\n // attempt must fall through so the next backoff slot fires;\n // otherwise one failed retry tears down every subscription.\n if (this.reconnectAttempts === 0) {\n this.skipReconnection = true\n }\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.clearIdleTimeout()\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 try {\n await this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n } catch (err) {\n const ep = this.openEventPublishes.get(event.id)\n if (ep) {\n ep.reject(err as Error)\n this.openEventPublishes.delete(event.id)\n }\n }\n\n // compute idleness state\n this.ongoingOperations--\n if (this.ongoingOperations === 0) {\n this.idleSince = Date.now()\n this.scheduleIdleClose()\n }\n\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n return (await this.countWithHLL(filters, params)).count\n }\n\n public async countWithHLL(\n filters: Filter[],\n params: { id?: string | null },\n ): Promise<{ count: number; hll?: string }> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<{ count: number; hll?: string }>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n try {\n await this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n } catch (err) {\n const cr = this.openCountRequests.get(id)\n if (cr) {\n cr.reject(err as Error)\n this.openCountRequests.delete(id)\n }\n }\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.clearIdleTimeout()\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.connectionPromise = undefined\n this.idleSince = undefined\n this.clearIdleTimeout()\n this.onclose?.()\n if (this.ws) {\n // detach the handlers before closing so the resulting ws.onclose doesn't\n // route into handleHardClose and fire onclose / closeAllSubscriptions a\n // second time -- this user-initiated close() is the single owner of that.\n this.ws.onopen = null\n this.ws.onerror = null\n this.ws.onclose = null\n // close the socket unless it's already closing/closed; this also aborts a\n // still-CONNECTING socket so it can't open and linger untracked.\n if (this.ws.readyState !== this._WebSocket.CLOSING && this.ws.readyState !== this._WebSocket.CLOSED) {\n this.ws.close()\n }\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 (matchFilters(so.filters, event) && this.verifyEvent(event, this.url)) {\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; hll?: string }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload)\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) {\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.reject(new Error(data[2] as string))\n this.openCountRequests.delete(id)\n }\n return\n }\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).catch(err => {\n // If the connection closed before auth could be sent, just ignore it.\n // This is a race condition when relays close connections quickly\n // (e.g., WoT-enforced relays that reject unknown pubkeys).\n if (!(err instanceof SendingOnClosedConnection)) {\n throw err // re-throw other errors\n }\n })\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 if (!this.id.startsWith('<forced-ping>')) {\n this.relay.ongoingOperations--\n if (this.relay.ongoingOperations === 0) {\n this.relay.idleSince = Date.now()\n this.relay.scheduleIdleClose()\n }\n }\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: (payload: { count: number; hll?: string }) => 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": ["import_utils", "i", "i", "i"]
7
7
  }