@qntx/nostr 0.6.0 → 0.8.0

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 (183) hide show
  1. package/dist/{abort-Ba8tDrOI.mjs → abort-DBq2STPj.mjs} +13 -6
  2. package/dist/abort-DBq2STPj.mjs.map +1 -0
  3. package/dist/{builder-sSflu6nB.d.mts → builder-CTwkB2zM.d.mts} +14 -15
  4. package/dist/{builder-9tjI6WQ3.mjs → builder-aNU2gGFP.mjs} +11 -17
  5. package/dist/builder-aNU2gGFP.mjs.map +1 -0
  6. package/dist/{client-CadO5fAX.mjs → client-Cj2lUaVh.mjs} +141 -353
  7. package/dist/client-Cj2lUaVh.mjs.map +1 -0
  8. package/dist/client.d.mts +2 -2
  9. package/dist/client.mjs +2 -2
  10. package/dist/collections-DtwMc1NU.mjs +33 -0
  11. package/dist/collections-DtwMc1NU.mjs.map +1 -0
  12. package/dist/core.d.mts +9 -8
  13. package/dist/core.mjs +7 -7
  14. package/dist/emitter-DkCY6NkU.mjs +32 -0
  15. package/dist/emitter-DkCY6NkU.mjs.map +1 -0
  16. package/dist/{error-BW7re1UN.d.mts → error-BD_0QFKT.d.mts} +2 -2
  17. package/dist/{error-DrEIM7FO.mjs → error-BILMe3Gr.mjs} +2 -2
  18. package/dist/{error-DrEIM7FO.mjs.map → error-BILMe3Gr.mjs.map} +1 -1
  19. package/dist/{error-CR8Urc84.d.mts → error-BquXDmIN.d.mts} +4 -4
  20. package/dist/{error-B__OMBRY.mjs → error-DlhGW4mJ.mjs} +2 -2
  21. package/dist/{error-B__OMBRY.mjs.map → error-DlhGW4mJ.mjs.map} +1 -1
  22. package/dist/{event-D8Nfoh4K.mjs → event-CHf47dPM.mjs} +16 -10
  23. package/dist/event-CHf47dPM.mjs.map +1 -0
  24. package/dist/{event-fU3Y01PR.d.mts → event-DJeb_DIL.d.mts} +4 -2
  25. package/dist/{filter-C0IMByE3.d.mts → filter-jI_9htF7.d.mts} +2 -2
  26. package/dist/{gossip-oloDMWEj.mjs → gossip-DFxIBlsr.mjs} +23 -33
  27. package/dist/gossip-DFxIBlsr.mjs.map +1 -0
  28. package/dist/{gossip-DpIvkBuj.d.mts → gossip-OOeeFzG5.d.mts} +37 -28
  29. package/dist/gossip.d.mts +1 -1
  30. package/dist/gossip.mjs +1 -1
  31. package/dist/{index-D1bqFHKB.d.mts → index-BxCBX-8R.d.mts} +18 -18
  32. package/dist/{index-lvXeER5t.d.mts → index-CPVEyzNX.d.mts} +32 -50
  33. package/dist/{index-MxC28S4P.d.mts → index-C_w2WfVz.d.mts} +27 -29
  34. package/dist/{index-CNl2q67H.d.mts → index-Cl_1XdYP.d.mts} +111 -180
  35. package/dist/{index-CvkvqB16.d.mts → index-DU9tRFTZ.d.mts} +7 -20
  36. package/dist/{index-q4MDce_r.d.mts → index-DyKwQnbt.d.mts} +6 -8
  37. package/dist/index.d.mts +23 -21
  38. package/dist/index.mjs +21 -19
  39. package/dist/{instance-DQE8BoWt.mjs → instance-C62w3cEt.mjs} +26 -27
  40. package/dist/instance-C62w3cEt.mjs.map +1 -0
  41. package/dist/{instance-CIca-ynn.d.mts → instance-DjsL8h84.d.mts} +5 -5
  42. package/dist/{key-Cv4_pN3x.d.mts → key-D_5OgGT7.d.mts} +11 -7
  43. package/dist/{key-Bps-LqX7.mjs → key-DnVpchl6.mjs} +13 -9
  44. package/dist/key-DnVpchl6.mjs.map +1 -0
  45. package/dist/{loaders-o6YXB_Ri.mjs → loaders-BmPkQfzI.mjs} +73 -82
  46. package/dist/loaders-BmPkQfzI.mjs.map +1 -0
  47. package/dist/loaders.d.mts +3 -3
  48. package/dist/loaders.mjs +2 -2
  49. package/dist/{memory-C2EVx0_O.mjs → memory-CdJ07kub.mjs} +2 -2
  50. package/dist/memory-CdJ07kub.mjs.map +1 -0
  51. package/dist/{memory-index-Do1mz0WF.mjs → memory-index-Cbc83vOZ.mjs} +30 -247
  52. package/dist/memory-index-Cbc83vOZ.mjs.map +1 -0
  53. package/dist/message-oNr7t0SJ.mjs +194 -0
  54. package/dist/message-oNr7t0SJ.mjs.map +1 -0
  55. package/dist/{message-iGPIqnn0.d.mts → message-tclYCVNc.d.mts} +6 -6
  56. package/dist/{nip17-CKIufV98.d.mts → nip17-B5WgW4C4.d.mts} +6 -7
  57. package/dist/{nip19-BevCJZsp.d.mts → nip19-DpPN17bY.d.mts} +25 -31
  58. package/dist/{nip46-DDV4dC56.d.mts → nip46-BHaxC9TZ.d.mts} +19 -21
  59. package/dist/nip51-CR0Q8eym.d.mts +87 -0
  60. package/dist/{nip59-zQgdLcEr.d.mts → nip59-C-RWFQIv.d.mts} +11 -5
  61. package/dist/nip65-D1fbmhOg.d.mts +23 -0
  62. package/dist/{nip77-DH4RhS5r.d.mts → nip77-DzUwUxHq.d.mts} +8 -9
  63. package/dist/nips/blossom.d.mts +17 -13
  64. package/dist/nips/blossom.mjs +30 -9
  65. package/dist/nips/blossom.mjs.map +1 -1
  66. package/dist/nips/nip04.mjs +17 -7
  67. package/dist/nips/nip04.mjs.map +1 -1
  68. package/dist/nips/nip05.d.mts +9 -10
  69. package/dist/nips/nip05.mjs +1 -4
  70. package/dist/nips/nip05.mjs.map +1 -1
  71. package/dist/nips/nip10.d.mts +8 -8
  72. package/dist/nips/nip10.mjs +34 -32
  73. package/dist/nips/nip10.mjs.map +1 -1
  74. package/dist/nips/nip11.d.mts +28 -28
  75. package/dist/nips/nip11.mjs +4 -4
  76. package/dist/nips/nip11.mjs.map +1 -1
  77. package/dist/nips/nip13.d.mts +7 -7
  78. package/dist/nips/nip13.mjs +32 -10
  79. package/dist/nips/nip13.mjs.map +1 -1
  80. package/dist/nips/nip17.d.mts +1 -1
  81. package/dist/nips/nip17.mjs +16 -34
  82. package/dist/nips/nip17.mjs.map +1 -1
  83. package/dist/nips/nip19.d.mts +2 -2
  84. package/dist/nips/nip19.mjs +16 -28
  85. package/dist/nips/nip19.mjs.map +1 -1
  86. package/dist/nips/nip21.d.mts +9 -4
  87. package/dist/nips/nip21.mjs +15 -5
  88. package/dist/nips/nip21.mjs.map +1 -1
  89. package/dist/nips/nip27.d.mts +22 -22
  90. package/dist/nips/nip27.mjs +2 -2
  91. package/dist/nips/nip27.mjs.map +1 -1
  92. package/dist/nips/nip42.d.mts +1 -1
  93. package/dist/nips/nip42.mjs +2 -1
  94. package/dist/nips/nip42.mjs.map +1 -1
  95. package/dist/nips/nip44.mjs +2 -2
  96. package/dist/nips/nip44.mjs.map +1 -1
  97. package/dist/nips/nip46.d.mts +2 -2
  98. package/dist/nips/nip46.mjs +15 -19
  99. package/dist/nips/nip46.mjs.map +1 -1
  100. package/dist/nips/nip49.d.mts +9 -9
  101. package/dist/nips/nip49.mjs +4 -4
  102. package/dist/nips/nip49.mjs.map +1 -1
  103. package/dist/nips/nip51.d.mts +2 -86
  104. package/dist/nips/nip51.mjs +7 -23
  105. package/dist/nips/nip51.mjs.map +1 -1
  106. package/dist/nips/nip57.d.mts +25 -23
  107. package/dist/nips/nip57.mjs +12 -17
  108. package/dist/nips/nip57.mjs.map +1 -1
  109. package/dist/nips/nip59.d.mts +1 -1
  110. package/dist/nips/nip59.mjs +27 -19
  111. package/dist/nips/nip59.mjs.map +1 -1
  112. package/dist/nips/nip65.d.mts +2 -2
  113. package/dist/nips/nip65.mjs +14 -37
  114. package/dist/nips/nip65.mjs.map +1 -1
  115. package/dist/nips/nip77.d.mts +1 -1
  116. package/dist/nips/nip77.mjs +33 -32
  117. package/dist/nips/nip77.mjs.map +1 -1
  118. package/dist/nips/nip98.d.mts +5 -5
  119. package/dist/nips/nip98.mjs +8 -8
  120. package/dist/nips/nip98.mjs.map +1 -1
  121. package/dist/{pool-DBIYMtwy.d.mts → pool-CqQvUnsq.d.mts} +132 -108
  122. package/dist/pool-vlw74C4t.mjs +606 -0
  123. package/dist/pool-vlw74C4t.mjs.map +1 -0
  124. package/dist/put-w13ci3sC.mjs +187 -0
  125. package/dist/put-w13ci3sC.mjs.map +1 -0
  126. package/dist/{reactive-BfhPp9a3.mjs → reactive-Tz0otDIP.mjs} +125 -88
  127. package/dist/reactive-Tz0otDIP.mjs.map +1 -0
  128. package/dist/{reactive-7aqeip4A.d.mts → reactive-gGqUrzW8.d.mts} +20 -26
  129. package/dist/relay-quCs7MHD.mjs +1811 -0
  130. package/dist/relay-quCs7MHD.mjs.map +1 -0
  131. package/dist/relay.d.mts +4 -4
  132. package/dist/relay.mjs +3 -2
  133. package/dist/serial-Bzpw-xz3.mjs +21 -0
  134. package/dist/serial-Bzpw-xz3.mjs.map +1 -0
  135. package/dist/{signer-CYQutDzD.mjs → signer-poTGe6Er.mjs} +12 -14
  136. package/dist/signer-poTGe6Er.mjs.map +1 -0
  137. package/dist/signer.d.mts +2 -2
  138. package/dist/signer.mjs +2 -2
  139. package/dist/{storage-Dky3wuoH.mjs → storage-B5IXTVuS.mjs} +28 -51
  140. package/dist/storage-B5IXTVuS.mjs.map +1 -0
  141. package/dist/storage.d.mts +3 -3
  142. package/dist/storage.mjs +4 -4
  143. package/dist/store.d.mts +2 -2
  144. package/dist/store.mjs +1 -1
  145. package/dist/testing.d.mts +19 -19
  146. package/dist/testing.mjs +9 -9
  147. package/dist/testing.mjs.map +1 -1
  148. package/dist/{types-2pCUprRU.d.mts → types-BacwnDtU.d.mts} +10 -10
  149. package/dist/{types-CRQEk0Oi.d.mts → types-DNmiscfd.d.mts} +2 -2
  150. package/dist/{util-LfQirgDk.mjs → util-DMF9AIO0.mjs} +33 -7
  151. package/dist/util-DMF9AIO0.mjs.map +1 -0
  152. package/dist/{verifier-t5WoWbtY.mjs → verifier-B51Wkt5H.mjs} +3 -3
  153. package/dist/verifier-B51Wkt5H.mjs.map +1 -0
  154. package/dist/verifier-CgTFpgsC.d.mts +22 -0
  155. package/dist/wasm.browser.d.mts +3 -3
  156. package/dist/wasm.browser.mjs +3 -3
  157. package/dist/wasm.d.mts +3 -3
  158. package/dist/wasm.mjs +3 -3
  159. package/dist/wasm.mjs.map +1 -1
  160. package/package.json +5 -9
  161. package/dist/abort-Ba8tDrOI.mjs.map +0 -1
  162. package/dist/builder-9tjI6WQ3.mjs.map +0 -1
  163. package/dist/client-CadO5fAX.mjs.map +0 -1
  164. package/dist/event-D8Nfoh4K.mjs.map +0 -1
  165. package/dist/gossip-oloDMWEj.mjs.map +0 -1
  166. package/dist/instance-DQE8BoWt.mjs.map +0 -1
  167. package/dist/key-Bps-LqX7.mjs.map +0 -1
  168. package/dist/loaders-o6YXB_Ri.mjs.map +0 -1
  169. package/dist/memory-C2EVx0_O.mjs.map +0 -1
  170. package/dist/memory-index-Do1mz0WF.mjs.map +0 -1
  171. package/dist/message-DcY6Fi9o.mjs +0 -193
  172. package/dist/message-DcY6Fi9o.mjs.map +0 -1
  173. package/dist/nip65-CjgmdpPB.d.mts +0 -26
  174. package/dist/nips/nip96.d.mts +0 -40
  175. package/dist/nips/nip96.mjs +0 -118
  176. package/dist/nips/nip96.mjs.map +0 -1
  177. package/dist/pool-As20OGxB.mjs +0 -2166
  178. package/dist/pool-As20OGxB.mjs.map +0 -1
  179. package/dist/reactive-BfhPp9a3.mjs.map +0 -1
  180. package/dist/signer-CYQutDzD.mjs.map +0 -1
  181. package/dist/storage-Dky3wuoH.mjs.map +0 -1
  182. package/dist/util-LfQirgDk.mjs.map +0 -1
  183. package/dist/verifier-t5WoWbtY.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"nip10.mjs","names":[],"sources":["../../src/nips/nip10.ts"],"sourcesContent":["/**\n * NIP-10: Text Notes and Threads\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/10.md\n */\nimport { EventBuilder } from \"../core/builder.ts\";\nimport { EventValidationError } from \"../core/error.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { formatEventAddress, parseEventAddress, Tag } from \"../core/tag.ts\";\nimport { isHex32 } from \"../core/util.ts\";\nimport type { AddressPointer, EventPointer, ProfilePointer } from \"./nip19.ts\";\n\n/** Parsed NIP-10 thread references from an event's `e`/`q`/`p` tags. */\nexport type ThreadReferences = {\n /** Pointer to the root of the thread. */\n root: EventPointer | undefined;\n /** Pointer to the parent event this note replies to. */\n reply: EventPointer | undefined;\n /** Other e-tagged events (not root/reply). */\n mentions: EventPointer[];\n /** Quoted events (`q` tags): event ids or addresses. Discriminate with `\"id\" in q`. */\n quotes: Array<EventPointer | AddressPointer>;\n /** P-tagged profiles involved in the thread. */\n profiles: ProfilePointer[];\n};\n\ntype ReplyParent = Pick<Event, \"id\" | \"pubkey\" | \"tags\" | \"kind\">;\ntype QuoteInput = string | EventPointer | AddressPointer;\n\nfunction eTagAuthor(tag: ReadonlyArray<string>): string | undefined {\n // NIP-10 5-tuple pubkey is index 4; NIP-01 4-tuple pubkey is index 3.\n for (const author of [tag[4], tag[3]]) {\n if (author !== undefined && isHex32(author.toLowerCase())) {\n return author.toLowerCase();\n }\n }\n return undefined;\n}\n\nfunction eventPointerFromETag(tag: ReadonlyArray<string>): EventPointer | undefined {\n const id = tag.at(1);\n if (tag[0] !== \"e\" || id === undefined || !isHex32(id.toLowerCase())) {\n return undefined;\n }\n const pointer: EventPointer = {\n id: id.toLowerCase(),\n relays: tag[2] !== undefined && tag[2] !== \"\" ? [tag[2]] : [],\n };\n const author = eTagAuthor(tag);\n if (author !== undefined) {\n pointer.author = author;\n }\n return pointer;\n}\n\nfunction quoteFromQTag(tag: ReadonlyArray<string>): EventPointer | AddressPointer | undefined {\n const value = tag.at(1);\n if (tag[0] !== \"q\" || value === undefined || value === \"\") {\n return undefined;\n }\n const relays = tag[2] !== undefined && tag[2] !== \"\" ? [tag[2]] : [];\n if (isHex32(value.toLowerCase())) {\n const pointer: EventPointer = { id: value.toLowerCase(), relays };\n const author = tag.at(3);\n if (author !== undefined && isHex32(author.toLowerCase())) {\n pointer.author = author.toLowerCase();\n }\n return pointer;\n }\n const addr = parseEventAddress(value);\n if (!addr) {\n return undefined;\n }\n // Address q tags do not use the event-id pubkey slot (index 3).\n return {\n identifier: addr.identifier,\n pubkey: addr.pubkey,\n kind: addr.kind,\n relays,\n };\n}\n\ntype BuiltQuote = { tag: Tag; author?: string | undefined; relay?: string | undefined };\n\nfunction quoteToTag(quote: QuoteInput): BuiltQuote | undefined {\n if (typeof quote === \"string\") {\n if (isHex32(quote.toLowerCase())) {\n return { tag: [\"q\", quote.toLowerCase()] };\n }\n const addr = parseEventAddress(quote);\n if (!addr) {\n return undefined;\n }\n return { tag: [\"q\", formatEventAddress(addr.kind, addr.pubkey, addr.identifier)] };\n }\n if (\"id\" in quote) {\n const id = quote.id.toLowerCase();\n const relay = quote.relays?.[0];\n const author =\n quote.author !== undefined && isHex32(quote.author.toLowerCase())\n ? quote.author.toLowerCase()\n : undefined;\n let tag: Tag;\n if (author === undefined) {\n tag = relay !== undefined && relay !== \"\" ? [\"q\", id, relay] : [\"q\", id];\n } else {\n tag = [\"q\", id, relay ?? \"\", author];\n }\n return { tag, author, relay };\n }\n const coord = formatEventAddress(quote.kind, quote.pubkey, quote.identifier);\n const relay = quote.relays?.[0];\n const tag: Tag = relay !== undefined && relay !== \"\" ? [\"q\", coord, relay] : [\"q\", coord];\n return { tag, author: quote.pubkey, relay };\n}\n\nfunction assertKind1Parent(parent: ReplyParent): void {\n // NIP-10 is kind 1 only; comments are NIP-22.\n if (parent.kind !== Kind.TextNote) {\n throw new EventValidationError(\"NIP-10 replyTo is for kind 1\");\n }\n}\n\n/** Parse NIP-10 thread markers and legacy positional e-tags from an event. */\nexport function parseThreadTags(event: Pick<Event, \"tags\">): ThreadReferences {\n const result: ThreadReferences = {\n root: undefined,\n reply: undefined,\n mentions: [],\n quotes: [],\n profiles: [],\n };\n\n let maybeParent: EventPointer | undefined;\n let maybeRoot: EventPointer | undefined;\n\n for (let i = event.tags.length - 1; i >= 0; i--) {\n const tag = event.tags[i];\n if (tag === undefined) {\n continue;\n }\n\n const eValue = tag.at(1);\n if (tag[0] === \"e\" && eValue !== undefined && isHex32(eValue.toLowerCase())) {\n const pointer = eventPointerFromETag(tag);\n if (pointer === undefined) {\n continue;\n }\n const marker = tag.at(3);\n\n if (marker === \"root\") {\n result.root = pointer;\n continue;\n }\n if (marker === \"reply\") {\n result.reply = pointer;\n continue;\n }\n // Preferred markers are root/reply only. A hex32 at index 3 is NIP-01 pubkey, not a marker.\n if (marker !== undefined && marker !== \"\" && !isHex32(marker.toLowerCase())) {\n result.mentions.push(pointer);\n continue;\n }\n\n // Legacy positional: last unmarked is parent, second-to-last is root.\n if (maybeParent) {\n maybeRoot = pointer;\n } else {\n maybeParent = pointer;\n }\n result.mentions.push(pointer);\n continue;\n }\n\n if (tag[0] === \"q\") {\n const quote = quoteFromQTag(tag);\n if (quote) {\n result.quotes.push(quote);\n }\n continue;\n }\n\n const pValue = tag.at(1);\n if (tag[0] === \"p\" && pValue !== undefined && isHex32(pValue.toLowerCase())) {\n result.profiles.push({\n pubkey: pValue.toLowerCase(),\n relays: tag[2] !== undefined && tag[2] !== \"\" ? [tag[2]] : [],\n });\n }\n }\n\n result.root ??= maybeRoot ?? maybeParent ?? result.reply;\n result.reply ??= maybeParent ?? result.root;\n\n // Drop root/reply from mentions (by id).\n const drop = new Set(\n [result.root?.id, result.reply?.id].filter((id): id is string => Boolean(id)),\n );\n result.mentions = result.mentions.filter((m) => !drop.has(m.id));\n\n // Inherit relay hints from matching p-tags.\n for (const ref of [result.reply, result.root, ...result.mentions]) {\n if (ref === undefined) {\n continue;\n }\n const refAuthor = ref.author;\n if (refAuthor === undefined || refAuthor === \"\") {\n continue;\n }\n const profile = result.profiles.find((p) => p.pubkey === refAuthor);\n const profileRelays = profile?.relays;\n if (profileRelays === undefined || profileRelays.length === 0) {\n continue;\n }\n const relays = [...(ref.relays ?? [])];\n for (const url of profileRelays) {\n if (!relays.includes(url)) {\n relays.push(url);\n }\n }\n ref.relays = relays;\n }\n\n return result;\n}\n\n/** Options for {@link buildReplyTags}. */\nexport type ReplyTagsOptions = {\n /** Parent event being replied to. */\n parent: ReplyParent;\n /** Optional relay hint for the parent e-tag. */\n relayHint?: string | undefined;\n /** Quoted events (`q` tags): hex ids, `kind:pubkey:d` coords, or pointers. */\n quotes?: QuoteInput[] | undefined;\n};\n\n/**\n * Build NIP-10 e/p tags for a reply to `parent`. Uses marked tags (`root` / `reply`) per preferred\n * modern style.\n */\nexport function buildReplyTags(opts: ReplyTagsOptions): Tag[] {\n assertKind1Parent(opts.parent);\n const thread = parseThreadTags(opts.parent);\n const root = thread.root ?? { id: opts.parent.id, relays: [], author: opts.parent.pubkey };\n const parentIsRoot = root.id.toLowerCase() === opts.parent.id.toLowerCase();\n\n const tags: Tag[] = [];\n const rootRelay = root.relays?.[0] ?? opts.relayHint ?? \"\";\n tags.push(Tag.e(root.id, rootRelay, \"root\", root.author));\n\n if (!parentIsRoot) {\n tags.push(Tag.e(opts.parent.id, opts.relayHint ?? \"\", \"reply\", opts.parent.pubkey));\n }\n\n // Ensure root + parent authors are p-tagged.\n const pSeen = new Set<string>();\n const addP = (pk: string, relay?: string) => {\n const key = pk.toLowerCase();\n if (pSeen.has(key)) {\n return;\n }\n pSeen.add(key);\n tags.push(Tag.p(pk, relay ?? undefined));\n };\n if (root.author !== undefined && root.author !== \"\") {\n addP(root.author, root.relays?.[0]);\n }\n addP(opts.parent.pubkey, opts.relayHint);\n for (const p of thread.profiles) {\n addP(p.pubkey, p.relays?.[0]);\n }\n\n const qTags: Tag[] = [];\n for (const quote of opts.quotes ?? []) {\n const built = quoteToTag(quote);\n if (built === undefined) {\n continue;\n }\n if (built.author !== undefined && built.author !== \"\") {\n addP(built.author, built.relay);\n }\n qTags.push(built.tag);\n }\n tags.push(...qTags);\n\n return tags;\n}\n\n/**\n * Build an {@link EventBuilder} reply with NIP-10 tags. Lives here (not on EventBuilder) so core\n * does not depend on nips.\n */\nexport function replyTo(\n parent: ReplyParent,\n content: string,\n opts?: Pick<ReplyTagsOptions, \"relayHint\" | \"quotes\">,\n): EventBuilder {\n return EventBuilder.textNote(content).tags(\n buildReplyTags({\n parent,\n relayHint: opts?.relayHint,\n quotes: opts?.quotes,\n }),\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"nip10.mjs","names":[],"sources":["../../src/nips/nip10.ts"],"sourcesContent":["/**\n * NIP-10: Text Notes and Threads\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/10.md\n */\nimport { EventBuilder } from \"../core/builder.ts\";\nimport { EventValidationError } from \"../core/error.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { formatEventAddress, parseEventAddress, Tag } from \"../core/tag.ts\";\nimport type { Mutable } from \"../core/util.ts\";\nimport { isHex32 } from \"../core/util.ts\";\nimport type { AddressPointer, EventPointer, ProfilePointer } from \"./nip19.ts\";\n\n/** Parsed NIP-10 thread references from an event's `e`/`q`/`p` tags. */\nexport type ThreadReferences = {\n /** Pointer to the root of the thread. */\n readonly root: EventPointer | undefined;\n /** Pointer to the parent event this note replies to. */\n readonly reply: EventPointer | undefined;\n /** Other e-tagged events (not root/reply). */\n readonly mentions: ReadonlyArray<EventPointer>;\n /** Quoted events (`q` tags): event ids or addresses. Discriminate with `\"id\" in q`. */\n readonly quotes: ReadonlyArray<EventPointer | AddressPointer>;\n /** P-tagged profiles involved in the thread. */\n readonly profiles: ReadonlyArray<ProfilePointer>;\n};\n\ntype ReplyParent = Pick<Event, \"id\" | \"pubkey\" | \"tags\" | \"kind\">;\ntype QuoteInput = string | EventPointer | AddressPointer;\n\nfunction eTagAuthor(tag: ReadonlyArray<string>): string | undefined {\n // NIP-10 5-tuple pubkey is index 4; NIP-01 4-tuple pubkey is index 3.\n for (const author of [tag[4], tag[3]]) {\n if (author !== undefined && isHex32(author.toLowerCase())) {\n return author.toLowerCase();\n }\n }\n return undefined;\n}\n\nfunction eventPointerFromETag(tag: ReadonlyArray<string>): EventPointer | undefined {\n const id = tag.at(1);\n if (tag[0] !== \"e\" || id === undefined || !isHex32(id.toLowerCase())) {\n return undefined;\n }\n const pointer: Mutable<EventPointer> = {\n id: id.toLowerCase(),\n relays: tag[2] !== undefined && tag[2] !== \"\" ? [tag[2]] : [],\n };\n const author = eTagAuthor(tag);\n if (author !== undefined) {\n pointer.author = author;\n }\n return pointer;\n}\n\nfunction quoteFromQTag(tag: ReadonlyArray<string>): EventPointer | AddressPointer | undefined {\n const value = tag.at(1);\n if (tag[0] !== \"q\" || value === undefined || value === \"\") {\n return undefined;\n }\n const relays = tag[2] !== undefined && tag[2] !== \"\" ? [tag[2]] : [];\n if (isHex32(value.toLowerCase())) {\n const pointer: Mutable<EventPointer> = { id: value.toLowerCase(), relays };\n const author = tag.at(3);\n if (author !== undefined && isHex32(author.toLowerCase())) {\n pointer.author = author.toLowerCase();\n }\n return pointer;\n }\n const addr = parseEventAddress(value);\n if (!addr) {\n return undefined;\n }\n // Address q tags do not use the event-id pubkey slot (index 3).\n return {\n identifier: addr.identifier,\n pubkey: addr.pubkey,\n kind: addr.kind,\n relays,\n };\n}\n\ntype BuiltQuote = { tag: Tag; author?: string | undefined; relay?: string | undefined };\n\nfunction quoteToTag(quote: QuoteInput): BuiltQuote | undefined {\n if (typeof quote === \"string\") {\n if (isHex32(quote.toLowerCase())) {\n return { tag: [\"q\", quote.toLowerCase()] };\n }\n const addr = parseEventAddress(quote);\n if (!addr) {\n return undefined;\n }\n return { tag: [\"q\", formatEventAddress(addr.kind, addr.pubkey, addr.identifier)] };\n }\n if (\"id\" in quote) {\n const id = quote.id.toLowerCase();\n const relay = quote.relays?.[0];\n const author =\n quote.author !== undefined && isHex32(quote.author.toLowerCase())\n ? quote.author.toLowerCase()\n : undefined;\n let tag: Tag;\n if (author === undefined) {\n tag = relay !== undefined && relay !== \"\" ? [\"q\", id, relay] : [\"q\", id];\n } else {\n tag = [\"q\", id, relay ?? \"\", author];\n }\n return { tag, author, relay };\n }\n const coord = formatEventAddress(quote.kind, quote.pubkey, quote.identifier);\n const relay = quote.relays?.[0];\n const tag: Tag = relay !== undefined && relay !== \"\" ? [\"q\", coord, relay] : [\"q\", coord];\n return { tag, author: quote.pubkey, relay };\n}\n\nfunction assertKind1Parent(parent: ReplyParent): void {\n // NIP-10 is kind 1 only; comments are NIP-22.\n if (parent.kind !== Kind.TextNote) {\n throw new EventValidationError(\"NIP-10 replyTo is for kind 1\");\n }\n}\n\n/** Parse NIP-10 thread markers and legacy positional e-tags from an event. */\nexport function parseThreadTags(event: Pick<Event, \"tags\">): ThreadReferences {\n const mentions: EventPointer[] = [];\n const quotes: Array<EventPointer | AddressPointer> = [];\n const profiles: ProfilePointer[] = [];\n let root: EventPointer | undefined;\n let reply: EventPointer | undefined;\n\n let maybeParent: EventPointer | undefined;\n let maybeRoot: EventPointer | undefined;\n\n for (let i = event.tags.length - 1; i >= 0; i--) {\n const tag = event.tags[i];\n if (tag === undefined) {\n continue;\n }\n\n const eValue = tag.at(1);\n if (tag[0] === \"e\" && eValue !== undefined && isHex32(eValue.toLowerCase())) {\n const pointer = eventPointerFromETag(tag);\n if (pointer === undefined) {\n continue;\n }\n const marker = tag.at(3);\n\n if (marker === \"root\") {\n root = pointer;\n continue;\n }\n if (marker === \"reply\") {\n reply = pointer;\n continue;\n }\n // Preferred markers are root/reply only. A hex32 at index 3 is NIP-01 pubkey, not a marker.\n if (marker !== undefined && marker !== \"\" && !isHex32(marker.toLowerCase())) {\n mentions.push(pointer);\n continue;\n }\n\n // Legacy positional: last unmarked is parent, second-to-last is root.\n if (maybeParent) {\n maybeRoot = pointer;\n } else {\n maybeParent = pointer;\n }\n mentions.push(pointer);\n continue;\n }\n\n if (tag[0] === \"q\") {\n const quote = quoteFromQTag(tag);\n if (quote) {\n quotes.push(quote);\n }\n continue;\n }\n\n const pValue = tag.at(1);\n if (tag[0] === \"p\" && pValue !== undefined && isHex32(pValue.toLowerCase())) {\n profiles.push({\n pubkey: pValue.toLowerCase(),\n relays: tag[2] !== undefined && tag[2] !== \"\" ? [tag[2]] : [],\n });\n }\n }\n\n root ??= maybeRoot ?? maybeParent ?? reply;\n reply ??= maybeParent ?? root;\n\n // Drop root/reply from mentions (by id).\n const drop = new Set([root?.id, reply?.id].filter((id): id is string => Boolean(id)));\n const keptMentions = mentions.filter((m) => !drop.has(m.id));\n\n // Inherit relay hints from matching p-tags.\n const inheritHints = (ref: EventPointer): EventPointer => {\n const refAuthor = ref.author;\n if (refAuthor === undefined || refAuthor === \"\") {\n return ref;\n }\n const profileRelays = profiles.find((p) => p.pubkey === refAuthor)?.relays;\n if (profileRelays === undefined || profileRelays.length === 0) {\n return ref;\n }\n const relays = [...(ref.relays ?? [])];\n for (const url of profileRelays) {\n if (!relays.includes(url)) {\n relays.push(url);\n }\n }\n return { ...ref, relays };\n };\n\n return {\n root: root === undefined ? undefined : inheritHints(root),\n reply: reply === undefined ? undefined : inheritHints(reply),\n mentions: keptMentions.map(inheritHints),\n quotes,\n profiles,\n };\n}\n\n/** Options for {@link buildReplyTags}. */\nexport type ReplyTagsOptions = {\n /** Parent event being replied to. */\n parent: ReplyParent;\n /** Optional relay hint for the parent e-tag. */\n relayHint?: string | undefined;\n /** Quoted events (`q` tags): hex ids, `kind:pubkey:d` coords, or pointers. */\n quotes?: QuoteInput[] | undefined;\n};\n\n/**\n * Build NIP-10 e/p tags for a reply to `parent`. Uses marked tags (`root` / `reply`) per preferred\n * modern style.\n */\nexport function buildReplyTags(opts: ReplyTagsOptions): Tag[] {\n assertKind1Parent(opts.parent);\n const thread = parseThreadTags(opts.parent);\n const root = thread.root ?? { id: opts.parent.id, relays: [], author: opts.parent.pubkey };\n const parentIsRoot = root.id.toLowerCase() === opts.parent.id.toLowerCase();\n\n const tags: Tag[] = [];\n const rootRelay = root.relays?.[0] ?? opts.relayHint ?? \"\";\n tags.push(Tag.e(root.id, rootRelay, \"root\", root.author));\n\n if (!parentIsRoot) {\n tags.push(Tag.e(opts.parent.id, opts.relayHint ?? \"\", \"reply\", opts.parent.pubkey));\n }\n\n // Ensure root + parent authors are p-tagged.\n const pSeen = new Set<string>();\n const addP = (pk: string, relay?: string) => {\n const key = pk.toLowerCase();\n if (pSeen.has(key)) {\n return;\n }\n pSeen.add(key);\n tags.push(Tag.p(pk, relay ?? undefined));\n };\n if (root.author !== undefined && root.author !== \"\") {\n addP(root.author, root.relays?.[0]);\n }\n addP(opts.parent.pubkey, opts.relayHint);\n for (const p of thread.profiles) {\n addP(p.pubkey, p.relays?.[0]);\n }\n\n const qTags: Tag[] = [];\n for (const quote of opts.quotes ?? []) {\n const built = quoteToTag(quote);\n if (built === undefined) {\n continue;\n }\n if (built.author !== undefined && built.author !== \"\") {\n addP(built.author, built.relay);\n }\n qTags.push(built.tag);\n }\n tags.push(...qTags);\n\n return tags;\n}\n\n/**\n * Build an {@link EventBuilder} reply with NIP-10 tags. Lives here (not on EventBuilder) so core\n * does not depend on nips.\n */\nexport function replyTo(\n parent: ReplyParent,\n content: string,\n opts?: Pick<ReplyTagsOptions, \"relayHint\" | \"quotes\">,\n): EventBuilder {\n return EventBuilder.textNote(content).tags(\n buildReplyTags({\n parent,\n relayHint: opts?.relayHint,\n quotes: opts?.quotes,\n }),\n );\n}\n"],"mappings":"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"}
