@bzzsocial/ndk 0.0.0-stage → 3.0.3-bzz.7

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 (245) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +104 -2
  3. package/dist/index.d.mts +7392 -0
  4. package/dist/index.d.ts +7392 -0
  5. package/dist/index.js +15372 -0
  6. package/dist/index.mjs +15195 -0
  7. package/dist/test/index.d.mts +4584 -0
  8. package/dist/test/index.d.ts +4584 -0
  9. package/dist/test/index.js +13744 -0
  10. package/dist/test/index.mjs +13712 -0
  11. package/dist/workers/sig-verification.d.mts +2 -0
  12. package/dist/workers/sig-verification.d.ts +2 -0
  13. package/dist/workers/sig-verification.js +38 -0
  14. package/dist/workers/sig-verification.mjs +36 -0
  15. package/package.json +72 -4
  16. package/src/ai-guardrails/event/publishing.test.ts +176 -0
  17. package/src/ai-guardrails/event/signing.test.ts +124 -0
  18. package/src/ai-guardrails/event/signing.ts +225 -0
  19. package/src/ai-guardrails/index.ts +364 -0
  20. package/src/ai-guardrails/ndk/fetch-events.test.ts +257 -0
  21. package/src/ai-guardrails/ndk/fetch-events.ts +166 -0
  22. package/src/ai-guardrails/ndk.test.ts +64 -0
  23. package/src/ai-guardrails/ndk.ts +34 -0
  24. package/src/ai-guardrails/subscription/deprecated-handlers.test.ts +105 -0
  25. package/src/ai-guardrails/subscription/deprecated-handlers.ts +75 -0
  26. package/src/ai-guardrails/types.ts +69 -0
  27. package/src/app-settings/index.ts +71 -0
  28. package/src/cache/filter.test.ts +139 -0
  29. package/src/cache/filter.ts +78 -0
  30. package/src/cache/index.ts +474 -0
  31. package/src/count/index.test.ts +247 -0
  32. package/src/count/index.ts +213 -0
  33. package/src/dvm/schedule.ts +132 -0
  34. package/src/events/content-tagger.test.ts +284 -0
  35. package/src/events/content-tagger.ts +249 -0
  36. package/src/events/dedup.ts +14 -0
  37. package/src/events/encode.test.ts +35 -0
  38. package/src/events/encryption.test.ts +484 -0
  39. package/src/events/encryption.ts +106 -0
  40. package/src/events/fetch-tagged-event.ts +44 -0
  41. package/src/events/gift-wrapping.test.ts +139 -0
  42. package/src/events/gift-wrapping.ts +155 -0
  43. package/src/events/index.test.ts +863 -0
  44. package/src/events/index.ts +1130 -0
  45. package/src/events/kind.ts +20 -0
  46. package/src/events/kinds/article.ts +152 -0
  47. package/src/events/kinds/blossom-list.ts +91 -0
  48. package/src/events/kinds/cashu/fedimint.ts +95 -0
  49. package/src/events/kinds/cashu/mint-recommendation.ts +95 -0
  50. package/src/events/kinds/cashu/mint.ts +93 -0
  51. package/src/events/kinds/cashu/token.ts +155 -0
  52. package/src/events/kinds/cashu/tx.test.ts +44 -0
  53. package/src/events/kinds/cashu/tx.ts +190 -0
  54. package/src/events/kinds/classified.ts +182 -0
  55. package/src/events/kinds/collaborative.test.ts +453 -0
  56. package/src/events/kinds/collaborative.ts +346 -0
  57. package/src/events/kinds/drafts.ts +152 -0
  58. package/src/events/kinds/dvm/NDKTranscriptionDVM.ts +69 -0
  59. package/src/events/kinds/dvm/feedback.ts +51 -0
  60. package/src/events/kinds/dvm/index.ts +6 -0
  61. package/src/events/kinds/dvm/request.ts +131 -0
  62. package/src/events/kinds/dvm/result.ts +93 -0
  63. package/src/events/kinds/follow-pack.test.ts +169 -0
  64. package/src/events/kinds/follow-pack.ts +123 -0
  65. package/src/events/kinds/highlight.ts +116 -0
  66. package/src/events/kinds/image.ts +51 -0
  67. package/src/events/kinds/index.ts +224 -0
  68. package/src/events/kinds/interest-list.test.ts +171 -0
  69. package/src/events/kinds/interest-list.ts +82 -0
  70. package/src/events/kinds/lists/index.test.ts +51 -0
  71. package/src/events/kinds/lists/index.ts +415 -0
  72. package/src/events/kinds/nip89/app-handler.test.ts +106 -0
  73. package/src/events/kinds/nip89/app-handler.ts +83 -0
  74. package/src/events/kinds/nutzap/index.test.ts +192 -0
  75. package/src/events/kinds/nutzap/index.ts +384 -0
  76. package/src/events/kinds/nutzap/mint-list.ts +76 -0
  77. package/src/events/kinds/nutzap/proof.ts +18 -0
  78. package/src/events/kinds/nutzap/validation.test.ts +340 -0
  79. package/src/events/kinds/nutzap/validation.ts +79 -0
  80. package/src/events/kinds/p2p-order.test.ts +359 -0
  81. package/src/events/kinds/p2p-order.ts +469 -0
  82. package/src/events/kinds/project-template.ts +132 -0
  83. package/src/events/kinds/project.ts +114 -0
  84. package/src/events/kinds/relay-feed-list.example.ts +86 -0
  85. package/src/events/kinds/relay-feed-list.test.ts +97 -0
  86. package/src/events/kinds/relay-feed-list.ts +108 -0
  87. package/src/events/kinds/relay-list.ts +118 -0
  88. package/src/events/kinds/repost.ts +67 -0
  89. package/src/events/kinds/simple-group/index.ts +234 -0
  90. package/src/events/kinds/simple-group/member-list.ts +43 -0
  91. package/src/events/kinds/simple-group/metadata.ts +64 -0
  92. package/src/events/kinds/story.test.ts +141 -0
  93. package/src/events/kinds/story.ts +458 -0
  94. package/src/events/kinds/subscriptions/amount.ts +61 -0
  95. package/src/events/kinds/subscriptions/receipt.ts +148 -0
  96. package/src/events/kinds/subscriptions/subscription-start.ts +149 -0
  97. package/src/events/kinds/subscriptions/tier.test.ts +76 -0
  98. package/src/events/kinds/subscriptions/tier.ts +121 -0
  99. package/src/events/kinds/task.ts +42 -0
  100. package/src/events/kinds/thread.ts +45 -0
  101. package/src/events/kinds/video.ts +140 -0
  102. package/src/events/kinds/voice-message.ts +257 -0
  103. package/src/events/kinds/wiki.ts +88 -0
  104. package/src/events/kinds/zap.ts +115 -0
  105. package/src/events/nip10.test.ts +108 -0
  106. package/src/events/nip10.ts +75 -0
  107. package/src/events/nip19.test.ts +49 -0
  108. package/src/events/nip19.ts +36 -0
  109. package/src/events/nip73.ts +13 -0
  110. package/src/events/repost.test.ts +40 -0
  111. package/src/events/repost.ts +44 -0
  112. package/src/events/serializer.test.ts +174 -0
  113. package/src/events/serializer.ts +120 -0
  114. package/src/events/signature.ts +97 -0
  115. package/src/events/signed-event-types.test.ts +149 -0
  116. package/src/events/validation.ts +113 -0
  117. package/src/events/wrap.test.ts +164 -0
  118. package/src/events/wrap.ts +128 -0
  119. package/src/index.ts +103 -0
  120. package/src/light-bolt11-decoder.d.ts +4 -0
  121. package/src/ndk/active-user.test.ts +89 -0
  122. package/src/ndk/active-user.ts +41 -0
  123. package/src/ndk/entity.ts +31 -0
  124. package/src/ndk/fetch-event-from-tag.ts +156 -0
  125. package/src/ndk/fetchEvent-guardrails.test.ts +208 -0
  126. package/src/ndk/fetchEvent-invalid-filter.test.ts +80 -0
  127. package/src/ndk/fetchUser.test.ts +149 -0
  128. package/src/ndk/guardrailOff.test.ts +75 -0
  129. package/src/ndk/index.ts +1249 -0
  130. package/src/ndk/nip19.test.ts +122 -0
  131. package/src/ndk/queue/index.ts +89 -0
  132. package/src/nip19/index.ts +5 -0
  133. package/src/nip49/index.test.ts +100 -0
  134. package/src/nip49/index.ts +5 -0
  135. package/src/outbox/index.ts +128 -0
  136. package/src/outbox/read/with-authors.ts +24 -0
  137. package/src/outbox/relay-ranking.ts +27 -0
  138. package/src/outbox/tracker.test.ts +68 -0
  139. package/src/outbox/tracker.ts +185 -0
  140. package/src/outbox/write.ts +37 -0
  141. package/src/relay/auth-on-demand.test.ts +197 -0
  142. package/src/relay/auth-policies.test.ts +19 -0
  143. package/src/relay/auth-policies.ts +109 -0
  144. package/src/relay/auth-retry.test.ts +241 -0
  145. package/src/relay/connections.test.ts +231 -0
  146. package/src/relay/connectivity.test.ts +370 -0
  147. package/src/relay/connectivity.ts +1106 -0
  148. package/src/relay/index.test.ts +167 -0
  149. package/src/relay/index.ts +446 -0
  150. package/src/relay/keepalive-bun.test.ts +86 -0
  151. package/src/relay/keepalive.test.ts +196 -0
  152. package/src/relay/keepalive.ts +118 -0
  153. package/src/relay/nip11.test.ts +196 -0
  154. package/src/relay/nip11.ts +85 -0
  155. package/src/relay/nip42.test.ts +269 -0
  156. package/src/relay/pool/index.test.ts +183 -0
  157. package/src/relay/pool/index.ts +537 -0
  158. package/src/relay/pool/system-disconnection.test.ts +280 -0
  159. package/src/relay/publisher.ts +114 -0
  160. package/src/relay/reconnection-backoff.test.ts +92 -0
  161. package/src/relay/reconnection-integration.bun.test.ts +112 -0
  162. package/src/relay/score.ts +2 -0
  163. package/src/relay/sets/calculate.test.ts +220 -0
  164. package/src/relay/sets/calculate.ts +203 -0
  165. package/src/relay/sets/index.ts +416 -0
  166. package/src/relay/sets/publish.test.ts +231 -0
  167. package/src/relay/sets/utils.ts +29 -0
  168. package/src/relay/signature-verification-stats.ts +150 -0
  169. package/src/relay/signature-verification.test.ts +192 -0
  170. package/src/relay/simple-verification.test.ts +13 -0
  171. package/src/relay/sub-manager.ts +81 -0
  172. package/src/relay/subscription.test.ts +166 -0
  173. package/src/relay/subscription.ts +542 -0
  174. package/src/relay/validation-ratio.test.ts +37 -0
  175. package/src/signers/deserialization.ts +39 -0
  176. package/src/signers/index.ts +97 -0
  177. package/src/signers/nip07/index.test.ts +32 -0
  178. package/src/signers/nip07/index.ts +302 -0
  179. package/src/signers/nip46/backend/connect.ts +41 -0
  180. package/src/signers/nip46/backend/get-public-key.ts +12 -0
  181. package/src/signers/nip46/backend/index.test.ts +340 -0
  182. package/src/signers/nip46/backend/index.ts +232 -0
  183. package/src/signers/nip46/backend/nip04-decrypt.ts +39 -0
  184. package/src/signers/nip46/backend/nip04-encrypt.ts +39 -0
  185. package/src/signers/nip46/backend/nip44-decrypt.ts +39 -0
  186. package/src/signers/nip46/backend/nip44-encrypt.ts +39 -0
  187. package/src/signers/nip46/backend/ping.ts +25 -0
  188. package/src/signers/nip46/backend/sign-event.ts +48 -0
  189. package/src/signers/nip46/backend/switch-relays.ts +28 -0
  190. package/src/signers/nip46/index.test.ts +560 -0
  191. package/src/signers/nip46/index.ts +640 -0
  192. package/src/signers/nip46/nostrconnect.ts +50 -0
  193. package/src/signers/nip46/restore.test.ts +44 -0
  194. package/src/signers/nip46/rpc.ts +221 -0
  195. package/src/signers/private-key/index.test.ts +151 -0
  196. package/src/signers/private-key/index.ts +241 -0
  197. package/src/signers/registry.ts +14 -0
  198. package/src/signers/serialization.test.ts +212 -0
  199. package/src/signers/types.ts +7 -0
  200. package/src/subscription/eose.test.ts +92 -0
  201. package/src/subscription/event-dedup.test.ts +445 -0
  202. package/src/subscription/exclusive-relay.test.ts +444 -0
  203. package/src/subscription/future-timestamp-grace.test.ts +276 -0
  204. package/src/subscription/grouping.test.ts +71 -0
  205. package/src/subscription/grouping.ts +76 -0
  206. package/src/subscription/index.test.ts +113 -0
  207. package/src/subscription/index.ts +1136 -0
  208. package/src/subscription/manager.test.ts +64 -0
  209. package/src/subscription/manager.ts +121 -0
  210. package/src/subscription/outbox-late-arrival.test.ts +172 -0
  211. package/src/subscription/utils/format-filters.ts +57 -0
  212. package/src/subscription/utils.test.ts +91 -0
  213. package/src/subscription/utils.ts +276 -0
  214. package/src/subscription/verify-before-emit.test.ts +108 -0
  215. package/src/subscription.test.ts +175 -0
  216. package/src/test-relay-autoconnect.ts +133 -0
  217. package/src/thread/index.test.ts +267 -0
  218. package/src/thread/index.ts +242 -0
  219. package/src/types.ts +45 -0
  220. package/src/user/follows.test.ts +58 -0
  221. package/src/user/follows.ts +45 -0
  222. package/src/user/index.test.ts +365 -0
  223. package/src/user/index.ts +465 -0
  224. package/src/user/nip05.test.ts +39 -0
  225. package/src/user/nip05.ts +107 -0
  226. package/src/user/pin.ts +45 -0
  227. package/src/user/profile.ts +112 -0
  228. package/src/utils/filter-validation.test.ts +925 -0
  229. package/src/utils/filter-validation.ts +436 -0
  230. package/src/utils/filter.ts +41 -0
  231. package/src/utils/get-users-relay-list.ts +171 -0
  232. package/src/utils/imeta.test.ts +100 -0
  233. package/src/utils/imeta.ts +74 -0
  234. package/src/utils/index.ts +5 -0
  235. package/src/utils/normalize-url.ts +352 -0
  236. package/src/utils/timeout.ts +15 -0
  237. package/src/utils/validation.ts +86 -0
  238. package/src/workers/sig-verification.ts +54 -0
  239. package/src/zap/invoice.ts +111 -0
  240. package/src/zapper/index.test.ts +151 -0
  241. package/src/zapper/index.ts +701 -0
  242. package/src/zapper/ln.ts +84 -0
  243. package/src/zapper/nip57.test.ts +329 -0
  244. package/src/zapper/nip57.ts +85 -0
  245. package/src/zapper/nip61.ts +57 -0
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Examples of using NDKRelayFeedList (NIP-51 kind 10012)
3
+ *
4
+ * This kind represents user's favorite browsable relays and relay sets.
5
+ * It can contain both individual relay URLs and references to relay sets (kind:30002).
6
+ */
7
+
8
+ import { NDK } from "../../ndk/index.js";
9
+ import { NDKPrivateKeySigner } from "../../signers/private-key/index.js";
10
+ import { NDKRelayFeedList } from "./relay-feed-list.js";
11
+
12
+ async function createRelayFeedList() {
13
+ // Initialize NDK with a signer
14
+ const ndk = new NDK();
15
+ const signer = NDKPrivateKeySigner.generate();
16
+ ndk.signer = signer;
17
+
18
+ // Create a new relay feed list
19
+ const relayFeedList = new NDKRelayFeedList(ndk);
20
+ relayFeedList.title = "My Favorite Relays";
21
+ relayFeedList.description = "Relays I browse regularly";
22
+
23
+ // Add individual relay URLs
24
+ await relayFeedList.addRelay("wss://relay.damus.io");
25
+ await relayFeedList.addRelay("wss://nos.lol");
26
+ await relayFeedList.addRelay("wss://relay.nostr.band");
27
+
28
+ // Add relay set references (kind:30002)
29
+ await relayFeedList.addRelaySet("30002:pubkey123:my-outbox-relays");
30
+ await relayFeedList.addRelaySet("30002:pubkey456:trusted-relays");
31
+
32
+ // Publish the list
33
+ await relayFeedList.publish();
34
+
35
+ return relayFeedList;
36
+ }
37
+
38
+ async function readRelayFeedList() {
39
+ const ndk = new NDK();
40
+ const signer = NDKPrivateKeySigner.generate();
41
+ ndk.signer = signer;
42
+
43
+ // Fetch the user's relay feed list
44
+ const user = await signer.user();
45
+ const lists = await ndk.fetchEvents({
46
+ kinds: [10012],
47
+ authors: [user.pubkey],
48
+ });
49
+
50
+ for (const event of lists) {
51
+ const relayFeedList = NDKRelayFeedList.from(event);
52
+
53
+ console.log("Title:", relayFeedList.title);
54
+ console.log("Description:", relayFeedList.description);
55
+
56
+ // Get all relay URLs
57
+ console.log("Relay URLs:", relayFeedList.relayUrls);
58
+
59
+ // Get all relay set references
60
+ console.log("Relay Sets:", relayFeedList.relaySets);
61
+ }
62
+ }
63
+
64
+ async function modifyRelayFeedList() {
65
+ const ndk = new NDK();
66
+ const signer = NDKPrivateKeySigner.generate();
67
+ ndk.signer = signer;
68
+
69
+ const relayFeedList = new NDKRelayFeedList(ndk);
70
+
71
+ // Add some relays
72
+ await relayFeedList.addRelay("wss://relay.damus.io");
73
+ await relayFeedList.addRelay("wss://nos.lol");
74
+
75
+ // Remove a relay (don't publish yet)
76
+ await relayFeedList.removeRelay("wss://nos.lol", false);
77
+
78
+ // Add it back at the top of the list
79
+ await relayFeedList.addRelay("wss://nos.lol", undefined, false, "top");
80
+
81
+ // Publish all changes at once
82
+ await relayFeedList.publish();
83
+ }
84
+
85
+ // Export examples for documentation purposes
86
+ export { createRelayFeedList, modifyRelayFeedList, readRelayFeedList };
@@ -0,0 +1,97 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import { NDK } from "../../ndk";
3
+ import { NDKPrivateKeySigner } from "../../signers/private-key";
4
+ import { NDKKind } from "./index.js";
5
+ import { NDKRelayFeedList } from "./relay-feed-list.js";
6
+
7
+ const ndk = new NDK();
8
+
9
+ describe("NDKRelayFeedList", () => {
10
+ test("creates a new relay feed list", () => {
11
+ const list = new NDKRelayFeedList(ndk);
12
+ expect(list.kind).toBe(NDKKind.RelayFeedList);
13
+ });
14
+
15
+ test("has correct title", () => {
16
+ const list = new NDKRelayFeedList(ndk);
17
+ expect(list.title).toBe("Relay Feeds");
18
+ });
19
+
20
+ test("adds relay URLs", async () => {
21
+ ndk.signer = NDKPrivateKeySigner.generate();
22
+
23
+ const list = new NDKRelayFeedList(ndk);
24
+ await list.addRelay("wss://relay.damus.io");
25
+ await list.addRelay("wss://nos.lol");
26
+
27
+ expect(list.relayUrls).toEqual(["wss://relay.damus.io", "wss://nos.lol"]);
28
+ });
29
+
30
+ test("adds relay sets", async () => {
31
+ const signer = NDKPrivateKeySigner.generate();
32
+ ndk.signer = signer;
33
+
34
+ const list = new NDKRelayFeedList(ndk);
35
+ const relaySetNaddr = "30002:pubkey123:my-relay-set";
36
+ await list.addRelaySet(relaySetNaddr);
37
+
38
+ expect(list.relaySets).toEqual([relaySetNaddr]);
39
+ });
40
+
41
+ test("removes relay URLs", async () => {
42
+ const signer = NDKPrivateKeySigner.generate();
43
+ ndk.signer = signer;
44
+
45
+ const list = new NDKRelayFeedList(ndk);
46
+ await list.addRelay("wss://relay.damus.io");
47
+ await list.addRelay("wss://nos.lol");
48
+ await list.removeRelay("wss://relay.damus.io", false);
49
+
50
+ expect(list.relayUrls).toEqual(["wss://nos.lol"]);
51
+ });
52
+
53
+ test("removes relay sets", async () => {
54
+ const signer = NDKPrivateKeySigner.generate();
55
+ ndk.signer = signer;
56
+
57
+ const list = new NDKRelayFeedList(ndk);
58
+ const relaySet1 = "30002:pubkey123:set1";
59
+ const relaySet2 = "30002:pubkey123:set2";
60
+ await list.addRelaySet(relaySet1);
61
+ await list.addRelaySet(relaySet2);
62
+ await list.removeRelaySet(relaySet1, false);
63
+
64
+ expect(list.relaySets).toEqual([relaySet2]);
65
+ });
66
+
67
+ // Note: Encrypted tags are supported via the base NDKList class but are not tested here
68
+ // due to a known issue with the encryptedTagsLength cache in the base class.
69
+ // The encryption functionality works but the cache invalidation needs to be fixed upstream.
70
+
71
+ test("creates from existing NDKEvent", () => {
72
+ const list = new NDKRelayFeedList(ndk);
73
+ list.tags = [
74
+ ["relay", "wss://relay.damus.io"],
75
+ ["a", "30002:pubkey:relay-set"],
76
+ ];
77
+
78
+ const wrapped = NDKRelayFeedList.from(list);
79
+ expect(wrapped).toBeInstanceOf(NDKRelayFeedList);
80
+ expect(wrapped.relayUrls).toEqual(["wss://relay.damus.io"]);
81
+ expect(wrapped.relaySets).toEqual(["30002:pubkey:relay-set"]);
82
+ });
83
+
84
+ test("supports mixed relay and relay set items", async () => {
85
+ const signer = NDKPrivateKeySigner.generate();
86
+ ndk.signer = signer;
87
+
88
+ const list = new NDKRelayFeedList(ndk);
89
+ await list.addRelay("wss://relay.damus.io");
90
+ await list.addRelaySet("30002:pubkey:outbox-relays");
91
+ await list.addRelay("wss://nos.lol");
92
+ await list.addRelaySet("30002:pubkey:inbox-relays");
93
+
94
+ expect(list.relayUrls).toEqual(["wss://relay.damus.io", "wss://nos.lol"]);
95
+ expect(list.relaySets).toEqual(["30002:pubkey:outbox-relays", "30002:pubkey:inbox-relays"]);
96
+ });
97
+ });
@@ -0,0 +1,108 @@
1
+ import type { NDK } from "../../ndk/index.js";
2
+ import type { NostrEvent } from "../index.js";
3
+ import { NDKEvent } from "../index.js";
4
+ import { NDKKind } from "./index.js";
5
+ import { NDKList } from "./lists/index.js";
6
+
7
+ /**
8
+ * Represents a NIP-51 kind 10012 Relay Feed List.
9
+ *
10
+ * This list contains user's favorite browsable relays and relay sets.
11
+ * Items can be:
12
+ * - `relay` tags pointing to relay URLs
13
+ * - `a` tags pointing to kind:30002 relay sets
14
+ *
15
+ * @example
16
+ * const relayFeedList = new NDKRelayFeedList(ndk);
17
+ * relayFeedList.addRelay("wss://relay.damus.io");
18
+ * relayFeedList.addRelaySet("30002:pubkey:dtagvalue");
19
+ * await relayFeedList.publish();
20
+ *
21
+ * @group Kind Wrapper
22
+ */
23
+ export class NDKRelayFeedList extends NDKList {
24
+ static kind = NDKKind.RelayFeedList;
25
+ static kinds = [NDKKind.RelayFeedList];
26
+
27
+ constructor(ndk?: NDK, rawEvent?: NostrEvent | NDKEvent) {
28
+ super(ndk, rawEvent);
29
+ if (!rawEvent?.kind) {
30
+ this.kind = NDKKind.RelayFeedList;
31
+ }
32
+ }
33
+
34
+ static from(ndkEvent: NDKEvent): NDKRelayFeedList {
35
+ return new NDKRelayFeedList(ndkEvent.ndk, ndkEvent);
36
+ }
37
+
38
+ /**
39
+ * Gets all relay URLs from the list.
40
+ */
41
+ get relayUrls(): string[] {
42
+ return this.getMatchingTags("relay").map(tag => tag[1]);
43
+ }
44
+
45
+ /**
46
+ * Gets all relay set references (kind:30002 naddr) from the list.
47
+ * Returns them in the format "kind:pubkey:dtag".
48
+ */
49
+ get relaySets(): string[] {
50
+ return this.getMatchingTags("a").map(tag => tag[1]);
51
+ }
52
+
53
+ /**
54
+ * Adds a relay URL to the list.
55
+ * @param relayUrl - WebSocket URL of the relay
56
+ * @param mark - Optional mark to add to the relay tag
57
+ * @param encrypted - Whether to encrypt the item
58
+ * @param position - Where to add the item in the list
59
+ */
60
+ async addRelay(
61
+ relayUrl: string,
62
+ mark?: string,
63
+ encrypted = false,
64
+ position: "top" | "bottom" = "bottom"
65
+ ): Promise<void> {
66
+ const tag: string[] = ["relay", relayUrl];
67
+ if (mark) tag.push(mark);
68
+ await this.addItem(tag, undefined, encrypted, position);
69
+ }
70
+
71
+ /**
72
+ * Adds a relay set reference to the list.
73
+ * @param relaySetNaddr - NIP-33 address in format "kind:pubkey:dtag" (kind should be 30002)
74
+ * @param mark - Optional mark to add to the relay set tag
75
+ * @param encrypted - Whether to encrypt the item
76
+ * @param position - Where to add the item in the list
77
+ */
78
+ async addRelaySet(
79
+ relaySetNaddr: string,
80
+ mark?: string,
81
+ encrypted = false,
82
+ position: "top" | "bottom" = "bottom"
83
+ ): Promise<void> {
84
+ const tag: string[] = ["a", relaySetNaddr];
85
+ if (mark) tag.push(mark);
86
+ await this.addItem(tag, undefined, encrypted, position);
87
+ }
88
+
89
+ /**
90
+ * Removes a relay URL from the list.
91
+ * @param relayUrl - The relay URL to remove
92
+ * @param publish - Whether to publish the change
93
+ */
94
+ async removeRelay(relayUrl: string, publish = true): Promise<void> {
95
+ await this.removeItemByValue(relayUrl, publish);
96
+ }
97
+
98
+ /**
99
+ * Removes a relay set from the list.
100
+ * @param relaySetNaddr - The relay set naddr to remove
101
+ * @param publish - Whether to publish the change
102
+ */
103
+ async removeRelaySet(relaySetNaddr: string, publish = true): Promise<void> {
104
+ await this.removeItemByValue(relaySetNaddr, publish);
105
+ }
106
+ }
107
+
108
+ export default NDKRelayFeedList;
@@ -0,0 +1,118 @@
1
+ import type { NDK } from "../../ndk/index.js";
2
+ import { NDKRelaySet } from "../../relay/sets/index.js";
3
+ import { normalizeRelayUrl, tryNormalizeRelayUrl } from "../../utils/normalize-url.js";
4
+ import type { NostrEvent } from "../index.js";
5
+ import { NDKEvent } from "../index.js";
6
+ import { NDKKind } from "./index.js";
7
+
8
+ const READ_MARKER = "read";
9
+ const WRITE_MARKER = "write";
10
+
11
+ /**
12
+ * Represents a relay list for a user, ideally coming from a NIP-65 kind:10002 or alternatively from a kind:3 event's content.
13
+ * @group Kind Wrapper
14
+ */
15
+ export class NDKRelayList extends NDKEvent {
16
+ static kind = NDKKind.RelayList;
17
+ static kinds = [NDKKind.RelayList];
18
+
19
+ constructor(ndk?: NDK, rawEvent?: NostrEvent) {
20
+ super(ndk, rawEvent);
21
+ this.kind ??= NDKKind.RelayList;
22
+ }
23
+
24
+ static from(ndkEvent: NDKEvent): NDKRelayList {
25
+ return new NDKRelayList(ndkEvent.ndk, ndkEvent.rawEvent());
26
+ }
27
+
28
+ get readRelayUrls(): WebSocket["url"][] {
29
+ return this.tags
30
+ .filter((tag) => tag[0] === "r" || tag[0] === "relay")
31
+ .filter((tag) => !tag[2] || (tag[2] && tag[2] === READ_MARKER))
32
+ .map((tag) => tryNormalizeRelayUrl(tag[1]))
33
+ .filter((url) => !!url) as WebSocket["url"][];
34
+ }
35
+
36
+ set readRelayUrls(relays: WebSocket["url"][]) {
37
+ for (const relay of relays) {
38
+ this.tags.push(["r", relay, READ_MARKER]);
39
+ }
40
+ }
41
+
42
+ get writeRelayUrls(): WebSocket["url"][] {
43
+ return this.tags
44
+ .filter((tag) => tag[0] === "r" || tag[0] === "relay")
45
+ .filter((tag) => !tag[2] || (tag[2] && tag[2] === WRITE_MARKER))
46
+ .map((tag) => tryNormalizeRelayUrl(tag[1]))
47
+ .filter((url) => !!url) as WebSocket["url"][];
48
+ }
49
+
50
+ set writeRelayUrls(relays: WebSocket["url"][]) {
51
+ for (const relay of relays) {
52
+ this.tags.push(["r", relay, WRITE_MARKER]);
53
+ }
54
+ }
55
+
56
+ get bothRelayUrls(): WebSocket["url"][] {
57
+ return this.tags
58
+ .filter((tag) => tag[0] === "r" || tag[0] === "relay")
59
+ .filter((tag) => !tag[2])
60
+ .map((tag) => tag[1]);
61
+ }
62
+ set bothRelayUrls(relays: WebSocket["url"][]) {
63
+ for (const relay of relays) {
64
+ this.tags.push(["r", relay]);
65
+ }
66
+ }
67
+
68
+ get relays(): WebSocket["url"][] {
69
+ return this.tags.filter((tag) => tag[0] === "r" || tag[0] === "relay").map((tag) => tag[1]);
70
+ }
71
+
72
+ /**
73
+ * Provides a relaySet for the relays in this list.
74
+ */
75
+ get relaySet(): NDKRelaySet {
76
+ if (!this.ndk) throw new Error("NDKRelayList has no NDK instance");
77
+
78
+ return new NDKRelaySet(
79
+ new Set(this.relays.map((u) => this.ndk?.pool.getRelay(u)).filter((r) => !!r)),
80
+ this.ndk,
81
+ );
82
+ }
83
+ }
84
+
85
+ export function relayListFromKind3(ndk: NDK, contactList: NDKEvent): NDKRelayList | undefined {
86
+ try {
87
+ const content = JSON.parse(contactList.content);
88
+ const relayList = new NDKRelayList(ndk);
89
+ const readRelays = new Set<string>();
90
+ const writeRelays = new Set<string>();
91
+
92
+ for (let [key, config] of Object.entries(content)) {
93
+ try {
94
+ key = normalizeRelayUrl(key);
95
+ } catch {
96
+ continue;
97
+ }
98
+
99
+ if (!config) {
100
+ readRelays.add(key);
101
+ writeRelays.add(key);
102
+ } else {
103
+ const relayConfig: { read?: boolean; write?: boolean } = config;
104
+ if (relayConfig.write) writeRelays.add(key);
105
+ if (relayConfig.read) readRelays.add(key);
106
+ }
107
+ }
108
+
109
+ relayList.readRelayUrls = Array.from(readRelays);
110
+ relayList.writeRelayUrls = Array.from(writeRelays);
111
+
112
+ return relayList;
113
+ } catch {
114
+ /* */
115
+ }
116
+
117
+ return undefined;
118
+ }
@@ -0,0 +1,67 @@
1
+ import type { NDK } from "../../ndk/index.js";
2
+ import type { NDKFilter, NDKSubscriptionOptions } from "../../subscription/index.js";
3
+ import type { NDKTag, NostrEvent } from "../index.js";
4
+ import { NDKEvent } from "../index.js";
5
+ import { NDKKind } from "./index.js";
6
+
7
+ type classWithConvertFunction<T> = {
8
+ from: (event: NDKEvent) => T;
9
+ };
10
+
11
+ /**
12
+ * Handles NIP-18 reposts.
13
+ * @group Kind Wrapper
14
+ */
15
+ export class NDKRepost<T> extends NDKEvent {
16
+ private _repostedEvents: T[] | undefined;
17
+ static kind = NDKKind.Repost;
18
+ static kinds = [NDKKind.Repost, NDKKind.GenericRepost];
19
+
20
+ static from(event: NDKEvent) {
21
+ return new NDKRepost(event.ndk, event.rawEvent());
22
+ }
23
+
24
+ /**
25
+ * Returns all reposted events by the current event.
26
+ *
27
+ * @param klass Optional class to convert the events to.
28
+ * @returns
29
+ */
30
+ async repostedEvents(klass?: classWithConvertFunction<T>, opts?: NDKSubscriptionOptions): Promise<T[]> {
31
+ const items: T[] = [];
32
+
33
+ if (!this.ndk) throw new Error("NDK instance not set");
34
+
35
+ if (this._repostedEvents !== undefined) return this._repostedEvents;
36
+
37
+ for (const eventId of this.repostedEventIds()) {
38
+ const filter = filterForId(eventId);
39
+ const event = await this.ndk.fetchEvent(filter, opts);
40
+
41
+ if (event) {
42
+ items.push(klass ? klass.from(event) : (event as T));
43
+ }
44
+ }
45
+
46
+ return items;
47
+ }
48
+
49
+ /**
50
+ * Returns the reposted event IDs.
51
+ */
52
+ repostedEventIds(): string[] {
53
+ return this.tags.filter((t: NDKTag) => t[0] === "e" || t[0] === "a").map((t: NDKTag) => t[1]);
54
+ }
55
+ }
56
+
57
+ function filterForId(id: string): NDKFilter {
58
+ if (id.match(/:/)) {
59
+ const [kind, pubkey, identifier] = id.split(":");
60
+ return {
61
+ kinds: [Number.parseInt(kind)],
62
+ authors: [pubkey],
63
+ "#d": [identifier],
64
+ };
65
+ }
66
+ return { ids: [id] };
67
+ }