nostr-tools 2.3.0 → 2.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/README.md +5 -1
  2. package/lib/cjs/abstract-pool.js +9 -6
  3. package/lib/cjs/abstract-pool.js.map +2 -2
  4. package/lib/cjs/abstract-relay.js +9 -6
  5. package/lib/cjs/abstract-relay.js.map +2 -2
  6. package/lib/cjs/filter.js.map +2 -2
  7. package/lib/cjs/index.js +60 -53
  8. package/lib/cjs/index.js.map +3 -3
  9. package/lib/cjs/kinds.js.map +2 -2
  10. package/lib/cjs/nip04.js.map +2 -2
  11. package/lib/cjs/nip11.js.map +2 -2
  12. package/lib/cjs/nip13.js.map +2 -2
  13. package/lib/cjs/nip18.js.map +2 -2
  14. package/lib/cjs/nip19.js.map +2 -2
  15. package/lib/cjs/nip21.js.map +2 -2
  16. package/lib/cjs/nip25.js.map +2 -2
  17. package/lib/cjs/nip27.js.map +2 -2
  18. package/lib/cjs/nip28.js.map +2 -2
  19. package/lib/cjs/nip29.js.map +2 -2
  20. package/lib/cjs/nip30.js.map +2 -2
  21. package/lib/cjs/nip42.js.map +1 -1
  22. package/lib/cjs/nip44.js +51 -47
  23. package/lib/cjs/nip44.js.map +2 -2
  24. package/lib/cjs/nip46.js +20 -9
  25. package/lib/cjs/nip46.js.map +3 -3
  26. package/lib/cjs/nip47.js.map +2 -2
  27. package/lib/cjs/nip57.js.map +2 -2
  28. package/lib/cjs/nip75.js.map +1 -1
  29. package/lib/cjs/nip94.js.map +1 -1
  30. package/lib/cjs/nip96.js +3 -5
  31. package/lib/cjs/nip96.js.map +2 -2
  32. package/lib/cjs/nip98.js.map +2 -2
  33. package/lib/cjs/nip99.js.map +1 -1
  34. package/lib/cjs/pool.js +9 -6
  35. package/lib/cjs/pool.js.map +2 -2
  36. package/lib/cjs/pure.js.map +2 -2
  37. package/lib/cjs/references.js.map +2 -2
  38. package/lib/cjs/relay.js +9 -6
  39. package/lib/cjs/relay.js.map +2 -2
  40. package/lib/cjs/utils.js.map +2 -2
  41. package/lib/esm/abstract-pool.js +9 -6
  42. package/lib/esm/abstract-pool.js.map +2 -2
  43. package/lib/esm/abstract-relay.js +9 -6
  44. package/lib/esm/abstract-relay.js.map +2 -2
  45. package/lib/esm/filter.js.map +2 -2
  46. package/lib/esm/index.js +60 -53
  47. package/lib/esm/index.js.map +3 -3
  48. package/lib/esm/kinds.js.map +2 -2
  49. package/lib/esm/nip04.js.map +2 -2
  50. package/lib/esm/nip11.js.map +2 -2
  51. package/lib/esm/nip13.js.map +2 -2
  52. package/lib/esm/nip18.js.map +2 -2
  53. package/lib/esm/nip19.js.map +2 -2
  54. package/lib/esm/nip21.js.map +2 -2
  55. package/lib/esm/nip25.js.map +2 -2
  56. package/lib/esm/nip27.js.map +2 -2
  57. package/lib/esm/nip28.js.map +2 -2
  58. package/lib/esm/nip29.js.map +2 -2
  59. package/lib/esm/nip30.js.map +2 -2
  60. package/lib/esm/nip42.js.map +1 -1
  61. package/lib/esm/nip44.js +53 -47
  62. package/lib/esm/nip44.js.map +2 -2
  63. package/lib/esm/nip46.js +20 -9
  64. package/lib/esm/nip46.js.map +3 -3
  65. package/lib/esm/nip47.js.map +2 -2
  66. package/lib/esm/nip57.js.map +2 -2
  67. package/lib/esm/nip75.js.map +1 -1
  68. package/lib/esm/nip94.js.map +1 -1
  69. package/lib/esm/nip96.js +5 -5
  70. package/lib/esm/nip96.js.map +3 -3
  71. package/lib/esm/nip98.js.map +2 -2
  72. package/lib/esm/nip99.js.map +1 -1
  73. package/lib/esm/pool.js +9 -6
  74. package/lib/esm/pool.js.map +2 -2
  75. package/lib/esm/pure.js.map +2 -2
  76. package/lib/esm/references.js.map +2 -2
  77. package/lib/esm/relay.js +9 -6
  78. package/lib/esm/relay.js.map +2 -2
  79. package/lib/esm/utils.js.map +2 -2
  80. package/lib/nostr.bundle.js +60 -53
  81. package/lib/nostr.bundle.js.map +3 -3
  82. package/lib/types/abstract-relay.d.ts +1 -0
  83. package/lib/types/nip44.d.ts +27 -53
  84. package/lib/types/nip46.d.ts +2 -1
  85. package/lib/types/nip47.d.ts +6 -3
  86. package/lib/types/nip96.d.ts +2 -0
  87. package/lib/types/test-helpers.d.ts +0 -1
  88. package/lib/types/utils.d.ts +1 -0
  89. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../nip27.ts", "../../nip19.ts", "../../utils.ts", "../../nip21.ts"],