@@ -1,35 +1,35 @@
1
- import { a as NostrError } from "../error-CR8Urc84.mjs";
1
+ import { a as NostrError } from "../error-BquXDmIN.mjs";
2
2
  import { t as ManualFetch } from "../http-C4HwIu4B.mjs";
3
3
  //#region src/nips/nip11.d.ts
4
4
  export type Nip11Fetch = ManualFetch;
5
5
  export type RelayInformation = {
6
- name?: string;
7
- description?: string;
8
- banner?: string;
9
- icon?: string;
10
- pubkey?: string;
11
- self?: string;
12
- contact?: string;
13
- supported_nips?: number[];
14
- software?: string;
15
- version?: string;
16
- limitation?: {
17
- max_message_length?: number;
18
- max_subscriptions?: number;
19
- max_limit?: number;
20
- max_subid_length?: number;
21
- max_event_tags?: number;
22
- max_content_length?: number;
23
- default_limit?: number;
24
- auth_required?: boolean;
25
- payment_required?: boolean;
26
- restricted_writes?: boolean;
27
- min_pow_difficulty?: number;
28
- created_at_lower_limit?: number;
29
- created_at_upper_limit?: number;
30
- };
31
- payments_url?: string;
32
- terms_of_service?: string;
6
+ readonly name?: string | undefined;
7
+ readonly description?: string | undefined;
8
+ readonly banner?: string | undefined;
9
+ readonly icon?: string | undefined;
10
+ readonly pubkey?: string | undefined;
11
+ readonly self?: string | undefined;
12
+ readonly contact?: string | undefined;
13
+ readonly supported_nips?: ReadonlyArray<number> | undefined;
14
+ readonly software?: string | undefined;
15
+ readonly version?: string | undefined;
16
+ readonly limitation?: {
17
+ readonly max_message_length?: number | undefined;
18
+ readonly max_subscriptions?: number | undefined;
19
+ readonly max_limit?: number | undefined;
20
+ readonly max_subid_length?: number | undefined;
21
+ readonly max_event_tags?: number | undefined;
22
+ readonly max_content_length?: number | undefined;
23
+ readonly default_limit?: number | undefined;
24
+ readonly auth_required?: boolean | undefined;
25
+ readonly payment_required?: boolean | undefined;
26
+ readonly restricted_writes?: boolean | undefined;
27
+ readonly min_pow_difficulty?: number | undefined;
28
+ readonly created_at_lower_limit?: number | undefined;
29
+ readonly created_at_upper_limit?: number | undefined;
30
+ } | undefined;
31
+ readonly payments_url?: string | undefined;
32
+ readonly terms_of_service?: string | undefined;
33
33
  };
