@openclaw/nostr 2026.7.2-beta.7 → 2026.7.33
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.
- package/dist/{channel-O6-jXoT5.js → .setup/channel-B4SX7Iq6.mjs} +554 -877
- package/dist/{config-schema-CelPzg1N.js → .setup/config-schema-DIiXiBKr.mjs} +1 -1
- package/dist/.setup/inbound-direct-dm-runtime-EdLLVtkh.mjs +2 -0
- package/dist/{setup-adapter-BjKmSwdW.js → .setup/setup-adapter-DEU3o8MF.mjs} +1 -31
- package/dist/.setup/setup-plugin-api-DzlCumkz.mjs +2 -0
- package/dist/.setup/setup-plugin-api-csfJrRxD.mjs +111 -0
- package/dist/{setup-surface-BJCFpe02.js → .setup/setup-surface-DWa6-9ku.mjs} +70 -41
- package/dist/api.js +72 -61
- package/dist/channel-plugin-api.js +1 -1
- package/dist/doctor-contract-api.js +3 -2
- package/dist/setup-api.js +1 -1
- package/dist/setup-entry.js +2 -1
- package/dist/setup-plugin-api.js +1 -112
- package/node_modules/nostr-tools/lib/cjs/abstract-pool.js +28 -59
- package/node_modules/nostr-tools/lib/cjs/abstract-pool.js.map +3 -3
- package/node_modules/nostr-tools/lib/cjs/abstract-relay.js +7 -44
- package/node_modules/nostr-tools/lib/cjs/abstract-relay.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/core.js +1 -17
- package/node_modules/nostr-tools/lib/cjs/core.js.map +3 -3
- package/node_modules/nostr-tools/lib/cjs/filter.js.map +1 -1
- package/node_modules/nostr-tools/lib/cjs/index.js +130 -172
- package/node_modules/nostr-tools/lib/cjs/index.js.map +4 -4
- package/node_modules/nostr-tools/lib/cjs/kinds.js +1 -17
- package/node_modules/nostr-tools/lib/cjs/kinds.js.map +3 -3
- package/node_modules/nostr-tools/lib/cjs/nip04.js.map +1 -1
- package/node_modules/nostr-tools/lib/cjs/nip10.js +5 -20
- package/node_modules/nostr-tools/lib/cjs/nip10.js.map +3 -3
- package/node_modules/nostr-tools/lib/cjs/nip13.js.map +1 -1
- package/node_modules/nostr-tools/lib/cjs/nip17.js +23 -30
- package/node_modules/nostr-tools/lib/cjs/nip17.js.map +4 -4
- package/node_modules/nostr-tools/lib/cjs/nip18.js +14 -21
- package/node_modules/nostr-tools/lib/cjs/nip18.js.map +4 -4
- package/node_modules/nostr-tools/lib/cjs/nip19.js.map +1 -1
- package/node_modules/nostr-tools/lib/cjs/nip21.js.map +1 -1
- package/node_modules/nostr-tools/lib/cjs/nip22.js +7 -22
- package/node_modules/nostr-tools/lib/cjs/nip22.js.map +3 -3
- package/node_modules/nostr-tools/lib/cjs/nip25.js +14 -21
- package/node_modules/nostr-tools/lib/cjs/nip25.js.map +4 -4
- package/node_modules/nostr-tools/lib/cjs/nip27.js.map +1 -1
- package/node_modules/nostr-tools/lib/cjs/nip28.js +14 -21
- package/node_modules/nostr-tools/lib/cjs/nip28.js.map +4 -4
- package/node_modules/nostr-tools/lib/cjs/nip29.js.map +1 -1
- package/node_modules/nostr-tools/lib/cjs/nip30.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/nip42.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/nip44.js.map +1 -1
- package/node_modules/nostr-tools/lib/cjs/nip45.js +9 -22
- package/node_modules/nostr-tools/lib/cjs/nip45.js.map +4 -4
- package/node_modules/nostr-tools/lib/cjs/nip46.js +70 -111
- package/node_modules/nostr-tools/lib/cjs/nip46.js.map +4 -4
- package/node_modules/nostr-tools/lib/cjs/nip47.js +18 -25
- package/node_modules/nostr-tools/lib/cjs/nip47.js.map +4 -4
- package/node_modules/nostr-tools/lib/cjs/nip57.js +16 -23
- package/node_modules/nostr-tools/lib/cjs/nip57.js.map +4 -4
- package/node_modules/nostr-tools/lib/cjs/nip58.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/nip59.js +7 -16
- package/node_modules/nostr-tools/lib/cjs/nip59.js.map +3 -3
- package/node_modules/nostr-tools/lib/cjs/nip75.js.map +1 -1
- package/node_modules/nostr-tools/lib/cjs/nip94.js.map +1 -1
- package/node_modules/nostr-tools/lib/cjs/nip98.js +16 -23
- package/node_modules/nostr-tools/lib/cjs/nip98.js.map +4 -4
- package/node_modules/nostr-tools/lib/cjs/nip99.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/nipb0.js +17 -38
- package/node_modules/nostr-tools/lib/cjs/nipb0.js.map +4 -4
- package/node_modules/nostr-tools/lib/cjs/nipb7.js +7 -13
- package/node_modules/nostr-tools/lib/cjs/nipb7.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/pool.js +61 -102
- package/node_modules/nostr-tools/lib/cjs/pool.js.map +4 -4
- package/node_modules/nostr-tools/lib/cjs/pure.js +14 -21
- package/node_modules/nostr-tools/lib/cjs/pure.js.map +4 -4
- package/node_modules/nostr-tools/lib/cjs/references.js.map +1 -1
- package/node_modules/nostr-tools/lib/cjs/relay.js +42 -86
- package/node_modules/nostr-tools/lib/cjs/relay.js.map +4 -4
- package/node_modules/nostr-tools/lib/cjs/signer.js +14 -21
- package/node_modules/nostr-tools/lib/cjs/signer.js.map +4 -4
- package/node_modules/nostr-tools/lib/cjs/utils.js +0 -10
- package/node_modules/nostr-tools/lib/cjs/utils.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/wasm.js +2 -16
- package/node_modules/nostr-tools/lib/cjs/wasm.js.map +4 -4
- package/node_modules/nostr-tools/lib/esm/abstract-pool.js +28 -59
- package/node_modules/nostr-tools/lib/esm/abstract-pool.js.map +3 -3
- package/node_modules/nostr-tools/lib/esm/abstract-relay.js +7 -44
- package/node_modules/nostr-tools/lib/esm/abstract-relay.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/core.js +1 -15
- package/node_modules/nostr-tools/lib/esm/core.js.map +3 -3
- package/node_modules/nostr-tools/lib/esm/filter.js.map +1 -1
- package/node_modules/nostr-tools/lib/esm/index.js +80 -122
- package/node_modules/nostr-tools/lib/esm/index.js.map +4 -4
- package/node_modules/nostr-tools/lib/esm/kinds.js +1 -17
- package/node_modules/nostr-tools/lib/esm/kinds.js.map +3 -3
- package/node_modules/nostr-tools/lib/esm/nip04.js.map +1 -1
- package/node_modules/nostr-tools/lib/esm/nip10.js +5 -18
- package/node_modules/nostr-tools/lib/esm/nip10.js.map +3 -3
- package/node_modules/nostr-tools/lib/esm/nip13.js.map +1 -1
- package/node_modules/nostr-tools/lib/esm/nip17.js +8 -15
- package/node_modules/nostr-tools/lib/esm/nip17.js.map +4 -4
- package/node_modules/nostr-tools/lib/esm/nip18.js +8 -15
- package/node_modules/nostr-tools/lib/esm/nip18.js.map +4 -4
- package/node_modules/nostr-tools/lib/esm/nip19.js.map +1 -1
- package/node_modules/nostr-tools/lib/esm/nip21.js.map +1 -1
- package/node_modules/nostr-tools/lib/esm/nip22.js +7 -20
- package/node_modules/nostr-tools/lib/esm/nip22.js.map +3 -3
- package/node_modules/nostr-tools/lib/esm/nip25.js +8 -15
- package/node_modules/nostr-tools/lib/esm/nip25.js.map +4 -4
- package/node_modules/nostr-tools/lib/esm/nip27.js.map +1 -1
- package/node_modules/nostr-tools/lib/esm/nip28.js +8 -15
- package/node_modules/nostr-tools/lib/esm/nip28.js.map +4 -4
- package/node_modules/nostr-tools/lib/esm/nip29.js.map +1 -1
- package/node_modules/nostr-tools/lib/esm/nip30.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/nip42.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/nip44.js.map +1 -1
- package/node_modules/nostr-tools/lib/esm/nip45.js +10 -23
- package/node_modules/nostr-tools/lib/esm/nip45.js.map +4 -4
- package/node_modules/nostr-tools/lib/esm/nip46.js +54 -95
- package/node_modules/nostr-tools/lib/esm/nip46.js.map +4 -4
- package/node_modules/nostr-tools/lib/esm/nip47.js +8 -15
- package/node_modules/nostr-tools/lib/esm/nip47.js.map +4 -4
- package/node_modules/nostr-tools/lib/esm/nip57.js +10 -17
- package/node_modules/nostr-tools/lib/esm/nip57.js.map +4 -4
- package/node_modules/nostr-tools/lib/esm/nip58.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/nip59.js +1 -10
- package/node_modules/nostr-tools/lib/esm/nip59.js.map +3 -3
- package/node_modules/nostr-tools/lib/esm/nip75.js.map +1 -1
- package/node_modules/nostr-tools/lib/esm/nip94.js.map +1 -1
- package/node_modules/nostr-tools/lib/esm/nip98.js +8 -15
- package/node_modules/nostr-tools/lib/esm/nip98.js.map +4 -4
- package/node_modules/nostr-tools/lib/esm/nip99.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/nipb0.js +18 -39
- package/node_modules/nostr-tools/lib/esm/nipb0.js.map +4 -4
- package/node_modules/nostr-tools/lib/esm/nipb7.js +7 -13
- package/node_modules/nostr-tools/lib/esm/nipb7.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/pool.js +54 -95
- package/node_modules/nostr-tools/lib/esm/pool.js.map +4 -4
- package/node_modules/nostr-tools/lib/esm/pure.js +8 -15
- package/node_modules/nostr-tools/lib/esm/pure.js.map +4 -4
- package/node_modules/nostr-tools/lib/esm/references.js.map +1 -1
- package/node_modules/nostr-tools/lib/esm/relay.js +36 -80
- package/node_modules/nostr-tools/lib/esm/relay.js.map +4 -4
- package/node_modules/nostr-tools/lib/esm/signer.js +8 -15
- package/node_modules/nostr-tools/lib/esm/signer.js.map +4 -4
- package/node_modules/nostr-tools/lib/esm/utils.js +0 -10
- package/node_modules/nostr-tools/lib/esm/utils.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/wasm.js +3 -17
- package/node_modules/nostr-tools/lib/esm/wasm.js.map +4 -4
- package/node_modules/nostr-tools/lib/nostr.bundle.js +77 -121
- package/node_modules/nostr-tools/lib/nostr.bundle.js.map +4 -4
- package/node_modules/nostr-tools/lib/types/abstract-pool.d.ts +4 -7
- package/node_modules/nostr-tools/lib/types/abstract-relay.d.ts +2 -7
- package/node_modules/nostr-tools/lib/types/helpers.d.ts +2 -0
- package/node_modules/nostr-tools/lib/types/kinds.d.ts +0 -2
- package/node_modules/nostr-tools/lib/types/nipb0.d.ts +1 -0
- package/node_modules/nostr-tools/lib/types/nipb7.d.ts +1 -0
- package/node_modules/nostr-tools/lib/types/relay.d.ts +2 -2
- package/node_modules/nostr-tools/lib/types/utils.d.ts +0 -4
- package/node_modules/nostr-tools/package.json +1 -1
- package/openclaw.plugin.json +5 -0
- package/package.json +15 -41
- package/dist/inbound-direct-dm-runtime-DHn9NoYN.js +0 -2
- package/node_modules/nostr-tools/lib/types/nipb0.test.d.ts +0 -1
- /package/dist/{state-account-id-CvBZ9s6P.js → .setup/state-account-id-CvBZ9s6P.mjs} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../pure.ts", "../../
|
|
4
|
-
"sourcesContent": ["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
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAwB;AACxB,IAAAA,gBAAuC;;;
|
|
6
|
-
"names": ["import_utils", "i"
|
|
3
|
+
"sources": ["../../pure.ts", "../../core.ts", "../../utils.ts"],
|
|
4
|
+
"sourcesContent": ["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", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { 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"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAwB;AACxB,IAAAA,gBAAuC;;;ACOhC,IAAM,iBAAiB,OAAO,UAAU;AAsB/C,IAAM,WAAW,CAAC,QAAiD,eAAe;AAE3E,SAAS,cAAiB,OAAsC;AACrE,MAAI,CAAC,SAAS,KAAK;AAAG,WAAO;AAC7B,MAAI,OAAO,MAAM,SAAS;AAAU,WAAO;AAC3C,MAAI,OAAO,MAAM,YAAY;AAAU,WAAO;AAC9C,MAAI,OAAO,MAAM,eAAe;AAAU,WAAO;AACjD,MAAI,OAAO,MAAM,WAAW;AAAU,WAAO;AAC7C,MAAI,CAAC,MAAM,OAAO,MAAM,gBAAgB;AAAG,WAAO;AAElD,MAAI,CAAC,MAAM,QAAQ,MAAM,IAAI;AAAG,WAAO;AACvC,WAASC,KAAI,GAAGA,KAAI,MAAM,KAAK,QAAQA,MAAK;AAC1C,QAAI,MAAM,MAAM,KAAKA;AACrB,QAAI,CAAC,MAAM,QAAQ,GAAG;AAAG,aAAO;AAChC,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAI,OAAO,IAAI,OAAO;AAAU,eAAO;AAAA,IACzC;AAAA,EACF;AAEA,SAAO;AACT;AAOO,SAAS,WAAW,QAA0B;AACnD,SAAO,OAAO,KAAK,CAAC,GAAe,MAA0B;AAC3D,QAAI,EAAE,eAAe,EAAE,YAAY;AACjC,aAAO,EAAE,aAAa,EAAE;AAAA,IAC1B;AACA,WAAO,EAAE,GAAG,cAAc,EAAE,EAAE;AAAA,EAChC,CAAC;AACH;;;AD7DA,kBAAuB;;;AEEvB,mBAAuC;AAHhC,IAAM,cAA2B,IAAI,YAAY,OAAO;AACxD,IAAM,cAA2B,IAAI,YAAY;;;AFIxD,IAAM,KAAN,MAA0B;AAAA,EACxB,oBAAgC;AAC9B,WAAO,yBAAQ,MAAM,gBAAgB;AAAA,EACvC;AAAA,EACA,aAAa,WAA+B;AAC1C,eAAO,0BAAW,yBAAQ,aAAa,SAAS,CAAC;AAAA,EACnD;AAAA,EACA,cAAc,GAAkB,WAAsC;AACpE,UAAM,QAAQ;AACd,UAAM,aAAS,0BAAW,yBAAQ,aAAa,SAAS,CAAC;AACzD,UAAM,KAAK,aAAa,KAAK;AAC7B,UAAM,UAAM,0BAAW,yBAAQ,SAAK,0BAAW,aAAa,KAAK,CAAC,GAAG,SAAS,CAAC;AAC/E,UAAM,kBAAkB;AACxB,WAAO;AAAA,EACT;AAAA,EACA,YAAY,OAAsC;AAChD,QAAI,OAAO,MAAM,oBAAoB;AAAW,aAAO,MAAM;AAE7D,QAAI;AACF,YAAM,OAAO,aAAa,KAAK;AAC/B,UAAI,SAAS,MAAM,IAAI;AACrB,cAAM,kBAAkB;AACxB,eAAO;AAAA,MACT;AAEA,YAAM,QAAQ,yBAAQ,WAAO,0BAAW,MAAM,GAAG,OAAG,0BAAW,IAAI,OAAG,0BAAW,MAAM,MAAM,CAAC;AAC9F,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT,SAAS,KAAP;AACA,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAAS,eAAe,KAA4B;AACzD,MAAI,CAAC,cAAc,GAAG;AAAG,UAAM,IAAI,MAAM,wDAAwD;AACjG,SAAO,KAAK,UAAU,CAAC,GAAG,IAAI,QAAQ,IAAI,YAAY,IAAI,MAAM,IAAI,MAAM,IAAI,OAAO,CAAC;AACxF;AAEO,SAAS,aAAa,OAA8B;AACzD,MAAI,gBAAY,oBAAO,YAAY,OAAO,eAAe,KAAK,CAAC,CAAC;AAChE,aAAO,0BAAW,SAAS;AAC7B;AAEA,IAAM,IAAQ,IAAI,GAAG;AAEd,IAAM,oBAAoB,EAAE;AAC5B,IAAM,eAAe,EAAE;AACvB,IAAM,gBAAgB,EAAE;AACxB,IAAM,cAAc,EAAE;",
|
|
6
|
+
"names": ["import_utils", "i"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../references.ts", "../../nip19.ts", "../../utils.ts"],
|
|
4
|
-
"sourcesContent": ["import { decode, type AddressPointer, type ProfilePointer, type EventPointer } from './nip19.ts'\n\nimport type { Event } from './core.ts'\n\ntype Reference = {\n text: string\n profile?: ProfilePointer\n event?: EventPointer\n address?: AddressPointer\n}\n\nconst mentionRegex = /\\bnostr:((note|npub|naddr|nevent|nprofile)1\\w+)\\b|#\\[(\\d+)\\]/g\n\nexport function parseReferences(evt: Event): Reference[] {\n let references: Reference[] = []\n for (let ref of evt.content.matchAll(mentionRegex)) {\n if (ref[2]) {\n // it's a NIP-27 mention\n try {\n let { type, data } = decode(ref[1])\n switch (type) {\n case 'npub': {\n references.push({\n text: ref[0],\n profile: { pubkey: data as string, relays: [] },\n })\n break\n }\n case 'nprofile': {\n references.push({\n text: ref[0],\n profile: data as ProfilePointer,\n })\n break\n }\n case 'note': {\n references.push({\n text: ref[0],\n event: { id: data as string, relays: [] },\n })\n break\n }\n case 'nevent': {\n references.push({\n text: ref[0],\n event: data as EventPointer,\n })\n break\n }\n case 'naddr': {\n references.push({\n text: ref[0],\n address: data as AddressPointer,\n })\n break\n }\n }\n } catch (err) {\n /***/\n }\n } else if (ref[3]) {\n // it's a NIP-10 mention\n let idx = parseInt(ref[3], 10)\n let tag = evt.tags[idx]\n if (!tag) continue\n\n switch (tag[0]) {\n case 'p': {\n references.push({\n text: ref[0],\n profile: { pubkey: tag[1], relays: tag[2] ? [tag[2]] : [] },\n })\n break\n }\n case 'e': {\n references.push({\n text: ref[0],\n event: { id: tag[1], relays: tag[2] ? [tag[2]] : [] },\n })\n break\n }\n case 'a': {\n try {\n let [kind, pubkey, identifier] = tag[1].split(':')\n references.push({\n text: ref[0],\n address: {\n identifier,\n pubkey,\n kind: parseInt(kind, 10),\n relays: tag[2] ? [tag[2]] : [],\n },\n })\n } catch (err) {\n /***/\n }\n break\n }\n }\n }\n }\n\n return references\n}\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils.js'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code as `${string}1${string}`, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n if (rest.length < 2) throw new Error('not enough data to read TLV')\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\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 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"],
|
|
4
|
+
"sourcesContent": ["import { decode, type AddressPointer, type ProfilePointer, type EventPointer } from './nip19.ts'\n\nimport type { Event } from './core.ts'\n\ntype Reference = {\n text: string\n profile?: ProfilePointer\n event?: EventPointer\n address?: AddressPointer\n}\n\nconst mentionRegex = /\\bnostr:((note|npub|naddr|nevent|nprofile)1\\w+)\\b|#\\[(\\d+)\\]/g\n\nexport function parseReferences(evt: Event): Reference[] {\n let references: Reference[] = []\n for (let ref of evt.content.matchAll(mentionRegex)) {\n if (ref[2]) {\n // it's a NIP-27 mention\n try {\n let { type, data } = decode(ref[1])\n switch (type) {\n case 'npub': {\n references.push({\n text: ref[0],\n profile: { pubkey: data as string, relays: [] },\n })\n break\n }\n case 'nprofile': {\n references.push({\n text: ref[0],\n profile: data as ProfilePointer,\n })\n break\n }\n case 'note': {\n references.push({\n text: ref[0],\n event: { id: data as string, relays: [] },\n })\n break\n }\n case 'nevent': {\n references.push({\n text: ref[0],\n event: data as EventPointer,\n })\n break\n }\n case 'naddr': {\n references.push({\n text: ref[0],\n address: data as AddressPointer,\n })\n break\n }\n }\n } catch (err) {\n /***/\n }\n } else if (ref[3]) {\n // it's a NIP-10 mention\n let idx = parseInt(ref[3], 10)\n let tag = evt.tags[idx]\n if (!tag) continue\n\n switch (tag[0]) {\n case 'p': {\n references.push({\n text: ref[0],\n profile: { pubkey: tag[1], relays: tag[2] ? [tag[2]] : [] },\n })\n break\n }\n case 'e': {\n references.push({\n text: ref[0],\n event: { id: tag[1], relays: tag[2] ? [tag[2]] : [] },\n })\n break\n }\n case 'a': {\n try {\n let [kind, pubkey, identifier] = tag[1].split(':')\n references.push({\n text: ref[0],\n address: {\n identifier,\n pubkey,\n kind: parseInt(kind, 10),\n relays: tag[2] ? [tag[2]] : [],\n },\n })\n } catch (err) {\n /***/\n }\n break\n }\n }\n }\n }\n\n return references\n}\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils.js'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code as `${string}1${string}`, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n if (rest.length < 2) throw new Error('not enough data to read TLV')\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\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"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["import_utils"]
|
|
7
7
|
}
|
|
@@ -30,42 +30,7 @@ module.exports = __toCommonJS(relay_exports);
|
|
|
30
30
|
|
|
31
31
|
// pure.ts
|
|
32
32
|
var import_secp256k1 = require("@noble/curves/secp256k1.js");
|
|
33
|
-
var
|
|
34
|
-
|
|
35
|
-
// utils.ts
|
|
36
|
-
var import_utils = require("@noble/hashes/utils.js");
|
|
37
|
-
var utf8Decoder = new TextDecoder("utf-8");
|
|
38
|
-
var utf8Encoder = new TextEncoder();
|
|
39
|
-
function normalizeURL(url) {
|
|
40
|
-
try {
|
|
41
|
-
if (url.indexOf("://") === -1)
|
|
42
|
-
url = "wss://" + url;
|
|
43
|
-
let p = new URL(url);
|
|
44
|
-
if (p.protocol === "http:")
|
|
45
|
-
p.protocol = "ws:";
|
|
46
|
-
else if (p.protocol === "https:")
|
|
47
|
-
p.protocol = "wss:";
|
|
48
|
-
p.pathname = p.pathname.replace(/\/+/g, "/");
|
|
49
|
-
if (p.pathname.endsWith("/"))
|
|
50
|
-
p.pathname = p.pathname.slice(0, -1);
|
|
51
|
-
if (p.port === "80" && p.protocol === "ws:" || p.port === "443" && p.protocol === "wss:")
|
|
52
|
-
p.port = "";
|
|
53
|
-
p.searchParams.sort();
|
|
54
|
-
p.hash = "";
|
|
55
|
-
return p.toString();
|
|
56
|
-
} catch (e) {
|
|
57
|
-
throw new Error(`Invalid URL: ${url}`);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
function isHex32(input) {
|
|
61
|
-
for (let i2 = 0; i2 < 64; i2++) {
|
|
62
|
-
let cc = input.charCodeAt(i2);
|
|
63
|
-
if (isNaN(cc) || cc < 48 || cc > 102 || cc > 57 && cc < 97) {
|
|
64
|
-
return false;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
return true;
|
|
68
|
-
}
|
|
33
|
+
var import_utils2 = require("@noble/hashes/utils.js");
|
|
69
34
|
|
|
70
35
|
// core.ts
|
|
71
36
|
var verifiedSymbol = Symbol("verified");
|
|
@@ -81,7 +46,7 @@ function validateEvent(event) {
|
|
|
81
46
|
return false;
|
|
82
47
|
if (typeof event.pubkey !== "string")
|
|
83
48
|
return false;
|
|
84
|
-
if (!
|
|
49
|
+
if (!event.pubkey.match(/^[a-f0-9]{64}$/))
|
|
85
50
|
return false;
|
|
86
51
|
if (!Array.isArray(event.tags))
|
|
87
52
|
return false;
|
|
@@ -99,18 +64,46 @@ function validateEvent(event) {
|
|
|
99
64
|
|
|
100
65
|
// pure.ts
|
|
101
66
|
var import_sha2 = require("@noble/hashes/sha2.js");
|
|
67
|
+
|
|
68
|
+
// utils.ts
|
|
69
|
+
var import_utils = require("@noble/hashes/utils.js");
|
|
70
|
+
var utf8Decoder = new TextDecoder("utf-8");
|
|
71
|
+
var utf8Encoder = new TextEncoder();
|
|
72
|
+
function normalizeURL(url) {
|
|
73
|
+
try {
|
|
74
|
+
if (url.indexOf("://") === -1)
|
|
75
|
+
url = "wss://" + url;
|
|
76
|
+
let p = new URL(url);
|
|
77
|
+
if (p.protocol === "http:")
|
|
78
|
+
p.protocol = "ws:";
|
|
79
|
+
else if (p.protocol === "https:")
|
|
80
|
+
p.protocol = "wss:";
|
|
81
|
+
p.pathname = p.pathname.replace(/\/+/g, "/");
|
|
82
|
+
if (p.pathname.endsWith("/"))
|
|
83
|
+
p.pathname = p.pathname.slice(0, -1);
|
|
84
|
+
if (p.port === "80" && p.protocol === "ws:" || p.port === "443" && p.protocol === "wss:")
|
|
85
|
+
p.port = "";
|
|
86
|
+
p.searchParams.sort();
|
|
87
|
+
p.hash = "";
|
|
88
|
+
return p.toString();
|
|
89
|
+
} catch (e) {
|
|
90
|
+
throw new Error(`Invalid URL: ${url}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// pure.ts
|
|
102
95
|
var JS = class {
|
|
103
96
|
generateSecretKey() {
|
|
104
97
|
return import_secp256k1.schnorr.utils.randomSecretKey();
|
|
105
98
|
}
|
|
106
99
|
getPublicKey(secretKey) {
|
|
107
|
-
return (0,
|
|
100
|
+
return (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
|
|
108
101
|
}
|
|
109
102
|
finalizeEvent(t, secretKey) {
|
|
110
103
|
const event = t;
|
|
111
|
-
event.pubkey = (0,
|
|
104
|
+
event.pubkey = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
|
|
112
105
|
event.id = getEventHash(event);
|
|
113
|
-
event.sig = (0,
|
|
106
|
+
event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign((0, import_utils2.hexToBytes)(getEventHash(event)), secretKey));
|
|
114
107
|
event[verifiedSymbol] = true;
|
|
115
108
|
return event;
|
|
116
109
|
}
|
|
@@ -123,7 +116,7 @@ var JS = class {
|
|
|
123
116
|
event[verifiedSymbol] = false;
|
|
124
117
|
return false;
|
|
125
118
|
}
|
|
126
|
-
const valid = import_secp256k1.schnorr.verify((0,
|
|
119
|
+
const valid = import_secp256k1.schnorr.verify((0, import_utils2.hexToBytes)(event.sig), (0, import_utils2.hexToBytes)(hash), (0, import_utils2.hexToBytes)(event.pubkey));
|
|
127
120
|
event[verifiedSymbol] = valid;
|
|
128
121
|
return valid;
|
|
129
122
|
} catch (err) {
|
|
@@ -139,7 +132,7 @@ function serializeEvent(evt) {
|
|
|
139
132
|
}
|
|
140
133
|
function getEventHash(event) {
|
|
141
134
|
let eventHash = (0, import_sha2.sha256)(utf8Encoder.encode(serializeEvent(event)));
|
|
142
|
-
return (0,
|
|
135
|
+
return (0, import_utils2.bytesToHex)(eventHash);
|
|
143
136
|
}
|
|
144
137
|
var i = new JS();
|
|
145
138
|
var generateSecretKey = i.generateSecretKey;
|
|
@@ -240,14 +233,12 @@ var AbstractRelay = class {
|
|
|
240
233
|
openSubs = /* @__PURE__ */ new Map();
|
|
241
234
|
enablePing;
|
|
242
235
|
enableReconnect;
|
|
243
|
-
idleTimeout = 0;
|
|
244
236
|
idleSince = Date.now();
|
|
245
237
|
ongoingOperations = 0;
|
|
246
238
|
reconnectTimeoutHandle;
|
|
247
239
|
pingIntervalHandle;
|
|
248
240
|
reconnectAttempts = 0;
|
|
249
241
|
skipReconnection = false;
|
|
250
|
-
idleTimeoutHandle;
|
|
251
242
|
connectionPromise;
|
|
252
243
|
openCountRequests = /* @__PURE__ */ new Map();
|
|
253
244
|
openEventPublishes = /* @__PURE__ */ new Map();
|
|
@@ -263,8 +254,6 @@ var AbstractRelay = class {
|
|
|
263
254
|
this._WebSocket = opts.websocketImplementation || WebSocket;
|
|
264
255
|
this.enablePing = opts.enablePing;
|
|
265
256
|
this.enableReconnect = opts.enableReconnect || false;
|
|
266
|
-
if (opts.idleTimeout)
|
|
267
|
-
this.idleTimeout = opts.idleTimeout;
|
|
268
257
|
}
|
|
269
258
|
static async connect(url, opts) {
|
|
270
259
|
const relay = new AbstractRelay(url, opts);
|
|
@@ -288,22 +277,6 @@ var AbstractRelay = class {
|
|
|
288
277
|
get connected() {
|
|
289
278
|
return this._connected;
|
|
290
279
|
}
|
|
291
|
-
clearIdleTimeout() {
|
|
292
|
-
if (this.idleTimeoutHandle) {
|
|
293
|
-
clearTimeout(this.idleTimeoutHandle);
|
|
294
|
-
this.idleTimeoutHandle = void 0;
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
scheduleIdleClose() {
|
|
298
|
-
this.clearIdleTimeout();
|
|
299
|
-
if (this.idleTimeout > 0) {
|
|
300
|
-
this.idleTimeoutHandle = setTimeout(() => {
|
|
301
|
-
if (this.ongoingOperations === 0 && this.idleSince) {
|
|
302
|
-
this.close();
|
|
303
|
-
}
|
|
304
|
-
}, this.idleTimeout);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
280
|
async reconnect() {
|
|
308
281
|
const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)];
|
|
309
282
|
this.reconnectAttempts++;
|
|
@@ -315,11 +288,6 @@ var AbstractRelay = class {
|
|
|
315
288
|
}, backoff);
|
|
316
289
|
}
|
|
317
290
|
handleHardClose(reason) {
|
|
318
|
-
if (this.ws) {
|
|
319
|
-
this.ws.onopen = null;
|
|
320
|
-
this.ws.onerror = null;
|
|
321
|
-
this.ws.onclose = null;
|
|
322
|
-
}
|
|
323
291
|
if (this.pingIntervalHandle) {
|
|
324
292
|
clearInterval(this.pingIntervalHandle);
|
|
325
293
|
this.pingIntervalHandle = void 0;
|
|
@@ -327,7 +295,6 @@ var AbstractRelay = class {
|
|
|
327
295
|
this._connected = false;
|
|
328
296
|
this.connectionPromise = void 0;
|
|
329
297
|
this.idleSince = void 0;
|
|
330
|
-
this.clearIdleTimeout();
|
|
331
298
|
if (this.enableReconnect && !this.skipReconnection) {
|
|
332
299
|
this.reconnect();
|
|
333
300
|
} else {
|
|
@@ -350,6 +317,7 @@ var AbstractRelay = class {
|
|
|
350
317
|
if (this.reconnectAttempts === 0) {
|
|
351
318
|
this.skipReconnection = true;
|
|
352
319
|
}
|
|
320
|
+
this.onclose?.();
|
|
353
321
|
this.handleHardClose("relay connection timed out");
|
|
354
322
|
}, opts.timeout);
|
|
355
323
|
}
|
|
@@ -395,6 +363,7 @@ var AbstractRelay = class {
|
|
|
395
363
|
if (this.reconnectAttempts === 0) {
|
|
396
364
|
this.skipReconnection = true;
|
|
397
365
|
}
|
|
366
|
+
this.onclose?.();
|
|
398
367
|
this.handleHardClose("relay connection failed");
|
|
399
368
|
};
|
|
400
369
|
this.ws.onclose = (ev) => {
|
|
@@ -483,7 +452,6 @@ var AbstractRelay = class {
|
|
|
483
452
|
}
|
|
484
453
|
async publish(event) {
|
|
485
454
|
this.idleSince = void 0;
|
|
486
|
-
this.clearIdleTimeout();
|
|
487
455
|
this.ongoingOperations++;
|
|
488
456
|
const ret = new Promise((resolve, reject) => {
|
|
489
457
|
const timeout = setTimeout(() => {
|
|
@@ -505,10 +473,8 @@ var AbstractRelay = class {
|
|
|
505
473
|
}
|
|
506
474
|
}
|
|
507
475
|
this.ongoingOperations--;
|
|
508
|
-
if (this.ongoingOperations === 0)
|
|
476
|
+
if (this.ongoingOperations === 0)
|
|
509
477
|
this.idleSince = Date.now();
|
|
510
|
-
this.scheduleIdleClose();
|
|
511
|
-
}
|
|
512
478
|
return ret;
|
|
513
479
|
}
|
|
514
480
|
async count(filters, params) {
|
|
@@ -534,7 +500,6 @@ var AbstractRelay = class {
|
|
|
534
500
|
subscribe(filters, params) {
|
|
535
501
|
if (params.label !== "<forced-ping>") {
|
|
536
502
|
this.idleSince = void 0;
|
|
537
|
-
this.clearIdleTimeout();
|
|
538
503
|
this.ongoingOperations++;
|
|
539
504
|
}
|
|
540
505
|
const sub = this.prepareSubscription(filters, params);
|
|
@@ -563,17 +528,10 @@ var AbstractRelay = class {
|
|
|
563
528
|
}
|
|
564
529
|
this.closeAllSubscriptions("relay connection closed by us");
|
|
565
530
|
this._connected = false;
|
|
566
|
-
this.connectionPromise = void 0;
|
|
567
531
|
this.idleSince = void 0;
|
|
568
|
-
this.clearIdleTimeout();
|
|
569
532
|
this.onclose?.();
|
|
570
|
-
if (this.ws) {
|
|
571
|
-
this.ws
|
|
572
|
-
this.ws.onerror = null;
|
|
573
|
-
this.ws.onclose = null;
|
|
574
|
-
if (this.ws.readyState !== this._WebSocket.CLOSING && this.ws.readyState !== this._WebSocket.CLOSED) {
|
|
575
|
-
this.ws.close();
|
|
576
|
-
}
|
|
533
|
+
if (this.ws?.readyState === this._WebSocket.OPEN) {
|
|
534
|
+
this.ws?.close();
|
|
577
535
|
}
|
|
578
536
|
}
|
|
579
537
|
_onmessage(ev) {
|
|
@@ -600,7 +558,7 @@ var AbstractRelay = class {
|
|
|
600
558
|
case "EVENT": {
|
|
601
559
|
const so = this.openSubs.get(data[1]);
|
|
602
560
|
const event = data[2];
|
|
603
|
-
if (
|
|
561
|
+
if (this.verifyEvent(event) && matchFilters(so.filters, event)) {
|
|
604
562
|
so.onevent(event);
|
|
605
563
|
} else {
|
|
606
564
|
so.oninvalidevent?.(event);
|
|
@@ -748,10 +706,8 @@ var Subscription = class {
|
|
|
748
706
|
}
|
|
749
707
|
this.relay.openSubs.delete(this.id);
|
|
750
708
|
this.relay.ongoingOperations--;
|
|
751
|
-
if (this.relay.ongoingOperations === 0)
|
|
709
|
+
if (this.relay.ongoingOperations === 0)
|
|
752
710
|
this.relay.idleSince = Date.now();
|
|
753
|
-
this.relay.scheduleIdleClose();
|
|
754
|
-
}
|
|
755
711
|
this.onclose?.(reason);
|
|
756
712
|
}
|
|
757
713
|
};
|