4
- "sourcesContent": ["import { decode } from './nip19.ts'\nimport { NOSTR_URI_REGEX, type NostrURI } from './nip21.ts'\n\n/** Regex to find NIP-21 URIs inside event content. */\nexport const regex = () => new RegExp(`\\\\b${NOSTR_URI_REGEX.source}\\\\b`, 'g')\n\n/** Match result for a Nostr URI in event content. */\nexport interface NostrURIMatch extends NostrURI {\n /** Index where the URI begins in the event content. */\n start: number\n /** Index where the URI ends in the event content. */\n end: number\n}\n\n/** Find and decode all NIP-21 URIs. */\nexport function* matchAll(content: string): Iterable<NostrURIMatch> {\n const matches = content.matchAll(regex())\n\n for (const match of matches) {\n try {\n const [uri, value] = match\n\n yield {\n uri: uri as `nostr:${string}`,\n value,\n decoded: decode(value),\n start: match.index!,\n end: match.index! + uri.length,\n }\n } catch (_e) {\n // do nothing\n }\n }\n}\n\n/**\n * Replace all occurrences of Nostr URIs in the text.\n *\n * WARNING: using this on an HTML string is potentially unsafe!\n *\n * @example\n * ```ts\n * nip27.replaceAll(event.content, ({ decoded, value }) => {\n * switch(decoded.type) {\n * case 'npub':\n * return renderMention(decoded)\n * case 'note':\n * return renderNote(decoded)\n * default:\n * return value\n * }\n * })\n * ```\n */\nexport function replaceAll(content: string, replacer: (match: NostrURI) => string): string {\n return content.replaceAll(regex(), (uri, value: string) => {\n return replacer({\n uri: uri as `nostr:${string}`,\n value,\n decoded: decode(value),\n })\n })\n}\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\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\ntype Prefixes = {\n nprofile: ProfilePointer\n nrelay: string\n nevent: EventPointer\n naddr: AddressPointer\n nsec: Uint8Array\n npub: string\n note: string\n}\n\ntype DecodeValue<Prefix extends keyof Prefixes> = {\n type: Prefix\n data: Prefixes[Prefix]\n}\n\nexport type DecodeResult = {\n [P in keyof Prefixes]: DecodeValue<P>\n}[keyof Prefixes]\n\nexport function decode<Prefix extends keyof Prefixes>(nip19: `${Prefix}1${string}`): DecodeValue<Prefix>\nexport function decode(nip19: string): DecodeResult\nexport function decode(nip19: string): DecodeResult {\n let { prefix, words } = bech32.decode(nip19, 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 'nrelay': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nrelay')\n\n return {\n type: 'nrelay',\n data: utf8Decoder.decode(tlv[0][0]),\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 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): `nsec1${string}` {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): `npub1${string}` {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): `note1${string}` {\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): `nprofile1${string}` {\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): `nevent1${string}` {\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): `naddr1${string}` {\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\nexport function nrelayEncode(url: string): `nrelay1${string}` {\n let data = encodeTLV({\n 0: [utf8Encoder.encode(url)],\n })\n return encodeBech32('nrelay', 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 { Event } from './core.ts'\n\nexport const utf8Decoder = new TextDecoder('utf-8')\nexport const utf8Encoder = new TextEncoder()\n\nexport function normalizeURL(url: string): string {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\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}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event) {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event) {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n\n return target.value\n }\n}\n", "import { BECH32_REGEX, decode, type DecodeResult } from './nip19.ts'\n\n/** Nostr URI regex, eg `nostr:npub1...` */\nexport const NOSTR_URI_REGEX = new RegExp(`nostr:(${BECH32_REGEX.source})`)\n\n/** Test whether the value is a Nostr URI. */\nexport function test(value: unknown): value is `nostr:${string}` {\n return typeof value === 'string' && new RegExp(`^${NOSTR_URI_REGEX.source}$`).test(value)\n}\n\n/** Parsed Nostr URI data. */\nexport interface NostrURI {\n /** Full URI including the `nostr:` protocol. */\n uri: `nostr:${string}`\n /** The bech32-encoded data (eg `npub1...`). */\n value: string\n /** Decoded bech32 string, according to NIP-19. */\n decoded: DecodeResult\n}\n\n/** Parse and decode a Nostr URI. */\nexport function parse(uri: string): NostrURI {\n const match = uri.match(new RegExp(`^${NOSTR_URI_REGEX.source}$`))\n if (!match) throw new Error(`Invalid Nostr URI: ${uri}`)\n return {\n uri: match[0] as `nostr:${string}`,\n value: match[1],\n decoded: decode(match[1]),\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { decode } from './nip19.ts'\nimport { NOSTR_URI_REGEX, type NostrURI } from './nip21.ts'\n\n/** Regex to find NIP-21 URIs inside event content. */\nexport const regex = (): RegExp => new RegExp(`\\\\b${NOSTR_URI_REGEX.source}\\\\b`, 'g')\n\n/** Match result for a Nostr URI in event content. */\nexport interface NostrURIMatch extends NostrURI {\n /** Index where the URI begins in the event content. */\n start: number\n /** Index where the URI ends in the event content. */\n end: number\n}\n\n/** Find and decode all NIP-21 URIs. */\nexport function* matchAll(content: string): Iterable<NostrURIMatch> {\n const matches = content.matchAll(regex())\n\n for (const match of matches) {\n try {\n const [uri, value] = match\n\n yield {\n uri: uri as `nostr:${string}`,\n value,\n decoded: decode(value),\n start: match.index!,\n end: match.index! + uri.length,\n }\n } catch (_e) {\n // do nothing\n }\n }\n}\n\n/**\n * Replace all occurrences of Nostr URIs in the text.\n *\n * WARNING: using this on an HTML string is potentially unsafe!\n *\n * @example\n * ```ts\n * nip27.replaceAll(event.content, ({ decoded, value }) => {\n * switch(decoded.type) {\n * case 'npub':\n * return renderMention(decoded)\n * case 'note':\n * return renderNote(decoded)\n * default:\n * return value\n * }\n * })\n * ```\n */\nexport function replaceAll(content: string, replacer: (match: NostrURI) => string): string {\n return content.replaceAll(regex(), (uri, value: string) => {\n return replacer({\n uri: uri as `nostr:${string}`,\n value,\n decoded: decode(value),\n })\n })\n}\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\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\ntype Prefixes = {\n nprofile: ProfilePointer\n nrelay: string\n nevent: EventPointer\n naddr: AddressPointer\n nsec: Uint8Array\n npub: string\n note: string\n}\n\ntype DecodeValue<Prefix extends keyof Prefixes> = {\n type: Prefix\n data: Prefixes[Prefix]\n}\n\nexport type DecodeResult = {\n [P in keyof Prefixes]: DecodeValue<P>\n}[keyof Prefixes]\n\nexport function decode<Prefix extends keyof Prefixes>(nip19: `${Prefix}1${string}`): DecodeValue<Prefix>\nexport function decode(nip19: string): DecodeResult\nexport function decode(nip19: string): DecodeResult {\n let { prefix, words } = bech32.decode(nip19, 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 'nrelay': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nrelay')\n\n return {\n type: 'nrelay',\n data: utf8Decoder.decode(tlv[0][0]),\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 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): `nsec1${string}` {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): `npub1${string}` {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): `note1${string}` {\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): `nprofile1${string}` {\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): `nevent1${string}` {\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): `naddr1${string}` {\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\nexport function nrelayEncode(url: string): `nrelay1${string}` {\n let data = encodeTLV({\n 0: [utf8Encoder.encode(url)],\n })\n return encodeBech32('nrelay', 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 { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport function normalizeURL(url: string): string {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\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}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n\n return target.value\n }\n}\n", "import { BECH32_REGEX, decode, type DecodeResult } from './nip19.ts'\n\n/** Nostr URI regex, eg `nostr:npub1...` */\nexport const NOSTR_URI_REGEX: RegExp = new RegExp(`nostr:(${BECH32_REGEX.source})`)\n\n/** Test whether the value is a Nostr URI. */\nexport function test(value: unknown): value is `nostr:${string}` {\n return typeof value === 'string' && new RegExp(`^${NOSTR_URI_REGEX.source}$`).test(value)\n}\n\n/** Parsed Nostr URI data. */\nexport interface NostrURI {\n /** Full URI including the `nostr:` protocol. */\n uri: `nostr:${string}`\n /** The bech32-encoded data (eg `npub1...`). */\n value: string\n /** Decoded bech32 string, according to NIP-19. */\n decoded: DecodeResult\n}\n\n/** Parse and decode a Nostr URI. */\nexport function parse(uri: string): NostrURI {\n const match = uri.match(new RegExp(`^${NOSTR_URI_REGEX.source}$`))\n if (!match) throw new Error(`Invalid Nostr URI: ${uri}`)\n return {\n uri: match[0] as `nostr:${string}`,\n value: match[1],\n decoded: decode(match[1]),\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../nip28.ts", "../../pure.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts"],
4
- "sourcesContent": ["import { Event, finalizeEvent } from './pure.ts'\nimport { ChannelCreation, ChannelHideMessage, ChannelMessage, ChannelMetadata, ChannelMuteUser } from './kinds.ts'\n\nexport interface ChannelMetadata {\n name: string\n about: string\n picture: string\n}\n\nexport interface ChannelCreateEventTemplate {\n /* JSON string containing ChannelMetadata as defined for Kind 40 and 41 in nip-28. */\n content: string | ChannelMetadata\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelMetadataEventTemplate {\n channel_create_event_id: string\n /* JSON string containing ChannelMetadata as defined for Kind 40 and 41 in nip-28. */\n content: string | ChannelMetadata\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelMessageEventTemplate {\n channel_create_event_id: string\n reply_to_channel_message_event_id?: string\n relay_url: string\n content: string\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelHideMessageEventTemplate {\n channel_message_event_id: string\n content: string | { reason: string }\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelMuteUserEventTemplate {\n content: string | { reason: string }\n created_at: number\n pubkey_to_mute: string\n tags?: string[][]\n}\n\nexport const channelCreateEvent = (t: ChannelCreateEventTemplate, privateKey: Uint8Array): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: ChannelCreation,\n tags: [...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport const channelMetadataEvent = (t: ChannelMetadataEventTemplate, privateKey: Uint8Array): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: ChannelMetadata,\n tags: [['e', t.channel_create_event_id], ...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport const channelMessageEvent = (t: ChannelMessageEventTemplate, privateKey: Uint8Array): Event => {\n const tags = [['e', t.channel_create_event_id, t.relay_url, 'root']]\n\n if (t.reply_to_channel_message_event_id) {\n tags.push(['e', t.reply_to_channel_message_event_id, t.relay_url, 'reply'])\n }\n\n return finalizeEvent(\n {\n kind: ChannelMessage,\n tags: [...tags, ...(t.tags ?? [])],\n content: t.content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\n/* \"e\" tag should be the kind 42 event to hide */\nexport const channelHideMessageEvent = (\n t: ChannelHideMessageEventTemplate,\n privateKey: Uint8Array,\n): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: ChannelHideMessage,\n tags: [['e', t.channel_message_event_id], ...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport const channelMuteUserEvent = (t: ChannelMuteUserEventTemplate, privateKey: Uint8Array): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: ChannelMuteUser,\n tags: [['p', t.pubkey_to_mute], ...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n", "import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\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(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 const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, 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 = 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 interface Event {\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 NostrEvent = Event\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] === 'object') return false\n }\n }\n\n return true\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder = new TextDecoder('utf-8')\nexport const utf8Encoder = new TextEncoder()\n\nexport function normalizeURL(url: string): string {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\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}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event) {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event) {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n\n return target.value\n }\n}\n", "/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number) {\n return (1000 <= kind && kind < 10000) || [1, 2, 4, 5, 6, 7, 8, 16, 40, 41, 42, 43, 44].includes(kind)\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number) {\n return [0, 3].includes(kind) || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number) {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **parameterized replaceable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isParameterizedReplaceableKind(kind: number) {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isParameterizedReplaceableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport const Metadata = 0\nexport const ShortTextNote = 1\nexport const RecommendRelay = 2\nexport const Contacts = 3\nexport const EncryptedDirectMessage = 4\nexport const EncryptedDirectMessages = 4\nexport const EventDeletion = 5\nexport const Repost = 6\nexport const Reaction = 7\nexport const BadgeAward = 8\nexport const GenericRepost = 16\nexport const ChannelCreation = 40\nexport const ChannelMetadata = 41\nexport const ChannelMessage = 42\nexport const ChannelHideMessage = 43\nexport const ChannelMuteUser = 44\nexport const OpenTimestamps = 1040\nexport const FileMetadata = 1063\nexport const LiveChatMessage = 1311\nexport const ProblemTracker = 1971\nexport const Report = 1984\nexport const Reporting = 1984\nexport const Label = 1985\nexport const CommunityPostApproval = 4550\nexport const JobRequest = 5999\nexport const JobResult = 6999\nexport const JobFeedback = 7000\nexport const ZapGoal = 9041\nexport const ZapRequest = 9734\nexport const Zap = 9735\nexport const Highlights = 9802\nexport const Mutelist = 10000\nexport const Pinlist = 10001\nexport const RelayList = 10002\nexport const BookmarkList = 10003\nexport const CommunitiesList = 10004\nexport const PublicChatsList = 10005\nexport const BlockedRelaysList = 10006\nexport const SearchRelaysList = 10007\nexport const InterestsList = 10015\nexport const UserEmojiList = 10030\nexport const FileServerPreference = 10096\nexport const NWCWalletInfo = 13194\nexport const LightningPubRPC = 21000\nexport const ClientAuth = 22242\nexport const NWCWalletRequest = 23194\nexport const NWCWalletResponse = 23195\nexport const NostrConnect = 24133\nexport const HTTPAuth = 27235\nexport const Followsets = 30000\nexport const Genericlists = 30001\nexport const Relaysets = 30002\nexport const Bookmarksets = 30003\nexport const Curationsets = 30004\nexport const ProfileBadges = 30008\nexport const BadgeDefinition = 30009\nexport const Interestsets = 30015\nexport const CreateOrUpdateStall = 30017\nexport const CreateOrUpdateProduct = 30018\nexport const LongFormArticle = 30023\nexport const DraftLong = 30024\nexport const Emojisets = 30030\nexport const Application = 30078\nexport const LiveEvent = 30311\nexport const UserStatuses = 30315\nexport const ClassifiedListing = 30402\nexport const DraftClassifiedListing = 30403\nexport const Date = 31922\nexport const Time = 31923\nexport const Calendar = 31924\nexport const CalendarEventRSVP = 31925\nexport const Handlerrecommendation = 31989\nexport const Handlerinformation = 31990\nexport const CommunityDefinition = 34550\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Event, finalizeEvent } from './pure.ts'\nimport { ChannelCreation, ChannelHideMessage, ChannelMessage, ChannelMetadata, ChannelMuteUser } from './kinds.ts'\n\nexport interface ChannelMetadata {\n name: string\n about: string\n picture: string\n}\n\nexport interface ChannelCreateEventTemplate {\n /* JSON string containing ChannelMetadata as defined for Kind 40 and 41 in nip-28. */\n content: string | ChannelMetadata\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelMetadataEventTemplate {\n channel_create_event_id: string\n /* JSON string containing ChannelMetadata as defined for Kind 40 and 41 in nip-28. */\n content: string | ChannelMetadata\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelMessageEventTemplate {\n channel_create_event_id: string\n reply_to_channel_message_event_id?: string\n relay_url: string\n content: string\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelHideMessageEventTemplate {\n channel_message_event_id: string\n content: string | { reason: string }\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelMuteUserEventTemplate {\n content: string | { reason: string }\n created_at: number\n pubkey_to_mute: string\n tags?: string[][]\n}\n\nexport const channelCreateEvent = (t: ChannelCreateEventTemplate, privateKey: Uint8Array): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: ChannelCreation,\n tags: [...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport const channelMetadataEvent = (t: ChannelMetadataEventTemplate, privateKey: Uint8Array): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: ChannelMetadata,\n tags: [['e', t.channel_create_event_id], ...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport const channelMessageEvent = (t: ChannelMessageEventTemplate, privateKey: Uint8Array): Event => {\n const tags = [['e', t.channel_create_event_id, t.relay_url, 'root']]\n\n if (t.reply_to_channel_message_event_id) {\n tags.push(['e', t.reply_to_channel_message_event_id, t.relay_url, 'reply'])\n }\n\n return finalizeEvent(\n {\n kind: ChannelMessage,\n tags: [...tags, ...(t.tags ?? [])],\n content: t.content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\n/* \"e\" tag should be the kind 42 event to hide */\nexport const channelHideMessageEvent = (\n t: ChannelHideMessageEventTemplate,\n privateKey: Uint8Array,\n): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: ChannelHideMessage,\n tags: [['e', t.channel_message_event_id], ...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport const channelMuteUserEvent = (t: ChannelMuteUserEventTemplate, privateKey: Uint8Array): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: ChannelMuteUser,\n tags: [['p', t.pubkey_to_mute], ...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n", "import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\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(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 const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, 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 interface Event {\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 NostrEvent = Event\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] === 'object') return false\n }\n }\n\n return true\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport function normalizeURL(url: string): string {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\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}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n\n return target.value\n }\n}\n", "/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return (1000 <= kind && kind < 10000) || [1, 2, 4, 5, 6, 7, 8, 16, 40, 41, 42, 43, 44].includes(kind)\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return [0, 3].includes(kind) || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **parameterized replaceable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isParameterizedReplaceableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isParameterizedReplaceableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport const Metadata = 0\nexport const ShortTextNote = 1\nexport const RecommendRelay = 2\nexport const Contacts = 3\nexport const EncryptedDirectMessage = 4\nexport const EncryptedDirectMessages = 4\nexport const EventDeletion = 5\nexport const Repost = 6\nexport const Reaction = 7\nexport const BadgeAward = 8\nexport const GenericRepost = 16\nexport const ChannelCreation = 40\nexport const ChannelMetadata = 41\nexport const ChannelMessage = 42\nexport const ChannelHideMessage = 43\nexport const ChannelMuteUser = 44\nexport const OpenTimestamps = 1040\nexport const FileMetadata = 1063\nexport const LiveChatMessage = 1311\nexport const ProblemTracker = 1971\nexport const Report = 1984\nexport const Reporting = 1984\nexport const Label = 1985\nexport const CommunityPostApproval = 4550\nexport const JobRequest = 5999\nexport const JobResult = 6999\nexport const JobFeedback = 7000\nexport const ZapGoal = 9041\nexport const ZapRequest = 9734\nexport const Zap = 9735\nexport const Highlights = 9802\nexport const Mutelist = 10000\nexport const Pinlist = 10001\nexport const RelayList = 10002\nexport const BookmarkList = 10003\nexport const CommunitiesList = 10004\nexport const PublicChatsList = 10005\nexport const BlockedRelaysList = 10006\nexport const SearchRelaysList = 10007\nexport const InterestsList = 10015\nexport const UserEmojiList = 10030\nexport const FileServerPreference = 10096\nexport const NWCWalletInfo = 13194\nexport const LightningPubRPC = 21000\nexport const ClientAuth = 22242\nexport const NWCWalletRequest = 23194\nexport const NWCWalletResponse = 23195\nexport const NostrConnect = 24133\nexport const HTTPAuth = 27235\nexport const Followsets = 30000\nexport const Genericlists = 30001\nexport const Relaysets = 30002\nexport const Bookmarksets = 30003\nexport const Curationsets = 30004\nexport const ProfileBadges = 30008\nexport const BadgeDefinition = 30009\nexport const Interestsets = 30015\nexport const CreateOrUpdateStall = 30017\nexport const CreateOrUpdateProduct = 30018\nexport const LongFormArticle = 30023\nexport const DraftLong = 30024\nexport const Emojisets = 30030\nexport const Application = 30078\nexport const LiveEvent = 30311\nexport const UserStatuses = 30315\nexport const ClassifiedListing = 30402\nexport const DraftClassifiedListing = 30403\nexport const Date = 31922\nexport const Time = 31923\nexport const Calendar = 31924\nexport const CalendarEventRSVP = 31925\nexport const Handlerrecommendation = 31989\nexport const Handlerinformation = 31990\nexport const CommunityDefinition = 34550\n"],
5
+ "mappings": "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",
6
6
  "names": ["i"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../nip29.ts", "../../nip19.ts", "../../utils.ts", "../../nip11.ts"],
4
- "sourcesContent": ["import { AbstractSimplePool } from './abstract-pool'\nimport { Subscription } from './abstract-relay'\nimport { decode } from './nip19'\nimport type { Event } from './core'\nimport { fetchRelayInformation } from './nip11'\nimport { normalizeURL } from './utils'\nimport { AddressPointer } from './nip19'\n\nexport function subscribeRelayGroups(\n pool: AbstractSimplePool,\n url: string,\n params: {\n ongroups: (_: Group[]) => void\n onerror: (_: Error) => void\n onconnect?: () => void\n },\n): () => void {\n let normalized = normalizeURL(url)\n let sub: Subscription\n let groups: Group[] = []\n\n fetchRelayInformation(normalized)\n .then(async info => {\n let rl = await pool.ensureRelay(normalized)\n params.onconnect?.()\n sub = rl.prepareSubscription(\n [\n {\n kinds: [39000],\n limit: 50,\n authors: [info.pubkey],\n },\n ],\n {\n onevent(event: Event) {\n groups.push(parseGroup(event, normalized))\n },\n oneose() {\n params.ongroups(groups)\n sub.onevent = (event: Event) => {\n groups.push(parseGroup(event, normalized))\n params.ongroups(groups)\n }\n },\n },\n )\n sub.fire()\n })\n .catch(params.onerror)\n\n return () => sub.close()\n}\n\nexport async function loadGroup(pool: AbstractSimplePool, gr: GroupReference): Promise<Group> {\n let normalized = normalizeURL(gr.host)\n\n let info = await fetchRelayInformation(normalized)\n let event = await pool.get([normalized], {\n kinds: [39000],\n authors: [info.pubkey],\n '#d': [gr.id],\n })\n if (!event) throw new Error(`group '${gr.id}' not found on ${gr.host}`)\n return parseGroup(event, normalized)\n}\n\nexport async function loadGroupFromCode(pool: AbstractSimplePool, code: string): Promise<Group> {\n let gr = parseGroupCode(code)\n if (!gr) throw new Error(`code \"${code}\" does not identify a group`)\n return loadGroup(pool, gr)\n}\n\nexport type GroupReference = {\n id: string\n host: string\n}\n\nexport function parseGroupCode(code: string): null | GroupReference {\n if (code.startsWith('naddr1')) {\n try {\n let { data } = decode(code)\n\n let { relays, identifier } = data as AddressPointer\n if (!relays || relays.length === 0) return null\n\n let host = relays![0]\n if (host.startsWith('wss://')) {\n host = host.slice(6)\n }\n return { host, id: identifier }\n } catch (err) {\n return null\n }\n } else if (code.split(\"'\").length === 2) {\n let spl = code.split(\"'\")\n return { host: spl[0], id: spl[1] }\n }\n\n return null\n}\n\nexport function encodeGroupReference(gr: GroupReference): string {\n if (gr.host.startsWith('https://')) gr.host = gr.host.slice(8)\n if (gr.host.startsWith('wss://')) gr.host = gr.host.slice(6)\n return `${gr.host}'${gr.id}`\n}\n\nexport type Group = {\n id: string\n relay: string\n pubkey: string\n name?: string\n picture?: string\n about?: string\n public?: boolean\n open?: boolean\n}\n\nexport function parseGroup(event: Event, relay: string): Group {\n const group: Partial<Group> = { relay, pubkey: event.pubkey }\n for (let i = 0; i < event.tags.length; i++) {\n const tag = event.tags[i]\n switch (tag[0]) {\n case 'd':\n group.id = tag[1] || ''\n break\n case 'name':\n group.name = tag[1] || ''\n break\n case 'about':\n group.about = tag[1] || ''\n break\n case 'picture':\n group.picture = tag[1] || ''\n break\n case 'open':\n group.open = true\n break\n case 'public':\n group.public = true\n break\n }\n }\n return group as Group\n}\n\nexport type Member = {\n pubkey: string\n label?: string\n permissions: string[]\n}\n\nexport function parseMembers(event: Event): Member[] {\n const members = []\n for (let i = 0; i < event.tags.length; i++) {\n const tag = event.tags[i]\n if (tag.length < 2) continue\n if (tag[0] !== 'p') continue\n if (!tag[1].match(/^[0-9a-f]{64}$/)) continue\n const member: Member = { pubkey: tag[1], permissions: [] }\n if (tag.length > 2) member.label = tag[2]\n if (tag.length > 3) member.permissions = tag.slice(3)\n members.push(member)\n }\n return members\n}\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\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\ntype Prefixes = {\n nprofile: ProfilePointer\n nrelay: string\n nevent: EventPointer\n naddr: AddressPointer\n nsec: Uint8Array\n npub: string\n note: string\n}\n\ntype DecodeValue<Prefix extends keyof Prefixes> = {\n type: Prefix\n data: Prefixes[Prefix]\n}\n\nexport type DecodeResult = {\n [P in keyof Prefixes]: DecodeValue<P>\n}[keyof Prefixes]\n\nexport function decode<Prefix extends keyof Prefixes>(nip19: `${Prefix}1${string}`): DecodeValue<Prefix>\nexport function decode(nip19: string): DecodeResult\nexport function decode(nip19: string): DecodeResult {\n let { prefix, words } = bech32.decode(nip19, 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 'nrelay': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nrelay')\n\n return {\n type: 'nrelay',\n data: utf8Decoder.decode(tlv[0][0]),\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 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): `nsec1${string}` {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): `npub1${string}` {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): `note1${string}` {\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): `nprofile1${string}` {\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): `nevent1${string}` {\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): `naddr1${string}` {\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\nexport function nrelayEncode(url: string): `nrelay1${string}` {\n let data = encodeTLV({\n 0: [utf8Encoder.encode(url)],\n })\n return encodeBech32('nrelay', 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 { Event } from './core.ts'\n\nexport const utf8Decoder = new TextDecoder('utf-8')\nexport const utf8Encoder = new TextEncoder()\n\nexport function normalizeURL(url: string): string {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\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}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event) {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event) {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n\n return target.value\n }\n}\n", "var _fetch: any\n\ntry {\n _fetch = fetch\n} catch {}\n\nexport function useFetchImplementation(fetchImplementation: any) {\n _fetch = fetchImplementation\n}\n\nexport async function fetchRelayInformation(url: string) {\n return (await (\n await fetch(url.replace('ws://', 'http://').replace('wss://', 'https://'), {\n headers: { Accept: 'application/nostr+json' },\n })\n ).json()) as RelayInformation\n}\n\n/**\n * ## Relay Information Document\n\n * Relays may provide server metadata to clients to inform\n * them of capabilities, administrative contacts, and\n * various server attributes. This is made available as a\n * JSON document over HTTP, on the same URI as the relay's\n * websocket.\n\n * Any field may be omitted, and clients MUST ignore any\n * additional fields they do not understand. Relays MUST\n * accept CORS requests by sending\n * `Access-Control-Allow-Origin`,\n * `Access-Control-Allow-Headers`, and\n * `Access-Control-Allow-Methods` headers.\n * @param name string identifying relay\n * @param description string with detailed information\n * @param pubkey administrative contact pubkey\n * @param contact: administrative alternate contact\n * @param supported_nips a list of NIP numbers supported by\n * the relay\n * @param software identifying relay software URL\n * @param version string version identifier\n */\nexport interface BasicRelayInformation {\n // string identifying relay\n name: string\n description: string\n pubkey: string\n contact: string\n supported_nips: number[]\n software: string\n version: string\n // limitation?: Limitations<A, P>\n}\n\n/**\n * * ## Extra Fields\n\n * * ### Server Limitations\n\n * These are limitations imposed by the relay on clients.\n * Your client should expect that requests which exceed\n * these practical_ limitations are rejected or fail immediately.\n * @param max_message_length this is the maximum number of\n * bytes for incoming JSON that the relay will attempt to\n * decode and act upon. When you send large subscriptions,\n * you will be limited by this value. It also effectively\n * limits the maximum size of any event. Value is calculated\n * from `[` to `]` and is after UTF-8 serialization (so some\n * unicode characters will cost 2-3 bytes). It is equal to\n * the maximum size of the WebSocket message frame.\n * @param max_subscription total number of subscriptions\n * that may be active on a single websocket connection to\n * this relay. It's possible that authenticated clients with\n * a (paid) relationship to the relay may have higher limits.\n * @param max_filters maximum number of filter values in\n * each subscription. Must be one or higher.\n * @param max_limit the relay server will clamp each\n * filter's `limit` value to this number.\n * This means the client won't be able to get more than this\n * number of events from a single subscription filter. This\n * clamping is typically done silently by the relay, but\n * with this number, you can know that there are additional\n * results if you narrowed your filter's time range or other\n * parameters.\n * @param max_subid_length maximum length of subscription id as a\n * string.\n * @param min_prefix for `authors` and `ids` filters which\n * are to match against a hex prefix, you must provide at\n * least this many hex digits in the prefix.\n * @param max_event_tags in any event, this is the maximum\n * number of elements in the `tags` list.\n * @param max_content_length maximum number of characters in\n * the `content` field of any event. This is a count of\n * unicode characters. After serializing into JSON it may be\n * larger (in bytes), and is still subject to the\n * max_message_length`, if defined.\n * @param min_pow_difficulty new events will require at\n * least this difficulty of PoW, based on [NIP-13](13.md),\n * or they will be rejected by this server.\n * @param auth_required this relay requires [NIP-42](42.md)\n * authentication to happen before a new connection may\n * perform any other action. Even if set to False,\n * authentication may be required for specific actions.\n * @param payment_required this relay requires payment\n * before a new connection may perform any action.\n */\nexport interface Limitations {\n max_message_length: number\n max_subscription: number\n max_filters: number\n max_limit: number\n max_subid_length: number\n min_prefix: number\n max_event_tags: number\n max_content_length: number\n min_pow_difficulty: number\n auth_required: boolean\n payment_required: boolean\n}\n\ninterface RetentionDetails {\n kinds: (number | number[])[]\n time?: number | null\n count?: number | null\n}\ntype AnyRetentionDetails = RetentionDetails\n/**\n * ### Event Retention\n\n * There may be a cost associated with storing data forever,\n * so relays may wish to state retention times. The values\n * stated here are defaults for unauthenticated users and\n * visitors. Paid users would likely have other policies.\n\n * Retention times are given in seconds, with `null`\n * indicating infinity. If zero is provided, this means the\n * event will not be stored at all, and preferably an error\n * will be provided when those are received.\n * ```json\n{\n...\n \"retention\": [\n { \"kinds\": [0, 1, [5, 7], [40, 49]], \"time\": 3600 },\n { \"kinds\": [[40000, 49999]], \"time\": 100 },\n { \"kinds\": [[30000, 39999]], \"count\": 1000 },\n { \"time\": 3600, \"count\": 10000 }\n ]\n...\n}\n```\n * @param retention is a list of specifications: each will\n * apply to either all kinds, or a subset of kinds. Ranges\n * may be specified for the kind field as a tuple of\n * inclusive start and end values. Events of indicated kind\n * (or all) are then limited to a `count` and/or time\n * period.\n\n * It is possible to effectively blacklist Nostr-based\n * protocols that rely on a specific `kind` number, by\n * giving a retention time of zero for those `kind` values.\n * While that is unfortunate, it does allow clients to\n * discover servers that will support their protocol quickly\n * via a single HTTP fetch.\n\n * There is no need to specify retention times for\n * _ephemeral events_ as defined in [NIP-16](16.md) since\n * they are not retained.\n */\nexport interface Retention {\n retention: AnyRetentionDetails[]\n}\n\n/**\n * Some relays may be governed by the arbitrary laws of a\n * nation state. This may limit what content can be stored\n * in cleartext on those relays. All clients are encouraged\n * to use encryption to work around this limitation.\n\n * It is not possible to describe the limitations of each\n * country's laws and policies which themselves are\n * typically vague and constantly shifting.\n\n * Therefore, this field allows the relay operator to\n * indicate which countries' laws might end up being\n * enforced on them, and then indirectly on their users'\n * content.\n\n * Users should be able to avoid relays in countries they\n * don't like, and/or select relays in more favourable\n * zones. Exposing this flexibility is up to the client\n * software.\n\n * @param relay_countries a list of two-level ISO country\n * codes (ISO 3166-1 alpha-2) whose laws and policies may\n * affect this relay. `EU` may be used for European Union\n * countries.\n\n * Remember that a relay may be hosted in a country which is\n * not the country of the legal entities who own the relay,\n * so it's very likely a number of countries are involved.\n */\nexport interface ContentLimitations {\n relay_countries: string[]\n}\n\n/**\n * ### Community Preferences\n\n * For public text notes at least, a relay may try to foster\n * a local community. This would encourage users to follow\n * the global feed on that relay, in addition to their usual\n * individual follows. To support this goal, relays MAY\n * specify some of the following values.\n\n * @param language_tags is an ordered list of [IETF\n * language\n * tags](https://en.wikipedia.org/wiki/IETF_language_tag\n * indicating the major languages spoken on the relay.\n * @param tags is a list of limitations on the topics to be\n * discussed. For example `sfw-only` indicates that only\n * \"Safe For Work\" content is encouraged on this relay. This\n * relies on assumptions of what the \"work\" \"community\"\n * feels \"safe\" talking about. In time, a common set of tags\n * may emerge that allow users to find relays that suit\n * their needs, and client software will be able to parse\n * these tags easily. The `bitcoin-only` tag indicates that\n * any _altcoin_, _\"crypto\"_ or _blockchain_ comments will\n * be ridiculed without mercy.\n * @param posting_policy is a link to a human-readable page\n * which specifies the community policies for the relay. In\n * cases where `sfw-only` is True, it's important to link to\n * a page which gets into the specifics of your posting\n * policy.\n\n * The `description` field should be used to describe your\n * community goals and values, in brief. The\n * `posting_policy` is for additional detail and legal\n * terms. Use the `tags` field to signify limitations on\n * content, or topics to be discussed, which could be\n * machine processed by appropriate client software.\n */\nexport interface CommunityPreferences {\n language_tags: string[]\n tags: string[]\n posting_policy: string\n}\n\nexport interface Amount {\n amount: number\n unit: 'msat'\n}\nexport interface PublicationAmount extends Amount {\n kinds: number[]\n}\nexport interface Subscription extends Amount {\n period: number\n}\nexport interface Fees {\n admission: Amount[]\n subscription: Subscription[]\n publication: PublicationAmount[]\n}\n/**\n * Relays that require payments may want to expose their fee\n * schedules.\n */\nexport interface PayToRelay {\n payments_url: string\n fees: Fees\n}\n\n/**\n * A URL pointing to an image to be used as an icon for the\n * relay. Recommended to be squared in shape.\n */\nexport interface Icon {\n icon: string\n}\n\nexport type RelayInformation = BasicRelayInformation &\n Partial<Retention> & {\n limitation?: Partial<Limitations>\n } & Partial<ContentLimitations> &\n Partial<CommunityPreferences> &\n Partial<PayToRelay> &\n Partial<Icon>\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { AbstractSimplePool } from './abstract-pool'\nimport { Subscription } from './abstract-relay'\nimport { decode } from './nip19'\nimport type { Event } from './core'\nimport { fetchRelayInformation } from './nip11'\nimport { normalizeURL } from './utils'\nimport { AddressPointer } from './nip19'\n\nexport function subscribeRelayGroups(\n pool: AbstractSimplePool,\n url: string,\n params: {\n ongroups: (_: Group[]) => void\n onerror: (_: Error) => void\n onconnect?: () => void\n },\n): () => void {\n let normalized = normalizeURL(url)\n let sub: Subscription\n let groups: Group[] = []\n\n fetchRelayInformation(normalized)\n .then(async info => {\n let rl = await pool.ensureRelay(normalized)\n params.onconnect?.()\n sub = rl.prepareSubscription(\n [\n {\n kinds: [39000],\n limit: 50,\n authors: [info.pubkey],\n },\n ],\n {\n onevent(event: Event) {\n groups.push(parseGroup(event, normalized))\n },\n oneose() {\n params.ongroups(groups)\n sub.onevent = (event: Event) => {\n groups.push(parseGroup(event, normalized))\n params.ongroups(groups)\n }\n },\n },\n )\n sub.fire()\n })\n .catch(params.onerror)\n\n return () => sub.close()\n}\n\nexport async function loadGroup(pool: AbstractSimplePool, gr: GroupReference): Promise<Group> {\n let normalized = normalizeURL(gr.host)\n\n let info = await fetchRelayInformation(normalized)\n let event = await pool.get([normalized], {\n kinds: [39000],\n authors: [info.pubkey],\n '#d': [gr.id],\n })\n if (!event) throw new Error(`group '${gr.id}' not found on ${gr.host}`)\n return parseGroup(event, normalized)\n}\n\nexport async function loadGroupFromCode(pool: AbstractSimplePool, code: string): Promise<Group> {\n let gr = parseGroupCode(code)\n if (!gr) throw new Error(`code \"${code}\" does not identify a group`)\n return loadGroup(pool, gr)\n}\n\nexport type GroupReference = {\n id: string\n host: string\n}\n\nexport function parseGroupCode(code: string): null | GroupReference {\n if (code.startsWith('naddr1')) {\n try {\n let { data } = decode(code)\n\n let { relays, identifier } = data as AddressPointer\n if (!relays || relays.length === 0) return null\n\n let host = relays![0]\n if (host.startsWith('wss://')) {\n host = host.slice(6)\n }\n return { host, id: identifier }\n } catch (err) {\n return null\n }\n } else if (code.split(\"'\").length === 2) {\n let spl = code.split(\"'\")\n return { host: spl[0], id: spl[1] }\n }\n\n return null\n}\n\nexport function encodeGroupReference(gr: GroupReference): string {\n if (gr.host.startsWith('https://')) gr.host = gr.host.slice(8)\n if (gr.host.startsWith('wss://')) gr.host = gr.host.slice(6)\n return `${gr.host}'${gr.id}`\n}\n\nexport type Group = {\n id: string\n relay: string\n pubkey: string\n name?: string\n picture?: string\n about?: string\n public?: boolean\n open?: boolean\n}\n\nexport function parseGroup(event: Event, relay: string): Group {\n const group: Partial<Group> = { relay, pubkey: event.pubkey }\n for (let i = 0; i < event.tags.length; i++) {\n const tag = event.tags[i]\n switch (tag[0]) {\n case 'd':\n group.id = tag[1] || ''\n break\n case 'name':\n group.name = tag[1] || ''\n break\n case 'about':\n group.about = tag[1] || ''\n break\n case 'picture':\n group.picture = tag[1] || ''\n break\n case 'open':\n group.open = true\n break\n case 'public':\n group.public = true\n break\n }\n }\n return group as Group\n}\n\nexport type Member = {\n pubkey: string\n label?: string\n permissions: string[]\n}\n\nexport function parseMembers(event: Event): Member[] {\n const members = []\n for (let i = 0; i < event.tags.length; i++) {\n const tag = event.tags[i]\n if (tag.length < 2) continue\n if (tag[0] !== 'p') continue\n if (!tag[1].match(/^[0-9a-f]{64}$/)) continue\n const member: Member = { pubkey: tag[1], permissions: [] }\n if (tag.length > 2) member.label = tag[2]\n if (tag.length > 3) member.permissions = tag.slice(3)\n members.push(member)\n }\n return members\n}\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\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\ntype Prefixes = {\n nprofile: ProfilePointer\n nrelay: string\n nevent: EventPointer\n naddr: AddressPointer\n nsec: Uint8Array\n npub: string\n note: string\n}\n\ntype DecodeValue<Prefix extends keyof Prefixes> = {\n type: Prefix\n data: Prefixes[Prefix]\n}\n\nexport type DecodeResult = {\n [P in keyof Prefixes]: DecodeValue<P>\n}[keyof Prefixes]\n\nexport function decode<Prefix extends keyof Prefixes>(nip19: `${Prefix}1${string}`): DecodeValue<Prefix>\nexport function decode(nip19: string): DecodeResult\nexport function decode(nip19: string): DecodeResult {\n let { prefix, words } = bech32.decode(nip19, 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 'nrelay': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nrelay')\n\n return {\n type: 'nrelay',\n data: utf8Decoder.decode(tlv[0][0]),\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 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): `nsec1${string}` {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): `npub1${string}` {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): `note1${string}` {\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): `nprofile1${string}` {\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): `nevent1${string}` {\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): `naddr1${string}` {\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\nexport function nrelayEncode(url: string): `nrelay1${string}` {\n let data = encodeTLV({\n 0: [utf8Encoder.encode(url)],\n })\n return encodeBech32('nrelay', 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 { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport function normalizeURL(url: string): string {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\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}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n\n return target.value\n }\n}\n", "var _fetch: any\n\ntry {\n _fetch = fetch\n} catch {}\n\nexport function useFetchImplementation(fetchImplementation: any): void {\n _fetch = fetchImplementation\n}\n\nexport async function fetchRelayInformation(url: string): Promise<RelayInformation> {\n return (await (\n await fetch(url.replace('ws://', 'http://').replace('wss://', 'https://'), {\n headers: { Accept: 'application/nostr+json' },\n })\n ).json()) as RelayInformation\n}\n\n/**\n * ## Relay Information Document\n\n * Relays may provide server metadata to clients to inform\n * them of capabilities, administrative contacts, and\n * various server attributes. This is made available as a\n * JSON document over HTTP, on the same URI as the relay's\n * websocket.\n\n * Any field may be omitted, and clients MUST ignore any\n * additional fields they do not understand. Relays MUST\n * accept CORS requests by sending\n * `Access-Control-Allow-Origin`,\n * `Access-Control-Allow-Headers`, and\n * `Access-Control-Allow-Methods` headers.\n * @param name string identifying relay\n * @param description string with detailed information\n * @param pubkey administrative contact pubkey\n * @param contact: administrative alternate contact\n * @param supported_nips a list of NIP numbers supported by\n * the relay\n * @param software identifying relay software URL\n * @param version string version identifier\n */\nexport interface BasicRelayInformation {\n // string identifying relay\n name: string\n description: string\n pubkey: string\n contact: string\n supported_nips: number[]\n software: string\n version: string\n // limitation?: Limitations<A, P>\n}\n\n/**\n * * ## Extra Fields\n\n * * ### Server Limitations\n\n * These are limitations imposed by the relay on clients.\n * Your client should expect that requests which exceed\n * these practical_ limitations are rejected or fail immediately.\n * @param max_message_length this is the maximum number of\n * bytes for incoming JSON that the relay will attempt to\n * decode and act upon. When you send large subscriptions,\n * you will be limited by this value. It also effectively\n * limits the maximum size of any event. Value is calculated\n * from `[` to `]` and is after UTF-8 serialization (so some\n * unicode characters will cost 2-3 bytes). It is equal to\n * the maximum size of the WebSocket message frame.\n * @param max_subscription total number of subscriptions\n * that may be active on a single websocket connection to\n * this relay. It's possible that authenticated clients with\n * a (paid) relationship to the relay may have higher limits.\n * @param max_filters maximum number of filter values in\n * each subscription. Must be one or higher.\n * @param max_limit the relay server will clamp each\n * filter's `limit` value to this number.\n * This means the client won't be able to get more than this\n * number of events from a single subscription filter. This\n * clamping is typically done silently by the relay, but\n * with this number, you can know that there are additional\n * results if you narrowed your filter's time range or other\n * parameters.\n * @param max_subid_length maximum length of subscription id as a\n * string.\n * @param min_prefix for `authors` and `ids` filters which\n * are to match against a hex prefix, you must provide at\n * least this many hex digits in the prefix.\n * @param max_event_tags in any event, this is the maximum\n * number of elements in the `tags` list.\n * @param max_content_length maximum number of characters in\n * the `content` field of any event. This is a count of\n * unicode characters. After serializing into JSON it may be\n * larger (in bytes), and is still subject to the\n * max_message_length`, if defined.\n * @param min_pow_difficulty new events will require at\n * least this difficulty of PoW, based on [NIP-13](13.md),\n * or they will be rejected by this server.\n * @param auth_required this relay requires [NIP-42](42.md)\n * authentication to happen before a new connection may\n * perform any other action. Even if set to False,\n * authentication may be required for specific actions.\n * @param payment_required this relay requires payment\n * before a new connection may perform any action.\n */\nexport interface Limitations {\n max_message_length: number\n max_subscription: number\n max_filters: number\n max_limit: number\n max_subid_length: number\n min_prefix: number\n max_event_tags: number\n max_content_length: number\n min_pow_difficulty: number\n auth_required: boolean\n payment_required: boolean\n}\n\ninterface RetentionDetails {\n kinds: (number | number[])[]\n time?: number | null\n count?: number | null\n}\ntype AnyRetentionDetails = RetentionDetails\n/**\n * ### Event Retention\n\n * There may be a cost associated with storing data forever,\n * so relays may wish to state retention times. The values\n * stated here are defaults for unauthenticated users and\n * visitors. Paid users would likely have other policies.\n\n * Retention times are given in seconds, with `null`\n * indicating infinity. If zero is provided, this means the\n * event will not be stored at all, and preferably an error\n * will be provided when those are received.\n * ```json\n{\n...\n \"retention\": [\n { \"kinds\": [0, 1, [5, 7], [40, 49]], \"time\": 3600 },\n { \"kinds\": [[40000, 49999]], \"time\": 100 },\n { \"kinds\": [[30000, 39999]], \"count\": 1000 },\n { \"time\": 3600, \"count\": 10000 }\n ]\n...\n}\n```\n * @param retention is a list of specifications: each will\n * apply to either all kinds, or a subset of kinds. Ranges\n * may be specified for the kind field as a tuple of\n * inclusive start and end values. Events of indicated kind\n * (or all) are then limited to a `count` and/or time\n * period.\n\n * It is possible to effectively blacklist Nostr-based\n * protocols that rely on a specific `kind` number, by\n * giving a retention time of zero for those `kind` values.\n * While that is unfortunate, it does allow clients to\n * discover servers that will support their protocol quickly\n * via a single HTTP fetch.\n\n * There is no need to specify retention times for\n * _ephemeral events_ as defined in [NIP-16](16.md) since\n * they are not retained.\n */\nexport interface Retention {\n retention: AnyRetentionDetails[]\n}\n\n/**\n * Some relays may be governed by the arbitrary laws of a\n * nation state. This may limit what content can be stored\n * in cleartext on those relays. All clients are encouraged\n * to use encryption to work around this limitation.\n\n * It is not possible to describe the limitations of each\n * country's laws and policies which themselves are\n * typically vague and constantly shifting.\n\n * Therefore, this field allows the relay operator to\n * indicate which countries' laws might end up being\n * enforced on them, and then indirectly on their users'\n * content.\n\n * Users should be able to avoid relays in countries they\n * don't like, and/or select relays in more favourable\n * zones. Exposing this flexibility is up to the client\n * software.\n\n * @param relay_countries a list of two-level ISO country\n * codes (ISO 3166-1 alpha-2) whose laws and policies may\n * affect this relay. `EU` may be used for European Union\n * countries.\n\n * Remember that a relay may be hosted in a country which is\n * not the country of the legal entities who own the relay,\n * so it's very likely a number of countries are involved.\n */\nexport interface ContentLimitations {\n relay_countries: string[]\n}\n\n/**\n * ### Community Preferences\n\n * For public text notes at least, a relay may try to foster\n * a local community. This would encourage users to follow\n * the global feed on that relay, in addition to their usual\n * individual follows. To support this goal, relays MAY\n * specify some of the following values.\n\n * @param language_tags is an ordered list of [IETF\n * language\n * tags](https://en.wikipedia.org/wiki/IETF_language_tag\n * indicating the major languages spoken on the relay.\n * @param tags is a list of limitations on the topics to be\n * discussed. For example `sfw-only` indicates that only\n * \"Safe For Work\" content is encouraged on this relay. This\n * relies on assumptions of what the \"work\" \"community\"\n * feels \"safe\" talking about. In time, a common set of tags\n * may emerge that allow users to find relays that suit\n * their needs, and client software will be able to parse\n * these tags easily. The `bitcoin-only` tag indicates that\n * any _altcoin_, _\"crypto\"_ or _blockchain_ comments will\n * be ridiculed without mercy.\n * @param posting_policy is a link to a human-readable page\n * which specifies the community policies for the relay. In\n * cases where `sfw-only` is True, it's important to link to\n * a page which gets into the specifics of your posting\n * policy.\n\n * The `description` field should be used to describe your\n * community goals and values, in brief. The\n * `posting_policy` is for additional detail and legal\n * terms. Use the `tags` field to signify limitations on\n * content, or topics to be discussed, which could be\n * machine processed by appropriate client software.\n */\nexport interface CommunityPreferences {\n language_tags: string[]\n tags: string[]\n posting_policy: string\n}\n\nexport interface Amount {\n amount: number\n unit: 'msat'\n}\nexport interface PublicationAmount extends Amount {\n kinds: number[]\n}\nexport interface Subscription extends Amount {\n period: number\n}\nexport interface Fees {\n admission: Amount[]\n subscription: Subscription[]\n publication: PublicationAmount[]\n}\n/**\n * Relays that require payments may want to expose their fee\n * schedules.\n */\nexport interface PayToRelay {\n payments_url: string\n fees: Fees\n}\n\n/**\n * A URL pointing to an image to be used as an icon for the\n * relay. Recommended to be squared in shape.\n */\nexport interface Icon {\n icon: string\n}\n\nexport type RelayInformation = BasicRelayInformation &\n Partial<Retention> & {\n limitation?: Partial<Limitations>\n } & Partial<ContentLimitations> &\n Partial<CommunityPreferences> &\n Partial<PayToRelay> &\n Partial<Icon>\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../nip30.ts"],
4
- "sourcesContent": ["/** Regex for a single emoji shortcode. */\nexport const EMOJI_SHORTCODE_REGEX = /:(\\w+):/\n\n/** Regex to find emoji shortcodes in content. */\nexport const regex = () => new RegExp(`\\\\B${EMOJI_SHORTCODE_REGEX.source}\\\\B`, 'g')\n\n/** Represents a Nostr custom emoji. */\nexport interface CustomEmoji {\n /** The matched emoji name with colons. */\n shortcode: `:${string}:`\n /** The matched emoji name without colons. */\n name: string\n}\n\n/** Match result for a custom emoji in text content. */\nexport interface CustomEmojiMatch extends CustomEmoji {\n /** Index where the emoji begins in the text content. */\n start: number\n /** Index where the emoji ends in the text content. */\n end: number\n}\n\n/** Find all custom emoji shortcodes. */\nexport function* matchAll(content: string): Iterable<CustomEmojiMatch> {\n const matches = content.matchAll(regex())\n\n for (const match of matches) {\n try {\n const [shortcode, name] = match\n\n yield {\n shortcode: shortcode as `:${string}:`,\n name,\n start: match.index!,\n end: match.index! + shortcode.length,\n }\n } catch (_e) {\n // do nothing\n }\n }\n}\n\n/** Replace all emoji shortcodes in the content. */\nexport function replaceAll(content: string, replacer: (match: CustomEmoji) => string): string {\n return content.replaceAll(regex(), (shortcode, name) => {\n return replacer({\n shortcode: shortcode as `:${string}:`,\n name,\n })\n })\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACO,IAAM,wBAAwB;AAG9B,IAAM,QAAQ,MAAM,IAAI,OAAO,MAAM,sBAAsB,aAAa,GAAG;AAmB3E,UAAU,SAAS,SAA6C;AACrE,QAAM,UAAU,QAAQ,SAAS,MAAM,CAAC;AAExC,aAAW,SAAS,SAAS;AAC3B,QAAI;AACF,YAAM,CAAC,WAAW,IAAI,IAAI;AAE1B,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA,OAAO,MAAM;AAAA,QACb,KAAK,MAAM,QAAS,UAAU;AAAA,MAChC;AAAA,IACF,SAAS,IAAP;AAAA,IAEF;AAAA,EACF;AACF;AAGO,SAAS,WAAW,SAAiB,UAAkD;AAC5F,SAAO,QAAQ,WAAW,MAAM,GAAG,CAAC,WAAW,SAAS;AACtD,WAAO,SAAS;AAAA,MACd;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;",
4
+ "sourcesContent": ["/** Regex for a single emoji shortcode. */\nexport const EMOJI_SHORTCODE_REGEX = /:(\\w+):/\n\n/** Regex to find emoji shortcodes in content. */\nexport const regex = (): RegExp => new RegExp(`\\\\B${EMOJI_SHORTCODE_REGEX.source}\\\\B`, 'g')\n\n/** Represents a Nostr custom emoji. */\nexport interface CustomEmoji {\n /** The matched emoji name with colons. */\n shortcode: `:${string}:`\n /** The matched emoji name without colons. */\n name: string\n}\n\n/** Match result for a custom emoji in text content. */\nexport interface CustomEmojiMatch extends CustomEmoji {\n /** Index where the emoji begins in the text content. */\n start: number\n /** Index where the emoji ends in the text content. */\n end: number\n}\n\n/** Find all custom emoji shortcodes. */\nexport function* matchAll(content: string): Iterable<CustomEmojiMatch> {\n const matches = content.matchAll(regex())\n\n for (const match of matches) {\n try {\n const [shortcode, name] = match\n\n yield {\n shortcode: shortcode as `:${string}:`,\n name,\n start: match.index!,\n end: match.index! + shortcode.length,\n }\n } catch (_e) {\n // do nothing\n }\n }\n}\n\n/** Replace all emoji shortcodes in the content. */\nexport function replaceAll(content: string, replacer: (match: CustomEmoji) => string): string {\n return content.replaceAll(regex(), (shortcode, name) => {\n return replacer({\n shortcode: shortcode as `:${string}:`,\n name,\n })\n })\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACO,IAAM,wBAAwB;AAG9B,IAAM,QAAQ,MAAc,IAAI,OAAO,MAAM,sBAAsB,aAAa,GAAG;AAmBnF,UAAU,SAAS,SAA6C;AACrE,QAAM,UAAU,QAAQ,SAAS,MAAM,CAAC;AAExC,aAAW,SAAS,SAAS;AAC3B,QAAI;AACF,YAAM,CAAC,WAAW,IAAI,IAAI;AAE1B,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA,OAAO,MAAM;AAAA,QACb,KAAK,MAAM,QAAS,UAAU;AAAA,MAChC;AAAA,IACF,SAAS,IAAP;AAAA,IAEF;AAAA,EACF;AACF;AAGO,SAAS,WAAW,SAAiB,UAAkD;AAC5F,SAAO,QAAQ,WAAW,MAAM,GAAG,CAAC,WAAW,SAAS;AACtD,WAAO,SAAS;AAAA,MACd;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../nip42.ts", "../../kinds.ts"],
4
- "sourcesContent": ["import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number) {\n return (1000 <= kind && kind < 10000) || [1, 2, 4, 5, 6, 7, 8, 16, 40, 41, 42, 43, 44].includes(kind)\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number) {\n return [0, 3].includes(kind) || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number) {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **parameterized replaceable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isParameterizedReplaceableKind(kind: number) {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isParameterizedReplaceableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport const Metadata = 0\nexport const ShortTextNote = 1\nexport const RecommendRelay = 2\nexport const Contacts = 3\nexport const EncryptedDirectMessage = 4\nexport const EncryptedDirectMessages = 4\nexport const EventDeletion = 5\nexport const Repost = 6\nexport const Reaction = 7\nexport const BadgeAward = 8\nexport const GenericRepost = 16\nexport const ChannelCreation = 40\nexport const ChannelMetadata = 41\nexport const ChannelMessage = 42\nexport const ChannelHideMessage = 43\nexport const ChannelMuteUser = 44\nexport const OpenTimestamps = 1040\nexport const FileMetadata = 1063\nexport const LiveChatMessage = 1311\nexport const ProblemTracker = 1971\nexport const Report = 1984\nexport const Reporting = 1984\nexport const Label = 1985\nexport const CommunityPostApproval = 4550\nexport const JobRequest = 5999\nexport const JobResult = 6999\nexport const JobFeedback = 7000\nexport const ZapGoal = 9041\nexport const ZapRequest = 9734\nexport const Zap = 9735\nexport const Highlights = 9802\nexport const Mutelist = 10000\nexport const Pinlist = 10001\nexport const RelayList = 10002\nexport const BookmarkList = 10003\nexport const CommunitiesList = 10004\nexport const PublicChatsList = 10005\nexport const BlockedRelaysList = 10006\nexport const SearchRelaysList = 10007\nexport const InterestsList = 10015\nexport const UserEmojiList = 10030\nexport const FileServerPreference = 10096\nexport const NWCWalletInfo = 13194\nexport const LightningPubRPC = 21000\nexport const ClientAuth = 22242\nexport const NWCWalletRequest = 23194\nexport const NWCWalletResponse = 23195\nexport const NostrConnect = 24133\nexport const HTTPAuth = 27235\nexport const Followsets = 30000\nexport const Genericlists = 30001\nexport const Relaysets = 30002\nexport const Bookmarksets = 30003\nexport const Curationsets = 30004\nexport const ProfileBadges = 30008\nexport const BadgeDefinition = 30009\nexport const Interestsets = 30015\nexport const CreateOrUpdateStall = 30017\nexport const CreateOrUpdateProduct = 30018\nexport const LongFormArticle = 30023\nexport const DraftLong = 30024\nexport const Emojisets = 30030\nexport const Application = 30078\nexport const LiveEvent = 30311\nexport const UserStatuses = 30315\nexport const ClassifiedListing = 30402\nexport const DraftClassifiedListing = 30403\nexport const Date = 31922\nexport const Time = 31923\nexport const Calendar = 31924\nexport const CalendarEventRSVP = 31925\nexport const Handlerrecommendation = 31989\nexport const Handlerinformation = 31990\nexport const CommunityDefinition = 34550\n"],
4
+ "sourcesContent": ["import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return (1000 <= kind && kind < 10000) || [1, 2, 4, 5, 6, 7, 8, 16, 40, 41, 42, 43, 44].includes(kind)\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return [0, 3].includes(kind) || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **parameterized replaceable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isParameterizedReplaceableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isParameterizedReplaceableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport const Metadata = 0\nexport const ShortTextNote = 1\nexport const RecommendRelay = 2\nexport const Contacts = 3\nexport const EncryptedDirectMessage = 4\nexport const EncryptedDirectMessages = 4\nexport const EventDeletion = 5\nexport const Repost = 6\nexport const Reaction = 7\nexport const BadgeAward = 8\nexport const GenericRepost = 16\nexport const ChannelCreation = 40\nexport const ChannelMetadata = 41\nexport const ChannelMessage = 42\nexport const ChannelHideMessage = 43\nexport const ChannelMuteUser = 44\nexport const OpenTimestamps = 1040\nexport const FileMetadata = 1063\nexport const LiveChatMessage = 1311\nexport const ProblemTracker = 1971\nexport const Report = 1984\nexport const Reporting = 1984\nexport const Label = 1985\nexport const CommunityPostApproval = 4550\nexport const JobRequest = 5999\nexport const JobResult = 6999\nexport const JobFeedback = 7000\nexport const ZapGoal = 9041\nexport const ZapRequest = 9734\nexport const Zap = 9735\nexport const Highlights = 9802\nexport const Mutelist = 10000\nexport const Pinlist = 10001\nexport const RelayList = 10002\nexport const BookmarkList = 10003\nexport const CommunitiesList = 10004\nexport const PublicChatsList = 10005\nexport const BlockedRelaysList = 10006\nexport const SearchRelaysList = 10007\nexport const InterestsList = 10015\nexport const UserEmojiList = 10030\nexport const FileServerPreference = 10096\nexport const NWCWalletInfo = 13194\nexport const LightningPubRPC = 21000\nexport const ClientAuth = 22242\nexport const NWCWalletRequest = 23194\nexport const NWCWalletResponse = 23195\nexport const NostrConnect = 24133\nexport const HTTPAuth = 27235\nexport const Followsets = 30000\nexport const Genericlists = 30001\nexport const Relaysets = 30002\nexport const Bookmarksets = 30003\nexport const Curationsets = 30004\nexport const ProfileBadges = 30008\nexport const BadgeDefinition = 30009\nexport const Interestsets = 30015\nexport const CreateOrUpdateStall = 30017\nexport const CreateOrUpdateProduct = 30018\nexport const LongFormArticle = 30023\nexport const DraftLong = 30024\nexport const Emojisets = 30030\nexport const Application = 30078\nexport const LiveEvent = 30311\nexport const UserStatuses = 30315\nexport const ClassifiedListing = 30402\nexport const DraftClassifiedListing = 30403\nexport const Date = 31922\nexport const Time = 31923\nexport const Calendar = 31924\nexport const CalendarEventRSVP = 31925\nexport const Handlerrecommendation = 31989\nexport const Handlerinformation = 31990\nexport const CommunityDefinition = 34550\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC4EO,IAAM,aAAa;;;ADtEnB,SAAS,cAAc,UAAkB,WAAkC;AAChF,SAAO;AAAA,IACL,MAAM;AAAA,IACN,YAAY,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAAA,IACxC,MAAM;AAAA,MACJ,CAAC,SAAS,QAAQ;AAAA,MAClB,CAAC,aAAa,SAAS;AAAA,IACzB;AAAA,IACA,SAAS;AAAA,EACX;AACF;",
6
6
  "names": []
7
7
  }
package/lib/cjs/nip44.js CHANGED
@@ -3,6 +3,7 @@ var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
7
  var __export = (target, all) => {
7
8
  for (var name in all)
8
9
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -16,6 +17,10 @@ var __copyProps = (to, from, except, desc) => {
16
17
  return to;
17
18
  };
18
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var __publicField = (obj, key, value) => {
21
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
22
+ return value;
23
+ };
19
24
 
20
25
  // nip44.ts
21
26
  var nip44_exports = {};
@@ -33,26 +38,23 @@ var import_sha256 = require("@noble/hashes/sha256");
33
38
  var import_utils2 = require("@noble/hashes/utils");
34
39
  var import_base = require("@scure/base");
35
40
  var decoder = new TextDecoder();
36
- var u = {
37
- minPlaintextSize: 1,
38
- maxPlaintextSize: 65535,
39
- utf8Encode: import_utils2.utf8ToBytes,
40
- utf8Decode(bytes) {
41
+ var _u = class {
42
+ static utf8Decode(bytes) {
41
43
  return decoder.decode(bytes);
42
- },
43
- getConversationKey(privkeyA, pubkeyB) {
44
+ }
45
+ static getConversationKey(privkeyA, pubkeyB) {
44
46
  const sharedX = import_secp256k1.secp256k1.getSharedSecret(privkeyA, "02" + pubkeyB).subarray(1, 33);
45
47
  return (0, import_hkdf.extract)(import_sha256.sha256, sharedX, "nip44-v2");
46
- },
47
- getMessageKeys(conversationKey, nonce) {
48
+ }
49
+ static getMessageKeys(conversationKey, nonce) {
48
50
  const keys = (0, import_hkdf.expand)(import_sha256.sha256, conversationKey, nonce, 76);
49
51
  return {
50
52
  chacha_key: keys.subarray(0, 32),
51
53
  chacha_nonce: keys.subarray(32, 44),
52
54
  hmac_key: keys.subarray(44, 76)
53
55
  };
54
- },
55
- calcPaddedLen(len) {
56
+ }
57
+ static calcPaddedLen(len) {
56
58
  if (!Number.isSafeInteger(len) || len < 1)
57
59
  throw new Error("expected positive integer");
58
60
  if (len <= 32)
@@ -60,35 +62,35 @@ var u = {
60
62
  const nextPower = 1 << Math.floor(Math.log2(len - 1)) + 1;
61
63
  const chunk = nextPower <= 256 ? 32 : nextPower / 8;
62
64
  return chunk * (Math.floor((len - 1) / chunk) + 1);
63
- },
64
- writeU16BE(num) {
65
- if (!Number.isSafeInteger(num) || num < u.minPlaintextSize || num > u.maxPlaintextSize)
65
+ }
66
+ static writeU16BE(num) {
67
+ if (!Number.isSafeInteger(num) || num < _u.minPlaintextSize || num > _u.maxPlaintextSize)
66
68
  throw new Error("invalid plaintext size: must be between 1 and 65535 bytes");
67
69
  const arr = new Uint8Array(2);
68
70
  new DataView(arr.buffer).setUint16(0, num, false);
69
71
  return arr;
70
- },
71
- pad(plaintext) {
72
- const unpadded = u.utf8Encode(plaintext);
72
+ }
73
+ static pad(plaintext) {
74
+ const unpadded = _u.utf8Encode(plaintext);
73
75
  const unpaddedLen = unpadded.length;
74
- const prefix = u.writeU16BE(unpaddedLen);
75
- const suffix = new Uint8Array(u.calcPaddedLen(unpaddedLen) - unpaddedLen);
76
+ const prefix = _u.writeU16BE(unpaddedLen);
77
+ const suffix = new Uint8Array(_u.calcPaddedLen(unpaddedLen) - unpaddedLen);
76
78
  return (0, import_utils2.concatBytes)(prefix, unpadded, suffix);
77
- },
78
- unpad(padded) {
79
+ }
80
+ static unpad(padded) {
79
81
  const unpaddedLen = new DataView(padded.buffer).getUint16(0);
80
82
  const unpadded = padded.subarray(2, 2 + unpaddedLen);
81
- if (unpaddedLen < u.minPlaintextSize || unpaddedLen > u.maxPlaintextSize || unpadded.length !== unpaddedLen || padded.length !== 2 + u.calcPaddedLen(unpaddedLen))
83
+ if (unpaddedLen < _u.minPlaintextSize || unpaddedLen > _u.maxPlaintextSize || unpadded.length !== unpaddedLen || padded.length !== 2 + _u.calcPaddedLen(unpaddedLen))
82
84
  throw new Error("invalid padding");
83
- return u.utf8Decode(unpadded);
84
- },
85
- hmacAad(key, message, aad) {
85
+ return _u.utf8Decode(unpadded);
86
+ }
87
+ static hmacAad(key, message, aad) {
86
88
  if (aad.length !== 32)
87
89
  throw new Error("AAD associated data must be 32 bytes");
88
90
  const combined = (0, import_utils2.concatBytes)(aad, message);
89
91
  return (0, import_hmac.hmac)(import_sha256.sha256, key, combined);
90
- },
91
- decodePayload(payload) {
92
+ }
93
+ static decodePayload(payload) {
92
94
  if (typeof payload !== "string")
93
95
  throw new Error("payload must be a valid string");
94
96
  const plen = payload.length;
@@ -115,25 +117,27 @@ var u = {
115
117
  };
116
118
  }
117
119
  };
118
- function encrypt(plaintext, conversationKey, nonce = (0, import_utils2.randomBytes)(32)) {
119
- const { chacha_key, chacha_nonce, hmac_key } = u.getMessageKeys(conversationKey, nonce);
120
- const padded = u.pad(plaintext);
121
- const ciphertext = (0, import_chacha.chacha20)(chacha_key, chacha_nonce, padded);
122
- const mac = u.hmacAad(hmac_key, ciphertext, nonce);
123
- return import_base.base64.encode((0, import_utils2.concatBytes)(new Uint8Array([2]), nonce, ciphertext, mac));
124
- }
125
- function decrypt(payload, conversationKey) {
126
- const { nonce, ciphertext, mac } = u.decodePayload(payload);
127
- const { chacha_key, chacha_nonce, hmac_key } = u.getMessageKeys(conversationKey, nonce);
128
- const calculatedMac = u.hmacAad(hmac_key, ciphertext, nonce);
129
- if (!(0, import_utils.equalBytes)(calculatedMac, mac))
130
- throw new Error("invalid MAC");
131
- const padded = (0, import_chacha.chacha20)(chacha_key, chacha_nonce, ciphertext);
132
- return u.unpad(padded);
133
- }
134
- var v2 = {
135
- utils: u,
136
- encrypt,
137
- decrypt
120
+ var u = _u;
121
+ __publicField(u, "minPlaintextSize", 1);
122
+ __publicField(u, "maxPlaintextSize", 65535);
123
+ __publicField(u, "utf8Encode", import_utils2.utf8ToBytes);
124
+ var v2 = class {
125
+ static encrypt(plaintext, conversationKey, nonce = (0, import_utils2.randomBytes)(32)) {
126
+ const { chacha_key, chacha_nonce, hmac_key } = u.getMessageKeys(conversationKey, nonce);
127
+ const padded = u.pad(plaintext);
128
+ const ciphertext = (0, import_chacha.chacha20)(chacha_key, chacha_nonce, padded);
129
+ const mac = u.hmacAad(hmac_key, ciphertext, nonce);
130
+ return import_base.base64.encode((0, import_utils2.concatBytes)(new Uint8Array([2]), nonce, ciphertext, mac));
131
+ }
132
+ static decrypt(payload, conversationKey) {
133
+ const { nonce, ciphertext, mac } = u.decodePayload(payload);
134
+ const { chacha_key, chacha_nonce, hmac_key } = u.getMessageKeys(conversationKey, nonce);
135
+ const calculatedMac = u.hmacAad(hmac_key, ciphertext, nonce);
136
+ if (!(0, import_utils.equalBytes)(calculatedMac, mac))
137
+ throw new Error("invalid MAC");
138
+ const padded = (0, import_chacha.chacha20)(chacha_key, chacha_nonce, ciphertext);
139
+ return u.unpad(padded);
140
+ }
138
141
  };
142
+ __publicField(v2, "utils", u);
139
143
  var nip44_default = { v2 };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../nip44.ts"],
4
- "sourcesContent": ["import { chacha20 } from '@noble/ciphers/chacha'\nimport { equalBytes } from '@noble/ciphers/utils'\nimport { secp256k1 } from '@noble/curves/secp256k1'\nimport { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf'\nimport { hmac } from '@noble/hashes/hmac'\nimport { sha256 } from '@noble/hashes/sha256'\nimport { concatBytes, randomBytes, utf8ToBytes } from '@noble/hashes/utils'\nimport { base64 } from '@scure/base'\n\nconst decoder = new TextDecoder()\nconst u = {\n minPlaintextSize: 0x0001, // 1b msg => padded to 32b\n maxPlaintextSize: 0xffff, // 65535 (64kb-1) => padded to 64kb\n\n utf8Encode: utf8ToBytes,\n utf8Decode(bytes: Uint8Array) {\n return decoder.decode(bytes)\n },\n\n getConversationKey(privkeyA: string, pubkeyB: string): Uint8Array {\n const sharedX = secp256k1.getSharedSecret(privkeyA, '02' + pubkeyB).subarray(1, 33)\n return hkdf_extract(sha256, sharedX, 'nip44-v2')\n },\n\n getMessageKeys(conversationKey: Uint8Array, nonce: 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\n 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 = 1 << (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\n writeU16BE(num: number) {\n if (!Number.isSafeInteger(num) || num < u.minPlaintextSize || num > u.maxPlaintextSize)\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\n pad(plaintext: string): Uint8Array {\n const unpadded = u.utf8Encode(plaintext)\n const unpaddedLen = unpadded.length\n const prefix = u.writeU16BE(unpaddedLen)\n const suffix = new Uint8Array(u.calcPaddedLen(unpaddedLen) - unpaddedLen)\n return concatBytes(prefix, unpadded, suffix)\n },\n\n unpad(padded: Uint8Array): string {\n const unpaddedLen = new DataView(padded.buffer).getUint16(0)\n const unpadded = padded.subarray(2, 2 + unpaddedLen)\n if (\n unpaddedLen < u.minPlaintextSize ||\n unpaddedLen > u.maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== 2 + u.calcPaddedLen(unpaddedLen)\n )\n throw new Error('invalid padding')\n return u.utf8Decode(unpadded)\n },\n\n hmacAad(key: Uint8Array, message: Uint8Array, aad: 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, max: 32b)\n // plaintext: 1b to 0xffff\n // padded plaintext: 32b to 0xffff\n // ciphertext: 32b+2 to 0xffff+2\n // raw payload: 99 (65+32+2) to 65603 (65+0xffff+2)\n // compressed payload (base64): 132b to 87472b\n decodePayload(payload: string) {\n if (typeof payload !== 'string') throw new Error('payload must be a valid string')\n const plen = payload.length\n if (plen < 132 || plen > 87472) 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 || dlen > 65603) 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}\n\nfunction encrypt(plaintext: string, conversationKey: Uint8Array, nonce = randomBytes(32)): string {\n const { chacha_key, chacha_nonce, hmac_key } = u.getMessageKeys(conversationKey, nonce)\n const padded = u.pad(plaintext)\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded)\n const mac = u.hmacAad(hmac_key, ciphertext, nonce)\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac))\n}\n\nfunction decrypt(payload: string, conversationKey: Uint8Array): string {\n const { nonce, ciphertext, mac } = u.decodePayload(payload)\n const { chacha_key, chacha_nonce, hmac_key } = u.getMessageKeys(conversationKey, nonce)\n const calculatedMac = u.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 u.unpad(padded)\n}\n\nexport const v2 = {\n utils: u,\n encrypt,\n decrypt,\n}\n\nexport default { v2 }\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { chacha20 } from '@noble/ciphers/chacha'\nimport { equalBytes } from '@noble/ciphers/utils'\nimport { secp256k1 } from '@noble/curves/secp256k1'\nimport { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf'\nimport { hmac } from '@noble/hashes/hmac'\nimport { sha256 } from '@noble/hashes/sha256'\nimport { concatBytes, randomBytes, utf8ToBytes } from '@noble/hashes/utils'\nimport { base64 } from '@scure/base'\n\nconst decoder = new TextDecoder()\n\nclass u {\n static minPlaintextSize = 0x0001 // 1b msg => padded to 32b\n static maxPlaintextSize = 0xffff // 65535 (64kb-1) => padded to 64kb\n\n static utf8Encode = utf8ToBytes\n\n static utf8Decode(bytes: Uint8Array): string {\n return decoder.decode(bytes)\n }\n\n static getConversationKey(privkeyA: string, pubkeyB: string): Uint8Array {\n const sharedX = secp256k1.getSharedSecret(privkeyA, '02' + pubkeyB).subarray(1, 33)\n return hkdf_extract(sha256, sharedX, 'nip44-v2')\n }\n\n static 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\n static 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 = 1 << (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\n static writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < u.minPlaintextSize || num > u.maxPlaintextSize)\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\n static pad(plaintext: string): Uint8Array {\n const unpadded = u.utf8Encode(plaintext)\n const unpaddedLen = unpadded.length\n const prefix = u.writeU16BE(unpaddedLen)\n const suffix = new Uint8Array(u.calcPaddedLen(unpaddedLen) - unpaddedLen)\n return concatBytes(prefix, unpadded, suffix)\n }\n\n static unpad(padded: Uint8Array): string {\n const unpaddedLen = new DataView(padded.buffer).getUint16(0)\n const unpadded = padded.subarray(2, 2 + unpaddedLen)\n if (\n unpaddedLen < u.minPlaintextSize ||\n unpaddedLen > u.maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== 2 + u.calcPaddedLen(unpaddedLen)\n )\n throw new Error('invalid padding')\n return u.utf8Decode(unpadded)\n }\n\n static 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, max: 32b)\n // plaintext: 1b to 0xffff\n // padded plaintext: 32b to 0xffff\n // ciphertext: 32b+2 to 0xffff+2\n // raw payload: 99 (65+32+2) to 65603 (65+0xffff+2)\n // compressed payload (base64): 132b to 87472b\n static 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 || plen > 87472) 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 || dlen > 65603) 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}\n\nexport class v2 {\n static utils = u\n\n static encrypt(plaintext: string, conversationKey: Uint8Array, nonce: Uint8Array = randomBytes(32)): string {\n const { chacha_key, chacha_nonce, hmac_key } = u.getMessageKeys(conversationKey, nonce)\n const padded = u.pad(plaintext)\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded)\n const mac = u.hmacAad(hmac_key, ciphertext, nonce)\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac))\n }\n\n static decrypt(payload: string, conversationKey: Uint8Array): string {\n const { nonce, ciphertext, mac } = u.decodePayload(payload)\n const { chacha_key, chacha_nonce, hmac_key } = u.getMessageKeys(conversationKey, nonce)\n const calculatedMac = u.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 u.unpad(padded)\n }\n}\n\nexport default { v2 }\n"],
5
+ "mappings": "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",
6
6
  "names": ["import_utils", "hkdf_extract", "hkdf_expand"]
7
7
  }