34
34
  export declare class Nip11Error extends NostrError {
35
35
  name: string;
@@ -1,4 +1,4 @@
1
- import { c as isRecord, g as NostrError } from "../util-LfQirgDk.mjs";
1
+ import { c as isRecord, v as NostrError } from "../util-DMF9AIO0.mjs";
2
2
  import { n as requireGlobalFetch, t as fetchManual } from "../http-CuazNRIP.mjs";
3
3
  //#region src/nips/nip11.ts
4
4
  /**
@@ -46,7 +46,7 @@ function relayInfoHttpUrl(wsUrl) {
46
46
  try {
47
47
  url = new URL(wsUrl);
48
48
  } catch (error) {
49
- throw new Nip11Error(`invalid relay URL: ${wsUrl}`, { cause: error instanceof Error ? error : void 0 });
49
+ throw new Nip11Error(`invalid relay URL: ${wsUrl}`, { cause: error });
50
50
  }
51
51
  if (url.protocol === "wss:") url.protocol = "https:";
52
52
  else if (url.protocol === "ws:") url.protocol = "http:";
@@ -86,13 +86,13 @@ async function fetchRelayInformation(wsUrl, opts) {
86
86
  const res = await fetchManual(fetchImpl, httpUrl, {
87
87
  headers: { Accept: ACCEPT },
88
88
  signal: opts?.signal
89
- }, (cause) => new Nip11Error(`relay information request failed: ${httpUrl}`, { cause: cause instanceof Error ? cause : void 0 }));
89
+ }, (cause) => new Nip11Error(`relay information request failed: ${httpUrl}`, { cause }));
90
90
  if (!res.ok) throw new Nip11Error(`relay information request failed: HTTP ${res.status}`);
91
91
  let json;
92
92
  try {
93
93
  json = await res.json();
94
94
  } catch (error) {
95
- throw new Nip11Error("relay information document is not valid JSON", { cause: error instanceof Error ? error : void 0 });
95
+ throw new Nip11Error("relay information document is not valid JSON", { cause: error });
96
96
  }
97
97
  return parseRelayInformation(json);
98
98
  }
@@ -1 +1 @@
1
- {"version":3,"file":"nip11.mjs","names":[],"sources":["../../src/nips/nip11.ts"],"sourcesContent":["/**\n * NIP-11: Relay Information Document\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/11.md\n */\nimport { NostrError } from \"../core/error.ts\";\nimport { isRecord } from \"../core/util.ts\";\nimport { fetchManual, requireGlobalFetch } from \"./http.ts\";\nimport type { ManualFetch } from \"./http.ts\";\n\nconst ACCEPT = \"application/nostr+json\";\n\nconst STRING_FIELDS = [\n \"name\",\n \"description\",\n \"banner\",\n \"icon\",\n \"pubkey\",\n \"self\",\n \"contact\",\n \"software\",\n \"version\",\n \"payments_url\",\n \"terms_of_service\",\n] as const;\n\nconst LIMITATION_NUMBERS = [\n \"max_message_length\",\n \"max_subscriptions\",\n \"max_limit\",\n \"max_subid_length\",\n \"max_event_tags\",\n \"max_content_length\",\n \"min_pow_difficulty\",\n \"created_at_lower_limit\",\n \"created_at_upper_limit\",\n \"default_limit\",\n] as const;\n\nconst LIMITATION_BOOLEANS = [\"auth_required\", \"payment_required\", \"restricted_writes\"] as const;\n\nexport type Nip11Fetch = ManualFetch;\n\nexport type RelayInformation = {\n name?: string;\n description?: string;\n banner?: string;\n icon?: string;\n pubkey?: string;\n self?: string;\n contact?: string;\n supported_nips?: number[];\n software?: string;\n version?: string;\n limitation?: {\n max_message_length?: number;\n max_subscriptions?: number;\n max_limit?: number;\n max_subid_length?: number;\n max_event_tags?: number;\n max_content_length?: number;\n default_limit?: number;\n auth_required?: boolean;\n payment_required?: boolean;\n restricted_writes?: boolean;\n min_pow_difficulty?: number;\n created_at_lower_limit?: number;\n created_at_upper_limit?: number;\n };\n payments_url?: string;\n terms_of_service?: string;\n};\n\nexport class Nip11Error extends NostrError {\n override name = \"Nip11Error\";\n}\n\n/** Convert a relay websocket URL to the HTTP URL that serves the NIP-11 document. */\nexport function relayInfoHttpUrl(wsUrl: string): string {\n let url: URL;\n try {\n url = new URL(wsUrl);\n } catch (error) {\n throw new Nip11Error(`invalid relay URL: ${wsUrl}`, {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n if (url.protocol === \"wss:\") {\n url.protocol = \"https:\";\n } else if (url.protocol === \"ws:\") {\n url.protocol = \"http:\";\n } else if (url.protocol !== \"https:\" && url.protocol !== \"http:\") {\n throw new Nip11Error(`unsupported relay URL scheme: ${url.protocol}`);\n }\n\n return url.toString();\n}\n\nfunction isNonNegativeInteger(value: unknown): value is number {\n return typeof value === \"number\" && Number.isInteger(value) && value >= 0;\n}\n\nfunction parseRelayInformation(json: unknown): RelayInformation {\n if (!isRecord(json)) {\n throw new Nip11Error(\"relay information document must be a JSON object\");\n }\n const raw = json;\n const info: RelayInformation = {};\n\n for (const key of STRING_FIELDS) {\n const value = raw[key];\n if (typeof value === \"string\") {\n info[key] = value;\n }\n }\n\n if (Array.isArray(raw[\"supported_nips\"])) {\n info.supported_nips = raw[\"supported_nips\"].filter(isNonNegativeInteger);\n }\n\n const rawLim = raw[\"limitation\"];\n if (isRecord(rawLim)) {\n const limitation: NonNullable<RelayInformation[\"limitation\"]> = {};\n for (const key of LIMITATION_NUMBERS) {\n const value = rawLim[key];\n if (isNonNegativeInteger(value)) {\n limitation[key] = value;\n }\n }\n for (const key of LIMITATION_BOOLEANS) {\n const value = rawLim[key];\n if (typeof value === \"boolean\") {\n limitation[key] = value;\n }\n }\n if (Object.keys(limitation).length > 0) {\n info.limitation = limitation;\n }\n }\n\n return info;\n}\n\nexport async function fetchRelayInformation(\n wsUrl: string,\n opts?: { fetch?: Nip11Fetch; signal?: AbortSignal },\n): Promise<RelayInformation> {\n const httpUrl = relayInfoHttpUrl(wsUrl);\n const fetchImpl =\n opts?.fetch ??\n requireGlobalFetch(() => new Nip11Error(\"no fetch implementation available; pass opts.fetch\"));\n\n const res = await fetchManual(\n fetchImpl,\n httpUrl,\n { headers: { Accept: ACCEPT }, signal: opts?.signal },\n (cause) =>\n new Nip11Error(`relay information request failed: ${httpUrl}`, {\n cause: cause instanceof Error ? cause : undefined,\n }),\n );\n\n if (!res.ok) {\n throw new Nip11Error(`relay information request failed: HTTP ${res.status}`);\n }\n\n let json: unknown;\n try {\n json = await res.json();\n } catch (error) {\n throw new Nip11Error(\"relay information document is not valid JSON\", {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n return parseRelayInformation(json);\n}\n"],"mappings":";;;;;;;;AAUA,MAAM,SAAS;AAEf,MAAM,gBAAgB;CACpB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,qBAAqB;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,sBAAsB;CAAC;CAAiB;CAAoB;AAAmB;AAkCrF,IAAa,aAAb,cAAgC,WAAW;CACzC,OAAgB;AAClB;;AAGA,SAAgB,iBAAiB,OAAuB;CACtD,IAAI;CACJ,IAAI;EACF,MAAM,IAAI,IAAI,KAAK;CACrB,SAAS,OAAO;EACd,MAAM,IAAI,WAAW,sBAAsB,SAAS,EAClD,OAAO,iBAAiB,QAAQ,QAAQ,KAAA,EAC1C,CAAC;CACH;CAEA,IAAI,IAAI,aAAa,QACnB,IAAI,WAAW;MACV,IAAI,IAAI,aAAa,OAC1B,IAAI,WAAW;MACV,IAAI,IAAI,aAAa,YAAY,IAAI,aAAa,SACvD,MAAM,IAAI,WAAW,iCAAiC,IAAI,UAAU;CAGtE,OAAO,IAAI,SAAS;AACtB;AAEA,SAAS,qBAAqB,OAAiC;CAC7D,OAAO,OAAO,UAAU,YAAY,OAAO,UAAU,KAAK,KAAK,SAAS;AAC1E;AAEA,SAAS,sBAAsB,MAAiC;CAC9D,IAAI,CAAC,SAAS,IAAI,GAChB,MAAM,IAAI,WAAW,kDAAkD;CAEzE,MAAM,MAAM;CACZ,MAAM,OAAyB,CAAC;CAEhC,KAAK,MAAM,OAAO,eAAe;EAC/B,MAAM,QAAQ,IAAI;EAClB,IAAI,OAAO,UAAU,UACnB,KAAK,OAAO;CAEhB;CAEA,IAAI,MAAM,QAAQ,IAAI,iBAAiB,GACrC,KAAK,iBAAiB,IAAI,iBAAiB,CAAC,OAAO,oBAAoB;CAGzE,MAAM,SAAS,IAAI;CACnB,IAAI,SAAS,MAAM,GAAG;EACpB,MAAM,aAA0D,CAAC;EACjE,KAAK,MAAM,OAAO,oBAAoB;GACpC,MAAM,QAAQ,OAAO;GACrB,IAAI,qBAAqB,KAAK,GAC5B,WAAW,OAAO;EAEtB;EACA,KAAK,MAAM,OAAO,qBAAqB;GACrC,MAAM,QAAQ,OAAO;GACrB,IAAI,OAAO,UAAU,WACnB,WAAW,OAAO;EAEtB;EACA,IAAI,OAAO,KAAK,UAAU,CAAC,CAAC,SAAS,GACnC,KAAK,aAAa;CAEtB;CAEA,OAAO;AACT;AAEA,eAAsB,sBACpB,OACA,MAC2B;CAC3B,MAAM,UAAU,iBAAiB,KAAK;CACtC,MAAM,YACJ,MAAM,SACN,yBAAyB,IAAI,WAAW,oDAAoD,CAAC;CAE/F,MAAM,MAAM,MAAM,YAChB,WACA,SACA;EAAE,SAAS,EAAE,QAAQ,OAAO;EAAG,QAAQ,MAAM;CAAO,IACnD,UACC,IAAI,WAAW,qCAAqC,WAAW,EAC7D,OAAO,iBAAiB,QAAQ,QAAQ,KAAA,EAC1C,CAAC,CACL;CAEA,IAAI,CAAC,IAAI,IACP,MAAM,IAAI,WAAW,0CAA0C,IAAI,QAAQ;CAG7E,IAAI;CACJ,IAAI;EACF,OAAO,MAAM,IAAI,KAAK;CACxB,SAAS,OAAO;EACd,MAAM,IAAI,WAAW,gDAAgD,EACnE,OAAO,iBAAiB,QAAQ,QAAQ,KAAA,EAC1C,CAAC;CACH;CAEA,OAAO,sBAAsB,IAAI;AACnC"}
1
+ {"version":3,"file":"nip11.mjs","names":[],"sources":["../../src/nips/nip11.ts"],"sourcesContent":["/**\n * NIP-11: Relay Information Document\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/11.md\n */\nimport { NostrError } from \"../core/error.ts\";\nimport type { Mutable } from \"../core/util.ts\";\nimport { isRecord } from \"../core/util.ts\";\nimport { fetchManual, requireGlobalFetch } from \"./http.ts\";\nimport type { ManualFetch } from \"./http.ts\";\n\nconst ACCEPT = \"application/nostr+json\";\n\nconst STRING_FIELDS = [\n \"name\",\n \"description\",\n \"banner\",\n \"icon\",\n \"pubkey\",\n \"self\",\n \"contact\",\n \"software\",\n \"version\",\n \"payments_url\",\n \"terms_of_service\",\n] as const;\n\nconst LIMITATION_NUMBERS = [\n \"max_message_length\",\n \"max_subscriptions\",\n \"max_limit\",\n \"max_subid_length\",\n \"max_event_tags\",\n \"max_content_length\",\n \"min_pow_difficulty\",\n \"created_at_lower_limit\",\n \"created_at_upper_limit\",\n \"default_limit\",\n] as const;\n\nconst LIMITATION_BOOLEANS = [\"auth_required\", \"payment_required\", \"restricted_writes\"] as const;\n\nexport type Nip11Fetch = ManualFetch;\n\nexport type RelayInformation = {\n readonly name?: string | undefined;\n readonly description?: string | undefined;\n readonly banner?: string | undefined;\n readonly icon?: string | undefined;\n readonly pubkey?: string | undefined;\n readonly self?: string | undefined;\n readonly contact?: string | undefined;\n readonly supported_nips?: ReadonlyArray<number> | undefined;\n readonly software?: string | undefined;\n readonly version?: string | undefined;\n readonly limitation?:\n | {\n readonly max_message_length?: number | undefined;\n readonly max_subscriptions?: number | undefined;\n readonly max_limit?: number | undefined;\n readonly max_subid_length?: number | undefined;\n readonly max_event_tags?: number | undefined;\n readonly max_content_length?: number | undefined;\n readonly default_limit?: number | undefined;\n readonly auth_required?: boolean | undefined;\n readonly payment_required?: boolean | undefined;\n readonly restricted_writes?: boolean | undefined;\n readonly min_pow_difficulty?: number | undefined;\n readonly created_at_lower_limit?: number | undefined;\n readonly created_at_upper_limit?: number | undefined;\n }\n | undefined;\n readonly payments_url?: string | undefined;\n readonly terms_of_service?: string | undefined;\n};\n\nexport class Nip11Error extends NostrError {\n override name = \"Nip11Error\";\n}\n\n/** Convert a relay websocket URL to the HTTP URL that serves the NIP-11 document. */\nexport function relayInfoHttpUrl(wsUrl: string): string {\n let url: URL;\n try {\n url = new URL(wsUrl);\n } catch (error) {\n throw new Nip11Error(`invalid relay URL: ${wsUrl}`, {\n cause: error,\n });\n }\n\n if (url.protocol === \"wss:\") {\n url.protocol = \"https:\";\n } else if (url.protocol === \"ws:\") {\n url.protocol = \"http:\";\n } else if (url.protocol !== \"https:\" && url.protocol !== \"http:\") {\n throw new Nip11Error(`unsupported relay URL scheme: ${url.protocol}`);\n }\n\n return url.toString();\n}\n\nfunction isNonNegativeInteger(value: unknown): value is number {\n return typeof value === \"number\" && Number.isInteger(value) && value >= 0;\n}\n\nfunction parseRelayInformation(json: unknown): RelayInformation {\n if (!isRecord(json)) {\n throw new Nip11Error(\"relay information document must be a JSON object\");\n }\n const raw = json;\n const info: Mutable<RelayInformation> = {};\n\n for (const key of STRING_FIELDS) {\n const value = raw[key];\n if (typeof value === \"string\") {\n info[key] = value;\n }\n }\n\n if (Array.isArray(raw[\"supported_nips\"])) {\n info.supported_nips = raw[\"supported_nips\"].filter(isNonNegativeInteger);\n }\n\n const rawLim = raw[\"limitation\"];\n if (isRecord(rawLim)) {\n const limitation: Mutable<NonNullable<RelayInformation[\"limitation\"]>> = {};\n for (const key of LIMITATION_NUMBERS) {\n const value = rawLim[key];\n if (isNonNegativeInteger(value)) {\n limitation[key] = value;\n }\n }\n for (const key of LIMITATION_BOOLEANS) {\n const value = rawLim[key];\n if (typeof value === \"boolean\") {\n limitation[key] = value;\n }\n }\n if (Object.keys(limitation).length > 0) {\n info.limitation = limitation;\n }\n }\n\n return info;\n}\n\nexport async function fetchRelayInformation(\n wsUrl: string,\n opts?: { fetch?: Nip11Fetch; signal?: AbortSignal },\n): Promise<RelayInformation> {\n const httpUrl = relayInfoHttpUrl(wsUrl);\n const fetchImpl =\n opts?.fetch ??\n requireGlobalFetch(() => new Nip11Error(\"no fetch implementation available; pass opts.fetch\"));\n\n const res = await fetchManual(\n fetchImpl,\n httpUrl,\n { headers: { Accept: ACCEPT }, signal: opts?.signal },\n (cause) =>\n new Nip11Error(`relay information request failed: ${httpUrl}`, {\n cause,\n }),\n );\n\n if (!res.ok) {\n throw new Nip11Error(`relay information request failed: HTTP ${res.status}`);\n }\n\n let json: unknown;\n try {\n json = await res.json();\n } catch (error) {\n throw new Nip11Error(\"relay information document is not valid JSON\", {\n cause: error,\n });\n }\n\n return parseRelayInformation(json);\n}\n"],"mappings":";;;;;;;;AAWA,MAAM,SAAS;AAEf,MAAM,gBAAgB;CACpB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,qBAAqB;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,sBAAsB;CAAC;CAAiB;CAAoB;AAAmB;AAoCrF,IAAa,aAAb,cAAgC,WAAW;CACzC,OAAgB;AAClB;;AAGA,SAAgB,iBAAiB,OAAuB;CACtD,IAAI;CACJ,IAAI;EACF,MAAM,IAAI,IAAI,KAAK;CACrB,SAAS,OAAO;EACd,MAAM,IAAI,WAAW,sBAAsB,SAAS,EAClD,OAAO,MACT,CAAC;CACH;CAEA,IAAI,IAAI,aAAa,QACnB,IAAI,WAAW;MACV,IAAI,IAAI,aAAa,OAC1B,IAAI,WAAW;MACV,IAAI,IAAI,aAAa,YAAY,IAAI,aAAa,SACvD,MAAM,IAAI,WAAW,iCAAiC,IAAI,UAAU;CAGtE,OAAO,IAAI,SAAS;AACtB;AAEA,SAAS,qBAAqB,OAAiC;CAC7D,OAAO,OAAO,UAAU,YAAY,OAAO,UAAU,KAAK,KAAK,SAAS;AAC1E;AAEA,SAAS,sBAAsB,MAAiC;CAC9D,IAAI,CAAC,SAAS,IAAI,GAChB,MAAM,IAAI,WAAW,kDAAkD;CAEzE,MAAM,MAAM;CACZ,MAAM,OAAkC,CAAC;CAEzC,KAAK,MAAM,OAAO,eAAe;EAC/B,MAAM,QAAQ,IAAI;EAClB,IAAI,OAAO,UAAU,UACnB,KAAK,OAAO;CAEhB;CAEA,IAAI,MAAM,QAAQ,IAAI,iBAAiB,GACrC,KAAK,iBAAiB,IAAI,iBAAiB,CAAC,OAAO,oBAAoB;CAGzE,MAAM,SAAS,IAAI;CACnB,IAAI,SAAS,MAAM,GAAG;EACpB,MAAM,aAAmE,CAAC;EAC1E,KAAK,MAAM,OAAO,oBAAoB;GACpC,MAAM,QAAQ,OAAO;GACrB,IAAI,qBAAqB,KAAK,GAC5B,WAAW,OAAO;EAEtB;EACA,KAAK,MAAM,OAAO,qBAAqB;GACrC,MAAM,QAAQ,OAAO;GACrB,IAAI,OAAO,UAAU,WACnB,WAAW,OAAO;EAEtB;EACA,IAAI,OAAO,KAAK,UAAU,CAAC,CAAC,SAAS,GACnC,KAAK,aAAa;CAEtB;CAEA,OAAO;AACT;AAEA,eAAsB,sBACpB,OACA,MAC2B;CAC3B,MAAM,UAAU,iBAAiB,KAAK;CACtC,MAAM,YACJ,MAAM,SACN,yBAAyB,IAAI,WAAW,oDAAoD,CAAC;CAE/F,MAAM,MAAM,MAAM,YAChB,WACA,SACA;EAAE,SAAS,EAAE,QAAQ,OAAO;EAAG,QAAQ,MAAM;CAAO,IACnD,UACC,IAAI,WAAW,qCAAqC,WAAW,EAC7D,MACF,CAAC,CACL;CAEA,IAAI,CAAC,IAAI,IACP,MAAM,IAAI,WAAW,0CAA0C,IAAI,QAAQ;CAG7E,IAAI;CACJ,IAAI;EACF,OAAO,MAAM,IAAI,KAAK;CACxB,SAAS,OAAO;EACd,MAAM,IAAI,WAAW,gDAAgD,EACnE,OAAO,MACT,CAAC;CACH;CAEA,OAAO,sBAAsB,IAAI;AACnC"}
@@ -1,20 +1,20 @@
1
- import { r as UnsignedEvent } from "../event-fU3Y01PR.mjs";
2
- import { a as NostrError } from "../error-CR8Urc84.mjs";
1
+ import { r as UnsignedEvent } from "../event-DJeb_DIL.mjs";
2
+ import { a as NostrError } from "../error-BquXDmIN.mjs";
3
3
  //#region src/nips/nip13.d.ts
