@qntx/nostr 0.0.1 → 0.2.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 (187) hide show
  1. package/dist/abort-Ba8tDrOI.mjs +38 -0
  2. package/dist/abort-Ba8tDrOI.mjs.map +1 -0
  3. package/dist/{builder-BphJa-Y-.d.mts → builder-BWn55Paf.d.mts} +20 -14
  4. package/dist/{builder-q0VsvnYE.mjs → builder-CyrGKRVP.mjs} +32 -16
  5. package/dist/builder-CyrGKRVP.mjs.map +1 -0
  6. package/dist/{client-Bd8B1mYm.mjs → client-BWsX9Cv1.mjs} +354 -195
  7. package/dist/client-BWsX9Cv1.mjs.map +1 -0
  8. package/dist/client.d.mts +1 -1
  9. package/dist/client.mjs +1 -1
  10. package/dist/core.d.mts +8 -8
  11. package/dist/core.mjs +8 -9
  12. package/dist/error-BW7re1UN.d.mts +9 -0
  13. package/dist/error-B__OMBRY.mjs +14 -0
  14. package/dist/error-B__OMBRY.mjs.map +1 -0
  15. package/dist/{error-WEFS-R-4.d.mts → error-CR8Urc84.d.mts} +20 -8
  16. package/dist/{error-CwBxle6N.mjs → error-DrEIM7FO.mjs} +5 -3
  17. package/dist/error-DrEIM7FO.mjs.map +1 -0
  18. package/dist/{event-CzoQEFMF.mjs → event-D8Nfoh4K.mjs} +40 -32
  19. package/dist/event-D8Nfoh4K.mjs.map +1 -0
  20. package/dist/{event-B5D2jxt_.d.mts → event-fU3Y01PR.d.mts} +23 -20
  21. package/dist/{filter-BxwjEkZp.mjs → filter-BQl3GlHt.mjs} +42 -35
  22. package/dist/filter-BQl3GlHt.mjs.map +1 -0
  23. package/dist/filter-C0IMByE3.d.mts +37 -0
  24. package/dist/{gossip-C5RVB1UB.d.mts → gossip-BRQwIM_q.d.mts} +25 -23
  25. package/dist/{gossip-3xkRRCm_.mjs → gossip-oloDMWEj.mjs} +52 -34
  26. package/dist/gossip-oloDMWEj.mjs.map +1 -0
  27. package/dist/gossip.d.mts +1 -1
  28. package/dist/gossip.mjs +1 -1
  29. package/dist/{http-6vevbBlu.d.mts → http-C4HwIu4B.d.mts} +7 -7
  30. package/dist/{http-D2rhokZo.mjs → http-CuazNRIP.mjs} +10 -6
  31. package/dist/http-CuazNRIP.mjs.map +1 -0
  32. package/dist/index-B425CAcQ.d.mts +328 -0
  33. package/dist/index-BVyfUBuG.d.mts +181 -0
  34. package/dist/{index-BYMnhRIC.d.mts → index-Ba7bJ7DD.d.mts} +68 -50
  35. package/dist/{index-DaRyjo7O.d.mts → index-Boe8FshM.d.mts} +13 -7
  36. package/dist/index-CUIvFQdE.d.mts +73 -0
  37. package/dist/index-JdaS_uce.d.mts +207 -0
  38. package/dist/index.d.mts +22 -20
  39. package/dist/index.mjs +19 -18
  40. package/dist/{key-Dn-aX4x4.mjs → key-Bbtys6o7.mjs} +22 -14
  41. package/dist/key-Bbtys6o7.mjs.map +1 -0
  42. package/dist/{key-BiGxGLhg.d.mts → key-BlsYhN1V.d.mts} +9 -6
  43. package/dist/{kind-BLl4cLOc.mjs → kind-Cxwhhkx8.mjs} +2 -1
  44. package/dist/kind-Cxwhhkx8.mjs.map +1 -0
  45. package/dist/{loaders-BNQszDAn.mjs → loaders-o6YXB_Ri.mjs} +329 -305
  46. package/dist/loaders-o6YXB_Ri.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 +46 -0
  50. package/dist/memory-C2EVx0_O.mjs.map +1 -0
  51. package/dist/{memory-BCmhZPek.mjs → memory-index-Do1mz0WF.mjs} +212 -82
  52. package/dist/memory-index-Do1mz0WF.mjs.map +1 -0
  53. package/dist/{message-C_Uj-Y-c.mjs → message-DcY6Fi9o.mjs} +38 -24
  54. package/dist/message-DcY6Fi9o.mjs.map +1 -0
  55. package/dist/{message-DJC-Jz6T.d.mts → message-iGPIqnn0.d.mts} +15 -8
  56. package/dist/{nip17-BWq-Kfq5.d.mts → nip17-DNEkz8rM.d.mts} +18 -17
  57. package/dist/{nip19-D7905oIv.d.mts → nip19-BevCJZsp.d.mts} +23 -3
  58. package/dist/{nip46-C_DoxiS_.d.mts → nip46-DDV4dC56.d.mts} +13 -12
  59. package/dist/{nip59-DljW_sYh.d.mts → nip59-zQgdLcEr.d.mts} +28 -25
  60. package/dist/{nip65-Di5hZRuV.d.mts → nip65-DBfh2smt.d.mts} +8 -3
  61. package/dist/{nip77-ByxlgoQO.d.mts → nip77-DH4RhS5r.d.mts} +9 -8
  62. package/dist/nips/blossom.d.mts +37 -37
  63. package/dist/nips/blossom.mjs +67 -52
  64. package/dist/nips/blossom.mjs.map +1 -1
  65. package/dist/nips/nip04.d.mts +2 -3
  66. package/dist/nips/nip04.mjs +6 -10
  67. package/dist/nips/nip04.mjs.map +1 -1
  68. package/dist/nips/nip05.d.mts +37 -43
  69. package/dist/nips/nip05.mjs +57 -57
  70. package/dist/nips/nip05.mjs.map +1 -1
  71. package/dist/nips/nip10.d.mts +18 -19
  72. package/dist/nips/nip10.mjs +76 -61
  73. package/dist/nips/nip10.mjs.map +1 -1
  74. package/dist/nips/nip11.d.mts +9 -8
  75. package/dist/nips/nip11.mjs +14 -11
  76. package/dist/nips/nip11.mjs.map +1 -1
  77. package/dist/nips/nip13.d.mts +9 -9
  78. package/dist/nips/nip13.mjs +15 -17
  79. package/dist/nips/nip13.mjs.map +1 -1
  80. package/dist/nips/nip17.d.mts +1 -1
  81. package/dist/nips/nip17.mjs +17 -12
  82. package/dist/nips/nip17.mjs.map +1 -1
  83. package/dist/nips/nip19.d.mts +1 -1
  84. package/dist/nips/nip19.mjs +52 -29
  85. package/dist/nips/nip19.mjs.map +1 -1
  86. package/dist/nips/nip21.d.mts +5 -6
  87. package/dist/nips/nip21.mjs +8 -7
  88. package/dist/nips/nip21.mjs.map +1 -1
  89. package/dist/nips/nip27.d.mts +7 -8
  90. package/dist/nips/nip27.mjs +26 -25
  91. package/dist/nips/nip27.mjs.map +1 -1
  92. package/dist/nips/nip42.d.mts +5 -6
  93. package/dist/nips/nip42.mjs +3 -3
  94. package/dist/nips/nip42.mjs.map +1 -1
  95. package/dist/nips/nip44.d.mts +24 -7
  96. package/dist/nips/nip44.mjs +25 -15
  97. package/dist/nips/nip44.mjs.map +1 -1
  98. package/dist/nips/nip46.d.mts +1 -1
  99. package/dist/nips/nip46.mjs +52 -49
  100. package/dist/nips/nip46.mjs.map +1 -1
  101. package/dist/nips/nip49.d.mts +8 -7
  102. package/dist/nips/nip49.mjs +16 -12
  103. package/dist/nips/nip49.mjs.map +1 -1
  104. package/dist/nips/nip51.d.mts +25 -27
  105. package/dist/nips/nip51.mjs +47 -36
  106. package/dist/nips/nip51.mjs.map +1 -1
  107. package/dist/nips/nip57.d.mts +12 -13
  108. package/dist/nips/nip57.mjs +35 -38
  109. package/dist/nips/nip57.mjs.map +1 -1
  110. package/dist/nips/nip59.d.mts +1 -1
  111. package/dist/nips/nip59.mjs +14 -18
  112. package/dist/nips/nip59.mjs.map +1 -1
  113. package/dist/nips/nip65.d.mts +1 -1
  114. package/dist/nips/nip65.mjs +11 -8
  115. package/dist/nips/nip65.mjs.map +1 -1
  116. package/dist/nips/nip77.d.mts +1 -1
  117. package/dist/nips/nip77.mjs +56 -34
  118. package/dist/nips/nip77.mjs.map +1 -1
  119. package/dist/nips/nip96.d.mts +21 -12
  120. package/dist/nips/nip96.mjs +59 -36
  121. package/dist/nips/nip96.mjs.map +1 -1
  122. package/dist/nips/nip98.d.mts +12 -12
  123. package/dist/nips/nip98.mjs +18 -19
  124. package/dist/nips/nip98.mjs.map +1 -1
  125. package/dist/{nostr_crypto_wasm_bg-hi5aXi5P.mjs → nostr_crypto_wasm_bg-Czrdty7Q.mjs} +1 -1
  126. package/dist/nostr_crypto_wasm_bg.wasm +0 -0
  127. package/dist/{pool-C_j1OmBB.mjs → pool-XmAGaufS.mjs} +611 -487
  128. package/dist/pool-XmAGaufS.mjs.map +1 -0
  129. package/dist/pool-tEr7c5bG.d.mts +302 -0
  130. package/dist/reactive-DDlThDSZ.mjs +324 -0
  131. package/dist/reactive-DDlThDSZ.mjs.map +1 -0
  132. package/dist/reactive-DFpqtIf_.d.mts +66 -0
  133. package/dist/relay.d.mts +5 -4
  134. package/dist/relay.mjs +2 -2
  135. package/dist/report-CHld4uWj.mjs +32 -0
  136. package/dist/report-CHld4uWj.mjs.map +1 -0
  137. package/dist/{signer-CZ6K6FUc.mjs → signer-CKR9EHce.mjs} +107 -72
  138. package/dist/signer-CKR9EHce.mjs.map +1 -0
  139. package/dist/signer.d.mts +3 -3
  140. package/dist/signer.mjs +3 -2
  141. package/dist/storage-xXxLGCVb.mjs +1376 -0
  142. package/dist/storage-xXxLGCVb.mjs.map +1 -0
  143. package/dist/storage.d.mts +4 -4
  144. package/dist/storage.mjs +5 -4
  145. package/dist/store.d.mts +2 -0
  146. package/dist/store.mjs +2 -0
  147. package/dist/testing.d.mts +125 -0
  148. package/dist/testing.mjs +957 -0
  149. package/dist/testing.mjs.map +1 -0
  150. package/dist/types-2pCUprRU.d.mts +47 -0
  151. package/dist/types-CRQEk0Oi.d.mts +19 -0
  152. package/dist/util-LfQirgDk.mjs +113 -0
  153. package/dist/util-LfQirgDk.mjs.map +1 -0
  154. package/dist/wasm.d.mts +4 -4
  155. package/dist/wasm.mjs +55 -56
  156. package/dist/wasm.mjs.map +1 -1
  157. package/dist/websocket-CmeqvAkp.d.mts +27 -0
  158. package/package.json +31 -9
  159. package/dist/builder-q0VsvnYE.mjs.map +0 -1
  160. package/dist/client-Bd8B1mYm.mjs.map +0 -1
  161. package/dist/error-B49rbDzT.d.mts +0 -7
  162. package/dist/error-CwBxle6N.mjs.map +0 -1
  163. package/dist/error-DZEs5OuZ.mjs +0 -24
  164. package/dist/error-DZEs5OuZ.mjs.map +0 -1
  165. package/dist/event-CzoQEFMF.mjs.map +0 -1
  166. package/dist/filter-BxwjEkZp.mjs.map +0 -1
  167. package/dist/filter-DUEKP3q1.d.mts +0 -40
  168. package/dist/gossip-3xkRRCm_.mjs.map +0 -1
  169. package/dist/http-D2rhokZo.mjs.map +0 -1
  170. package/dist/index-C0C4e-Gn.d.mts +0 -55
  171. package/dist/index-DgOugrpF.d.mts +0 -275
  172. package/dist/index-EwL6fHLo.d.mts +0 -267
  173. package/dist/index-k2YhCgsh.d.mts +0 -57
  174. package/dist/key-Dn-aX4x4.mjs.map +0 -1
  175. package/dist/kind-BLl4cLOc.mjs.map +0 -1
  176. package/dist/loaders-BNQszDAn.mjs.map +0 -1
  177. package/dist/memory-BCmhZPek.mjs.map +0 -1
  178. package/dist/message-C_Uj-Y-c.mjs.map +0 -1
  179. package/dist/pool-C_j1OmBB.mjs.map +0 -1
  180. package/dist/pool-DhRi7l-b.d.mts +0 -297
  181. package/dist/signer-CZ6K6FUc.mjs.map +0 -1
  182. package/dist/storage-DOy0iLRE.mjs +0 -870
  183. package/dist/storage-DOy0iLRE.mjs.map +0 -1
  184. package/dist/types-BzyADqnw.d.mts +0 -19
  185. package/dist/types-Dn24TPFs.d.mts +0 -43
  186. package/dist/util-6tfLQ9JF.mjs +0 -73
  187. package/dist/util-6tfLQ9JF.mjs.map +0 -1
