@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
3
|
"sources": ["../../nip44.ts", "../../utils.ts"],
|
|
4
|
-
"sourcesContent": ["import { chacha20 } from '@noble/ciphers/chacha.js'\nimport { equalBytes } from '@noble/ciphers/utils.js'\nimport { secp256k1 } from '@noble/curves/secp256k1.js'\nimport { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf.js'\nimport { hmac } from '@noble/hashes/hmac.js'\nimport { sha256 } from '@noble/hashes/sha2.js'\nimport { concatBytes, hexToBytes, randomBytes } from '@noble/hashes/utils.js'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst minPlaintextSize = 0x0001 // 1b msg => padded to 32b\nconst maxPlaintextSize = 0xffffffff // 4294967295 (2^32-1)\nconst extendedPrefixThreshold = 0x10000 // 65536: lengths below use 2-byte u16 prefix, at or above use 6-byte prefix\n\nexport function getConversationKey(privkeyA: Uint8Array, pubkeyB: string): Uint8Array {\n const sharedX = secp256k1.getSharedSecret(privkeyA, hexToBytes('02' + pubkeyB)).subarray(1, 33)\n return hkdf_extract(sha256, sharedX, utf8Encoder.encode('nip44-v2'))\n}\n\nfunction getMessageKeys(\n conversationKey: Uint8Array,\n nonce: Uint8Array,\n): { chacha_key: Uint8Array; chacha_nonce: Uint8Array; hmac_key: Uint8Array } {\n const keys = hkdf_expand(sha256, conversationKey, nonce, 76)\n return {\n chacha_key: keys.subarray(0, 32),\n chacha_nonce: keys.subarray(32, 44),\n hmac_key: keys.subarray(44, 76),\n }\n}\n\nfunction calcPaddedLen(len: number): number {\n if (!Number.isSafeInteger(len) || len < 1) throw new Error('expected positive integer')\n if (len <= 32) return 32\n const nextPower = 2 ** (Math.floor(Math.log2(len - 1)) + 1)\n const chunk = nextPower <= 256 ? 32 : nextPower / 8\n return chunk * (Math.floor((len - 1) / chunk) + 1)\n}\n\nfunction writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > 0xffff)\n throw new Error('invalid plaintext size: must be between 1 and 65535 bytes')\n const arr = new Uint8Array(2)\n new DataView(arr.buffer).setUint16(0, num, false)\n return arr\n}\n\nfunction writeU32BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < extendedPrefixThreshold || num > maxPlaintextSize)\n throw new Error('invalid plaintext size: must be between 65536 and 4294967295 bytes')\n const arr = new Uint8Array(4)\n new DataView(arr.buffer).setUint32(0, num, false)\n return arr\n}\n\nfunction pad(plaintext: string): Uint8Array {\n const unpadded = utf8Encoder.encode(plaintext)\n const unpaddedLen = unpadded.length\n if (unpaddedLen < minPlaintextSize || unpaddedLen > maxPlaintextSize)\n throw new Error('invalid plaintext size: must be between 1 and 4294967295 bytes')\n const prefix =\n unpaddedLen >= extendedPrefixThreshold\n ? concatBytes(new Uint8Array([0, 0]), writeU32BE(unpaddedLen)) // 6 bytes\n : writeU16BE(unpaddedLen) // 2 bytes\n const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen)\n return concatBytes(prefix, unpadded, suffix)\n}\n\nfunction unpad(padded: Uint8Array): string {\n const dv = new DataView(padded.buffer, padded.byteOffset, padded.byteLength)\n const firstTwo = dv.getUint16(0)\n let unpaddedLen: number\n let prefixLen: number\n if (firstTwo === 0) {\n // Extended format: 2 zero bytes + 4-byte u32 length\n unpaddedLen = dv.getUint32(2)\n if (unpaddedLen < extendedPrefixThreshold) throw new Error('invalid padding')\n prefixLen = 6\n } else {\n unpaddedLen = firstTwo\n prefixLen = 2\n }\n const unpadded = padded.subarray(prefixLen, prefixLen + unpaddedLen)\n if (\n unpaddedLen < minPlaintextSize ||\n unpaddedLen > maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== prefixLen + calcPaddedLen(unpaddedLen)\n )\n throw new Error('invalid padding')\n return utf8Decoder.decode(unpadded)\n}\n\nfunction hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array): Uint8Array {\n if (aad.length !== 32) throw new Error('AAD associated data must be 32 bytes')\n const combined = concatBytes(aad, message)\n return hmac(sha256, key, combined)\n}\n\n// metadata: always 65b (version: 1b, nonce: 32b, mac: 32b)\n// plaintext: 1b to 0xffffffff\n// padded plaintext (small, <65536): 32b to 0x10000, with 2b prefix -> 34b to 0x10000+2\n// padded plaintext (large, >=65536): 0x10000 to 0x100000000, with 6b prefix -> 0x10006 to 0x100000000+6\n// ciphertext: same as padded plaintext (chacha20 doesn't change length)\n// raw payload (small): 99 (65+34) to 65603 (65+0x10000+2)\n// raw payload (large): 65607 (65+0x10006) to 4294967367 (65+0x100000000+6)\nfunction decodePayload(payload: string): { nonce: Uint8Array; ciphertext: Uint8Array; mac: Uint8Array } {\n if (typeof payload !== 'string') throw new Error('payload must be a valid string')\n const plen = payload.length\n if (plen < 132) throw new Error('invalid payload length: ' + plen)\n if (payload[0] === '#') throw new Error('unknown encryption version')\n let data: Uint8Array\n try {\n data = base64.decode(payload)\n } catch (error) {\n throw new Error('invalid base64: ' + (error as any).message)\n }\n const dlen = data.length\n if (dlen < 99) throw new Error('invalid data length: ' + dlen)\n const vers = data[0]\n if (vers !== 2) throw new Error('unknown encryption version ' + vers)\n return {\n nonce: data.subarray(1, 33),\n ciphertext: data.subarray(33, -32),\n mac: data.subarray(-32),\n }\n}\n\nexport function encrypt(plaintext: string, conversationKey: Uint8Array, nonce: Uint8Array = randomBytes(32)): string {\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const padded = pad(plaintext)\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded)\n const mac = hmacAad(hmac_key, ciphertext, nonce)\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac))\n}\n\n/** Callers should validate payload size before calling to prevent DoS from oversized inputs. */\nexport function decrypt(payload: string, conversationKey: Uint8Array): string {\n const { nonce, ciphertext, mac } = decodePayload(payload)\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const calculatedMac = hmacAad(hmac_key, ciphertext, nonce)\n if (!equalBytes(calculatedMac, mac)) throw new Error('invalid MAC')\n const padded = chacha20(chacha_key, chacha_nonce, ciphertext)\n return unpad(padded)\n}\n\nexport const v2 = {\n utils: {\n getConversationKey,\n calcPaddedLen,\n pad,\n unpad,\n },\n encrypt,\n decrypt,\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 { chacha20 } from '@noble/ciphers/chacha.js'\nimport { equalBytes } from '@noble/ciphers/utils.js'\nimport { secp256k1 } from '@noble/curves/secp256k1.js'\nimport { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf.js'\nimport { hmac } from '@noble/hashes/hmac.js'\nimport { sha256 } from '@noble/hashes/sha2.js'\nimport { concatBytes, hexToBytes, randomBytes } from '@noble/hashes/utils.js'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst minPlaintextSize = 0x0001 // 1b msg => padded to 32b\nconst maxPlaintextSize = 0xffffffff // 4294967295 (2^32-1)\nconst extendedPrefixThreshold = 0x10000 // 65536: lengths below use 2-byte u16 prefix, at or above use 6-byte prefix\n\nexport function getConversationKey(privkeyA: Uint8Array, pubkeyB: string): Uint8Array {\n const sharedX = secp256k1.getSharedSecret(privkeyA, hexToBytes('02' + pubkeyB)).subarray(1, 33)\n return hkdf_extract(sha256, sharedX, utf8Encoder.encode('nip44-v2'))\n}\n\nfunction getMessageKeys(\n conversationKey: Uint8Array,\n nonce: Uint8Array,\n): { chacha_key: Uint8Array; chacha_nonce: Uint8Array; hmac_key: Uint8Array } {\n const keys = hkdf_expand(sha256, conversationKey, nonce, 76)\n return {\n chacha_key: keys.subarray(0, 32),\n chacha_nonce: keys.subarray(32, 44),\n hmac_key: keys.subarray(44, 76),\n }\n}\n\nfunction calcPaddedLen(len: number): number {\n if (!Number.isSafeInteger(len) || len < 1) throw new Error('expected positive integer')\n if (len <= 32) return 32\n const nextPower = 2 ** (Math.floor(Math.log2(len - 1)) + 1)\n const chunk = nextPower <= 256 ? 32 : nextPower / 8\n return chunk * (Math.floor((len - 1) / chunk) + 1)\n}\n\nfunction writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > 0xffff)\n throw new Error('invalid plaintext size: must be between 1 and 65535 bytes')\n const arr = new Uint8Array(2)\n new DataView(arr.buffer).setUint16(0, num, false)\n return arr\n}\n\nfunction writeU32BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < extendedPrefixThreshold || num > maxPlaintextSize)\n throw new Error('invalid plaintext size: must be between 65536 and 4294967295 bytes')\n const arr = new Uint8Array(4)\n new DataView(arr.buffer).setUint32(0, num, false)\n return arr\n}\n\nfunction pad(plaintext: string): Uint8Array {\n const unpadded = utf8Encoder.encode(plaintext)\n const unpaddedLen = unpadded.length\n if (unpaddedLen < minPlaintextSize || unpaddedLen > maxPlaintextSize)\n throw new Error('invalid plaintext size: must be between 1 and 4294967295 bytes')\n const prefix =\n unpaddedLen >= extendedPrefixThreshold\n ? concatBytes(new Uint8Array([0, 0]), writeU32BE(unpaddedLen)) // 6 bytes\n : writeU16BE(unpaddedLen) // 2 bytes\n const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen)\n return concatBytes(prefix, unpadded, suffix)\n}\n\nfunction unpad(padded: Uint8Array): string {\n const dv = new DataView(padded.buffer, padded.byteOffset, padded.byteLength)\n const firstTwo = dv.getUint16(0)\n let unpaddedLen: number\n let prefixLen: number\n if (firstTwo === 0) {\n // Extended format: 2 zero bytes + 4-byte u32 length\n unpaddedLen = dv.getUint32(2)\n if (unpaddedLen < extendedPrefixThreshold) throw new Error('invalid padding')\n prefixLen = 6\n } else {\n unpaddedLen = firstTwo\n prefixLen = 2\n }\n const unpadded = padded.subarray(prefixLen, prefixLen + unpaddedLen)\n if (\n unpaddedLen < minPlaintextSize ||\n unpaddedLen > maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== prefixLen + calcPaddedLen(unpaddedLen)\n )\n throw new Error('invalid padding')\n return utf8Decoder.decode(unpadded)\n}\n\nfunction hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array): Uint8Array {\n if (aad.length !== 32) throw new Error('AAD associated data must be 32 bytes')\n const combined = concatBytes(aad, message)\n return hmac(sha256, key, combined)\n}\n\n// metadata: always 65b (version: 1b, nonce: 32b, mac: 32b)\n// plaintext: 1b to 0xffffffff\n// padded plaintext (small, <65536): 32b to 0x10000, with 2b prefix -> 34b to 0x10000+2\n// padded plaintext (large, >=65536): 0x10000 to 0x100000000, with 6b prefix -> 0x10006 to 0x100000000+6\n// ciphertext: same as padded plaintext (chacha20 doesn't change length)\n// raw payload (small): 99 (65+34) to 65603 (65+0x10000+2)\n// raw payload (large): 65607 (65+0x10006) to 4294967367 (65+0x100000000+6)\nfunction decodePayload(payload: string): { nonce: Uint8Array; ciphertext: Uint8Array; mac: Uint8Array } {\n if (typeof payload !== 'string') throw new Error('payload must be a valid string')\n const plen = payload.length\n if (plen < 132) throw new Error('invalid payload length: ' + plen)\n if (payload[0] === '#') throw new Error('unknown encryption version')\n let data: Uint8Array\n try {\n data = base64.decode(payload)\n } catch (error) {\n throw new Error('invalid base64: ' + (error as any).message)\n }\n const dlen = data.length\n if (dlen < 99) throw new Error('invalid data length: ' + dlen)\n const vers = data[0]\n if (vers !== 2) throw new Error('unknown encryption version ' + vers)\n return {\n nonce: data.subarray(1, 33),\n ciphertext: data.subarray(33, -32),\n mac: data.subarray(-32),\n }\n}\n\nexport function encrypt(plaintext: string, conversationKey: Uint8Array, nonce: Uint8Array = randomBytes(32)): string {\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const padded = pad(plaintext)\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded)\n const mac = hmacAad(hmac_key, ciphertext, nonce)\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac))\n}\n\n/** Callers should validate payload size before calling to prevent DoS from oversized inputs. */\nexport function decrypt(payload: string, conversationKey: Uint8Array): string {\n const { nonce, ciphertext, mac } = decodePayload(payload)\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const calculatedMac = hmacAad(hmac_key, ciphertext, nonce)\n if (!equalBytes(calculatedMac, mac)) throw new Error('invalid MAC')\n const padded = chacha20(chacha_key, chacha_nonce, ciphertext)\n return unpad(padded)\n}\n\nexport const v2 = {\n utils: {\n getConversationKey,\n calcPaddedLen,\n pad,\n unpad,\n },\n encrypt,\n decrypt,\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": ["hexToBytes", "hexToBytes"]
|
|
7
7
|
}
|
|
@@ -1,25 +1,9 @@
|
|
|
1
1
|
// nip45.ts
|
|
2
2
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
3
|
-
import { bytesToHex
|
|
4
|
-
|
|
5
|
-
// utils.ts
|
|
6
|
-
import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
|
|
7
|
-
var utf8Decoder = new TextDecoder("utf-8");
|
|
8
|
-
var utf8Encoder = new TextEncoder();
|
|
9
|
-
function isHex32(input) {
|
|
10
|
-
for (let i = 0; i < 64; i++) {
|
|
11
|
-
let cc = input.charCodeAt(i);
|
|
12
|
-
if (isNaN(cc) || cc < 48 || cc > 102 || cc > 57 && cc < 97) {
|
|
13
|
-
return false;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
return true;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// nip45.ts
|
|
3
|
+
import { bytesToHex } from "@noble/hashes/utils.js";
|
|
20
4
|
var M = 256;
|
|
21
5
|
var HLL_HEX_LENGTH = M * 2;
|
|
22
|
-
var
|
|
6
|
+
var utf8Encoder = new TextEncoder();
|
|
23
7
|
function getCountManyFilter(target, directive) {
|
|
24
8
|
switch (directive) {
|
|
25
9
|
case "reactions":
|
|
@@ -40,7 +24,7 @@ function newHll() {
|
|
|
40
24
|
return new Uint8Array(M);
|
|
41
25
|
}
|
|
42
26
|
function hllDecode(hex) {
|
|
43
|
-
if (hex.length !== HLL_HEX_LENGTH || !/^[0-9a-
|
|
27
|
+
if (hex.length !== HLL_HEX_LENGTH || !/^[0-9a-fA-F]+$/.test(hex))
|
|
44
28
|
return void 0;
|
|
45
29
|
const registers = new Uint8Array(M);
|
|
46
30
|
for (let i = 0; i < M; i++) {
|
|
@@ -59,12 +43,12 @@ function hllEncode(registers) {
|
|
|
59
43
|
}
|
|
60
44
|
function computeOffset(filterFirstTagValue) {
|
|
61
45
|
let hex = filterFirstTagValue;
|
|
62
|
-
if (!
|
|
46
|
+
if (!isHex64(hex)) {
|
|
63
47
|
const parts = hex.split(":");
|
|
64
|
-
if (parts.length === 3 &&
|
|
48
|
+
if (parts.length === 3 && isHex64(parts[1])) {
|
|
65
49
|
hex = parts[1];
|
|
66
50
|
} else {
|
|
67
|
-
hex =
|
|
51
|
+
hex = bytesToHex(sha256(utf8Encoder.encode(filterFirstTagValue)));
|
|
68
52
|
}
|
|
69
53
|
}
|
|
70
54
|
return parseInt(hex[32], 16) + 8;
|
|
@@ -82,7 +66,7 @@ function getFilterFirstTagValue(filter) {
|
|
|
82
66
|
function feedPubkey(hll, pubkey, offset) {
|
|
83
67
|
if (offset < 0 || offset > 24)
|
|
84
68
|
throw new Error(`invalid offset ${offset}`);
|
|
85
|
-
if (!
|
|
69
|
+
if (!isHex64(pubkey))
|
|
86
70
|
throw new Error("pubkey must be 32-byte hex");
|
|
87
71
|
if (hll.length === 0)
|
|
88
72
|
hll = newHll();
|
|
@@ -126,6 +110,9 @@ function estimateCount(hll) {
|
|
|
126
110
|
return Math.floor(linearCounting(M, v));
|
|
127
111
|
return Math.floor(estimate);
|
|
128
112
|
}
|
|
113
|
+
function isHex64(value) {
|
|
114
|
+
return /^[0-9a-fA-F]{64}$/.test(value);
|
|
115
|
+
}
|
|
129
116
|
function countLeadingZeroBitsAfterOffset(pubkey, offset) {
|
|
130
117
|
let zeroBits = 0;
|
|
131
118
|
for (let i = offset + 1; i < offset + 8; i++) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../nip45.ts"
|
|
4
|
-
"sourcesContent": ["import { sha256 } from '@noble/hashes/sha2.js'\nimport { bytesToHex } from '@noble/hashes/utils.js'\n\nimport type { Event } from './core.ts'\nimport type { Filter } from './filter.ts'\
|
|
5
|
-
"mappings": ";AAAA,SAAS,cAAc;AACvB,SAAS,
|
|
6
|
-
"names": [
|
|
3
|
+
"sources": ["../../nip45.ts"],
|
|
4
|
+
"sourcesContent": ["import { sha256 } from '@noble/hashes/sha2.js'\nimport { bytesToHex } from '@noble/hashes/utils.js'\n\nimport type { Event } from './core.ts'\nimport type { Filter } from './filter.ts'\n\nconst M = 256\nconst HLL_HEX_LENGTH = M * 2\nconst utf8Encoder = new TextEncoder()\n\nexport type CountManyDirective = 'reactions' | 'reposts' | 'quotes' | 'replies' | 'comments' | 'followers'\n\nexport function getCountManyFilter(target: string, directive: CountManyDirective): Filter {\n switch (directive) {\n case 'reactions':\n return { '#e': [target], kinds: [7] }\n case 'reposts':\n return { '#e': [target], kinds: [6] }\n case 'quotes':\n return { '#q': [target], kinds: [1, 1111] }\n case 'replies':\n return { '#e': [target], kinds: [1] }\n case 'comments':\n return { '#E': [target], kinds: [1111] }\n case 'followers':\n return { '#p': [target], kinds: [3] }\n }\n}\n\nexport function newHll(): Uint8Array {\n return new Uint8Array(M)\n}\n\nexport function hllDecode(hex: string): Uint8Array | undefined {\n if (hex.length !== HLL_HEX_LENGTH || !/^[0-9a-fA-F]+$/.test(hex)) return undefined\n\n const registers = new Uint8Array(M)\n for (let i = 0; i < M; i++) {\n registers[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16)\n }\n return registers\n}\n\nexport function hllEncode(registers: Uint8Array): string {\n if (registers.length !== M) throw new Error(`invalid number of registers ${registers.length}`)\n\n let hex = ''\n for (let i = 0; i < M; i++) {\n hex += registers[i].toString(16).padStart(2, '0')\n }\n return hex\n}\n\nexport function computeOffset(filterFirstTagValue: string): number {\n let hex = filterFirstTagValue\n\n if (!isHex64(hex)) {\n const parts = hex.split(':')\n if (parts.length === 3 && isHex64(parts[1])) {\n hex = parts[1]\n } else {\n hex = bytesToHex(sha256(utf8Encoder.encode(filterFirstTagValue)))\n }\n }\n\n return parseInt(hex[32], 16) + 8\n}\n\nexport function getFilterFirstTagValue(filter: Filter): string | undefined {\n for (const key in filter) {\n if (key[0] !== '#') continue\n\n const values = filter[key as `#${string}`]\n if (Array.isArray(values) && typeof values[0] === 'string') return values[0]\n }\n\n return undefined\n}\n\nexport function feedPubkey(hll: Uint8Array, pubkey: string, offset: number): Uint8Array {\n if (offset < 0 || offset > 24) throw new Error(`invalid offset ${offset}`)\n if (!isHex64(pubkey)) throw new Error('pubkey must be 32-byte hex')\n\n if (hll.length === 0) hll = newHll()\n if (hll.length !== M) throw new Error(`invalid number of registers ${hll.length}`)\n\n const ri = parseInt(pubkey.slice(offset * 2, offset * 2 + 2), 16)\n const value = countLeadingZeroBitsAfterOffset(pubkey, offset) + 1\n if (value > hll[ri]) hll[ri] = value\n\n return hll\n}\n\nexport function feedEvent(hll: Uint8Array, event: Event, offset: number): Uint8Array {\n return feedPubkey(hll, event.pubkey, offset)\n}\n\nexport function mergeHll(target: Uint8Array, source: Uint8Array): Uint8Array {\n if (target.length === 0) target = newHll()\n if (target.length !== M) throw new Error(`invalid number of registers ${target.length}`)\n if (source.length !== M) throw new Error(`invalid number of registers ${source.length}`)\n\n for (let i = 0; i < M; i++) {\n if (source[i] > target[i]) target[i] = source[i]\n }\n\n return target\n}\n\nexport function estimateCount(hll: Uint8Array): number {\n if (hll.length === 0) return 0\n if (hll.length !== M) throw new Error(`invalid number of registers ${hll.length}`)\n\n const v = countZeros(hll)\n if (v !== 0) {\n const lc = linearCounting(M, v)\n if (lc <= 220) return Math.floor(lc)\n }\n\n const estimate = calculateEstimate(hll)\n if (estimate <= M * 3 && v !== 0) return Math.floor(linearCounting(M, v))\n\n return Math.floor(estimate)\n}\n\nfunction isHex64(value: string): boolean {\n return /^[0-9a-fA-F]{64}$/.test(value)\n}\n\nfunction countLeadingZeroBitsAfterOffset(pubkey: string, offset: number): number {\n let zeroBits = 0\n for (let i = offset + 1; i < offset + 8; i++) {\n const byte = parseInt(pubkey.slice(i * 2, i * 2 + 2), 16)\n if (byte === 0) {\n zeroBits += 8\n continue\n }\n\n let mask = 0x80\n while ((byte & mask) === 0) {\n zeroBits++\n mask >>= 1\n }\n break\n }\n return zeroBits\n}\n\nfunction countZeros(registers: Uint8Array): number {\n let count = 0\n for (let i = 0; i < M; i++) {\n if (registers[i] === 0) count++\n }\n return count\n}\n\nfunction linearCounting(m: number, v: number): number {\n return m * Math.log(m / v)\n}\n\nfunction calculateEstimate(registers: Uint8Array): number {\n let sum = 0\n for (let i = 0; i < M; i++) {\n sum += 1 / 2 ** registers[i]\n }\n return (0.7182725932495458 * M * M) / sum\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
7
|
}
|
|
@@ -2,41 +2,6 @@
|
|
|
2
2
|
import { schnorr } from "@noble/curves/secp256k1.js";
|
|
3
3
|
import { bytesToHex as bytesToHex2, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
|
|
4
4
|
|
|
5
|
-
// utils.ts
|
|
6
|
-
import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
|
|
7
|
-
var utf8Decoder = new TextDecoder("utf-8");
|
|
8
|
-
var utf8Encoder = new TextEncoder();
|
|
9
|
-
function normalizeURL(url) {
|
|
10
|
-
try {
|
|
11
|
-
if (url.indexOf("://") === -1)
|
|
12
|
-
url = "wss://" + url;
|
|
13
|
-
let p = new URL(url);
|
|
14
|
-
if (p.protocol === "http:")
|
|
15
|
-
p.protocol = "ws:";
|
|
16
|
-
else if (p.protocol === "https:")
|
|
17
|
-
p.protocol = "wss:";
|
|
18
|
-
p.pathname = p.pathname.replace(/\/+/g, "/");
|
|
19
|
-
if (p.pathname.endsWith("/"))
|
|
20
|
-
p.pathname = p.pathname.slice(0, -1);
|
|
21
|
-
if (p.port === "80" && p.protocol === "ws:" || p.port === "443" && p.protocol === "wss:")
|
|
22
|
-
p.port = "";
|
|
23
|
-
p.searchParams.sort();
|
|
24
|
-
p.hash = "";
|
|
25
|
-
return p.toString();
|
|
26
|
-
} catch (e) {
|
|
27
|
-
throw new Error(`Invalid URL: ${url}`);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
function isHex32(input) {
|
|
31
|
-
for (let i2 = 0; i2 < 64; i2++) {
|
|
32
|
-
let cc = input.charCodeAt(i2);
|
|
33
|
-
if (isNaN(cc) || cc < 48 || cc > 102 || cc > 57 && cc < 97) {
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
return true;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
5
|
// core.ts
|
|
41
6
|
var verifiedSymbol = Symbol("verified");
|
|
42
7
|
var isRecord = (obj) => obj instanceof Object;
|
|
@@ -51,7 +16,7 @@ function validateEvent(event) {
|
|
|
51
16
|
return false;
|
|
52
17
|
if (typeof event.pubkey !== "string")
|
|
53
18
|
return false;
|
|
54
|
-
if (!
|
|
19
|
+
if (!event.pubkey.match(/^[a-f0-9]{64}$/))
|
|
55
20
|
return false;
|
|
56
21
|
if (!Array.isArray(event.tags))
|
|
57
22
|
return false;
|
|
@@ -69,6 +34,34 @@ function validateEvent(event) {
|
|
|
69
34
|
|
|
70
35
|
// pure.ts
|
|
71
36
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
37
|
+
|
|
38
|
+
// utils.ts
|
|
39
|
+
import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
|
|
40
|
+
var utf8Decoder = new TextDecoder("utf-8");
|
|
41
|
+
var utf8Encoder = new TextEncoder();
|
|
42
|
+
function normalizeURL(url) {
|
|
43
|
+
try {
|
|
44
|
+
if (url.indexOf("://") === -1)
|
|
45
|
+
url = "wss://" + url;
|
|
46
|
+
let p = new URL(url);
|
|
47
|
+
if (p.protocol === "http:")
|
|
48
|
+
p.protocol = "ws:";
|
|
49
|
+
else if (p.protocol === "https:")
|
|
50
|
+
p.protocol = "wss:";
|
|
51
|
+
p.pathname = p.pathname.replace(/\/+/g, "/");
|
|
52
|
+
if (p.pathname.endsWith("/"))
|
|
53
|
+
p.pathname = p.pathname.slice(0, -1);
|
|
54
|
+
if (p.port === "80" && p.protocol === "ws:" || p.port === "443" && p.protocol === "wss:")
|
|
55
|
+
p.port = "";
|
|
56
|
+
p.searchParams.sort();
|
|
57
|
+
p.hash = "";
|
|
58
|
+
return p.toString();
|
|
59
|
+
} catch (e) {
|
|
60
|
+
throw new Error(`Invalid URL: ${url}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// pure.ts
|
|
72
65
|
var JS = class {
|
|
73
66
|
generateSecretKey() {
|
|
74
67
|
return schnorr.utils.randomSecretKey();
|
|
@@ -345,14 +338,12 @@ var AbstractRelay = class {
|
|
|
345
338
|
openSubs = /* @__PURE__ */ new Map();
|
|
346
339
|
enablePing;
|
|
347
340
|
enableReconnect;
|
|
348
|
-
idleTimeout = 0;
|
|
349
341
|
idleSince = Date.now();
|
|
350
342
|
ongoingOperations = 0;
|
|
351
343
|
reconnectTimeoutHandle;
|
|
352
344
|
pingIntervalHandle;
|
|
353
345
|
reconnectAttempts = 0;
|
|
354
346
|
skipReconnection = false;
|
|
355
|
-
idleTimeoutHandle;
|
|
356
347
|
connectionPromise;
|
|
357
348
|
openCountRequests = /* @__PURE__ */ new Map();
|
|
358
349
|
openEventPublishes = /* @__PURE__ */ new Map();
|
|
@@ -368,8 +359,6 @@ var AbstractRelay = class {
|
|
|
368
359
|
this._WebSocket = opts.websocketImplementation || WebSocket;
|
|
369
360
|
this.enablePing = opts.enablePing;
|
|
370
361
|
this.enableReconnect = opts.enableReconnect || false;
|
|
371
|
-
if (opts.idleTimeout)
|
|
372
|
-
this.idleTimeout = opts.idleTimeout;
|
|
373
362
|
}
|
|
374
363
|
static async connect(url, opts) {
|
|
375
364
|
const relay = new AbstractRelay(url, opts);
|
|
@@ -393,22 +382,6 @@ var AbstractRelay = class {
|
|
|
393
382
|
get connected() {
|
|
394
383
|
return this._connected;
|
|
395
384
|
}
|
|
396
|
-
clearIdleTimeout() {
|
|
397
|
-
if (this.idleTimeoutHandle) {
|
|
398
|
-
clearTimeout(this.idleTimeoutHandle);
|
|
399
|
-
this.idleTimeoutHandle = void 0;
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
scheduleIdleClose() {
|
|
403
|
-
this.clearIdleTimeout();
|
|
404
|
-
if (this.idleTimeout > 0) {
|
|
405
|
-
this.idleTimeoutHandle = setTimeout(() => {
|
|
406
|
-
if (this.ongoingOperations === 0 && this.idleSince) {
|
|
407
|
-
this.close();
|
|
408
|
-
}
|
|
409
|
-
}, this.idleTimeout);
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
385
|
async reconnect() {
|
|
413
386
|
const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)];
|
|
414
387
|
this.reconnectAttempts++;
|
|
@@ -420,11 +393,6 @@ var AbstractRelay = class {
|
|
|
420
393
|
}, backoff);
|
|
421
394
|
}
|
|
422
395
|
handleHardClose(reason) {
|
|
423
|
-
if (this.ws) {
|
|
424
|
-
this.ws.onopen = null;
|
|
425
|
-
this.ws.onerror = null;
|
|
426
|
-
this.ws.onclose = null;
|
|
427
|
-
}
|
|
428
396
|
if (this.pingIntervalHandle) {
|
|
429
397
|
clearInterval(this.pingIntervalHandle);
|
|
430
398
|
this.pingIntervalHandle = void 0;
|
|
@@ -432,7 +400,6 @@ var AbstractRelay = class {
|
|
|
432
400
|
this._connected = false;
|
|
433
401
|
this.connectionPromise = void 0;
|
|
434
402
|
this.idleSince = void 0;
|
|
435
|
-
this.clearIdleTimeout();
|
|
436
403
|
if (this.enableReconnect && !this.skipReconnection) {
|
|
437
404
|
this.reconnect();
|
|
438
405
|
} else {
|
|
@@ -455,6 +422,7 @@ var AbstractRelay = class {
|
|
|
455
422
|
if (this.reconnectAttempts === 0) {
|
|
456
423
|
this.skipReconnection = true;
|
|
457
424
|
}
|
|
425
|
+
this.onclose?.();
|
|
458
426
|
this.handleHardClose("relay connection timed out");
|
|
459
427
|
}, opts.timeout);
|
|
460
428
|
}
|
|
@@ -500,6 +468,7 @@ var AbstractRelay = class {
|
|
|
500
468
|
if (this.reconnectAttempts === 0) {
|
|
501
469
|
this.skipReconnection = true;
|
|
502
470
|
}
|
|
471
|
+
this.onclose?.();
|
|
503
472
|
this.handleHardClose("relay connection failed");
|
|
504
473
|
};
|
|
505
474
|
this.ws.onclose = (ev) => {
|
|
@@ -588,7 +557,6 @@ var AbstractRelay = class {
|
|
|
588
557
|
}
|
|
589
558
|
async publish(event) {
|
|
590
559
|
this.idleSince = void 0;
|
|
591
|
-
this.clearIdleTimeout();
|
|
592
560
|
this.ongoingOperations++;
|
|
593
561
|
const ret = new Promise((resolve, reject) => {
|
|
594
562
|
const timeout = setTimeout(() => {
|
|
@@ -610,10 +578,8 @@ var AbstractRelay = class {
|
|
|
610
578
|
}
|
|
611
579
|
}
|
|
612
580
|
this.ongoingOperations--;
|
|
613
|
-
if (this.ongoingOperations === 0)
|
|
581
|
+
if (this.ongoingOperations === 0)
|
|
614
582
|
this.idleSince = Date.now();
|
|
615
|
-
this.scheduleIdleClose();
|
|
616
|
-
}
|
|
617
583
|
return ret;
|
|
618
584
|
}
|
|
619
585
|
async count(filters, params) {
|
|
@@ -639,7 +605,6 @@ var AbstractRelay = class {
|
|
|
639
605
|
subscribe(filters, params) {
|
|
640
606
|
if (params.label !== "<forced-ping>") {
|
|
641
607
|
this.idleSince = void 0;
|
|
642
|
-
this.clearIdleTimeout();
|
|
643
608
|
this.ongoingOperations++;
|
|
644
609
|
}
|
|
645
610
|
const sub = this.prepareSubscription(filters, params);
|
|
@@ -668,17 +633,10 @@ var AbstractRelay = class {
|
|
|
668
633
|
}
|
|
669
634
|
this.closeAllSubscriptions("relay connection closed by us");
|
|
670
635
|
this._connected = false;
|
|
671
|
-
this.connectionPromise = void 0;
|
|
672
636
|
this.idleSince = void 0;
|
|
673
|
-
this.clearIdleTimeout();
|
|
674
637
|
this.onclose?.();
|
|
675
|
-
if (this.ws) {
|
|
676
|
-
this.ws
|
|
677
|
-
this.ws.onerror = null;
|
|
678
|
-
this.ws.onclose = null;
|
|
679
|
-
if (this.ws.readyState !== this._WebSocket.CLOSING && this.ws.readyState !== this._WebSocket.CLOSED) {
|
|
680
|
-
this.ws.close();
|
|
681
|
-
}
|
|
638
|
+
if (this.ws?.readyState === this._WebSocket.OPEN) {
|
|
639
|
+
this.ws?.close();
|
|
682
640
|
}
|
|
683
641
|
}
|
|
684
642
|
_onmessage(ev) {
|
|
@@ -705,7 +663,7 @@ var AbstractRelay = class {
|
|
|
705
663
|
case "EVENT": {
|
|
706
664
|
const so = this.openSubs.get(data[1]);
|
|
707
665
|
const event = data[2];
|
|
708
|
-
if (
|
|
666
|
+
if (this.verifyEvent(event) && matchFilters(so.filters, event)) {
|
|
709
667
|
so.onevent(event);
|
|
710
668
|
} else {
|
|
711
669
|
so.oninvalidevent?.(event);
|
|
@@ -853,14 +811,18 @@ var Subscription = class {
|
|
|
853
811
|
}
|
|
854
812
|
this.relay.openSubs.delete(this.id);
|
|
855
813
|
this.relay.ongoingOperations--;
|
|
856
|
-
if (this.relay.ongoingOperations === 0)
|
|
814
|
+
if (this.relay.ongoingOperations === 0)
|
|
857
815
|
this.relay.idleSince = Date.now();
|
|
858
|
-
this.relay.scheduleIdleClose();
|
|
859
|
-
}
|
|
860
816
|
this.onclose?.(reason);
|
|
861
817
|
}
|
|
862
818
|
};
|
|
863
819
|
|
|
820
|
+
// helpers.ts
|
|
821
|
+
var alwaysTrue = (t) => {
|
|
822
|
+
t[verifiedSymbol] = true;
|
|
823
|
+
return true;
|
|
824
|
+
};
|
|
825
|
+
|
|
864
826
|
// nip45.ts
|
|
865
827
|
import { sha256 as sha2563 } from "@noble/hashes/sha2.js";
|
|
866
828
|
import { bytesToHex as bytesToHex3 } from "@noble/hashes/utils.js";
|
|
@@ -887,7 +849,7 @@ function newHll() {
|
|
|
887
849
|
return new Uint8Array(M);
|
|
888
850
|
}
|
|
889
851
|
function hllDecode(hex) {
|
|
890
|
-
if (hex.length !== HLL_HEX_LENGTH || !/^[0-9a-
|
|
852
|
+
if (hex.length !== HLL_HEX_LENGTH || !/^[0-9a-fA-F]+$/.test(hex))
|
|
891
853
|
return void 0;
|
|
892
854
|
const registers = new Uint8Array(M);
|
|
893
855
|
for (let i2 = 0; i2 < M; i2++) {
|
|
@@ -926,8 +888,8 @@ var AbstractSimplePool = class {
|
|
|
926
888
|
verifyEvent;
|
|
927
889
|
enablePing;
|
|
928
890
|
enableReconnect;
|
|
929
|
-
idleTimeout = 2e4;
|
|
930
891
|
automaticallyAuth;
|
|
892
|
+
trustedRelayURLs = /* @__PURE__ */ new Set();
|
|
931
893
|
onRelayConnectionFailure;
|
|
932
894
|
onRelayConnectionSuccess;
|
|
933
895
|
allowConnectingToRelay;
|
|
@@ -938,8 +900,6 @@ var AbstractSimplePool = class {
|
|
|
938
900
|
this._WebSocket = opts.websocketImplementation;
|
|
939
901
|
this.enablePing = opts.enablePing;
|
|
940
902
|
this.enableReconnect = opts.enableReconnect || false;
|
|
941
|
-
if (opts.idleTimeout)
|
|
942
|
-
this.idleTimeout = opts.idleTimeout;
|
|
943
903
|
this.automaticallyAuth = opts.automaticallyAuth;
|
|
944
904
|
this.onRelayConnectionFailure = opts.onRelayConnectionFailure;
|
|
945
905
|
this.onRelayConnectionSuccess = opts.onRelayConnectionSuccess;
|
|
@@ -951,11 +911,10 @@ var AbstractSimplePool = class {
|
|
|
951
911
|
let relay = this.relays.get(url);
|
|
952
912
|
if (!relay) {
|
|
953
913
|
relay = new AbstractRelay(url, {
|
|
954
|
-
verifyEvent: this.verifyEvent,
|
|
914
|
+
verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,
|
|
955
915
|
websocketImplementation: this._WebSocket,
|
|
956
916
|
enablePing: this.enablePing,
|
|
957
|
-
enableReconnect: this.enableReconnect
|
|
958
|
-
idleTimeout: this.idleTimeout
|
|
917
|
+
enableReconnect: this.enableReconnect
|
|
959
918
|
});
|
|
960
919
|
relay.onclose = () => {
|
|
961
920
|
this.relays.delete(url);
|
|
@@ -1035,11 +994,11 @@ var AbstractSimplePool = class {
|
|
|
1035
994
|
}
|
|
1036
995
|
};
|
|
1037
996
|
const closesReceived = [];
|
|
1038
|
-
let handleClose = (i2,
|
|
997
|
+
let handleClose = (i2, reason) => {
|
|
1039
998
|
if (closesReceived[i2])
|
|
1040
999
|
return;
|
|
1041
1000
|
handleEose(i2);
|
|
1042
|
-
closesReceived[i2] =
|
|
1001
|
+
closesReceived[i2] = reason;
|
|
1043
1002
|
if (closesReceived.filter((a) => a).length === groupedRequests.length) {
|
|
1044
1003
|
params.onclose?.(closesReceived);
|
|
1045
1004
|
handleClose = () => {
|
|
@@ -1057,7 +1016,7 @@ var AbstractSimplePool = class {
|
|
|
1057
1016
|
const allOpened = Promise.all(
|
|
1058
1017
|
groupedRequests.map(async ({ url, filters }, i2) => {
|
|
1059
1018
|
if (this.allowConnectingToRelay?.(url, ["read", filters]) === false) {
|
|
1060
|
-
handleClose(i2,
|
|
1019
|
+
handleClose(i2, "connection skipped by allowConnectingToRelay");
|
|
1061
1020
|
return;
|
|
1062
1021
|
}
|
|
1063
1022
|
let relay;
|
|
@@ -1068,7 +1027,7 @@ var AbstractSimplePool = class {
|
|
|
1068
1027
|
});
|
|
1069
1028
|
} catch (err) {
|
|
1070
1029
|
this.onRelayConnectionFailure?.(url);
|
|
1071
|
-
handleClose(i2,
|
|
1030
|
+
handleClose(i2, err?.message || String(err));
|
|
1072
1031
|
return;
|
|
1073
1032
|
}
|
|
1074
1033
|
this.onRelayConnectionSuccess?.(url);
|
|
@@ -1082,17 +1041,17 @@ var AbstractSimplePool = class {
|
|
|
1082
1041
|
...params,
|
|
1083
1042
|
oneose: () => handleEose(i2),
|
|
1084
1043
|
onclose: (reason2) => {
|
|
1085
|
-
handleClose(i2,
|
|
1044
|
+
handleClose(i2, reason2);
|
|
1086
1045
|
},
|
|
1087
1046
|
alreadyHaveEvent: localAlreadyHaveEventHandler,
|
|
1088
1047
|
eoseTimeout: params.maxWait,
|
|
1089
1048
|
abort: params.abort
|
|
1090
1049
|
});
|
|
1091
1050
|
}).catch((err) => {
|
|
1092
|
-
handleClose(i2,
|
|
1051
|
+
handleClose(i2, `auth was required and attempted, but failed with: ${err}`);
|
|
1093
1052
|
});
|
|
1094
1053
|
} else {
|
|
1095
|
-
handleClose(i2,
|
|
1054
|
+
handleClose(i2, reason);
|
|
1096
1055
|
}
|
|
1097
1056
|
},
|
|
1098
1057
|
alreadyHaveEvent: localAlreadyHaveEventHandler,
|
|
@@ -1120,7 +1079,7 @@ var AbstractSimplePool = class {
|
|
|
1120
1079
|
if (subcloser)
|
|
1121
1080
|
subcloser.close(reason);
|
|
1122
1081
|
else
|
|
1123
|
-
params.onclose?.(relays.map((
|
|
1082
|
+
params.onclose?.(relays.map((_) => reason));
|
|
1124
1083
|
}
|
|
1125
1084
|
});
|
|
1126
1085
|
return subcloser;
|