@qntx/nostr 0.7.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 (147) hide show
  1. package/dist/{builder-DgkqDylK.d.mts → builder-CTwkB2zM.d.mts} +10 -10
  2. package/dist/{builder-CdLE4J6O.mjs → builder-aNU2gGFP.mjs} +4 -4
  3. package/dist/builder-aNU2gGFP.mjs.map +1 -0
  4. package/dist/{client-CILhdfsF.mjs → client-Cj2lUaVh.mjs} +70 -72
  5. package/dist/client-Cj2lUaVh.mjs.map +1 -0
  6. package/dist/client.d.mts +1 -1
  7. package/dist/client.mjs +1 -1
  8. package/dist/core.d.mts +2 -2
  9. package/dist/core.mjs +6 -6
  10. package/dist/emitter-DkCY6NkU.mjs +32 -0
  11. package/dist/emitter-DkCY6NkU.mjs.map +1 -0
  12. package/dist/{error-L_QdmSnV.mjs → error-BILMe3Gr.mjs} +2 -2
  13. package/dist/{error-L_QdmSnV.mjs.map → error-BILMe3Gr.mjs.map} +1 -1
  14. package/dist/{error-gtJvV6YS.mjs → error-DlhGW4mJ.mjs} +2 -2
  15. package/dist/{error-gtJvV6YS.mjs.map → error-DlhGW4mJ.mjs.map} +1 -1
  16. package/dist/{event-DinQMmJ1.mjs → event-CHf47dPM.mjs} +2 -2
  17. package/dist/{event-DinQMmJ1.mjs.map → event-CHf47dPM.mjs.map} +1 -1
  18. package/dist/{gossip-CcTp9VpU.mjs → gossip-DFxIBlsr.mjs} +3 -3
  19. package/dist/gossip-DFxIBlsr.mjs.map +1 -0
  20. package/dist/{gossip-C7HLW5kI.d.mts → gossip-OOeeFzG5.d.mts} +4 -4
  21. package/dist/gossip.d.mts +1 -1
  22. package/dist/gossip.mjs +1 -1
  23. package/dist/{index-InQZpHyQ.d.mts → index-BxCBX-8R.d.mts} +2 -2
  24. package/dist/{index-iLT8UzY3.d.mts → index-CPVEyzNX.d.mts} +22 -22
  25. package/dist/{index-Tx15HGAD.d.mts → index-C_w2WfVz.d.mts} +4 -4
  26. package/dist/{index-DocgD9K0.d.mts → index-Cl_1XdYP.d.mts} +29 -23
  27. package/dist/{index-DiXwNn2M.d.mts → index-DyKwQnbt.d.mts} +2 -2
  28. package/dist/index.d.mts +14 -14
  29. package/dist/index.mjs +17 -17
  30. package/dist/{instance-BcKzxHIP.mjs → instance-C62w3cEt.mjs} +3 -3
  31. package/dist/{instance-BcKzxHIP.mjs.map → instance-C62w3cEt.mjs.map} +1 -1
  32. package/dist/{key-bshqfmZL.mjs → key-DnVpchl6.mjs} +3 -3
  33. package/dist/{key-bshqfmZL.mjs.map → key-DnVpchl6.mjs.map} +1 -1
  34. package/dist/{loaders-DD0XAGzw.mjs → loaders-BmPkQfzI.mjs} +6 -6
  35. package/dist/loaders-BmPkQfzI.mjs.map +1 -0
  36. package/dist/loaders.d.mts +2 -2
  37. package/dist/loaders.mjs +1 -1
  38. package/dist/{memory-D_-5-T31.mjs → memory-CdJ07kub.mjs} +2 -2
  39. package/dist/memory-CdJ07kub.mjs.map +1 -0
  40. package/dist/{memory-index-C6rujtoc.mjs → memory-index-Cbc83vOZ.mjs} +3 -3
  41. package/dist/{memory-index-C6rujtoc.mjs.map → memory-index-Cbc83vOZ.mjs.map} +1 -1
  42. package/dist/{message-CWLcFTQ1.mjs → message-oNr7t0SJ.mjs} +3 -3
  43. package/dist/message-oNr7t0SJ.mjs.map +1 -0
  44. package/dist/{message-CbBZOhq3.d.mts → message-tclYCVNc.d.mts} +4 -4
  45. package/dist/{nip17-cTDFfFVt.d.mts → nip17-B5WgW4C4.d.mts} +4 -4
  46. package/dist/{nip19-D1OnJ192.d.mts → nip19-DpPN17bY.d.mts} +23 -23
  47. package/dist/{nip46-DrsPI8EX.d.mts → nip46-BHaxC9TZ.d.mts} +17 -17
  48. package/dist/{nip51-DoPUvQ--.d.mts → nip51-CR0Q8eym.d.mts} +10 -10
  49. package/dist/{nip59-BFIihLYY.d.mts → nip59-C-RWFQIv.d.mts} +9 -2
  50. package/dist/{nip65-52HiwiyD.d.mts → nip65-D1fbmhOg.d.mts} +2 -2
  51. package/dist/{nip77-C9QcZn7b.d.mts → nip77-DzUwUxHq.d.mts} +6 -6
  52. package/dist/nips/blossom.d.mts +6 -6
  53. package/dist/nips/blossom.mjs +2 -2
  54. package/dist/nips/blossom.mjs.map +1 -1
  55. package/dist/nips/nip04.mjs +1 -1
  56. package/dist/nips/nip05.d.mts +8 -8
  57. package/dist/nips/nip05.mjs +1 -1
  58. package/dist/nips/nip05.mjs.map +1 -1
  59. package/dist/nips/nip10.d.mts +7 -7
  60. package/dist/nips/nip10.mjs +34 -32
  61. package/dist/nips/nip10.mjs.map +1 -1
  62. package/dist/nips/nip11.d.mts +27 -27
  63. package/dist/nips/nip11.mjs +1 -1
  64. package/dist/nips/nip11.mjs.map +1 -1
  65. package/dist/nips/nip13.mjs +1 -1
  66. package/dist/nips/nip17.d.mts +1 -1
  67. package/dist/nips/nip17.mjs +6 -4
  68. package/dist/nips/nip17.mjs.map +1 -1
  69. package/dist/nips/nip19.d.mts +1 -1
  70. package/dist/nips/nip19.mjs +1 -1
  71. package/dist/nips/nip19.mjs.map +1 -1
  72. package/dist/nips/nip21.d.mts +4 -4
  73. package/dist/nips/nip21.mjs +1 -1
  74. package/dist/nips/nip21.mjs.map +1 -1
  75. package/dist/nips/nip27.d.mts +19 -19
  76. package/dist/nips/nip27.mjs +2 -2
  77. package/dist/nips/nip27.mjs.map +1 -1
  78. package/dist/nips/nip42.mjs +1 -1
  79. package/dist/nips/nip44.mjs +2 -2
  80. package/dist/nips/nip44.mjs.map +1 -1
  81. package/dist/nips/nip46.d.mts +1 -1
  82. package/dist/nips/nip46.mjs +1 -1
  83. package/dist/nips/nip46.mjs.map +1 -1
  84. package/dist/nips/nip49.d.mts +4 -4
  85. package/dist/nips/nip49.mjs +1 -1
  86. package/dist/nips/nip49.mjs.map +1 -1
  87. package/dist/nips/nip51.d.mts +1 -1
  88. package/dist/nips/nip51.mjs +3 -3
  89. package/dist/nips/nip51.mjs.map +1 -1
  90. package/dist/nips/nip57.d.mts +18 -18
  91. package/dist/nips/nip57.mjs +3 -3
  92. package/dist/nips/nip57.mjs.map +1 -1
  93. package/dist/nips/nip59.d.mts +1 -1
  94. package/dist/nips/nip59.mjs +15 -7
  95. package/dist/nips/nip59.mjs.map +1 -1
  96. package/dist/nips/nip65.d.mts +1 -1
  97. package/dist/nips/nip65.mjs +2 -2
  98. package/dist/nips/nip77.d.mts +1 -1
  99. package/dist/nips/nip77.mjs +1 -1
  100. package/dist/nips/nip77.mjs.map +1 -1
  101. package/dist/nips/nip98.mjs +3 -3
  102. package/dist/{pool-SzJKPIa3.d.mts → pool-CqQvUnsq.d.mts} +43 -24
  103. package/dist/{pool-YHRZgcQ3.mjs → pool-vlw74C4t.mjs} +39 -29
  104. package/dist/pool-vlw74C4t.mjs.map +1 -0
  105. package/dist/{put-DS0yzVJx.mjs → put-w13ci3sC.mjs} +3 -3
  106. package/dist/put-w13ci3sC.mjs.map +1 -0
  107. package/dist/{reactive-BJRoVHxU.mjs → reactive-Tz0otDIP.mjs} +49 -27
  108. package/dist/reactive-Tz0otDIP.mjs.map +1 -0
  109. package/dist/{reactive-BJ1ggn4d.d.mts → reactive-gGqUrzW8.d.mts} +16 -7
  110. package/dist/{relay-CvxPiQ_m.mjs → relay-quCs7MHD.mjs} +1049 -861
  111. package/dist/relay-quCs7MHD.mjs.map +1 -0
  112. package/dist/relay.d.mts +4 -4
  113. package/dist/relay.mjs +2 -2
  114. package/dist/{signer-yW3slDC2.mjs → signer-poTGe6Er.mjs} +6 -6
  115. package/dist/signer-poTGe6Er.mjs.map +1 -0
  116. package/dist/signer.d.mts +1 -1
  117. package/dist/signer.mjs +2 -2
  118. package/dist/{storage-CZ52ifcQ.mjs → storage-B5IXTVuS.mjs} +16 -14
  119. package/dist/storage-B5IXTVuS.mjs.map +1 -0
  120. package/dist/storage.d.mts +2 -2
  121. package/dist/storage.mjs +4 -4
  122. package/dist/store.d.mts +2 -2
  123. package/dist/store.mjs +1 -1
  124. package/dist/testing.d.mts +3 -3
  125. package/dist/testing.mjs +6 -6
  126. package/dist/testing.mjs.map +1 -1
  127. package/dist/{types-Cm-XMgtH.d.mts → types-BacwnDtU.d.mts} +5 -5
  128. package/dist/{util-yFYzlbrm.mjs → util-DMF9AIO0.mjs} +6 -2
  129. package/dist/util-DMF9AIO0.mjs.map +1 -0
  130. package/dist/{verifier-BTLOpo1n.mjs → verifier-B51Wkt5H.mjs} +3 -3
  131. package/dist/{verifier-BTLOpo1n.mjs.map → verifier-B51Wkt5H.mjs.map} +1 -1
  132. package/dist/wasm.browser.mjs +2 -2
  133. package/dist/wasm.mjs +2 -2
  134. package/package.json +1 -1
  135. package/dist/builder-CdLE4J6O.mjs.map +0 -1
  136. package/dist/client-CILhdfsF.mjs.map +0 -1
  137. package/dist/gossip-CcTp9VpU.mjs.map +0 -1
  138. package/dist/loaders-DD0XAGzw.mjs.map +0 -1
  139. package/dist/memory-D_-5-T31.mjs.map +0 -1
  140. package/dist/message-CWLcFTQ1.mjs.map +0 -1
  141. package/dist/pool-YHRZgcQ3.mjs.map +0 -1
  142. package/dist/put-DS0yzVJx.mjs.map +0 -1
  143. package/dist/reactive-BJRoVHxU.mjs.map +0 -1
  144. package/dist/relay-CvxPiQ_m.mjs.map +0 -1
  145. package/dist/signer-yW3slDC2.mjs.map +0 -1
  146. package/dist/storage-CZ52ifcQ.mjs.map +0 -1
  147. package/dist/util-yFYzlbrm.mjs.map +0 -1