@@ -1,85 +1,94 @@
1
- import { a as isHex32 } from "../util-6tfLQ9JF.mjs";
2
- import { n as EventValidationError } from "../error-DZEs5OuZ.mjs";
3
- import { t as Kind } from "../kind-BLl4cLOc.mjs";
4
- import { g as formatEventAddress, m as Tag, y as parseEventAddress } from "../event-CzoQEFMF.mjs";
5
- import { t as EventBuilder } from "../builder-q0VsvnYE.mjs";
1
+ import { o as isHex32, p as EventValidationError } from "../util-LfQirgDk.mjs";
2
+ import { t as Kind } from "../kind-Cxwhhkx8.mjs";
3
+ import { _ as formatEventAddress, b as parseEventAddress, h as Tag } from "../event-D8Nfoh4K.mjs";
4
+ import { t as EventBuilder } from "../builder-CyrGKRVP.mjs";
6
5
  //#region src/nips/nip10.ts
7
6
  /**
8
7
  * NIP-10: Text Notes and Threads
8
+ *
9
9
  * @see https://github.com/nostr-protocol/nips/blob/master/10.md
10
10
  */
11
+ function eTagAuthor(tag) {
12
+ for (const author of [tag[4], tag[3]]) if (author !== void 0 && isHex32(author.toLowerCase())) return author.toLowerCase();
13
+ }
11
14
  function eventPointerFromETag(tag) {
12
- if (tag[0] !== "e" || !tag[1] || !isHex32(tag[1])) return void 0;
13
- const author = tag[4] && isHex32(tag[4]) ? tag[4].toLowerCase() : tag[3] && isHex32(tag[3]) ? tag[3].toLowerCase() : void 0;
14
- return {
15
- id: tag[1].toLowerCase(),
16
- relays: tag[2] ? [tag[2]] : [],
17
- author
15
+ const id = tag.at(1);
16
+ if (tag[0] !== "e" || id === void 0 || !isHex32(id.toLowerCase())) return;
17
+ const pointer = {
18
+ id: id.toLowerCase(),
19
+ relays: tag[2] !== void 0 && tag[2] !== "" ? [tag[2]] : []
18
20
  };
21
+ const author = eTagAuthor(tag);
22
+ if (author !== void 0) pointer.author = author;
23
+ return pointer;
19
24
  }
20
25
  function quoteFromQTag(tag) {
21
- if (tag[0] !== "q" || !tag[1]) return void 0;
22
- if (isHex32(tag[1])) {
26
+ const value = tag.at(1);
27
+ if (tag[0] !== "q" || value === void 0 || value === "") return;
28
+ const relays = tag[2] !== void 0 && tag[2] !== "" ? [tag[2]] : [];
29
+ if (isHex32(value.toLowerCase())) {
23
30
  const pointer = {
24
- id: tag[1].toLowerCase(),
25
- relays: tag[2] ? [tag[2]] : []
31
+ id: value.toLowerCase(),
32
+ relays
26
33
  };
27
- if (tag[3] && isHex32(tag[3])) pointer.author = tag[3].toLowerCase();
34
+ const author = tag.at(3);
35
+ if (author !== void 0 && isHex32(author.toLowerCase())) pointer.author = author.toLowerCase();
28
36
  return pointer;
29
37
  }
30
- const addr = parseEventAddress(tag[1]);
31
- if (!addr) return void 0;
38
+ const addr = parseEventAddress(value);
39
+ if (!addr) return;
32
40
  return {
33
41
  identifier: addr.identifier,
34
42
  pubkey: addr.pubkey,
35
43
  kind: addr.kind,
36
- relays: tag[2] ? [tag[2]] : []
44
+ relays
37
45
  };
38
46
  }
39
47
  function quoteToTag(quote) {
40
48
  if (typeof quote === "string") {
41
- if (isHex32(quote)) return { tag: ["q", quote.toLowerCase()] };
49
+ if (isHex32(quote.toLowerCase())) return { tag: ["q", quote.toLowerCase()] };
42
50
  const addr = parseEventAddress(quote);
43
- if (!addr) return void 0;
51
+ if (!addr) return;
44
52
  return { tag: ["q", formatEventAddress(addr.kind, addr.pubkey, addr.identifier)] };
45
53
  }
46
54
  if ("id" in quote) {
47
55
  const id = quote.id.toLowerCase();
48
56
  const relay = quote.relays?.[0];
49
- const author = quote.author && isHex32(quote.author) ? quote.author.toLowerCase() : void 0;
57
+ const author = quote.author !== void 0 && isHex32(quote.author.toLowerCase()) ? quote.author.toLowerCase() : void 0;
58
+ let tag;
59
+ if (author === void 0) tag = relay !== void 0 && relay !== "" ? [
60
+ "q",
61
+ id,
62
+ relay
63
+ ] : ["q", id];
64
+ else tag = [
65
+ "q",
66
+ id,
67
+ relay ?? "",
68
+ author
69
+ ];
50
70
  return {
51
- tag: author !== void 0 ? [
52
- "q",
53
- id,
54
- relay ?? "",
55
- author
56
- ] : relay ? [
57
- "q",
58
- id,
59
- relay
60
- ] : ["q", id],
71
+ tag,
61
72
  author,
62
- relay: relay || void 0
73
+ relay
63
74
  };
64
75
  }
65
76
  const coord = formatEventAddress(quote.kind, quote.pubkey, quote.identifier);
66
77
  const relay = quote.relays?.[0];
67
78
  return {
68
- tag: relay ? [
79
+ tag: relay !== void 0 && relay !== "" ? [
69
80
  "q",
70
81
  coord,
71
82
  relay
72
83
  ] : ["q", coord],
73
84
  author: quote.pubkey,
74
- relay: relay || void 0
85
+ relay
75
86
  };
76
87
  }
77
88
  function assertKind1Parent(parent) {
78
89
  if (parent.kind !== Kind.TextNote) throw new EventValidationError("NIP-10 replyTo is for kind 1");
79
90
  }
80
- /**
81
- * Parse NIP-10 thread markers and legacy positional e-tags from an event.
82
- */
91
+ /** Parse NIP-10 thread markers and legacy positional e-tags from an event. */
83
92
  function parseThreadTags(event) {
84
93
  const result = {
85
94
  root: void 0,
@@ -92,9 +101,12 @@ function parseThreadTags(event) {
92
101
  let maybeRoot;
93
102
  for (let i = event.tags.length - 1; i >= 0; i--) {
94
103
  const tag = event.tags[i];
95
- if (tag[0] === "e" && tag[1] && isHex32(tag[1])) {
104
+ if (tag === void 0) continue;
105
+ const eValue = tag.at(1);
106
+ if (tag[0] === "e" && eValue !== void 0 && isHex32(eValue.toLowerCase())) {
96
107
  const pointer = eventPointerFromETag(tag);
97
- const marker = tag[3];
108
+ if (pointer === void 0) continue;
109
+ const marker = tag.at(3);
98
110
  if (marker === "root") {
99
111
  result.root = pointer;
100
112
  continue;
@@ -103,12 +115,12 @@ function parseThreadTags(event) {
103
115
  result.reply = pointer;
104
116
  continue;
105
117
  }
106
- if (marker && !isHex32(marker)) {
118
+ if (marker !== void 0 && marker !== "" && !isHex32(marker.toLowerCase())) {
107
119
  result.mentions.push(pointer);
108
120
  continue;
109
121
  }
110
- if (!maybeParent) maybeParent = pointer;
111
- else maybeRoot = pointer;
122
+ if (maybeParent) maybeRoot = pointer;
123
+ else maybeParent = pointer;
112
124
  result.mentions.push(pointer);
113
125
  continue;
114
126
  }
@@ -117,13 +129,14 @@ function parseThreadTags(event) {
117
129
  if (quote) result.quotes.push(quote);
118
130
  continue;
119
131
  }
120
- if (tag[0] === "p" && tag[1] && isHex32(tag[1])) result.profiles.push({
121
- pubkey: tag[1].toLowerCase(),
122
- relays: tag[2] ? [tag[2]] : []
132
+ const pValue = tag.at(1);
133
+ if (tag[0] === "p" && pValue !== void 0 && isHex32(pValue.toLowerCase())) result.profiles.push({
134
+ pubkey: pValue.toLowerCase(),
135
+ relays: tag[2] !== void 0 && tag[2] !== "" ? [tag[2]] : []
123
136
  });
124
137
  }
125
- if (!result.root) result.root = maybeRoot ?? maybeParent ?? result.reply;
126
- if (!result.reply) result.reply = maybeParent ?? result.root;
138
+ result.root ??= maybeRoot ?? maybeParent ?? result.reply;
139
+ result.reply ??= maybeParent ?? result.root;
127
140
  const drop = new Set([result.root?.id, result.reply?.id].filter((id) => Boolean(id)));
128
141
  result.mentions = result.mentions.filter((m) => !drop.has(m.id));
129
142
  for (const ref of [
@@ -131,18 +144,20 @@ function parseThreadTags(event) {
131
144
  result.root,
132
145
  ...result.mentions
133
146
  ]) {
134
- if (!ref?.author) continue;
135
- const author = result.profiles.find((p) => p.pubkey === ref.author);
136
- if (!author?.relays?.length) continue;
147
+ if (ref === void 0) continue;
148
+ 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;
137
152
  const relays = [...ref.relays ?? []];
138
- for (const url of author.relays) if (!relays.includes(url)) relays.push(url);
153
+ for (const url of profileRelays) if (!relays.includes(url)) relays.push(url);
139
154
  ref.relays = relays;
140
155
  }
141
156
  return result;
142
157
  }
143
158
  /**
144
- * Build NIP-10 e/p tags for a reply to `parent`.
145
- * Uses marked tags (`root` / `reply`) per preferred modern style.
159
+ * Build NIP-10 e/p tags for a reply to `parent`. Uses marked tags (`root` / `reply`) per preferred
160
+ * modern style.
146
161
  */
147
162
  function buildReplyTags(opts) {
148
163
  assertKind1Parent(opts.parent);
@@ -155,31 +170,31 @@ function buildReplyTags(opts) {
155
170
  const parentIsRoot = root.id.toLowerCase() === opts.parent.id.toLowerCase();
156
171
  const tags = [];
157
172
  const rootRelay = root.relays?.[0] ?? opts.relayHint ?? "";
158
- tags.push(Tag.e(root.id, rootRelay, "root", root.author ?? opts.parent.pubkey));
173
+ tags.push(Tag.e(root.id, rootRelay, "root", root.author));
159
174
  if (!parentIsRoot) tags.push(Tag.e(opts.parent.id, opts.relayHint ?? "", "reply", opts.parent.pubkey));
160
175
  const pSeen = /* @__PURE__ */ new Set();
161
176
  const addP = (pk, relay) => {
162
177
  const key = pk.toLowerCase();
163
178
  if (pSeen.has(key)) return;
164
179
  pSeen.add(key);
165
- tags.push(Tag.p(pk, relay || void 0));
180
+ tags.push(Tag.p(pk, relay ?? void 0));
166
181
  };
167
- if (root.author) addP(root.author, root.relays?.[0]);
182
+ if (root.author !== void 0 && root.author !== "") addP(root.author, root.relays?.[0]);
168
183
  addP(opts.parent.pubkey, opts.relayHint);
169
184
  for (const p of thread.profiles) addP(p.pubkey, p.relays?.[0]);
170
185
  const qTags = [];
171
186
  for (const quote of opts.quotes ?? []) {
172
187
  const built = quoteToTag(quote);
173
- if (!built) continue;
174
- if (built.author) addP(built.author, built.relay);
188
+ if (built === void 0) continue;
189
+ if (built.author !== void 0 && built.author !== "") addP(built.author, built.relay);
175
190
  qTags.push(built.tag);
176
191
  }
177
192
  tags.push(...qTags);
178
193
  return tags;
179
194
  }
180
195
  /**
181
- * Build an {@link EventBuilder} reply with NIP-10 tags.
182
- * Lives here (not on EventBuilder) so core does not depend on nips.
196
+ * Build an {@link EventBuilder} reply with NIP-10 tags. Lives here (not on EventBuilder) so core
197
+ * does not depend on nips.
183
198
  */
184
199
  function replyTo(parent, content, opts) {
185
200
  return EventBuilder.textNote(content).tags(buildReplyTags({
@@ -1 +1 @@
1
- {"version":3,"file":"nip10.mjs","names":[],"sources":["../../src/nips/nip10.ts"],"sourcesContent":["/**\n * NIP-10: Text Notes and Threads\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\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 eventPointerFromETag(tag: readonly string[]): EventPointer | undefined {\n if (tag[0] !== \"e\" || !tag[1] || !isHex32(tag[1])) return undefined;\n // NIP-10 5-tuple pubkey is index 4; NIP-01 4-tuple pubkey is index 3.\n const author =\n tag[4] && isHex32(tag[4])\n ? tag[4].toLowerCase()\n : tag[3] && isHex32(tag[3])\n ? tag[3].toLowerCase()\n : undefined;\n return {\n id: tag[1].toLowerCase(),\n relays: tag[2] ? [tag[2]] : [],\n author,\n };\n}\n\nfunction quoteFromQTag(tag: readonly string[]): EventPointer | AddressPointer | undefined {\n if (tag[0] !== \"q\" || !tag[1]) return undefined;\n if (isHex32(tag[1])) {\n const pointer: EventPointer = {\n id: tag[1].toLowerCase(),\n relays: tag[2] ? [tag[2]] : [],\n };\n if (tag[3] && isHex32(tag[3])) pointer.author = tag[3].toLowerCase();\n return pointer;\n }\n const addr = parseEventAddress(tag[1]);\n if (!addr) return undefined;\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: tag[2] ? [tag[2]] : [],\n };\n}\n\nfunction quoteToTag(quote: QuoteInput): { tag: Tag; author?: string; relay?: string } | undefined {\n if (typeof quote === \"string\") {\n if (isHex32(quote)) return { tag: [\"q\", quote.toLowerCase()] };\n const addr = parseEventAddress(quote);\n if (!addr) return undefined;\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 = quote.author && isHex32(quote.author) ? quote.author.toLowerCase() : undefined;\n const tag: Tag =\n author !== undefined ? [\"q\", id, relay ?? \"\", author] : relay ? [\"q\", id, relay] : [\"q\", id];\n return { tag, author, relay: relay || undefined };\n }\n const coord = formatEventAddress(quote.kind, quote.pubkey, quote.identifier);\n const relay = quote.relays?.[0];\n const tag: Tag = relay ? [\"q\", coord, relay] : [\"q\", coord];\n return { tag, author: quote.pubkey, relay: relay || undefined };\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/**\n * Parse NIP-10 thread markers and legacy positional e-tags from an event.\n */\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\n if (tag[0] === \"e\" && tag[1] && isHex32(tag[1])) {\n const pointer = eventPointerFromETag(tag)!;\n const marker = tag[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 && !isHex32(marker)) {\n result.mentions.push(pointer);\n continue;\n }\n\n // Legacy positional: last unmarked is parent, second-to-last is root.\n if (!maybeParent) maybeParent = pointer;\n else maybeRoot = pointer;\n result.mentions.push(pointer);\n continue;\n }\n\n if (tag[0] === \"q\") {\n const quote = quoteFromQTag(tag);\n if (quote) result.quotes.push(quote);\n continue;\n }\n\n if (tag[0] === \"p\" && tag[1] && isHex32(tag[1])) {\n result.profiles.push({\n pubkey: tag[1].toLowerCase(),\n relays: tag[2] ? [tag[2]] : [],\n });\n }\n }\n\n if (!result.root) {\n result.root = maybeRoot ?? maybeParent ?? result.reply;\n }\n if (!result.reply) {\n result.reply = maybeParent ?? result.root;\n }\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?.author) continue;\n const author = result.profiles.find((p) => p.pubkey === ref.author);\n if (!author?.relays?.length) continue;\n const relays = [...(ref.relays ?? [])];\n for (const url of author.relays) {\n if (!relays.includes(url)) relays.push(url);\n }\n ref.relays = relays;\n }\n\n return result;\n}\n\nexport type ReplyTagsOptions = {\n /** Parent event being replied to. */\n parent: ReplyParent;\n /** Optional relay hint for the parent e-tag. */\n relayHint?: string;\n /** Quoted events (`q` tags): hex ids, `kind:pubkey:d` coords, or pointers. */\n quotes?: QuoteInput[];\n};\n\n/**\n * Build NIP-10 e/p tags for a reply to `parent`.\n * Uses marked tags (`root` / `reply`) per preferred 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 ?? opts.parent.pubkey));\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)) return;\n pSeen.add(key);\n tags.push(Tag.p(pk, relay || undefined));\n };\n if (root.author) addP(root.author, root.relays?.[0]);\n addP(opts.parent.pubkey, opts.relayHint);\n for (const p of thread.profiles) addP(p.pubkey, p.relays?.[0]);\n\n const qTags: Tag[] = [];\n for (const quote of opts.quotes ?? []) {\n const built = quoteToTag(quote);\n if (!built) continue;\n if (built.author) addP(built.author, built.relay);\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.\n * Lives here (not on EventBuilder) so core 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 { 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,8 +1,8 @@
1
- import { a as NostrError } from "../error-WEFS-R-4.mjs";
2
- import { t as ManualFetch } from "../http-6vevbBlu.mjs";
1
+ import { a as NostrError } from "../error-CR8Urc84.mjs";
2
+ import { t as ManualFetch } from "../http-C4HwIu4B.mjs";
3
3
  //#region src/nips/nip11.d.ts
4
- type Nip11Fetch = ManualFetch;
5
- type RelayInformation = {
4
+ export type Nip11Fetch = ManualFetch;
5
+ export type RelayInformation = {
6
6
  name?: string;
7
7
  description?: string;
8
8
  banner?: string;
@@ -31,13 +31,14 @@ type RelayInformation = {
31
31
  payments_url?: string;
32
32
  terms_of_service?: string;
33
33
  };
34
- declare class Nip11Error extends NostrError {}
34
+ export declare class Nip11Error extends NostrError {
35
+ name: string;
36
+ }
35
37
  /** Convert a relay websocket URL to the HTTP URL that serves the NIP-11 document. */
36
- declare function relayInfoHttpUrl(wsUrl: string): string;
37
- declare function fetchRelayInformation(wsUrl: string, opts?: {
38
+ export declare function relayInfoHttpUrl(wsUrl: string): string;
39
+ export declare function fetchRelayInformation(wsUrl: string, opts?: {
38
40
  fetch?: Nip11Fetch;
39
41
  signal?: AbortSignal;
40
42
  }): Promise<RelayInformation>;
41
43
  //#endregion
42
- export { Nip11Error, Nip11Fetch, RelayInformation, fetchRelayInformation, relayInfoHttpUrl };
43
44
  //# sourceMappingURL=nip11.d.mts.map
@@ -1,8 +1,9 @@
1
- import { a as NostrError } from "../error-DZEs5OuZ.mjs";
2
- import { n as requireGlobalFetch, t as fetchManual } from "../http-D2rhokZo.mjs";
1
+ import { c as isRecord, g as NostrError } from "../util-LfQirgDk.mjs";
2
+ import { n as requireGlobalFetch, t as fetchManual } from "../http-CuazNRIP.mjs";
3
3
  //#region src/nips/nip11.ts
4
4
  /**
5
5
  * NIP-11: Relay Information Document
6
+ *
6
7
  * @see https://github.com/nostr-protocol/nips/blob/master/11.md
7
8
  */
8
9
  const ACCEPT = "application/nostr+json";
@@ -36,14 +37,16 @@ const LIMITATION_BOOLEANS = [
36
37
  "payment_required",
37
38
  "restricted_writes"
38
39
  ];
39
- var Nip11Error = class extends NostrError {};
40
+ var Nip11Error = class extends NostrError {
41
+ name = "Nip11Error";
42
+ };
40
43
  /** Convert a relay websocket URL to the HTTP URL that serves the NIP-11 document. */
41
44
  function relayInfoHttpUrl(wsUrl) {
42
45
  let url;
43
46
  try {
44
47
  url = new URL(wsUrl);
45
- } catch (cause) {
46
- throw new Nip11Error(`invalid relay URL: ${wsUrl}`, { cause: cause instanceof Error ? cause : void 0 });
48
+ } catch (error) {
49
+ throw new Nip11Error(`invalid relay URL: ${wsUrl}`, { cause: error instanceof Error ? error : void 0 });
47
50
  }
48
51
  if (url.protocol === "wss:") url.protocol = "https:";
49
52
  else if (url.protocol === "ws:") url.protocol = "http:";
@@ -54,16 +57,16 @@ function isNonNegativeInteger(value) {
54
57
  return typeof value === "number" && Number.isInteger(value) && value >= 0;
55
58
  }
56
59
  function parseRelayInformation(json) {
57
- if (json === null || typeof json !== "object" || Array.isArray(json)) throw new Nip11Error("relay information document must be a JSON object");
60
+ if (!isRecord(json)) throw new Nip11Error("relay information document must be a JSON object");
58
61
  const raw = json;
59
62
  const info = {};
60
63
  for (const key of STRING_FIELDS) {
61
64
  const value = raw[key];
62
65
  if (typeof value === "string") info[key] = value;
63
66
  }
64
- if (Array.isArray(raw.supported_nips)) info.supported_nips = raw.supported_nips.filter(isNonNegativeInteger);
65
- if (raw.limitation && typeof raw.limitation === "object" && !Array.isArray(raw.limitation)) {
66
- const rawLim = raw.limitation;
67
+ if (Array.isArray(raw["supported_nips"])) info.supported_nips = raw["supported_nips"].filter(isNonNegativeInteger);
68
+ const rawLim = raw["limitation"];
69
+ if (isRecord(rawLim)) {
67
70
  const limitation = {};
68
71
  for (const key of LIMITATION_NUMBERS) {
69
72
  const value = rawLim[key];
@@ -88,8 +91,8 @@ async function fetchRelayInformation(wsUrl, opts) {
88
91
  let json;
89
92
  try {
90
93
  json = await res.json();
91
- } catch (cause) {
92
- throw new Nip11Error("relay information document is not valid JSON", { cause: cause instanceof Error ? cause : void 0 });
94
+ } catch (error) {
95
+ throw new Nip11Error("relay information document is not valid JSON", { cause: error instanceof Error ? error : void 0 });
93
96
  }
94
97
  return parseRelayInformation(json);
95
98
  }
@@ -1 +1 @@
1
- {"version":3,"file":"nip11.mjs","names":[],"sources":["../../src/nips/nip11.ts"],"sourcesContent":["/**\n * NIP-11: Relay Information Document\n * @see https://github.com/nostr-protocol/nips/blob/master/11.md\n */\nimport { NostrError } from \"../core/error.ts\";\nimport { fetchManual, requireGlobalFetch, 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\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 (cause) {\n throw new Nip11Error(`invalid relay URL: ${wsUrl}`, {\n cause: cause instanceof Error ? cause : undefined,\n });\n }\n\n if (url.protocol === \"wss:\") url.protocol = \"https:\";\n else if (url.protocol === \"ws:\") 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 (json === null || typeof json !== \"object\" || Array.isArray(json)) {\n throw new Nip11Error(\"relay information document must be a JSON object\");\n }\n const raw = json as Record<string, unknown>;\n const info: RelayInformation = {};\n\n for (const key of STRING_FIELDS) {\n const value = raw[key];\n if (typeof value === \"string\") info[key] = value;\n }\n\n if (Array.isArray(raw.supported_nips)) {\n info.supported_nips = raw.supported_nips.filter(isNonNegativeInteger);\n }\n\n if (raw.limitation && typeof raw.limitation === \"object\" && !Array.isArray(raw.limitation)) {\n const rawLim = raw.limitation as Record<string, unknown>;\n const limitation: NonNullable<RelayInformation[\"limitation\"]> = {};\n for (const key of LIMITATION_NUMBERS) {\n const value = rawLim[key];\n if (isNonNegativeInteger(value)) limitation[key] = value;\n }\n for (const key of LIMITATION_BOOLEANS) {\n const value = rawLim[key];\n if (typeof value === \"boolean\") limitation[key] = value;\n }\n if (Object.keys(limitation).length > 0) info.limitation = limitation;\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 (cause) {\n throw new Nip11Error(\"relay information document is not valid JSON\", {\n cause: cause instanceof Error ? cause : undefined,\n });\n }\n\n return parseRelayInformation(json);\n}\n"],"mappings":";;;;;;;AAOA,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,CAAC;;AAG5C,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,QAAQ,IAAI,WAAW;MACvC,IAAI,IAAI,aAAa,OAAO,IAAI,WAAW;MAC3C,IAAI,IAAI,aAAa,YAAY,IAAI,aAAa,SACrD,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,SAAS,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,IAAI,GACjE,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,UAAU,KAAK,OAAO;CAC7C;CAEA,IAAI,MAAM,QAAQ,IAAI,cAAc,GAClC,KAAK,iBAAiB,IAAI,eAAe,OAAO,oBAAoB;CAGtE,IAAI,IAAI,cAAc,OAAO,IAAI,eAAe,YAAY,CAAC,MAAM,QAAQ,IAAI,UAAU,GAAG;EAC1F,MAAM,SAAS,IAAI;EACnB,MAAM,aAA0D,CAAC;EACjE,KAAK,MAAM,OAAO,oBAAoB;GACpC,MAAM,QAAQ,OAAO;GACrB,IAAI,qBAAqB,KAAK,GAAG,WAAW,OAAO;EACrD;EACA,KAAK,MAAM,OAAO,qBAAqB;GACrC,MAAM,QAAQ,OAAO;GACrB,IAAI,OAAO,UAAU,WAAW,WAAW,OAAO;EACpD;EACA,IAAI,OAAO,KAAK,UAAU,CAAC,CAAC,SAAS,GAAG,KAAK,aAAa;CAC5D;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 { 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,23 +1,23 @@
1
- import { r as UnsignedEvent } from "../event-B5D2jxt_.mjs";
2
- import { a as NostrError } from "../error-WEFS-R-4.mjs";
1
+ import { r as UnsignedEvent } from "../event-fU3Y01PR.mjs";
2
+ import { a as NostrError } from "../error-CR8Urc84.mjs";
3
3
  //#region src/nips/nip13.d.ts
4
- declare class Nip13Error extends NostrError {
4
+ export declare class Nip13Error extends NostrError {
5
+ name: string;
5
6
  constructor(message: string, options?: ErrorOptions);
6
7
  }
7
- type MinePowOptions = {
8
+ export type MinePowOptions = {
8
9
  /** Yield to the event loop after this many hashes. Default 1000. */
9
10
  yieldEvery?: number;
10
11
  signal?: AbortSignal;
11
12
  };
12
13
  /** Leading zero bits of a hex event id or raw sha256 bytes. */
13
- declare function getPow(idOrHash: string | Uint8Array): number;
14
+ export declare function getPow(idOrHash: string | Uint8Array): number;
14
15
  /**
15
- * Returns a new unsigned event with nonce tag and computed id.
16
- * Does not mutate input. Yields every `yieldEvery` hashes.
16
+ * Returns a new unsigned event with nonce tag and computed id. Does not mutate input. Yields every
17
+ * `yieldEvery` hashes.
17
18
  */
18
- declare function minePow(unsigned: UnsignedEvent, difficulty: number, opts?: MinePowOptions): Promise<UnsignedEvent & {
19
+ export declare function minePow(unsigned: UnsignedEvent, difficulty: number, opts?: MinePowOptions): Promise<UnsignedEvent & {
19
20
  id: string;
20
21
  }>;
21
22
  //#endregion
22
- export { MinePowOptions, Nip13Error, getPow, minePow };
23
23
  //# sourceMappingURL=nip13.d.mts.map
@@ -1,15 +1,15 @@
1
- import { l as utf8Encoder, r as bytesToHex } from "../util-6tfLQ9JF.mjs";
2
- import { a as NostrError } from "../error-DZEs5OuZ.mjs";
3
- import { c as serializeEvent } from "../event-CzoQEFMF.mjs";
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";
4
4
  import { sha256 } from "@noble/hashes/sha2.js";
5
5
  //#region src/nips/nip13.ts
6
6
  /**
7
- * NIP-13: Proof of Work.
8
- * Does not import signer, relay, or client. Does not sign.
7
+ * NIP-13: Proof of Work. Does not import signer, relay, or client. Does not sign.
9
8
  *
10
9
  * @see https://github.com/nostr-protocol/nips/blob/master/13.md
11
10
  */
12
11
  var Nip13Error = class extends NostrError {
12
+ name = "Nip13Error";
13
13
  constructor(message, options) {
14
14
  super(message, options);
15
15
  }
@@ -17,9 +17,10 @@ var Nip13Error = class extends NostrError {
17
17
  /** Leading zero bits of a hex event id or raw sha256 bytes. */
18
18
  function getPow(idOrHash) {
19
19
  if (typeof idOrHash === "string") {
20
+ if (!isHex32(idOrHash.toLowerCase())) throw new Nip13Error(`expected 64-char hex event id, got ${idOrHash.length} chars`);
20
21
  let count = 0;
21
22
  for (let i = 0; i < idOrHash.length; i += 8) {
22
- const chunk = Number.parseInt(idOrHash.substring(i, i + 8), 16);
23
+ const chunk = Number.parseInt(idOrHash.slice(i, i + 8), 16);
23
24
  if (chunk === 0) count += 32;
24
25
  else {
25
26
  count += Math.clz32(chunk);
@@ -29,19 +30,16 @@ function getPow(idOrHash) {
29
30
  return count;
30
31
  }
31
32
  let count = 0;
32
- for (let i = 0; i < idOrHash.length; i++) {
33
- const byte = idOrHash[i];
34
- if (byte === 0) count += 8;
35
- else {
36
- count += Math.clz32(byte) - 24;
37
- break;
38
- }
33
+ for (const byte of idOrHash) if (byte === 0) count += 8;
34
+ else {
35
+ count += Math.clz32(byte) - 24;
36
+ break;
39
37
  }
40
38
  return count;
41
39
  }
42
40
  /**
43
- * Returns a new unsigned event with nonce tag and computed id.
44
- * Does not mutate input. Yields every `yieldEvery` hashes.
41
+ * Returns a new unsigned event with nonce tag and computed id. Does not mutate input. Yields every
42
+ * `yieldEvery` hashes.
45
43
  */
46
44
  async function minePow(unsigned, difficulty, opts) {
47
45
  const signal = opts?.signal;
@@ -61,7 +59,7 @@ async function minePow(unsigned, difficulty, opts) {
61
59
  let count = 0;
62
60
  let iterations = 0;
63
61
  while (true) {
64
- if (signal?.aborted) throw new Nip13Error("mining aborted", { cause: signal.reason });
62
+ if (signal?.aborted === true) throw abortReason(signal);
65
63
  const now = Math.floor(Date.now() / 1e3);
66
64
  if (now !== mined.created_at) {
67
65
  count = 0;
@@ -77,7 +75,7 @@ async function minePow(unsigned, difficulty, opts) {
77
75
  if (iterations >= yieldEvery) {
78
76
  iterations = 0;
79
77
  await new Promise((resolve) => {
80
- setTimeout(resolve, 0);
78
+ setTimeout(resolve);
81
79
  });
82
80
  }
83
81
  }
@@ -1 +1 @@
1
- {"version":3,"file":"nip13.mjs","names":[],"sources":["../../src/nips/nip13.ts"],"sourcesContent":["/**\n * NIP-13: Proof of Work.\n * 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\";\nimport { NostrError } from \"../core/error.ts\";\nimport { serializeEvent, type UnsignedEvent } from \"../core/event.ts\";\nimport { bytesToHex, utf8Encoder } from \"../core/util.ts\";\n\nexport class Nip13Error extends NostrError {\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 let count = 0;\n for (let i = 0; i < idOrHash.length; i += 8) {\n const chunk = Number.parseInt(idOrHash.substring(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 (let i = 0; i < idOrHash.length; i++) {\n const byte = idOrHash[i]!;\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.\n * Does not mutate input. Yields every `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) {\n throw new Nip13Error(\"mining aborted\", { cause: signal.reason });\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 await new Promise<void>((resolve) => {\n setTimeout(resolve, 0);\n });\n }\n }\n}\n"],"mappings":";;;;;;;;;;;AAWA,IAAa,aAAb,cAAgC,WAAW;CACzC,YAAY,SAAiB,SAAwB;EACnD,MAAM,SAAS,OAAO;CACxB;AACF;;AASA,SAAgB,OAAO,UAAuC;CAC5D,IAAI,OAAO,aAAa,UAAU;EAChC,IAAI,QAAQ;EACZ,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,GAAG;GAC3C,MAAM,QAAQ,OAAO,SAAS,SAAS,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE;GAC9D,IAAI,UAAU,GACZ,SAAS;QACJ;IACL,SAAS,KAAK,MAAM,KAAK;IACzB;GACF;EACF;EACA,OAAO;CACT;CAEA,IAAI,QAAQ;CACZ,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;EACxC,MAAM,OAAO,SAAS;EACtB,IAAI,SAAS,GACX,SAAS;OACJ;GACL,SAAS,KAAK,MAAM,IAAI,IAAI;GAC5B;EACF;CACF;CACA,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,SACV,MAAM,IAAI,WAAW,kBAAkB,EAAE,OAAO,OAAO,OAAO,CAAC;EAGjE,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;GACb,MAAM,IAAI,SAAe,YAAY;IACnC,WAAW,SAAS,CAAC;GACvB,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 { 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,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-BWq-Kfq5.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-DNEkz8rM.mjs";
2
2
  export { ChatMessageOptions, Nip17Error, Recipient, ReplyTo, buildChatMessageRumor, dmRelayListEventBuilder, dmRelayListToTags, normalizeRecipients, parseDmRelayList, requireDmRelays, wrapDirectMessage };