4
4
  export declare class Nip13Error extends NostrError {
5
5
  name: string;
6
- constructor(message: string, options?: ErrorOptions);
7
6
  }
8
7
  export type MinePowOptions = {
9
8
  /** Yield to the event loop after this many hashes. Default 1000. */
10
- yieldEvery?: number;
11
- signal?: AbortSignal;
9
+ yieldEvery?: number | undefined;
10
+ signal?: AbortSignal | undefined;
12
11
  };
13
12
  /** Leading zero bits of a hex event id or raw sha256 bytes. */
14
13
  export declare function getPow(idOrHash: string | Uint8Array): number;
15
14
  /**
16
- * Returns a new unsigned event with nonce tag and computed id. Does not mutate input. Yields every
17
- * `yieldEvery` hashes.
15
+ * Returns a new unsigned event with nonce tag and computed id. Does not mutate input. `created_at`
16
+ * is advanced to the current second whenever it elapses while mining. Yields every `yieldEvery`
17
+ * hashes.
18
18
  */
19
19
  export declare function minePow(unsigned: UnsignedEvent, difficulty: number, opts?: MinePowOptions): Promise<UnsignedEvent & {
20
20
  id: string;
@@ -1,6 +1,5 @@
1
- import { d as utf8Encoder, g as NostrError, i as bytesToHex, o as isHex32 } from "../util-LfQirgDk.mjs";
2
- import { l as serializeEvent } from "../event-D8Nfoh4K.mjs";
3
- import { t as abortReason } from "../abort-Ba8tDrOI.mjs";
1
+ import { d as nowSeconds, i as bytesToHex, o as isHex32, p as utf8Encoder, v as NostrError } from "../util-DMF9AIO0.mjs";
2
+ import { t as abortReason } from "../abort-DBq2STPj.mjs";
4
3
  import { sha256 } from "@noble/hashes/sha2.js";
5
4
  //#region src/nips/nip13.ts
6
5
  /**
@@ -10,9 +9,6 @@ import { sha256 } from "@noble/hashes/sha2.js";
10
9
  */
11
10
  var Nip13Error = class extends NostrError {
12
11
  name = "Nip13Error";
13
- constructor(message, options) {
14
- super(message, options);
15
- }
16
12
  };
17
13
  /** Leading zero bits of a hex event id or raw sha256 bytes. */
18
14
  function getPow(idOrHash) {
@@ -38,8 +34,9 @@ function getPow(idOrHash) {
38
34
  return count;
39
35
  }
40
36
  /**
41
- * Returns a new unsigned event with nonce tag and computed id. Does not mutate input. Yields every
42
- * `yieldEvery` hashes.
37
+ * Returns a new unsigned event with nonce tag and computed id. Does not mutate input. `created_at`
38
+ * is advanced to the current second whenever it elapses while mining. Yields every `yieldEvery`
39
+ * hashes.
43
40
  */
44
41
  async function minePow(unsigned, difficulty, opts) {
45
42
  const signal = opts?.signal;
@@ -56,17 +53,42 @@ async function minePow(unsigned, difficulty, opts) {
56
53
  created_at: unsigned.created_at,
57
54
  pubkey: unsigned.pubkey
58
55
  };
56
+ let head = /* @__PURE__ */ new Uint8Array(0);
57
+ let tail = /* @__PURE__ */ new Uint8Array(0);
58
+ let buf = /* @__PURE__ */ new Uint8Array(0);
59
+ const rebuild = () => {
60
+ const headText = JSON.stringify([
61
+ 0,
62
+ mined.pubkey,
63
+ mined.created_at,
64
+ mined.kind,
65
+ [...unsigned.tags, ["nonce", ""]]
66
+ ]).slice(0, -4);
67
+ head = utf8Encoder.encode(headText);
68
+ tail = utf8Encoder.encode(`","${difficulty}"]],${JSON.stringify(mined.content)}]`);
69
+ buf = new Uint8Array(head.length + 24 + tail.length);
70
+ buf.set(head, 0);
71
+ };
72
+ rebuild();
59
73
  let count = 0;
60
74
  let iterations = 0;
61
75
  while (true) {
62
76
  if (signal?.aborted === true) throw abortReason(signal);
63
- const now = Math.floor(Date.now() / 1e3);
77
+ const now = nowSeconds();
64
78
  if (now !== mined.created_at) {
65
79
  count = 0;
66
80
  mined.created_at = now;
81
+ rebuild();
67
82
  }
68
83
  nonce[1] = String(++count);
69
- const hash = sha256(utf8Encoder.encode(serializeEvent(mined)));
84
+ let pos = head.length;
85
+ for (let i = 0; i < nonce[1].length; i++) {
86
+ buf[pos] = nonce[1].codePointAt(i) ?? 0;
87
+ pos += 1;
88
+ }
89
+ buf.set(tail, pos);
90
+ pos += tail.length;
91
+ const hash = sha256(buf.subarray(0, pos));
70
92
  if (getPow(hash) >= difficulty) return {
71
93
  ...mined,
72
94
  id: bytesToHex(hash)
@@ -1 +1 @@
1
- {"version":3,"file":"nip13.mjs","names":[],"sources":["../../src/nips/nip13.ts"],"sourcesContent":["/**\n * NIP-13: Proof of Work. Does not import signer, relay, or client. Does not sign.\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/13.md\n */\nimport { sha256 } from \"@noble/hashes/sha2.js\";\n\nimport { abortReason } from \"../core/abort.ts\";\nimport { NostrError } from \"../core/error.ts\";\nimport { serializeEvent } from \"../core/event.ts\";\nimport type { UnsignedEvent } from \"../core/event.ts\";\nimport { bytesToHex, isHex32, utf8Encoder } from \"../core/util.ts\";\n\nexport class Nip13Error extends NostrError {\n override name = \"Nip13Error\";\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n }\n}\n\nexport type MinePowOptions = {\n /** Yield to the event loop after this many hashes. Default 1000. */\n yieldEvery?: number;\n signal?: AbortSignal;\n};\n\n/** Leading zero bits of a hex event id or raw sha256 bytes. */\nexport function getPow(idOrHash: string | Uint8Array): number {\n if (typeof idOrHash === \"string\") {\n if (!isHex32(idOrHash.toLowerCase())) {\n throw new Nip13Error(`expected 64-char hex event id, got ${idOrHash.length} chars`);\n }\n let count = 0;\n for (let i = 0; i < idOrHash.length; i += 8) {\n const chunk = Number.parseInt(idOrHash.slice(i, i + 8), 16);\n if (chunk === 0) {\n count += 32;\n } else {\n count += Math.clz32(chunk);\n break;\n }\n }\n return count;\n }\n\n let count = 0;\n for (const byte of idOrHash) {\n if (byte === 0) {\n count += 8;\n } else {\n count += Math.clz32(byte) - 24;\n break;\n }\n }\n return count;\n}\n\n/**\n * Returns a new unsigned event with nonce tag and computed id. Does not mutate input. Yields every\n * `yieldEvery` hashes.\n */\nexport async function minePow(\n unsigned: UnsignedEvent,\n difficulty: number,\n opts?: MinePowOptions,\n): Promise<UnsignedEvent & { id: string }> {\n const signal = opts?.signal;\n const yieldEvery = Math.max(1, opts?.yieldEvery ?? 1000);\n\n const nonce: [string, string, string] = [\"nonce\", \"0\", String(difficulty)];\n const mined = {\n kind: unsigned.kind,\n tags: [...unsigned.tags, nonce],\n content: unsigned.content,\n created_at: unsigned.created_at,\n pubkey: unsigned.pubkey,\n };\n\n let count = 0;\n let iterations = 0;\n\n while (true) {\n if (signal?.aborted === true) {\n throw abortReason(signal);\n }\n\n const now = Math.floor(Date.now() / 1000);\n if (now !== mined.created_at) {\n count = 0;\n mined.created_at = now;\n }\n\n nonce[1] = String(++count);\n const hash = sha256(utf8Encoder.encode(serializeEvent(mined)));\n if (getPow(hash) >= difficulty) {\n return { ...mined, id: bytesToHex(hash) };\n }\n\n iterations++;\n if (iterations >= yieldEvery) {\n iterations = 0;\n // oxlint-disable-next-line no-await-in-loop -- the yield is part of each mining round\n await new Promise<void>((resolve) => {\n setTimeout(resolve);\n });\n }\n }\n}\n"],"mappings":";;;;;;;;;;AAaA,IAAa,aAAb,cAAgC,WAAW;CACzC,OAAgB;CAChB,YAAY,SAAiB,SAAwB;EACnD,MAAM,SAAS,OAAO;CACxB;AACF;;AASA,SAAgB,OAAO,UAAuC;CAC5D,IAAI,OAAO,aAAa,UAAU;EAChC,IAAI,CAAC,QAAQ,SAAS,YAAY,CAAC,GACjC,MAAM,IAAI,WAAW,sCAAsC,SAAS,OAAO,OAAO;EAEpF,IAAI,QAAQ;EACZ,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,GAAG;GAC3C,MAAM,QAAQ,OAAO,SAAS,SAAS,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE;GAC1D,IAAI,UAAU,GACZ,SAAS;QACJ;IACL,SAAS,KAAK,MAAM,KAAK;IACzB;GACF;EACF;EACA,OAAO;CACT;CAEA,IAAI,QAAQ;CACZ,KAAK,MAAM,QAAQ,UACjB,IAAI,SAAS,GACX,SAAS;MACJ;EACL,SAAS,KAAK,MAAM,IAAI,IAAI;EAC5B;CACF;CAEF,OAAO;AACT;;;;;AAMA,eAAsB,QACpB,UACA,YACA,MACyC;CACzC,MAAM,SAAS,MAAM;CACrB,MAAM,aAAa,KAAK,IAAI,GAAG,MAAM,cAAc,GAAI;CAEvD,MAAM,QAAkC;EAAC;EAAS;EAAK,OAAO,UAAU;CAAC;CACzE,MAAM,QAAQ;EACZ,MAAM,SAAS;EACf,MAAM,CAAC,GAAG,SAAS,MAAM,KAAK;EAC9B,SAAS,SAAS;EAClB,YAAY,SAAS;EACrB,QAAQ,SAAS;CACnB;CAEA,IAAI,QAAQ;CACZ,IAAI,aAAa;CAEjB,OAAO,MAAM;EACX,IAAI,QAAQ,YAAY,MACtB,MAAM,YAAY,MAAM;EAG1B,MAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;EACxC,IAAI,QAAQ,MAAM,YAAY;GAC5B,QAAQ;GACR,MAAM,aAAa;EACrB;EAEA,MAAM,KAAK,OAAO,EAAE,KAAK;EACzB,MAAM,OAAO,OAAO,YAAY,OAAO,eAAe,KAAK,CAAC,CAAC;EAC7D,IAAI,OAAO,IAAI,KAAK,YAClB,OAAO;GAAE,GAAG;GAAO,IAAI,WAAW,IAAI;EAAE;EAG1C;EACA,IAAI,cAAc,YAAY;GAC5B,aAAa;GAEb,MAAM,IAAI,SAAe,YAAY;IACnC,WAAW,OAAO;GACpB,CAAC;EACH;CACF;AACF"}
1
+ {"version":3,"file":"nip13.mjs","names":[],"sources":["../../src/nips/nip13.ts"],"sourcesContent":["/**\n * NIP-13: Proof of Work. Does not import signer, relay, or client. Does not sign.\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/13.md\n */\nimport { sha256 } from \"@noble/hashes/sha2.js\";\n\nimport { abortReason } from \"../core/abort.ts\";\nimport { NostrError } from \"../core/error.ts\";\nimport type { UnsignedEvent } from \"../core/event.ts\";\nimport { bytesToHex, isHex32, nowSeconds, utf8Encoder } from \"../core/util.ts\";\n\nexport class Nip13Error extends NostrError {\n override name = \"Nip13Error\";\n}\n\nexport type MinePowOptions = {\n /** Yield to the event loop after this many hashes. Default 1000. */\n yieldEvery?: number | undefined;\n signal?: AbortSignal | undefined;\n};\n\n/** Leading zero bits of a hex event id or raw sha256 bytes. */\nexport function getPow(idOrHash: string | Uint8Array): number {\n if (typeof idOrHash === \"string\") {\n if (!isHex32(idOrHash.toLowerCase())) {\n throw new Nip13Error(`expected 64-char hex event id, got ${idOrHash.length} chars`);\n }\n let count = 0;\n for (let i = 0; i < idOrHash.length; i += 8) {\n const chunk = Number.parseInt(idOrHash.slice(i, i + 8), 16);\n if (chunk === 0) {\n count += 32;\n } else {\n count += Math.clz32(chunk);\n break;\n }\n }\n return count;\n }\n\n let count = 0;\n for (const byte of idOrHash) {\n if (byte === 0) {\n count += 8;\n } else {\n count += Math.clz32(byte) - 24;\n break;\n }\n }\n return count;\n}\n\n/**\n * Returns a new unsigned event with nonce tag and computed id. Does not mutate input. `created_at`\n * is advanced to the current second whenever it elapses while mining. Yields every `yieldEvery`\n * hashes.\n */\nexport async function minePow(\n unsigned: UnsignedEvent,\n difficulty: number,\n opts?: MinePowOptions,\n): Promise<UnsignedEvent & { id: string }> {\n const signal = opts?.signal;\n const yieldEvery = Math.max(1, opts?.yieldEvery ?? 1000);\n\n const nonce: [string, string, string] = [\"nonce\", \"0\", String(difficulty)];\n const mined = {\n kind: unsigned.kind,\n tags: [...unsigned.tags, nonce],\n content: unsigned.content,\n created_at: unsigned.created_at,\n pubkey: unsigned.pubkey,\n };\n\n // Serialize once per created_at second: the reused buffer holds\n // [0, pubkey, created_at, kind, [...tags, [\"nonce\",\"<digits>\",\"<difficulty>\"]], content]\n // where `head` ends at the opening quote of the nonce value and `tail` completes the tag, the\n // tags array, and the trailing content element.\n let head = new Uint8Array(0);\n let tail = new Uint8Array(0);\n let buf = new Uint8Array(0);\n\n const rebuild = (): void => {\n const headText = JSON.stringify([\n 0,\n mined.pubkey,\n mined.created_at,\n mined.kind,\n [...unsigned.tags, [\"nonce\", \"\"]],\n ]).slice(0, -4);\n head = utf8Encoder.encode(headText);\n tail = utf8Encoder.encode(`\",\"${difficulty}\"]],${JSON.stringify(mined.content)}]`);\n buf = new Uint8Array(head.length + 24 + tail.length);\n buf.set(head, 0);\n };\n rebuild();\n\n let count = 0;\n let iterations = 0;\n\n while (true) {\n if (signal?.aborted === true) {\n throw abortReason(signal);\n }\n\n const now = nowSeconds();\n if (now !== mined.created_at) {\n count = 0;\n mined.created_at = now;\n rebuild();\n }\n\n nonce[1] = String(++count);\n let pos = head.length;\n for (let i = 0; i < nonce[1].length; i++) {\n buf[pos] = nonce[1].codePointAt(i) ?? 0;\n pos += 1;\n }\n buf.set(tail, pos);\n pos += tail.length;\n const hash = sha256(buf.subarray(0, pos));\n if (getPow(hash) >= difficulty) {\n return { ...mined, id: bytesToHex(hash) };\n }\n\n iterations++;\n if (iterations >= yieldEvery) {\n iterations = 0;\n // oxlint-disable-next-line no-await-in-loop -- the yield is part of each mining round\n await new Promise<void>((resolve) => {\n setTimeout(resolve);\n });\n }\n }\n}\n"],"mappings":";;;;;;;;;AAYA,IAAa,aAAb,cAAgC,WAAW;CACzC,OAAgB;AAClB;;AASA,SAAgB,OAAO,UAAuC;CAC5D,IAAI,OAAO,aAAa,UAAU;EAChC,IAAI,CAAC,QAAQ,SAAS,YAAY,CAAC,GACjC,MAAM,IAAI,WAAW,sCAAsC,SAAS,OAAO,OAAO;EAEpF,IAAI,QAAQ;EACZ,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,GAAG;GAC3C,MAAM,QAAQ,OAAO,SAAS,SAAS,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE;GAC1D,IAAI,UAAU,GACZ,SAAS;QACJ;IACL,SAAS,KAAK,MAAM,KAAK;IACzB;GACF;EACF;EACA,OAAO;CACT;CAEA,IAAI,QAAQ;CACZ,KAAK,MAAM,QAAQ,UACjB,IAAI,SAAS,GACX,SAAS;MACJ;EACL,SAAS,KAAK,MAAM,IAAI,IAAI;EAC5B;CACF;CAEF,OAAO;AACT;;;;;;AAOA,eAAsB,QACpB,UACA,YACA,MACyC;CACzC,MAAM,SAAS,MAAM;CACrB,MAAM,aAAa,KAAK,IAAI,GAAG,MAAM,cAAc,GAAI;CAEvD,MAAM,QAAkC;EAAC;EAAS;EAAK,OAAO,UAAU;CAAC;CACzE,MAAM,QAAQ;EACZ,MAAM,SAAS;EACf,MAAM,CAAC,GAAG,SAAS,MAAM,KAAK;EAC9B,SAAS,SAAS;EAClB,YAAY,SAAS;EACrB,QAAQ,SAAS;CACnB;CAMA,IAAI,uBAAO,IAAI,WAAW,CAAC;CAC3B,IAAI,uBAAO,IAAI,WAAW,CAAC;CAC3B,IAAI,sBAAM,IAAI,WAAW,CAAC;CAE1B,MAAM,gBAAsB;EAC1B,MAAM,WAAW,KAAK,UAAU;GAC9B;GACA,MAAM;GACN,MAAM;GACN,MAAM;GACN,CAAC,GAAG,SAAS,MAAM,CAAC,SAAS,EAAE,CAAC;EAClC,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE;EACd,OAAO,YAAY,OAAO,QAAQ;EAClC,OAAO,YAAY,OAAO,MAAM,WAAW,MAAM,KAAK,UAAU,MAAM,OAAO,EAAE,EAAE;EACjF,MAAM,IAAI,WAAW,KAAK,SAAS,KAAK,KAAK,MAAM;EACnD,IAAI,IAAI,MAAM,CAAC;CACjB;CACA,QAAQ;CAER,IAAI,QAAQ;CACZ,IAAI,aAAa;CAEjB,OAAO,MAAM;EACX,IAAI,QAAQ,YAAY,MACtB,MAAM,YAAY,MAAM;EAG1B,MAAM,MAAM,WAAW;EACvB,IAAI,QAAQ,MAAM,YAAY;GAC5B,QAAQ;GACR,MAAM,aAAa;GACnB,QAAQ;EACV;EAEA,MAAM,KAAK,OAAO,EAAE,KAAK;EACzB,IAAI,MAAM,KAAK;EACf,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,EAAE,CAAC,QAAQ,KAAK;GACxC,IAAI,OAAO,MAAM,EAAE,CAAC,YAAY,CAAC,KAAK;GACtC,OAAO;EACT;EACA,IAAI,IAAI,MAAM,GAAG;EACjB,OAAO,KAAK;EACZ,MAAM,OAAO,OAAO,IAAI,SAAS,GAAG,GAAG,CAAC;EACxC,IAAI,OAAO,IAAI,KAAK,YAClB,OAAO;GAAE,GAAG;GAAO,IAAI,WAAW,IAAI;EAAE;EAG1C;EACA,IAAI,cAAc,YAAY;GAC5B,aAAa;GAEb,MAAM,IAAI,SAAe,YAAY;IACnC,WAAW,OAAO;GACpB,CAAC;EACH;CACF;AACF"}
@@ -1,2 +1,2 @@
1
- import { a as buildChatMessageRumor, c as normalizeRecipients, d as wrapDirectMessage, i as ReplyTo, l as parseDmRelayList, n as Nip17Error, o as dmRelayListEventBuilder, r as Recipient, s as dmRelayListToTags, t as ChatMessageOptions, u as requireDmRelays } from "../nip17-CKIufV98.mjs";
1
+ import { a as buildChatMessageRumor, c as normalizeRecipients, d as wrapDirectMessage, i as ReplyTo, l as parseDmRelayList, n as Nip17Error, o as dmRelayListEventBuilder, r as Recipient, s as dmRelayListToTags, t as ChatMessageOptions, u as requireDmRelays } from "../nip17-B5WgW4C4.mjs";
2
2
  export { ChatMessageOptions, Nip17Error, Recipient, ReplyTo, buildChatMessageRumor, dmRelayListEventBuilder, dmRelayListToTags, normalizeRecipients, parseDmRelayList, requireDmRelays, wrapDirectMessage };
@@ -1,51 +1,31 @@
1
- import { g as NostrError, l as normalizeURL, n as assertHex32, p as EventValidationError } from "../util-LfQirgDk.mjs";
1
+ import { h as EventValidationError, l as normalizeRelayUrls, n as assertHex32, v as NostrError } from "../util-DMF9AIO0.mjs";
2
2
  import { t as Kind } from "../kind-Cxwhhkx8.mjs";
3
- import { h as Tag } from "../event-D8Nfoh4K.mjs";
4
- import { t as EventBuilder } from "../builder-9tjI6WQ3.mjs";
3
+ import { h as Tag } from "../event-CHf47dPM.mjs";
4
+ import { t as EventBuilder } from "../builder-aNU2gGFP.mjs";
5
5
  import { createGiftWrap, createRumor, createSeal } from "./nip59.mjs";
6
6
  //#region src/nips/nip17.ts
7
+ /**
8
+ * NIP-17: Private Direct Messages. Kind 10050 advertises where gift-wraps should be delivered. Kind
9
+ * 14 rumor construction and per-recipient wrap live here. Envelope primitives live in nip59.ts.
10
+ *
11
+ * @see https://github.com/nostr-protocol/nips/blob/master/17.md
12
+ */
7
13
  var Nip17Error = class extends NostrError {
8
14
  name = "Nip17Error";
9
- constructor(message, options) {
10
- super(message, options);
11
- }
12
15
  };
13
16
  /** Parse kind:10050 DM relay list (`["relay", url]` tags). */
14
17
  function parseDmRelayList(event) {
15
18
  if (event.kind !== Kind.DirectMessageRelaysList) throw new EventValidationError(`expected kind ${Kind.DirectMessageRelaysList}, got ${event.kind}`);
16
- const out = [];
17
- const seen = /* @__PURE__ */ new Set();
19
+ const urls = [];
18
20
  for (const tag of event.tags) {
19
21
  const value = tag.at(1);
20
- if (tag[0] !== "relay" || value === void 0 || value === "") continue;
21
- let url;
22
- try {
23
- url = normalizeURL(value);
24
- } catch {
25
- continue;
26
- }
27
- if (seen.has(url)) continue;
28
- seen.add(url);
29
- out.push(url);
22
+ if (tag[0] === "relay" && value !== void 0) urls.push(value);
30
23
  }
31
- return out;
24
+ return normalizeRelayUrls(urls);
32
25
  }
33
26
  /** Encode DM relay URLs as NIP-17 `relay` tags. */
34
27
  function dmRelayListToTags(relays) {
35
- const tags = [];
36
- const seen = /* @__PURE__ */ new Set();
37
- for (const raw of relays) {
38
- let url;
39
- try {
40
- url = normalizeURL(raw);
41
- } catch {
42
- continue;
43
- }
44
- if (seen.has(url)) continue;
45
- seen.add(url);
46
- tags.push(["relay", url]);
47
- }
48
- return tags;
28
+ return normalizeRelayUrls(relays).map((url) => ["relay", url]);
49
29
  }
50
30
  /** Build an unsigned kind:10050 EventBuilder. NIP-17 requires ≥1 relay tag. */
51
31
  function dmRelayListEventBuilder(relays) {
@@ -118,13 +98,15 @@ async function wrapDirectMessage(crypto, recipients, rumor, opts) {
118
98
  now: opts.now,
119
99
  randomInt: opts.randomInt,
120
100
  timestamps: opts.timestamps,
101
+ expiration: opts.expiration,
121
102
  randomize: opts.randomize
122
103
  } : void 0;
123
104
  for (const target of targets) {
124
105
  const seal = await createSeal(crypto, target.pubkey, rumor, timeOpts);
125
106
  const wrap = createGiftWrap(seal, target.pubkey, {
126
107
  ...timeOpts,
127
- relayHint: target.relayHint
108
+ relayHint: target.relayHint,
109
+ ephemeral: opts?.ephemeral
128
110
  });
129
111
  out.push({
130
112
  recipient: target.pubkey,
@@ -1 +1 @@
1
- {"version":3,"file":"nip17.mjs","names":["TagBuilder"],"sources":["../../src/nips/nip17.ts"],"sourcesContent":["import { EventBuilder } from \"../core/builder.ts\";\nimport { EventValidationError, NostrError } from \"../core/error.ts\";\n/**\n * NIP-17: Private Direct Messages. Kind 10050 advertises where gift-wraps should be delivered. Kind\n * 14 rumor construction and per-recipient wrap live here. Envelope primitives live in nip59.ts.\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/17.md\n */\nimport type { Event } from \"../core/event.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport type { Tag } from \"../core/tag.ts\";\nimport { Tag as TagBuilder } from \"../core/tag.ts\";\nimport { assertHex32, normalizeURL } from \"../core/util.ts\";\nimport { createGiftWrap, createRumor, createSeal } from \"./nip59.ts\";\nimport type { Nip59Crypto, Rumor, WrapOptions } from \"./nip59.ts\";\n\nexport class Nip17Error extends NostrError {\n override name = \"Nip17Error\";\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n }\n}\n\nexport type Recipient = {\n readonly pubkey: string;\n readonly relayHint?: string | undefined;\n};\n\nexport type ReplyTo = {\n readonly id: string;\n readonly relayHint?: string | undefined;\n};\n\nexport type ChatMessageOptions = {\n readonly created_at?: number | undefined;\n readonly subject?: string | undefined;\n readonly replyTo?: ReplyTo | undefined;\n};\n\n/** Parse kind:10050 DM relay list (`[\"relay\", url]` tags). */\nexport function parseDmRelayList(event: Pick<Event, \"kind\" | \"tags\">): string[] {\n if (event.kind !== Kind.DirectMessageRelaysList) {\n throw new EventValidationError(\n `expected kind ${Kind.DirectMessageRelaysList}, got ${event.kind}`,\n );\n }\n const out: string[] = [];\n const seen = new Set<string>();\n for (const tag of event.tags) {\n const value = tag.at(1);\n if (tag[0] !== \"relay\" || value === undefined || value === \"\") {\n continue;\n }\n let url: string;\n try {\n url = normalizeURL(value);\n } catch {\n continue;\n }\n if (seen.has(url)) {\n continue;\n }\n seen.add(url);\n out.push(url);\n }\n return out;\n}\n\n/** Encode DM relay URLs as NIP-17 `relay` tags. */\nexport function dmRelayListToTags(relays: ReadonlyArray<string>): Tag[] {\n const tags: Tag[] = [];\n const seen = new Set<string>();\n for (const raw of relays) {\n let url: string;\n try {\n url = normalizeURL(raw);\n } catch {\n continue;\n }\n if (seen.has(url)) {\n continue;\n }\n seen.add(url);\n tags.push([\"relay\", url]);\n }\n return tags;\n}\n\n/** Build an unsigned kind:10050 EventBuilder. NIP-17 requires ≥1 relay tag. */\nexport function dmRelayListEventBuilder(relays: ReadonlyArray<string>): EventBuilder {\n const tags = dmRelayListToTags(relays);\n if (tags.length === 0) {\n throw new Nip17Error(\"DM relay list requires at least one relay\");\n }\n return new EventBuilder(Kind.DirectMessageRelaysList, \"\").tags(tags);\n}\n\nfunction isRecipient(value: unknown): value is Recipient {\n return typeof value === \"object\" && value !== null && \"pubkey\" in value;\n}\n\nfunction asRecipientList(\n input: string | Recipient | ReadonlyArray<string | Recipient>,\n): ReadonlyArray<string | Recipient> {\n if (typeof input === \"string\" || isRecipient(input)) {\n return [input];\n }\n return input;\n}\n\n/** Accept a hex pubkey, a Recipient, or a readonly array of either. Dedup by pubkey. */\nexport function normalizeRecipients(\n input: string | Recipient | ReadonlyArray<string | Recipient>,\n): Recipient[] {\n const out: Recipient[] = [];\n const seen = new Set<string>();\n for (const item of asRecipientList(input)) {\n const rec: Recipient = typeof item === \"string\" ? { pubkey: item } : item;\n const pubkey = assertHex32(rec.pubkey, \"public key\");\n if (seen.has(pubkey)) {\n continue;\n }\n seen.add(pubkey);\n out.push({ pubkey, relayHint: rec.relayHint });\n }\n return out;\n}\n\nexport function buildChatMessageRumor(\n senderPubkey: string,\n recipients: ReadonlyArray<Recipient>,\n content: string,\n opts?: ChatMessageOptions,\n): Rumor {\n if (recipients.length === 0) {\n throw new Nip17Error(\"recipients must not be empty\");\n }\n const tags: Tag[] = [];\n for (const recipient of recipients) {\n const pk = assertHex32(recipient.pubkey, \"public key\");\n tags.push(TagBuilder.p(pk, recipient.relayHint));\n }\n if (opts?.replyTo) {\n // Kind 14 reply e-tag is unmarked: [\"e\", <id>, <relay-url>]\n tags.push(TagBuilder.e(assertHex32(opts.replyTo.id, \"event id\"), opts.replyTo.relayHint ?? \"\"));\n }\n if (opts?.subject !== undefined) {\n tags.push([\"subject\", opts.subject]);\n }\n return createRumor(senderPubkey, {\n kind: Kind.PrivateDirectMessage,\n content,\n tags,\n created_at: opts?.created_at,\n });\n}\n\nfunction wrapTargets(sender: string, recipients: ReadonlyArray<Recipient>): Recipient[] {\n const senderPk = sender.toLowerCase();\n const self = recipients.find((r) => r.pubkey.toLowerCase() === senderPk);\n const out: Recipient[] = [{ pubkey: senderPk, relayHint: self?.relayHint }];\n const seen = new Set<string>([senderPk]);\n for (const recipient of recipients) {\n const pk = recipient.pubkey.toLowerCase();\n if (seen.has(pk)) {\n continue;\n }\n seen.add(pk);\n out.push({ pubkey: pk, relayHint: recipient.relayHint });\n }\n return out;\n}\n\nexport async function wrapDirectMessage(\n crypto: Nip59Crypto,\n recipients: ReadonlyArray<Recipient>,\n rumor: Rumor,\n opts?: Pick<WrapOptions, \"now\" | \"randomInt\" | \"timestamps\" | \"randomize\">,\n): Promise<ReadonlyArray<{ recipient: string; wrap: Event }>> {\n if (recipients.length === 0) {\n throw new Nip17Error(\"recipients must not be empty\");\n }\n const targets = wrapTargets(rumor.pubkey, recipients);\n const out: Array<{ recipient: string; wrap: Event }> = [];\n const timeOpts = opts\n ? {\n now: opts.now,\n randomInt: opts.randomInt,\n timestamps: opts.timestamps,\n randomize: opts.randomize,\n }\n : undefined;\n for (const target of targets) {\n // oxlint-disable-next-line no-await-in-loop -- signer calls stay ordered, one recipient at a time\n const seal = await createSeal(crypto, target.pubkey, rumor, timeOpts);\n const wrap = createGiftWrap(seal, target.pubkey, {\n ...timeOpts,\n relayHint: target.relayHint,\n });\n out.push({ recipient: target.pubkey, wrap });\n }\n return out;\n}\n\nexport function requireDmRelays(pubkey: string, relays: ReadonlyArray<string>): string[] {\n if (relays.length === 0) {\n throw new Nip17Error(`pubkey ${pubkey} is not ready to receive DMs (no kind 10050)`);\n }\n return [...relays];\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"nip17.mjs","names":["TagBuilder"],"sources":["../../src/nips/nip17.ts"],"sourcesContent":["/**\n * NIP-17: Private Direct Messages. Kind 10050 advertises where gift-wraps should be delivered. Kind\n * 14 rumor construction and per-recipient wrap live here. Envelope primitives live in nip59.ts.\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/17.md\n */\nimport { EventBuilder } from \"../core/builder.ts\";\nimport { EventValidationError, NostrError } from \"../core/error.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport type { Tag } from \"../core/tag.ts\";\nimport { Tag as TagBuilder } from \"../core/tag.ts\";\nimport { assertHex32, normalizeRelayUrls } from \"../core/util.ts\";\nimport { createGiftWrap, createRumor, createSeal } from \"./nip59.ts\";\nimport type { Nip59Crypto, Rumor, WrapOptions } from \"./nip59.ts\";\n\nexport class Nip17Error extends NostrError {\n override name = \"Nip17Error\";\n}\n\nexport type Recipient = {\n readonly pubkey: string;\n readonly relayHint?: string | undefined;\n};\n\nexport type ReplyTo = {\n readonly id: string;\n readonly relayHint?: string | undefined;\n};\n\nexport type ChatMessageOptions = {\n readonly created_at?: number | undefined;\n readonly subject?: string | undefined;\n readonly replyTo?: ReplyTo | undefined;\n};\n\n/** Parse kind:10050 DM relay list (`[\"relay\", url]` tags). */\nexport function parseDmRelayList(event: Pick<Event, \"kind\" | \"tags\">): string[] {\n if (event.kind !== Kind.DirectMessageRelaysList) {\n throw new EventValidationError(\n `expected kind ${Kind.DirectMessageRelaysList}, got ${event.kind}`,\n );\n }\n const urls: string[] = [];\n for (const tag of event.tags) {\n const value = tag.at(1);\n if (tag[0] === \"relay\" && value !== undefined) {\n urls.push(value);\n }\n }\n return normalizeRelayUrls(urls);\n}\n\n/** Encode DM relay URLs as NIP-17 `relay` tags. */\nexport function dmRelayListToTags(relays: ReadonlyArray<string>): Tag[] {\n return normalizeRelayUrls(relays).map((url) => [\"relay\", url]);\n}\n\n/** Build an unsigned kind:10050 EventBuilder. NIP-17 requires ≥1 relay tag. */\nexport function dmRelayListEventBuilder(relays: ReadonlyArray<string>): EventBuilder {\n const tags = dmRelayListToTags(relays);\n if (tags.length === 0) {\n throw new Nip17Error(\"DM relay list requires at least one relay\");\n }\n return new EventBuilder(Kind.DirectMessageRelaysList, \"\").tags(tags);\n}\n\nfunction isRecipient(value: unknown): value is Recipient {\n return typeof value === \"object\" && value !== null && \"pubkey\" in value;\n}\n\nfunction asRecipientList(\n input: string | Recipient | ReadonlyArray<string | Recipient>,\n): ReadonlyArray<string | Recipient> {\n if (typeof input === \"string\" || isRecipient(input)) {\n return [input];\n }\n return input;\n}\n\n/** Accept a hex pubkey, a Recipient, or a readonly array of either. Dedup by pubkey. */\nexport function normalizeRecipients(\n input: string | Recipient | ReadonlyArray<string | Recipient>,\n): Recipient[] {\n const out: Recipient[] = [];\n const seen = new Set<string>();\n for (const item of asRecipientList(input)) {\n const rec: Recipient = typeof item === \"string\" ? { pubkey: item } : item;\n const pubkey = assertHex32(rec.pubkey, \"public key\");\n if (seen.has(pubkey)) {\n continue;\n }\n seen.add(pubkey);\n out.push({ pubkey, relayHint: rec.relayHint });\n }\n return out;\n}\n\nexport function buildChatMessageRumor(\n senderPubkey: string,\n recipients: ReadonlyArray<Recipient>,\n content: string,\n opts?: ChatMessageOptions,\n): Rumor {\n if (recipients.length === 0) {\n throw new Nip17Error(\"recipients must not be empty\");\n }\n const tags: Tag[] = [];\n for (const recipient of recipients) {\n const pk = assertHex32(recipient.pubkey, \"public key\");\n tags.push(TagBuilder.p(pk, recipient.relayHint));\n }\n if (opts?.replyTo) {\n // Kind 14 reply e-tag is unmarked: [\"e\", <id>, <relay-url>]\n tags.push(TagBuilder.e(assertHex32(opts.replyTo.id, \"event id\"), opts.replyTo.relayHint ?? \"\"));\n }\n if (opts?.subject !== undefined) {\n tags.push([\"subject\", opts.subject]);\n }\n return createRumor(senderPubkey, {\n kind: Kind.PrivateDirectMessage,\n content,\n tags,\n created_at: opts?.created_at,\n });\n}\n\nfunction wrapTargets(sender: string, recipients: ReadonlyArray<Recipient>): Recipient[] {\n const senderPk = sender.toLowerCase();\n const self = recipients.find((r) => r.pubkey.toLowerCase() === senderPk);\n const out: Recipient[] = [{ pubkey: senderPk, relayHint: self?.relayHint }];\n const seen = new Set<string>([senderPk]);\n for (const recipient of recipients) {\n const pk = recipient.pubkey.toLowerCase();\n if (seen.has(pk)) {\n continue;\n }\n seen.add(pk);\n out.push({ pubkey: pk, relayHint: recipient.relayHint });\n }\n return out;\n}\n\nexport async function wrapDirectMessage(\n crypto: Nip59Crypto,\n recipients: ReadonlyArray<Recipient>,\n rumor: Rumor,\n opts?: Pick<\n WrapOptions,\n \"now\" | \"randomInt\" | \"timestamps\" | \"expiration\" | \"ephemeral\" | \"randomize\"\n >,\n): Promise<ReadonlyArray<{ recipient: string; wrap: Event }>> {\n if (recipients.length === 0) {\n throw new Nip17Error(\"recipients must not be empty\");\n }\n const targets = wrapTargets(rumor.pubkey, recipients);\n const out: Array<{ recipient: string; wrap: Event }> = [];\n const timeOpts = opts\n ? {\n now: opts.now,\n randomInt: opts.randomInt,\n timestamps: opts.timestamps,\n expiration: opts.expiration,\n randomize: opts.randomize,\n }\n : undefined;\n for (const target of targets) {\n // oxlint-disable-next-line no-await-in-loop -- signer calls stay ordered, one recipient at a time\n const seal = await createSeal(crypto, target.pubkey, rumor, timeOpts);\n const wrap = createGiftWrap(seal, target.pubkey, {\n ...timeOpts,\n relayHint: target.relayHint,\n ephemeral: opts?.ephemeral,\n });\n out.push({ recipient: target.pubkey, wrap });\n }\n return out;\n}\n\nexport function requireDmRelays(pubkey: string, relays: ReadonlyArray<string>): string[] {\n if (relays.length === 0) {\n throw new Nip17Error(`pubkey ${pubkey} is not ready to receive DMs (no kind 10050)`);\n }\n return [...relays];\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import { _ as neventEncode, a as NAddr, b as npubEncode, c as NPub, d as Note, f as ProfilePointer, g as naddrEncode, h as encodeBytes, i as EventPointer, l as NSec, m as decodeNostrURI, n as Bech32MaxSize, o as NEvent, p as decode, r as DecodedResult, s as NProfile, t as AddressPointer, u as Nip19Error, v as noteEncode, x as nsecEncode, y as nprofileEncode } from "../nip19-BevCJZsp.mjs";
2
- export { AddressPointer, Bech32MaxSize, DecodedResult, EventPointer, NAddr, NEvent, NProfile, NPub, NSec, Nip19Error, Note, ProfilePointer, decode, decodeNostrURI, encodeBytes, naddrEncode, neventEncode, noteEncode, nprofileEncode, npubEncode, nsecEncode };
1
+ import { _ as noteEncode, a as NAddr, b as nsecEncode, c as NPub, d as Note, f as ProfilePointer, g as neventEncode, h as naddrEncode, i as EventPointer, l as NSec, m as encodeBytes, n as Bech32MaxSize, o as NEvent, p as decode, r as DecodedResult, s as NProfile, t as AddressPointer, u as Nip19Error, v as nprofileEncode, y as npubEncode } from "../nip19-DpPN17bY.mjs";
2
+ export { AddressPointer, Bech32MaxSize, DecodedResult, EventPointer, NAddr, NEvent, NProfile, NPub, NSec, Nip19Error, Note, ProfilePointer, decode, encodeBytes, naddrEncode, neventEncode, noteEncode, nprofileEncode, npubEncode, nsecEncode };
@@ -1,4 +1,4 @@
1
- import { a as hexToBytes, d as utf8Encoder, g as NostrError, i as bytesToHex, n as assertHex32, t as assertByteLength, u as utf8Decoder } from "../util-LfQirgDk.mjs";
1
+ import { a as hexToBytes, f as utf8Decoder, i as bytesToHex, n as assertHex32, p as utf8Encoder, t as assertByteLength, v as NostrError, x as errorMessage } from "../util-DMF9AIO0.mjs";
2
2
  import { bech32 } from "@scure/base";
3
3
  //#region src/nips/nip19.ts
4
4
  /** Maximum bech32 string length accepted by {@link decode} (NIP-19). */
@@ -6,9 +6,6 @@ const Bech32MaxSize = 5e3;
6
6
  /** Error thrown by NIP-19 encoding/decoding failures. */
7
7
  var Nip19Error = class extends NostrError {
8
8
  name = "Nip19Error";
9
- constructor(message) {
10
- super(message);
11
- }
12
9
  };
13
10
  function integerToUint8Array(number) {
14
11
  const out = /* @__PURE__ */ new Uint8Array(4);
@@ -103,10 +100,20 @@ function naddrEncode(addr) {
103
100
  3: [kind]
104
101
  }));
105
102
  }
103
+ function readUint32(bytes) {
104
+ return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(0);
105
+ }
106
106
  /** Decode a NIP-19 bech32 entity; throws {@link Nip19Error} on bad input or unknown prefix. */
107
107
  function decode(code) {
108
- const { prefix, words } = bech32.decode(code, Bech32MaxSize);
109
- const data = new Uint8Array(bech32.fromWords(words));
108
+ let prefix;
109
+ let data;
110
+ try {
111
+ const { prefix: hrp, words } = bech32.decode(code, Bech32MaxSize);
112
+ prefix = hrp;
113
+ data = new Uint8Array(bech32.fromWords(words));
114
+ } catch (error) {
115
+ throw new Nip19Error(`invalid bech32: ${errorMessage(error)}`, { cause: error });
116
+ }
110
117
  switch (prefix) {
111
118
  case "nprofile": {
112
119
  const tlv = parseTLV(data);
@@ -133,7 +140,7 @@ function decode(code) {
133
140
  const author = tlv[2]?.[0];
134
141
  if (author !== void 0) pointer.author = bytesToHex(author);
135
142
  const kind = tlv[3]?.[0];
136
- if (kind !== void 0) pointer.kind = Number.parseInt(bytesToHex(kind), 16);
143
+ if (kind !== void 0) pointer.kind = readUint32(kind);
137
144
  return {
138
145
  type: "nevent",
139
146
  data: pointer
@@ -151,7 +158,7 @@ function decode(code) {
151
158
  data: {
152
159
  identifier: utf8Decoder.decode(tlv[0][0]),
153
160
  pubkey: bytesToHex(tlv[2][0]),
154
- kind: Number.parseInt(bytesToHex(tlv[3][0]), 16),
161
+ kind: readUint32(tlv[3][0]),
155
162
  relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : []
156
163
  }
157
164
  };
@@ -172,26 +179,7 @@ function decode(code) {
172
179
  default: throw new Nip19Error(`unknown prefix ${prefix}`);
173
180
  }
174
181
  }
175
- /** Decode `nostr:` URI or bare bech32; returns invalid sentinel instead of throwing. */
176
- function decodeNostrURI(nip19code) {
177
- try {
178
- let code = nip19code;
179
- if (code.startsWith("nostr:")) {
180
- code = code.slice(6);
181
- if (code.startsWith("nsec1")) return {
182
- type: "invalid",
183
- data: void 0
184
- };
185
- }
186
- return decode(code);
187
- } catch {
188
- return {
189
- type: "invalid",
190
- data: void 0
191
- };
192
- }
193
- }
194
182
  //#endregion
195
- export { Bech32MaxSize, Nip19Error, decode, decodeNostrURI, encodeBytes, naddrEncode, neventEncode, noteEncode, nprofileEncode, npubEncode, nsecEncode };
183
+ export { Bech32MaxSize, Nip19Error, decode, encodeBytes, naddrEncode, neventEncode, noteEncode, nprofileEncode, npubEncode, nsecEncode };
196
184
 
197
185
  //# sourceMappingURL=nip19.mjs.map