@@ -1,7 +1,7 @@
1
- import { h as EventValidationError, o as isHex32 } from "../util-yFYzlbrm.mjs";
1
+ import { h as EventValidationError, o as isHex32 } from "../util-DMF9AIO0.mjs";
2
2
  import { t as Kind } from "../kind-Cxwhhkx8.mjs";
3
- import { h as Tag, v as formatEventAddress, x as parseEventAddress } from "../event-DinQMmJ1.mjs";
4
- import { t as EventBuilder } from "../builder-CdLE4J6O.mjs";
3
+ import { h as Tag, v as formatEventAddress, x as parseEventAddress } from "../event-CHf47dPM.mjs";
4
+ import { t as EventBuilder } from "../builder-aNU2gGFP.mjs";
5
5
  //#region src/nips/nip10.ts
6
6
  /**
7
7
  * NIP-10: Text Notes and Threads
@@ -90,13 +90,11 @@ function assertKind1Parent(parent) {
90
90
  }
91
91
  /** Parse NIP-10 thread markers and legacy positional e-tags from an event. */
92
92
  function parseThreadTags(event) {
93
- const result = {
94
- root: void 0,
95
- reply: void 0,
96
- mentions: [],
97
- quotes: [],
98
- profiles: []
99
- };
93
+ const mentions = [];
94
+ const quotes = [];
95
+ const profiles = [];
96
+ let root;
97
+ let reply;
100
98
  let maybeParent;
101
99
  let maybeRoot;
102
100
  for (let i = event.tags.length - 1; i >= 0; i--) {
@@ -108,52 +106,56 @@ function parseThreadTags(event) {
108
106
  if (pointer === void 0) continue;
109
107
  const marker = tag.at(3);
110
108
  if (marker === "root") {
111
- result.root = pointer;
109
+ root = pointer;
112
110
  continue;
113
111
  }
114
112
  if (marker === "reply") {
115
- result.reply = pointer;
113
+ reply = pointer;
116
114
  continue;
117
115
  }
118
116
  if (marker !== void 0 && marker !== "" && !isHex32(marker.toLowerCase())) {
119
- result.mentions.push(pointer);
117
+ mentions.push(pointer);
120
118
  continue;
121
119
  }
122
120
  if (maybeParent) maybeRoot = pointer;
123
121
  else maybeParent = pointer;
124
- result.mentions.push(pointer);
122
+ mentions.push(pointer);
125
123
  continue;
126
124
  }
127
125
  if (tag[0] === "q") {
128
126
  const quote = quoteFromQTag(tag);
129
- if (quote) result.quotes.push(quote);
127
+ if (quote) quotes.push(quote);
130
128
  continue;
131
129
  }
132
130
  const pValue = tag.at(1);
133
- if (tag[0] === "p" && pValue !== void 0 && isHex32(pValue.toLowerCase())) result.profiles.push({
131
+ if (tag[0] === "p" && pValue !== void 0 && isHex32(pValue.toLowerCase())) profiles.push({
134
132
  pubkey: pValue.toLowerCase(),
135
133
  relays: tag[2] !== void 0 && tag[2] !== "" ? [tag[2]] : []
136
134
  });
137
135
  }
138
- result.root ??= maybeRoot ?? maybeParent ?? result.reply;
139
- result.reply ??= maybeParent ?? result.root;
140
- const drop = new Set([result.root?.id, result.reply?.id].filter((id) => Boolean(id)));
141
- result.mentions = result.mentions.filter((m) => !drop.has(m.id));
142
- for (const ref of [
143
- result.reply,
144
- result.root,
145
- ...result.mentions
146
- ]) {
147
- if (ref === void 0) continue;
136
+ root ??= maybeRoot ?? maybeParent ?? reply;
137
+ reply ??= maybeParent ?? root;
138
+ const drop = new Set([root?.id, reply?.id].filter((id) => Boolean(id)));
139
+ const keptMentions = mentions.filter((m) => !drop.has(m.id));
140
+ const inheritHints = (ref) => {
148
141
  const refAuthor = ref.author;
149
- if (refAuthor === void 0 || refAuthor === "") continue;
150
- const profileRelays = result.profiles.find((p) => p.pubkey === refAuthor)?.relays;
151
- if (profileRelays === void 0 || profileRelays.length === 0) continue;
142
+ if (refAuthor === void 0 || refAuthor === "") return ref;
143
+ const profileRelays = profiles.find((p) => p.pubkey === refAuthor)?.relays;
144
+ if (profileRelays === void 0 || profileRelays.length === 0) return ref;
152
145
  const relays = [...ref.relays ?? []];
153
146
  for (const url of profileRelays) if (!relays.includes(url)) relays.push(url);
154
- ref.relays = relays;
155
- }
156
- return result;
147
+ return {
148
+ ...ref,
149
+ relays
150
+ };
151
+ };
152
+ return {
153
+ root: root === void 0 ? void 0 : inheritHints(root),
154
+ reply: reply === void 0 ? void 0 : inheritHints(reply),
155
+ mentions: keptMentions.map(inheritHints),
156
+ quotes,
157
+ profiles
158
+ };
157
159
  }
158
160
  /**
159
161
  * Build NIP-10 e/p tags for a reply to `parent`. Uses marked tags (`root` / `reply`) per preferred
@@ -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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"}
@@ -3,33 +3,33 @@ 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, v as NostrError } from "../util-yFYzlbrm.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
  /**
@@ -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,\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,\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":";;;;;;;;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,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,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,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
+ {"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,4 +1,4 @@
1
- import { d as nowSeconds, i as bytesToHex, o as isHex32, p as utf8Encoder, v as NostrError } from "../util-yFYzlbrm.mjs";
1
+ import { d as nowSeconds, i as bytesToHex, o as isHex32, p as utf8Encoder, v as NostrError } from "../util-DMF9AIO0.mjs";
2
2
  import { t as abortReason } from "../abort-DBq2STPj.mjs";
3
3
  import { sha256 } from "@noble/hashes/sha2.js";
4
4
  //#region src/nips/nip13.ts
@@ -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-cTDFfFVt.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,7 +1,7 @@
1
- import { h as EventValidationError, l as normalizeRelayUrls, n as assertHex32, v as NostrError } from "../util-yFYzlbrm.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-DinQMmJ1.mjs";
4
- import { t as EventBuilder } from "../builder-CdLE4J6O.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
7
  /**
@@ -98,13 +98,15 @@ async function wrapDirectMessage(crypto, recipients, rumor, opts) {
98
98
  now: opts.now,
99
99
  randomInt: opts.randomInt,
100
100
  timestamps: opts.timestamps,
101
+ expiration: opts.expiration,
101
102
  randomize: opts.randomize
102
103
  } : void 0;
103
104
  for (const target of targets) {
104
105
  const seal = await createSeal(crypto, target.pubkey, rumor, timeOpts);
105
106
  const wrap = createGiftWrap(seal, target.pubkey, {
106
107
  ...timeOpts,
107
- relayHint: target.relayHint
108
+ relayHint: target.relayHint,
109
+ ephemeral: opts?.ephemeral
108
110
  });
109
111
  out.push({
110
112
  recipient: target.pubkey,
@@ -1 +1 @@
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<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 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-D1OnJ192.mjs";
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
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, f as utf8Decoder, i as bytesToHex, n as assertHex32, p as utf8Encoder, t as assertByteLength, v as NostrError, x as errorMessage } from "../util-yFYzlbrm.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). */
@@ -1 +1 @@
1
- {"version":3,"file":"nip19.mjs","names":[],"sources":["../../src/nips/nip19.ts"],"sourcesContent":["import { bech32 } from \"@scure/base\";\n\nimport { NostrError, errorMessage } from \"../core/error.ts\";\nimport {\n assertByteLength,\n assertHex32,\n bytesToHex,\n hexToBytes,\n utf8Decoder,\n utf8Encoder,\n} from \"../core/util.ts\";\n\n/** Bech32 `nprofile1…` string (TLV profile pointer). */\nexport type NProfile = `nprofile1${string}`;\n/** Bech32 `nevent1…` string (TLV event pointer). */\nexport type NEvent = `nevent1${string}`;\n/** Bech32 `naddr1…` string (TLV address pointer). */\nexport type NAddr = `naddr1${string}`;\n/** Bech32 `nsec1…` string (32-byte secret key). */\nexport type NSec = `nsec1${string}`;\n/** Bech32 `npub1…` string (32-byte public key). */\nexport type NPub = `npub1${string}`;\n/** Bech32 `note1…` string (32-byte event id). */\nexport type Note = `note1${string}`;\n\n/** Maximum bech32 string length accepted by {@link decode} (NIP-19). */\nexport const Bech32MaxSize = 5000;\n\n/** Decoded `nprofile` payload: a pubkey plus optional relay hints. */\nexport type ProfilePointer = {\n pubkey: string;\n relays?: string[];\n};\n\n/** Decoded `nevent` payload: an event id plus optional relay/author/kind hints. */\nexport type EventPointer = {\n id: string;\n relays?: string[];\n author?: string;\n kind?: number;\n};\n\n/** Decoded `naddr` payload: a replaceable-event coordinate plus optional relay hints. */\nexport type AddressPointer = {\n identifier: string;\n pubkey: string;\n kind: number;\n relays?: string[];\n};\n\n/** Result of {@link decode}: the bech32 prefix and its decoded payload. */\nexport type DecodedResult =\n | { type: \"nprofile\"; data: ProfilePointer }\n | { type: \"nevent\"; data: EventPointer }\n | { type: \"naddr\"; data: AddressPointer }\n | { type: \"nsec\"; data: Uint8Array }\n | { type: \"npub\"; data: string }\n | { type: \"note\"; data: string };\n\n/** Error thrown by NIP-19 encoding/decoding failures. */\nexport class Nip19Error extends NostrError {\n override name = \"Nip19Error\";\n}\n\ntype TLV = Record<number, Uint8Array[]>;\n\nfunction integerToUint8Array(number: number): Uint8Array {\n const out = new Uint8Array(4);\n new DataView(out.buffer).setUint32(0, number);\n return out;\n}\n\nfunction parseTLV(data: Uint8Array): TLV {\n const result: TLV = {};\n let rest = data;\n while (rest.length > 0) {\n if (rest.length < 2) {\n throw new Nip19Error(\"not enough data to read TLV\");\n }\n const t = rest.at(0);\n const l = rest.at(1);\n if (t === undefined || l === undefined) {\n throw new Nip19Error(\"not enough data to read TLV\");\n }\n const v = rest.slice(2, 2 + l);\n rest = rest.slice(2 + l);\n if (v.length < l) {\n throw new Nip19Error(`not enough data to read on TLV ${t}`);\n }\n result[t] = result[t] ?? [];\n result[t].push(v);\n }\n return result;\n}\n\nfunction assertNip19Kind(kind: number): void {\n if (!Number.isInteger(kind) || kind < 0 || kind > 0xffffffff) {\n throw new Nip19Error(`invalid kind: ${kind}`);\n }\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n const entries: Uint8Array[] = [];\n for (const [t, vs] of Object.entries(tlv).reverse()) {\n for (const v of vs) {\n if (v.length > 255) {\n throw new Nip19Error(\"TLV value exceeds 255 bytes\");\n }\n const entry = new Uint8Array(v.length + 2);\n entry[0] = Math.trunc(Number(t));\n entry[1] = v.length;\n entry.set(v, 2);\n entries.push(entry);\n }\n }\n let total = 0;\n for (const e of entries) {\n total += e.length;\n }\n const out = new Uint8Array(total);\n let offset = 0;\n for (const e of entries) {\n out.set(e, offset);\n offset += e.length;\n }\n return out;\n}\n\nfunction encodeBech32<Prefix extends string>(\n prefix: Prefix,\n data: Uint8Array,\n): `${Prefix}1${string}` {\n const words = bech32.toWords(data);\n // oxlint-disable-next-line no-unsafe-type-assertion -- bech32 output is `${prefix}1…` by construction\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`;\n}\n\nexport function encodeBytes<Prefix extends string>(\n prefix: Prefix,\n bytes: Uint8Array,\n): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes);\n}\n\n/** Encode a 32-byte secret key as `nsec1…`; throws {@link Nip19Error} on wrong length. */\nexport function nsecEncode(key: Uint8Array): NSec {\n assertByteLength(key, 32, \"secret key\");\n return encodeBytes(\"nsec\", key);\n}\n\n/** Encode a hex public key as `npub1…`; throws {@link HexError} on bad hex. */\nexport function npubEncode(hex: string): NPub {\n return encodeBytes(\"npub\", hexToBytes(assertHex32(hex, \"pubkey\")));\n}\n\n/** Encode a hex event id as `note1…`; throws {@link HexError} on bad hex. */\nexport function noteEncode(hex: string): Note {\n return encodeBytes(\"note\", hexToBytes(assertHex32(hex, \"event id\")));\n}\n\n/** Encode a profile pointer as `nprofile1…`. */\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n const data = encodeTLV({\n 0: [hexToBytes(assertHex32(profile.pubkey, \"pubkey\"))],\n 1: (profile.relays ?? []).map((url) => utf8Encoder.encode(url)),\n });\n return encodeBech32(\"nprofile\", data);\n}\n\n/** Encode an event pointer as `nevent1…`. */\nexport function neventEncode(event: EventPointer): NEvent {\n if (event.kind !== undefined) {\n assertNip19Kind(event.kind);\n }\n const kindArray = event.kind === undefined ? undefined : integerToUint8Array(event.kind);\n const data = encodeTLV({\n 0: [hexToBytes(assertHex32(event.id, \"event id\"))],\n 1: (event.relays ?? []).map((url) => utf8Encoder.encode(url)),\n 2:\n event.author !== undefined && event.author !== \"\"\n ? [hexToBytes(assertHex32(event.author, \"author\"))]\n : [],\n 3: kindArray ? [kindArray] : [],\n });\n return encodeBech32(\"nevent\", data);\n}\n\n/** Encode an address pointer as `naddr1…`. */\nexport function naddrEncode(addr: AddressPointer): NAddr {\n assertNip19Kind(addr.kind);\n const kind = integerToUint8Array(addr.kind);\n const data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays ?? []).map((url) => utf8Encoder.encode(url)),\n 2: [hexToBytes(assertHex32(addr.pubkey, \"pubkey\"))],\n 3: [kind],\n });\n return encodeBech32(\"naddr\", data);\n}\n\nfunction readUint32(bytes: Uint8Array): number {\n return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(0);\n}\n\n/** Decode a NIP-19 bech32 entity; throws {@link Nip19Error} on bad input or unknown prefix. */\nexport function decode(code: string): DecodedResult {\n let prefix: string;\n let data: Uint8Array;\n try {\n const { prefix: hrp, words } = bech32.decode(code, Bech32MaxSize);\n prefix = hrp;\n data = new Uint8Array(bech32.fromWords(words));\n } catch (error) {\n throw new Nip19Error(`invalid bech32: ${errorMessage(error)}`, { cause: error });\n }\n\n switch (prefix) {\n case \"nprofile\": {\n const tlv = parseTLV(data);\n if (!tlv[0]?.[0]) {\n throw new Nip19Error(\"missing TLV 0 for nprofile\");\n }\n if (tlv[0][0].length !== 32) {\n throw new Nip19Error(\"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 const tlv = parseTLV(data);\n if (!tlv[0]?.[0]) {\n throw new Nip19Error(\"missing TLV 0 for nevent\");\n }\n if (tlv[0][0].length !== 32) {\n throw new Nip19Error(\"TLV 0 should be 32 bytes\");\n }\n if (tlv[2]?.[0] && tlv[2][0].length !== 32) {\n throw new Nip19Error(\"TLV 2 should be 32 bytes\");\n }\n if (tlv[3]?.[0] && tlv[3][0].length !== 4) {\n throw new Nip19Error(\"TLV 3 should be 4 bytes\");\n }\n const pointer: EventPointer = {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [],\n };\n const author = tlv[2]?.[0];\n if (author !== undefined) {\n pointer.author = bytesToHex(author);\n }\n const kind = tlv[3]?.[0];\n if (kind !== undefined) {\n pointer.kind = readUint32(kind);\n }\n return { type: \"nevent\", data: pointer };\n }\n case \"naddr\": {\n const tlv = parseTLV(data);\n if (!tlv[0]?.[0]) {\n throw new Nip19Error(\"missing TLV 0 for naddr\");\n }\n if (!tlv[2]?.[0]) {\n throw new Nip19Error(\"missing TLV 2 for naddr\");\n }\n if (tlv[2][0].length !== 32) {\n throw new Nip19Error(\"TLV 2 should be 32 bytes\");\n }\n if (!tlv[3]?.[0]) {\n throw new Nip19Error(\"missing TLV 3 for naddr\");\n }\n if (tlv[3][0].length !== 4) {\n throw new Nip19Error(\"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: readUint32(tlv[3][0]),\n relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [],\n },\n };\n }\n case \"nsec\":\n if (data.length !== 32) {\n throw new Nip19Error(\"nsec must be 32 bytes\");\n }\n return { type: \"nsec\", data };\n case \"npub\":\n case \"note\":\n if (data.length !== 32) {\n throw new Nip19Error(`${prefix} must be 32 bytes`);\n }\n return { type: prefix, data: bytesToHex(data) };\n default:\n throw new Nip19Error(`unknown prefix ${prefix}`);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"nip19.mjs","names":[],"sources":["../../src/nips/nip19.ts"],"sourcesContent":["import { bech32 } from \"@scure/base\";\n\nimport { NostrError, errorMessage } from \"../core/error.ts\";\nimport type { Mutable } from \"../core/util.ts\";\nimport {\n assertByteLength,\n assertHex32,\n bytesToHex,\n hexToBytes,\n utf8Decoder,\n utf8Encoder,\n} from \"../core/util.ts\";\n\n/** Bech32 `nprofile1…` string (TLV profile pointer). */\nexport type NProfile = `nprofile1${string}`;\n/** Bech32 `nevent1…` string (TLV event pointer). */\nexport type NEvent = `nevent1${string}`;\n/** Bech32 `naddr1…` string (TLV address pointer). */\nexport type NAddr = `naddr1${string}`;\n/** Bech32 `nsec1…` string (32-byte secret key). */\nexport type NSec = `nsec1${string}`;\n/** Bech32 `npub1…` string (32-byte public key). */\nexport type NPub = `npub1${string}`;\n/** Bech32 `note1…` string (32-byte event id). */\nexport type Note = `note1${string}`;\n\n/** Maximum bech32 string length accepted by {@link decode} (NIP-19). */\nexport const Bech32MaxSize = 5000;\n\n/** Decoded `nprofile` payload: a pubkey plus optional relay hints. */\nexport type ProfilePointer = {\n readonly pubkey: string;\n readonly relays?: ReadonlyArray<string> | undefined;\n};\n\n/** Decoded `nevent` payload: an event id plus optional relay/author/kind hints. */\nexport type EventPointer = {\n readonly id: string;\n readonly relays?: ReadonlyArray<string> | undefined;\n readonly author?: string | undefined;\n readonly kind?: number | undefined;\n};\n\n/** Decoded `naddr` payload: a replaceable-event coordinate plus optional relay hints. */\nexport type AddressPointer = {\n readonly identifier: string;\n readonly pubkey: string;\n readonly kind: number;\n readonly relays?: ReadonlyArray<string> | undefined;\n};\n\n/** Result of {@link decode}: the bech32 prefix and its decoded payload. */\nexport type DecodedResult =\n | { readonly type: \"nprofile\"; readonly data: ProfilePointer }\n | { readonly type: \"nevent\"; readonly data: EventPointer }\n | { readonly type: \"naddr\"; readonly data: AddressPointer }\n | { readonly type: \"nsec\"; readonly data: Uint8Array }\n | { readonly type: \"npub\"; readonly data: string }\n | { readonly type: \"note\"; readonly data: string };\n\n/** Error thrown by NIP-19 encoding/decoding failures. */\nexport class Nip19Error extends NostrError {\n override name = \"Nip19Error\";\n}\n\ntype TLV = Record<number, Uint8Array[]>;\n\nfunction integerToUint8Array(number: number): Uint8Array {\n const out = new Uint8Array(4);\n new DataView(out.buffer).setUint32(0, number);\n return out;\n}\n\nfunction parseTLV(data: Uint8Array): TLV {\n const result: TLV = {};\n let rest = data;\n while (rest.length > 0) {\n if (rest.length < 2) {\n throw new Nip19Error(\"not enough data to read TLV\");\n }\n const t = rest.at(0);\n const l = rest.at(1);\n if (t === undefined || l === undefined) {\n throw new Nip19Error(\"not enough data to read TLV\");\n }\n const v = rest.slice(2, 2 + l);\n rest = rest.slice(2 + l);\n if (v.length < l) {\n throw new Nip19Error(`not enough data to read on TLV ${t}`);\n }\n result[t] = result[t] ?? [];\n result[t].push(v);\n }\n return result;\n}\n\nfunction assertNip19Kind(kind: number): void {\n if (!Number.isInteger(kind) || kind < 0 || kind > 0xffffffff) {\n throw new Nip19Error(`invalid kind: ${kind}`);\n }\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n const entries: Uint8Array[] = [];\n for (const [t, vs] of Object.entries(tlv).reverse()) {\n for (const v of vs) {\n if (v.length > 255) {\n throw new Nip19Error(\"TLV value exceeds 255 bytes\");\n }\n const entry = new Uint8Array(v.length + 2);\n entry[0] = Math.trunc(Number(t));\n entry[1] = v.length;\n entry.set(v, 2);\n entries.push(entry);\n }\n }\n let total = 0;\n for (const e of entries) {\n total += e.length;\n }\n const out = new Uint8Array(total);\n let offset = 0;\n for (const e of entries) {\n out.set(e, offset);\n offset += e.length;\n }\n return out;\n}\n\nfunction encodeBech32<Prefix extends string>(\n prefix: Prefix,\n data: Uint8Array,\n): `${Prefix}1${string}` {\n const words = bech32.toWords(data);\n // oxlint-disable-next-line no-unsafe-type-assertion -- bech32 output is `${prefix}1…` by construction\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`;\n}\n\nexport function encodeBytes<Prefix extends string>(\n prefix: Prefix,\n bytes: Uint8Array,\n): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes);\n}\n\n/** Encode a 32-byte secret key as `nsec1…`; throws {@link Nip19Error} on wrong length. */\nexport function nsecEncode(key: Uint8Array): NSec {\n assertByteLength(key, 32, \"secret key\");\n return encodeBytes(\"nsec\", key);\n}\n\n/** Encode a hex public key as `npub1…`; throws {@link HexError} on bad hex. */\nexport function npubEncode(hex: string): NPub {\n return encodeBytes(\"npub\", hexToBytes(assertHex32(hex, \"pubkey\")));\n}\n\n/** Encode a hex event id as `note1…`; throws {@link HexError} on bad hex. */\nexport function noteEncode(hex: string): Note {\n return encodeBytes(\"note\", hexToBytes(assertHex32(hex, \"event id\")));\n}\n\n/** Encode a profile pointer as `nprofile1…`. */\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n const data = encodeTLV({\n 0: [hexToBytes(assertHex32(profile.pubkey, \"pubkey\"))],\n 1: (profile.relays ?? []).map((url) => utf8Encoder.encode(url)),\n });\n return encodeBech32(\"nprofile\", data);\n}\n\n/** Encode an event pointer as `nevent1…`. */\nexport function neventEncode(event: EventPointer): NEvent {\n if (event.kind !== undefined) {\n assertNip19Kind(event.kind);\n }\n const kindArray = event.kind === undefined ? undefined : integerToUint8Array(event.kind);\n const data = encodeTLV({\n 0: [hexToBytes(assertHex32(event.id, \"event id\"))],\n 1: (event.relays ?? []).map((url) => utf8Encoder.encode(url)),\n 2:\n event.author !== undefined && event.author !== \"\"\n ? [hexToBytes(assertHex32(event.author, \"author\"))]\n : [],\n 3: kindArray ? [kindArray] : [],\n });\n return encodeBech32(\"nevent\", data);\n}\n\n/** Encode an address pointer as `naddr1…`. */\nexport function naddrEncode(addr: AddressPointer): NAddr {\n assertNip19Kind(addr.kind);\n const kind = integerToUint8Array(addr.kind);\n const data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays ?? []).map((url) => utf8Encoder.encode(url)),\n 2: [hexToBytes(assertHex32(addr.pubkey, \"pubkey\"))],\n 3: [kind],\n });\n return encodeBech32(\"naddr\", data);\n}\n\nfunction readUint32(bytes: Uint8Array): number {\n return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(0);\n}\n\n/** Decode a NIP-19 bech32 entity; throws {@link Nip19Error} on bad input or unknown prefix. */\nexport function decode(code: string): DecodedResult {\n let prefix: string;\n let data: Uint8Array;\n try {\n const { prefix: hrp, words } = bech32.decode(code, Bech32MaxSize);\n prefix = hrp;\n data = new Uint8Array(bech32.fromWords(words));\n } catch (error) {\n throw new Nip19Error(`invalid bech32: ${errorMessage(error)}`, { cause: error });\n }\n\n switch (prefix) {\n case \"nprofile\": {\n const tlv = parseTLV(data);\n if (!tlv[0]?.[0]) {\n throw new Nip19Error(\"missing TLV 0 for nprofile\");\n }\n if (tlv[0][0].length !== 32) {\n throw new Nip19Error(\"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 const tlv = parseTLV(data);\n if (!tlv[0]?.[0]) {\n throw new Nip19Error(\"missing TLV 0 for nevent\");\n }\n if (tlv[0][0].length !== 32) {\n throw new Nip19Error(\"TLV 0 should be 32 bytes\");\n }\n if (tlv[2]?.[0] && tlv[2][0].length !== 32) {\n throw new Nip19Error(\"TLV 2 should be 32 bytes\");\n }\n if (tlv[3]?.[0] && tlv[3][0].length !== 4) {\n throw new Nip19Error(\"TLV 3 should be 4 bytes\");\n }\n const pointer: Mutable<EventPointer> = {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [],\n };\n const author = tlv[2]?.[0];\n if (author !== undefined) {\n pointer.author = bytesToHex(author);\n }\n const kind = tlv[3]?.[0];\n if (kind !== undefined) {\n pointer.kind = readUint32(kind);\n }\n return { type: \"nevent\", data: pointer };\n }\n case \"naddr\": {\n const tlv = parseTLV(data);\n if (!tlv[0]?.[0]) {\n throw new Nip19Error(\"missing TLV 0 for naddr\");\n }\n if (!tlv[2]?.[0]) {\n throw new Nip19Error(\"missing TLV 2 for naddr\");\n }\n if (tlv[2][0].length !== 32) {\n throw new Nip19Error(\"TLV 2 should be 32 bytes\");\n }\n if (!tlv[3]?.[0]) {\n throw new Nip19Error(\"missing TLV 3 for naddr\");\n }\n if (tlv[3][0].length !== 4) {\n throw new Nip19Error(\"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: readUint32(tlv[3][0]),\n relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [],\n },\n };\n }\n case \"nsec\":\n if (data.length !== 32) {\n throw new Nip19Error(\"nsec must be 32 bytes\");\n }\n return { type: \"nsec\", data };\n case \"npub\":\n case \"note\":\n if (data.length !== 32) {\n throw new Nip19Error(`${prefix} must be 32 bytes`);\n }\n return { type: prefix, data: bytesToHex(data) };\n default:\n throw new Nip19Error(`unknown prefix ${prefix}`);\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { a as NostrError } from "../error-BquXDmIN.mjs";
2
- import { r as DecodedResult } from "../nip19-D1OnJ192.mjs";
2
+ import { r as DecodedResult } from "../nip19-DpPN17bY.mjs";
3
3
  //#region src/nips/nip21.d.ts
4
4
  /** Error thrown by {@link parseNostrURI} on malformed or non-decodable URIs. */
5
5
  export declare class Nip21Error extends NostrError {
@@ -9,10 +9,10 @@ export declare class Nip21Error extends NostrError {
9
9
  export declare const NOSTR_URI_REGEX: RegExp;
10
10
  export type NostrURI = {
11
11
  /** Full URI including `nostr:` */
12
- uri: `nostr:${string}`;
12
+ readonly uri: `nostr:${string}`;
13
13
  /** Bech32 entity without prefix */
14
- value: string;
15
- decoded: DecodedResult;
14
+ readonly value: string;
15
+ readonly decoded: DecodedResult;
16
16
  };
17
17
  export declare function isNostrURI(value: unknown): value is `nostr:${string}`;
18
18
  /** Parse and decode a full `nostr:…` URI. NIP-21 excludes `nsec`. */
@@ -1,4 +1,4 @@
1
- import { v as NostrError } from "../util-yFYzlbrm.mjs";
1
+ import { v as NostrError } from "../util-DMF9AIO0.mjs";
2
2
  import { decode } from "./nip19.mjs";
3
3
  //#region src/nips/nip21.ts
4
4
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"nip21.mjs","names":[],"sources":["../../src/nips/nip21.ts"],"sourcesContent":["/**\n * NIP-21: `nostr:` URI scheme\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/21.md\n */\nimport { NostrError } from \"../core/error.ts\";\nimport { decode } from \"./nip19.ts\";\nimport type { DecodedResult } from \"./nip19.ts\";\n\n/** Error thrown by {@link parseNostrURI} on malformed or non-decodable URIs. */\nexport class Nip21Error extends NostrError {\n override name = \"Nip21Error\";\n}\n\n/** Matches `nostr:<bech32>` (not anchored). */\n// oxlint-disable-next-line no-inferrable-types -- isolatedDeclarations requires the annotation for dts emit\nexport const NOSTR_URI_REGEX: RegExp = /nostr:([a-z0-9]+1[02-9ac-hj-np-z]+)/i;\n\nexport type NostrURI = {\n /** Full URI including `nostr:` */\n uri: `nostr:${string}`;\n /** Bech32 entity without prefix */\n value: string;\n decoded: DecodedResult;\n};\n\nexport function isNostrURI(value: unknown): value is `nostr:${string}` {\n if (typeof value !== \"string\") {\n return false;\n }\n if (!/^nostr:[a-z0-9]+1[02-9ac-hj-np-z]+$/i.test(value)) {\n return false;\n }\n return !value.toLowerCase().startsWith(\"nostr:nsec1\");\n}\n\n/** Parse and decode a full `nostr:…` URI. NIP-21 excludes `nsec`. */\nexport function parseNostrURI(uri: string): NostrURI {\n const match = /^nostr:([a-z0-9]+1[02-9ac-hj-np-z]+)$/i.exec(uri);\n const entity = match?.at(1);\n if (entity === undefined) {\n throw new Nip21Error(`invalid Nostr URI: ${uri}`);\n }\n if (entity.toLowerCase().startsWith(\"nsec1\")) {\n throw new Nip21Error(\"NIP-21 identifiers exclude nsec\");\n }\n let decoded: DecodedResult;\n try {\n decoded = decode(entity);\n } catch (error) {\n throw new Nip21Error(`invalid Nostr URI: ${uri}`, { cause: error });\n }\n return {\n uri: `nostr:${entity}`,\n value: entity,\n decoded,\n };\n}\n"],"mappings":";;;;;;;;;AAUA,IAAa,aAAb,cAAgC,WAAW;CACzC,OAAgB;AAClB;;AAIA,MAAa,kBAA0B;AAUvC,SAAgB,WAAW,OAA4C;CACrE,IAAI,OAAO,UAAU,UACnB,OAAO;CAET,IAAI,CAAC,uCAAuC,KAAK,KAAK,GACpD,OAAO;CAET,OAAO,CAAC,MAAM,YAAY,CAAC,CAAC,WAAW,aAAa;AACtD;;AAGA,SAAgB,cAAc,KAAuB;CAEnD,MAAM,SADQ,yCAAyC,KAAK,GACzC,CAAC,EAAE,GAAG,CAAC;CAC1B,IAAI,WAAW,KAAA,GACb,MAAM,IAAI,WAAW,sBAAsB,KAAK;CAElD,IAAI,OAAO,YAAY,CAAC,CAAC,WAAW,OAAO,GACzC,MAAM,IAAI,WAAW,iCAAiC;CAExD,IAAI;CACJ,IAAI;EACF,UAAU,OAAO,MAAM;CACzB,SAAS,OAAO;EACd,MAAM,IAAI,WAAW,sBAAsB,OAAO,EAAE,OAAO,MAAM,CAAC;CACpE;CACA,OAAO;EACL,KAAK,SAAS;EACd,OAAO;EACP;CACF;AACF"}
1
+ {"version":3,"file":"nip21.mjs","names":[],"sources":["../../src/nips/nip21.ts"],"sourcesContent":["/**\n * NIP-21: `nostr:` URI scheme\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/21.md\n */\nimport { NostrError } from \"../core/error.ts\";\nimport { decode } from \"./nip19.ts\";\nimport type { DecodedResult } from \"./nip19.ts\";\n\n/** Error thrown by {@link parseNostrURI} on malformed or non-decodable URIs. */\nexport class Nip21Error extends NostrError {\n override name = \"Nip21Error\";\n}\n\n/** Matches `nostr:<bech32>` (not anchored). */\n// oxlint-disable-next-line no-inferrable-types -- isolatedDeclarations requires the annotation for dts emit\nexport const NOSTR_URI_REGEX: RegExp = /nostr:([a-z0-9]+1[02-9ac-hj-np-z]+)/i;\n\nexport type NostrURI = {\n /** Full URI including `nostr:` */\n readonly uri: `nostr:${string}`;\n /** Bech32 entity without prefix */\n readonly value: string;\n readonly decoded: DecodedResult;\n};\n\nexport function isNostrURI(value: unknown): value is `nostr:${string}` {\n if (typeof value !== \"string\") {\n return false;\n }\n if (!/^nostr:[a-z0-9]+1[02-9ac-hj-np-z]+$/i.test(value)) {\n return false;\n }\n return !value.toLowerCase().startsWith(\"nostr:nsec1\");\n}\n\n/** Parse and decode a full `nostr:…` URI. NIP-21 excludes `nsec`. */\nexport function parseNostrURI(uri: string): NostrURI {\n const match = /^nostr:([a-z0-9]+1[02-9ac-hj-np-z]+)$/i.exec(uri);\n const entity = match?.at(1);\n if (entity === undefined) {\n throw new Nip21Error(`invalid Nostr URI: ${uri}`);\n }\n if (entity.toLowerCase().startsWith(\"nsec1\")) {\n throw new Nip21Error(\"NIP-21 identifiers exclude nsec\");\n }\n let decoded: DecodedResult;\n try {\n decoded = decode(entity);\n } catch (error) {\n throw new Nip21Error(`invalid Nostr URI: ${uri}`, { cause: error });\n }\n return {\n uri: `nostr:${entity}`,\n value: entity,\n decoded,\n };\n}\n"],"mappings":";;;;;;;;;AAUA,IAAa,aAAb,cAAgC,WAAW;CACzC,OAAgB;AAClB;;AAIA,MAAa,kBAA0B;AAUvC,SAAgB,WAAW,OAA4C;CACrE,IAAI,OAAO,UAAU,UACnB,OAAO;CAET,IAAI,CAAC,uCAAuC,KAAK,KAAK,GACpD,OAAO;CAET,OAAO,CAAC,MAAM,YAAY,CAAC,CAAC,WAAW,aAAa;AACtD;;AAGA,SAAgB,cAAc,KAAuB;CAEnD,MAAM,SADQ,yCAAyC,KAAK,GACzC,CAAC,EAAE,GAAG,CAAC;CAC1B,IAAI,WAAW,KAAA,GACb,MAAM,IAAI,WAAW,sBAAsB,KAAK;CAElD,IAAI,OAAO,YAAY,CAAC,CAAC,WAAW,OAAO,GACzC,MAAM,IAAI,WAAW,iCAAiC;CAExD,IAAI;CACJ,IAAI;EACF,UAAU,OAAO,MAAM;CACzB,SAAS,OAAO;EACd,MAAM,IAAI,WAAW,sBAAsB,OAAO,EAAE,OAAO,MAAM,CAAC;CACpE;CACA,OAAO;EACL,KAAK,SAAS;EACd,OAAO;EACP;CACF;AACF"}
@@ -1,36 +1,36 @@
1
1
  import { t as Event } from "../event-DJeb_DIL.mjs";
2
- import { f as ProfilePointer, i as EventPointer, t as AddressPointer } from "../nip19-D1OnJ192.mjs";
2
+ import { f as ProfilePointer, i as EventPointer, t as AddressPointer } from "../nip19-DpPN17bY.mjs";
3
3
  //#region src/nips/nip27.d.ts
4
4
  export type ContentBlock = {
5
- type: "text";
6
- text: string;
5
+ readonly type: "text";
6
+ readonly text: string;
7
7
  } | {
8
- type: "reference";
9
- pointer: ProfilePointer | EventPointer | AddressPointer;
8
+ readonly type: "reference";
9
+ readonly pointer: ProfilePointer | EventPointer | AddressPointer;
10
10
  /**
11
11
  * `true` when the reference had no `nostr:` prefix (see
12
12
  * {@link ParseContentOptions.legacyBech32}).
13
13
  */
14
- bare: boolean;
14
+ readonly bare: boolean;
15
15
  } | {
16
- type: "url";
17
- url: string;
16
+ readonly type: "url";
17
+ readonly url: string;
18
18
  } | {
19
- type: "image" | "video" | "audio";
20
- url: string;
19
+ readonly type: "image" | "video" | "audio";
20
+ readonly url: string;
21
21
  } | {
22
- type: "relay";
23
- url: string;
22
+ readonly type: "relay";
23
+ readonly url: string;
24
24
  } | {
25
- type: "hashtag";
26
- value: string;
25
+ readonly type: "hashtag";
26
+ readonly value: string;
27
27
  } | {
28
- type: "emoji";
29
- shortcode: string;
30
- url: string;
28
+ readonly type: "emoji";
29
+ readonly shortcode: string;
30
+ readonly url: string;
31
31
  } | {
32
- type: "invoice";
33
- bolt11: string;
32
+ readonly type: "invoice";
33
+ readonly bolt11: string;
34
34
  };
35
35
  export type ParseContentOptions = {
36
36
  /**
@@ -10,7 +10,7 @@ const SCAN_BODY = [
10
10
  `(?<relay>wss?://${URL_RUN})`,
11
11
  `(?<invoice>(?:lightning:)?ln(?:bcrt|tbs|bc|tb)(?:\\d+[munp]?)?1[${BECH32_CHARS}]+)`,
12
12
  `(?<hashtag>#[\\p{L}\\p{M}\\p{N}_]{1,42})`,
13
- `(?<emoji>:[A-Za-z0-9_]+:)`
13
+ `(?<emoji>:[A-Za-z0-9_-]+:)`
14
14
  ].join("|");
15
15
  const SCAN = new RegExp(SCAN_BODY, "giu");
16
16
  const SCAN_LEGACY = new RegExp(`${SCAN_BODY}|(?<bare>${NIP19_BARE_PREFIX}[${BECH32_CHARS}]+)`, "giu");
@@ -178,7 +178,7 @@ function parseContent(content, opts) {
178
178
  bolt11: (token.toLowerCase().startsWith("lightning:") ? token.slice(10) : token).toLowerCase()
179
179
  };
180
180
  } else if (g?.["hashtag"] !== void 0) {
181
- if (!isChar(start === 0 ? void 0 : text.codePointAt(start - 1), TAG_CHAR)) block = {
181
+ if (!isChar(start === 0 ? void 0 : text.codePointAt(start - 1), TAG_CHAR) && !isChar(text.codePointAt(end), TAG_CHAR)) block = {
182
182
  type: "hashtag",
183
183
  value: token.slice(1)
184
184
  };