@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,4584 @@
1
+ import { EventEmitter } from 'tseep';
2
+ import debug$1 from 'debug';
3
+ import { LRUCache } from 'typescript-lru-cache';
4
+ import { nip19 } from 'nostr-tools';
5
+ import { EventEmitter as EventEmitter$1 } from 'node:events';
6
+
7
+ declare enum NDKKind {
8
+ Metadata = 0,
9
+ Text = 1,
10
+ RecommendRelay = 2,
11
+ Contacts = 3,
12
+ EncryptedDirectMessage = 4,
13
+ EventDeletion = 5,
14
+ Repost = 6,
15
+ Reaction = 7,
16
+ BadgeAward = 8,
17
+ GroupChat = 9,
18
+ Thread = 11,
19
+ GroupReply = 12,
20
+ GiftWrapSeal = 13,
21
+ PrivateDirectMessage = 14,
22
+ Image = 20,
23
+ Video = 21,
24
+ ShortVideo = 22,
25
+ Story = 23,
26
+ Vanish = 62,
27
+ CashuWalletBackup = 375,
28
+ GiftWrap = 1059,
29
+ GenericRepost = 16,
30
+ ChannelCreation = 40,
31
+ ChannelMetadata = 41,
32
+ ChannelMessage = 42,
33
+ ChannelHideMessage = 43,
34
+ ChannelMuteUser = 44,
35
+ WikiMergeRequest = 818,
36
+ GenericReply = 1111,
37
+ Media = 1063,
38
+ VoiceMessage = 1222,
39
+ VoiceReply = 1244,
40
+ DraftCheckpoint = 1234,
41
+ Task = 1934,
42
+ Report = 1984,
43
+ Label = 1985,
44
+ DVMReqTextExtraction = 5000,
45
+ DVMReqTextSummarization = 5001,
46
+ DVMReqTextTranslation = 5002,
47
+ DVMReqTextGeneration = 5050,
48
+ DVMReqImageGeneration = 5100,
49
+ DVMReqTextToSpeech = 5250,
50
+ DVMReqDiscoveryNostrContent = 5300,
51
+ DVMReqDiscoveryNostrPeople = 5301,
52
+ DVMReqTimestamping = 5900,
53
+ DVMEventSchedule = 5905,
54
+ DVMJobFeedback = 7000,
55
+ Subscribe = 7001,
56
+ Unsubscribe = 7002,
57
+ SubscriptionReceipt = 7003,
58
+ CashuReserve = 7373,
59
+ CashuQuote = 7374,
60
+ CashuToken = 7375,
61
+ CashuWalletTx = 7376,
62
+ GroupAdminAddUser = 9000,
63
+ GroupAdminRemoveUser = 9001,
64
+ GroupAdminEditMetadata = 9002,
65
+ GroupAdminEditStatus = 9006,
66
+ GroupAdminCreateGroup = 9007,
67
+ GroupAdminRequestJoin = 9021,
68
+ MuteList = 10000,
69
+ PinList = 10001,
70
+ RelayList = 10002,
71
+ BookmarkList = 10003,
72
+ CommunityList = 10004,
73
+ PublicChatList = 10005,
74
+ BlockRelayList = 10006,
75
+ SearchRelayList = 10007,
76
+ SimpleGroupList = 10009,
77
+ RelayFeedList = 10012,
78
+ InterestList = 10015,
79
+ CashuMintList = 10019,
80
+ EmojiList = 10030,
81
+ DirectMessageReceiveRelayList = 10050,
82
+ BlossomList = 10063,
83
+ NostrWaletConnectInfo = 13194,
84
+ TierList = 17000,
85
+ CashuWallet = 17375,
86
+ FollowSet = 30000,
87
+ CategorizedPeopleList = 30000,// Deprecated but left for backwards compatibility
88
+ CategorizedBookmarkList = 30001,// Deprecated but left for backwards compatibility
89
+ RelaySet = 30002,
90
+ CategorizedRelayList = 30002,// Deprecated but left for backwards compatibility
91
+ BookmarkSet = 30003,
92
+ /**
93
+ * @deprecated Use ArticleCurationSet instead
94
+ */
95
+ CurationSet = 30004,// Deprecated but left for backwards compatibility
96
+ ArticleCurationSet = 30004,
97
+ VideoCurationSet = 30005,
98
+ ImageCurationSet = 30006,
99
+ InterestSet = 30015,
100
+ InterestsList = 30015,// Deprecated but left for backwards compatibility
101
+ ProjectTemplate = 30717,
102
+ EmojiSet = 30030,
103
+ ModularArticle = 30040,
104
+ ModularArticleItem = 30041,
105
+ Wiki = 30818,
106
+ Draft = 31234,
107
+ Project = 31933,
108
+ SubscriptionTier = 37001,
109
+ EcashMintRecommendation = 38000,
110
+ CashuMintAnnouncement = 38172,
111
+ FedimintMintAnnouncement = 38173,
112
+ P2POrder = 38383,
113
+ CollaborativeEvent = 39382,
114
+ HighlightSet = 39802,
115
+ CategorizedHighlightList = 39802,// Deprecated but left for backwards compatibility
116
+ Nutzap = 9321,
117
+ ZapRequest = 9734,
118
+ Zap = 9735,
119
+ Highlight = 9802,
120
+ ClientAuth = 22242,
121
+ NostrWalletConnectReq = 23194,
122
+ NostrWalletConnectRes = 23195,
123
+ NostrConnect = 24133,
124
+ BlossomUpload = 24242,
125
+ HttpAuth = 27235,
126
+ ProfileBadge = 30008,
127
+ BadgeDefinition = 30009,
128
+ MarketStall = 30017,
129
+ MarketProduct = 30018,
130
+ Article = 30023,
131
+ AppSpecificData = 30078,
132
+ Classified = 30402,
133
+ HorizontalVideo = 34235,
134
+ VerticalVideo = 34236,
135
+ GroupMetadata = 39000,// NIP-29
136
+ GroupAdmins = 39001,// NIP-29
137
+ GroupMembers = 39002,// NIP-29
138
+ FollowPack = 39089,
139
+ MediaFollowPack = 39092,
140
+ AppRecommendation = 31989,
141
+ AppHandler = 31990
142
+ }
143
+
144
+ /**
145
+ * Represents an HLL (HyperLogLog) data structure for cardinality estimation.
146
+ * Contains 256 uint8 registers as specified in NIP-45.
147
+ */
148
+ declare class NDKCountHll {
149
+ /**
150
+ * The 256 uint8 registers used for HLL estimation
151
+ */
152
+ readonly registers: Uint8Array;
153
+ constructor(registers?: Uint8Array);
154
+ /**
155
+ * Creates an NDKCountHll from a hex-encoded string (512 characters).
156
+ * Each register is a uint8 value encoded as 2 hex characters.
157
+ *
158
+ * @param hex - The hex string (512 characters = 256 bytes)
159
+ * @returns A new NDKCountHll instance
160
+ * @throws Error if the hex string is invalid
161
+ */
162
+ static fromHex(hex: string): NDKCountHll;
163
+ /**
164
+ * Converts the HLL registers to a hex-encoded string.
165
+ *
166
+ * @returns The hex string representation (512 characters)
167
+ */
168
+ toHex(): string;
169
+ /**
170
+ * Merges this HLL with another HLL by taking the maximum value for each register.
171
+ * This is the standard HLL merge operation that allows combining counts
172
+ * from multiple relays without double-counting.
173
+ *
174
+ * @param other - The other HLL to merge with
175
+ * @returns A new NDKCountHll with the merged registers
176
+ */
177
+ merge(other: NDKCountHll): NDKCountHll;
178
+ /**
179
+ * Merges multiple HLLs by taking the maximum value for each register.
180
+ *
181
+ * @param hlls - Array of HLLs to merge
182
+ * @returns A new NDKCountHll with the merged registers
183
+ */
184
+ static merge(hlls: NDKCountHll[]): NDKCountHll;
185
+ /**
186
+ * Estimates the cardinality (unique count) using the HyperLogLog algorithm.
187
+ *
188
+ * Uses the standard HLL formula with bias correction for small and large cardinalities.
189
+ *
190
+ * @returns The estimated unique count
191
+ */
192
+ estimate(): number;
193
+ /**
194
+ * Checks if this HLL is empty (all registers are zero).
195
+ *
196
+ * @returns True if all registers are zero
197
+ */
198
+ isEmpty(): boolean;
199
+ /**
200
+ * Creates a copy of this HLL.
201
+ *
202
+ * @returns A new NDKCountHll with the same register values
203
+ */
204
+ clone(): NDKCountHll;
205
+ }
206
+ /**
207
+ * Result of a COUNT request, including optional HLL data.
208
+ */
209
+ interface NDKCountResult {
210
+ /**
211
+ * The count value returned by the relay.
212
+ * This is the exact count if HLL is not available,
213
+ * or an approximate count if HLL is used.
214
+ */
215
+ count: number;
216
+ /**
217
+ * The HLL data if returned by the relay.
218
+ * Can be used to merge counts from multiple relays.
219
+ */
220
+ hll?: NDKCountHll;
221
+ }
222
+ /**
223
+ * Aggregated result from multiple relays for a COUNT request.
224
+ */
225
+ interface NDKAggregatedCountResult {
226
+ /**
227
+ * The best estimate of the count.
228
+ * If HLL data is available from multiple relays, this is computed from the merged HLL.
229
+ * Otherwise, it's the maximum count from all relays.
230
+ */
231
+ count: number;
232
+ /**
233
+ * The merged HLL from all relays that returned HLL data.
234
+ * Can be used for further aggregation or analysis.
235
+ */
236
+ mergedHll?: NDKCountHll;
237
+ /**
238
+ * Individual results from each relay.
239
+ */
240
+ relayResults: Map<string, NDKCountResult>;
241
+ }
242
+ /**
243
+ * Options for count requests.
244
+ */
245
+ interface NDKCountOptions {
246
+ /**
247
+ * Custom ID for the count request.
248
+ */
249
+ id?: string;
250
+ /**
251
+ * Timeout in milliseconds for the count request.
252
+ * @default 5000
253
+ */
254
+ timeout?: number;
255
+ }
256
+
257
+ /**
258
+ * NDKUserProfile represents a user's kind 0 profile metadata
259
+ */
260
+ interface NDKUserProfile {
261
+ [key: string]: string | number | undefined;
262
+ created_at?: number;
263
+ name?: string;
264
+ displayName?: string;
265
+ /**
266
+ * @deprecated Use picture instead
267
+ */
268
+ image?: string;
269
+ picture?: string;
270
+ banner?: string;
271
+ bio?: string;
272
+ nip05?: string;
273
+ lud06?: string;
274
+ lud16?: string;
275
+ about?: string;
276
+ website?: string;
277
+ profileEvent?: string;
278
+ }
279
+
280
+ type Hexpubkey = string;
281
+ type Npub = string;
282
+ type ProfilePointer = {
283
+ pubkey: string;
284
+ relays?: string[];
285
+ nip46?: string[];
286
+ };
287
+ interface NDKUserParams {
288
+ npub?: Npub;
289
+ hexpubkey?: Hexpubkey;
290
+ pubkey?: Hexpubkey;
291
+ nip05?: string;
292
+ relayUrls?: string[];
293
+ nip46Urls?: string[];
294
+ nprofile?: string;
295
+ }
296
+ /**
297
+ * Represents a pubkey.
298
+ */
299
+ declare class NDKUser {
300
+ ndk: NDK | undefined;
301
+ profile?: NDKUserProfile;
302
+ profileEvent?: NDKEvent;
303
+ private _npub?;
304
+ private _pubkey?;
305
+ relayUrls: string[];
306
+ readonly nip46Urls: string[];
307
+ constructor(opts: NDKUserParams);
308
+ get npub(): string;
309
+ get nprofile(): string;
310
+ set npub(npub: Npub);
311
+ /**
312
+ * Get the user's pubkey
313
+ * @returns {string} The user's pubkey
314
+ */
315
+ get pubkey(): string;
316
+ /**
317
+ * Set the user's pubkey
318
+ * @param pubkey {string} The user's pubkey
319
+ */
320
+ set pubkey(pubkey: string);
321
+ /**
322
+ * Equivalent to NDKEvent.filters().
323
+ * @returns {NDKFilter}
324
+ */
325
+ filter(): NDKFilter;
326
+ /**
327
+ * Gets NIP-57 and NIP-61 information that this user has signaled
328
+ *
329
+ * @param getAll {boolean} Whether to get all zap info or just the first one
330
+ */
331
+ getZapInfo(timeoutMs?: number): Promise<Map<NDKZapMethod, NDKZapMethodInfo>>;
332
+ /**
333
+ * Instantiate an NDKUser from a NIP-05 string
334
+ * @param nip05Id {string} The user's NIP-05
335
+ * @param ndk {NDK} An NDK instance
336
+ * @param skipCache {boolean} Whether to skip the cache or not
337
+ * @returns {NDKUser | undefined} An NDKUser if one is found for the given NIP-05, undefined otherwise.
338
+ */
339
+ static fromNip05(nip05Id: string, ndk: NDK, skipCache?: boolean): Promise<NDKUser | undefined>;
340
+ /**
341
+ * Fetch a user's profile
342
+ * @param opts {NDKSubscriptionOptions} A set of NDKSubscriptionOptions
343
+ * @param storeProfileEvent {boolean} Whether to store the profile event or not
344
+ * @returns User Profile
345
+ */
346
+ fetchProfile(opts?: NDKSubscriptionOptions, storeProfileEvent?: boolean): Promise<NDKUserProfile | null>;
347
+ /**
348
+ * Returns a set of users that this user follows.
349
+ *
350
+ * @deprecated Use followSet instead
351
+ */
352
+ follows: (opts?: NDKSubscriptionOptions | undefined, outbox?: boolean | undefined, kind?: number | undefined) => Promise<Set<NDKUser>>;
353
+ /**
354
+ * Returns a set of pubkeys that this user follows.
355
+ *
356
+ * @param opts - NDKSubscriptionOptions
357
+ * @param outbox - boolean
358
+ * @param kind - number
359
+ */
360
+ followSet(opts?: NDKSubscriptionOptions, outbox?: boolean, kind?: number): Promise<Set<Hexpubkey>>;
361
+ /** @deprecated Use referenceTags instead. */
362
+ /**
363
+ * Get the tag that can be used to reference this user in an event
364
+ * @returns {NDKTag} an NDKTag
365
+ */
366
+ tagReference(): NDKTag;
367
+ /**
368
+ * Get the tags that can be used to reference this user in an event
369
+ * @returns {NDKTag[]} an array of NDKTag
370
+ */
371
+ referenceTags(marker?: string): NDKTag[];
372
+ /**
373
+ * Publishes the current profile.
374
+ */
375
+ publish(): Promise<void>;
376
+ /**
377
+ * Add one or more follows to this user's contact list
378
+ *
379
+ * @param newFollow {NDKUser | Hexpubkey | Array} The user(s) to follow
380
+ * @param currentFollowList {Set<NDKUser | Hexpubkey>} The current follow list
381
+ * @param kind {NDKKind} The kind to use for this contact list (defaults to `3`)
382
+ * @returns {Promise<boolean>} True if any follows were added, false if all already exist
383
+ */
384
+ follow(newFollow: NDKUser | Hexpubkey | (NDKUser | Hexpubkey)[], currentFollowList?: Set<NDKUser | Hexpubkey>, kind?: NDKKind): Promise<boolean>;
385
+ /**
386
+ * Remove one or more follows from this user's contact list
387
+ *
388
+ * @param user {NDKUser | Hexpubkey | Array} The user(s) to unfollow
389
+ * @param currentFollowList {Set<NDKUser | Hexpubkey>} The current follow list
390
+ * @param kind {NDKKind} The kind to use for this contact list (defaults to `3`)
391
+ * @returns The relays where the follow list was published or false if none were found
392
+ */
393
+ unfollow(user: NDKUser | Hexpubkey | (NDKUser | Hexpubkey)[], currentFollowList?: Set<NDKUser | Hexpubkey>, kind?: NDKKind): Promise<Set<NDKRelay> | boolean>;
394
+ /**
395
+ * Validate a user's NIP-05 identifier (usually fetched from their kind:0 profile data)
396
+ *
397
+ * @param nip05Id The NIP-05 string to validate
398
+ * @returns {Promise<boolean | null>} True if the NIP-05 is found and matches this user's pubkey,
399
+ * False if the NIP-05 is found but doesn't match this user's pubkey,
400
+ * null if the NIP-05 isn't found on the domain or we're unable to verify (because of network issues, etc.)
401
+ */
402
+ validateNip05(nip05Id: string): Promise<boolean | null>;
403
+ }
404
+
405
+ interface NDKSigner {
406
+ /**
407
+ * Synchronously get the public key of the signer.
408
+ * @throws {Error} "Not ready" when the signer is not ready to provide a pubkey synchronously (e.g., NIP-07 or NIP-46 signers)
409
+ * @returns The public key in hex format
410
+ */
411
+ get pubkey(): string;
412
+ /**
413
+ * Blocks until the signer is ready and returns the associated NDKUser.
414
+ * @returns A promise that resolves to the NDKUser instance.
415
+ */
416
+ blockUntilReady(): Promise<NDKUser>;
417
+ /**
418
+ * Getter for the user property.
419
+ * @returns A promise that resolves to the NDKUser instance.
420
+ */
421
+ user(): Promise<NDKUser>;
422
+ get userSync(): NDKUser;
423
+ /**
424
+ * Signs the given Nostr event.
425
+ * @param event - The Nostr event to be signed.
426
+ * @returns A promise that resolves to the signature of the signed event.
427
+ */
428
+ sign(event: NostrEvent): Promise<string>;
429
+ /**
430
+ * Getter for the preferred relays.
431
+ * @returns A promise containing a simple map of preferred relays and their read/write policies.
432
+ */
433
+ relays?(ndk?: NDK): Promise<NDKRelay[]>;
434
+ /**
435
+ * Determine the types of encryption (by nip) that this signer can perform.
436
+ * Implementing classes SHOULD return a value even for legacy (only nip04) third party signers.
437
+ * @nip Optionally returns an array with single supported nip or empty, to check for truthy or falsy.
438
+ * @return A promised list of any (or none) of these strings ['nip04', 'nip44']
439
+ */
440
+ encryptionEnabled?(scheme?: NDKEncryptionScheme): Promise<NDKEncryptionScheme[]>;
441
+ /**
442
+ * Encrypts the given Nostr event for the given recipient.
443
+ * Implementing classes SHOULD equate legacy (only nip04) to nip == `nip04` || undefined
444
+ * @param recipient - The recipient (pubkey or conversationKey) of the encrypted value.
445
+ * @param value - The value to be encrypted.
446
+ * @param nip - which NIP is being implemented ('nip04', 'nip44')
447
+ */
448
+ encrypt(recipient: NDKUser, value: string, scheme?: NDKEncryptionScheme): Promise<string>;
449
+ /**
450
+ * Decrypts the given value.
451
+ * Implementing classes SHOULD equate legacy (only nip04) to nip == `nip04` || undefined
452
+ * @param sender - The sender (pubkey or conversationKey) of the encrypted value
453
+ * @param value - The value to be decrypted
454
+ * @param scheme - which NIP is being implemented ('nip04', 'nip44', 'nip49')
455
+ */
456
+ decrypt(sender: NDKUser, value: string, scheme?: NDKEncryptionScheme): Promise<string>;
457
+ /**
458
+ * Serializes the signer's essential data into a storable format.
459
+ * @returns A JSON string containing the type and payload.
460
+ */
461
+ toPayload(): string;
462
+ }
463
+
464
+ type NDKPoolStats = {
465
+ total: number;
466
+ connected: number;
467
+ disconnected: number;
468
+ connecting: number;
469
+ };
470
+ /**
471
+ * Handles connections to all relays. A single pool should be used per NDK instance.
472
+ *
473
+ * @emit connecting - Emitted when a relay in the pool is connecting.
474
+ * @emit connect - Emitted when all relays in the pool are connected, or when the specified timeout has elapsed, and some relays are connected.
475
+ * @emit notice - Emitted when a relay in the pool sends a notice.
476
+ * @emit flapping - Emitted when a relay in the pool is flapping.
477
+ * @emit relay:connect - Emitted when a relay in the pool connects.
478
+ * @emit relay:ready - Emitted when a relay in the pool is ready to serve requests.
479
+ * @emit relay:disconnect - Emitted when a relay in the pool disconnects.
480
+ */
481
+ declare class NDKPool extends EventEmitter<{
482
+ notice: (relay: NDKRelay, notice: string) => void;
483
+ flapping: (relay: NDKRelay) => void;
484
+ connect: () => void;
485
+ "relay:connecting": (relay: NDKRelay) => void;
486
+ /**
487
+ * Emitted when a relay in the pool connects.
488
+ * @param relay - The relay that connected.
489
+ */
490
+ "relay:connect": (relay: NDKRelay) => void;
491
+ "relay:ready": (relay: NDKRelay) => void;
492
+ "relay:disconnect": (relay: NDKRelay) => void;
493
+ "relay:auth": (relay: NDKRelay, challenge: string) => void;
494
+ "relay:authed": (relay: NDKRelay) => void;
495
+ }> {
496
+ private _relays;
497
+ private status;
498
+ autoConnectRelays: Set<string>;
499
+ private debug;
500
+ private temporaryRelayTimers;
501
+ private flappingRelays;
502
+ private backoffTimes;
503
+ private ndk;
504
+ private disconnectionTimes;
505
+ private systemEventDetector?;
506
+ /**
507
+ * @param relayUrls - The URLs of the relays to connect to.
508
+ * @param ndk - The NDK instance.
509
+ * @param opts - Options for the pool.
510
+ */
511
+ constructor(relayUrls: WebSocket["url"][], ndk: NDK, { debug, name, }?: {
512
+ debug?: debug$1.Debugger;
513
+ name?: string;
514
+ });
515
+ get relays(): Map<string, NDKRelay>;
516
+ set relayUrls(urls: WebSocket["url"][]);
517
+ private _name;
518
+ get name(): string;
519
+ set name(name: string);
520
+ /**
521
+ * Adds a relay to the pool, and sets a timer to remove it if it is not used within the specified time.
522
+ * @param relay - The relay to add to the pool.
523
+ * @param removeIfUnusedAfter - The time in milliseconds to wait before removing the relay from the pool after it is no longer used.
524
+ */
525
+ useTemporaryRelay(relay: NDKRelay, removeIfUnusedAfter?: number, filters?: NDKFilter[] | string): void;
526
+ /**
527
+ * Adds a relay to the pool.
528
+ *
529
+ * @param relay - The relay to add to the pool.
530
+ * @param connect - Whether or not to connect to the relay.
531
+ */
532
+ addRelay(relay: NDKRelay, connect?: boolean): void;
533
+ /**
534
+ * Removes a relay from the pool.
535
+ * @param relayUrl - The URL of the relay to remove.
536
+ * @returns {boolean} True if the relay was removed, false if it was not found.
537
+ */
538
+ removeRelay(relayUrl: string): boolean;
539
+ /**
540
+ * Checks whether a relay is already connected in the pool.
541
+ */
542
+ isRelayConnected(url: WebSocket["url"]): boolean;
543
+ /**
544
+ * Fetches a relay from the pool, or creates a new one if it does not exist.
545
+ *
546
+ * New relays will be attempted to be connected.
547
+ */
548
+ getRelay(url: WebSocket["url"], connect?: boolean, temporary?: boolean, filters?: NDKFilter[]): NDKRelay;
549
+ private handleRelayConnect;
550
+ private handleRelayReady;
551
+ /**
552
+ * Attempts to establish a connection to each relay in the pool.
553
+ *
554
+ * @async
555
+ * @param {number} [timeoutMs] - Optional timeout in milliseconds for each connection attempt.
556
+ * @returns {Promise<void>} A promise that resolves when all connection attempts have completed.
557
+ * @throws {Error} If any of the connection attempts result in an error or timeout.
558
+ */
559
+ connect(timeoutMs?: number): Promise<void>;
560
+ private checkOnFlappingRelays;
561
+ /**
562
+ * Records when a relay disconnects to detect system-wide events
563
+ */
564
+ private recordDisconnection;
565
+ /**
566
+ * Checks if multiple relays disconnected simultaneously, indicating a system event
567
+ */
568
+ private checkForSystemWideDisconnection;
569
+ /**
570
+ * Handles system-wide reconnection (e.g., after sleep/wake or network change)
571
+ */
572
+ private handleSystemWideReconnection;
573
+ private handleFlapping;
574
+ size(): number;
575
+ /**
576
+ * Returns the status of each relay in the pool.
577
+ * @returns {NDKPoolStats} An object containing the number of relays in each status.
578
+ */
579
+ stats(): NDKPoolStats;
580
+ connectedRelays(): NDKRelay[];
581
+ permanentAndConnectedRelays(): NDKRelay[];
582
+ /**
583
+ * Get a list of all relay urls in the pool.
584
+ */
585
+ urls(): string[];
586
+ }
587
+
588
+ /**
589
+ * Why a policy is being asked to authenticate.
590
+ *
591
+ * - `challenge`: the relay sent an AUTH challenge and nothing is waiting on it. Many relays send
592
+ * one on every connection as an offer; declining it is quiet and leaves the connection as is.
593
+ * - `auth-required`: the relay refused a publish or a REQ with `auth-required:` — answering is
594
+ * the only way that publish or REQ gets through.
595
+ * - `manual`: the application called `relay.authenticate()`.
596
+ */
597
+ type NDKAuthReason = "challenge" | "auth-required" | "manual";
598
+ /**
599
+ * NDKAuthPolicies are functions that are called when a relay requests authentication
600
+ * so that you can define a behavior for your application.
601
+ *
602
+ * @param relay The relay that requested authentication.
603
+ * @param challenge The challenge that the relay sent.
604
+ * @param reason Why authentication is being asked for. See NDKAuthReason.
605
+ */
606
+ type NDKAuthPolicy = (relay: NDKRelay, challenge: string, reason?: NDKAuthReason) => Promise<boolean | undefined | NDKEvent>;
607
+
608
+ type NDKFilterFingerprint = string;
609
+
610
+ type NDKSubscriptionId = string;
611
+ /**
612
+ * This class monitors active subscriptions.
613
+ */
614
+ declare class NDKSubscriptionManager {
615
+ subscriptions: Map<NDKSubscriptionId, NDKSubscription>;
616
+ seenEvents: LRUCache<string, NDKRelay[]>;
617
+ constructor();
618
+ add(sub: NDKSubscription): void;
619
+ seenEvent(eventId: NDKEventId, relay: NDKRelay): void;
620
+ /**
621
+ * Whenever an event comes in, this function is called.
622
+ * This function matches the received event against all the
623
+ * known (i.e. active) NDKSubscriptions, and if it matches,
624
+ * it sends the event to the subscription.
625
+ *
626
+ * This is the single place in the codebase that matches
627
+ * incoming events with parties interested in the event.
628
+ *
629
+ * This is also what allows for reactivity in NDK apps, such that
630
+ * whenever an active subscription receives an event that some
631
+ * other active subscription would want to receive, both receive it.
632
+ *
633
+ * TODO This also allows for subscriptions that overlap in meaning
634
+ * to be collapsed into one.
635
+ *
636
+ * I.e. if a subscription with filter: kinds: [1], authors: [alice]
637
+ * is created and EOSEs, and then a subsequent subscription with
638
+ * kinds: [1], authors: [alice] is created, once the second subscription
639
+ * EOSEs we can safely close it, increment its refCount and close it,
640
+ * and when the first subscription receives a new event from Alice this
641
+ * code will make the second subscription receive the event even though
642
+ * it has no active subscription on a relay.
643
+ * @param event Raw event received from a relay
644
+ * @param relay Relay that sent the event
645
+ * @param optimisticPublish Whether the event is coming from an optimistic publish
646
+ */
647
+ dispatchEvent(event: NostrEvent, relay?: NDKRelay, optimisticPublish?: boolean): void;
648
+ }
649
+
650
+ type Item = {
651
+ subscription: NDKSubscription;
652
+ filters: NDKFilter[];
653
+ };
654
+ declare enum NDKRelaySubscriptionStatus {
655
+ INITIAL = 0,
656
+ /**
657
+ * The subscription is pending execution.
658
+ */
659
+ PENDING = 1,
660
+ /**
661
+ * The subscription is waiting for the relay to be ready.
662
+ */
663
+ WAITING = 2,
664
+ /**
665
+ * The subscription is currently running.
666
+ */
667
+ RUNNING = 3,
668
+ CLOSED = 4
669
+ }
670
+ /**
671
+ * Groups together a number of NDKSubscriptions (as created by the user),
672
+ * filters (as computed internally), executed, or to be executed, within
673
+ * a single specific relay.
674
+ */
675
+ declare class NDKRelaySubscription {
676
+ fingerprint: NDKFilterFingerprint;
677
+ items: Map<NDKSubscriptionInternalId, Item>;
678
+ topSubManager: NDKSubscriptionManager;
679
+ debug: debug.Debugger;
680
+ /**
681
+ * Tracks the status of this REQ.
682
+ */
683
+ status: NDKRelaySubscriptionStatus;
684
+ onClose?: (sub: NDKRelaySubscription) => void;
685
+ private relay;
686
+ /**
687
+ * Whether this subscription has reached EOSE.
688
+ */
689
+ private eosed;
690
+ /** Whether this REQ already re-sent after a CLOSED "auth-required:". */
691
+ private authRetried;
692
+ /**
693
+ * Timeout at which this subscription will
694
+ * start executing.
695
+ */
696
+ private executionTimer?;
697
+ /**
698
+ * Track the time at which this subscription will fire.
699
+ */
700
+ private fireTime?;
701
+ /**
702
+ * The delay type that the current fireTime was calculated with.
703
+ */
704
+ private delayType?;
705
+ /**
706
+ * The filters that have been executed.
707
+ */
708
+ executeFilters?: NDKFilter[];
709
+ readonly id: string;
710
+ /**
711
+ *
712
+ * @param fingerprint The fingerprint of this subscription.
713
+ */
714
+ constructor(relay: NDKRelay, fingerprint: NDKFilterFingerprint | null, topSubManager: NDKSubscriptionManager);
715
+ private _subId?;
716
+ get subId(): string;
717
+ private subIdParts;
718
+ private addSubIdPart;
719
+ addItem(subscription: NDKSubscription, filters: NDKFilter[]): void;
720
+ /**
721
+ * A subscription has been closed, remove it from the list of items.
722
+ * @param subscription
723
+ */
724
+ removeItem(subscription: NDKSubscription): void;
725
+ private close;
726
+ cleanup(): void;
727
+ private evaluateExecutionPlan;
728
+ private schedule;
729
+ private executeOnRelayReady;
730
+ private finalizeSubId;
731
+ private reExecuteAfterAuth;
732
+ private execute;
733
+ /**
734
+ * Sends this REQ again on a new connection, if anyone still wants it.
735
+ */
736
+ resubscribe(): void;
737
+ onstart(): void;
738
+ onevent(event: NostrEvent): void;
739
+ oneose(subId: string): void;
740
+ onclose(_reason?: string): void;
741
+ /**
742
+ * The relay ended this REQ (NIP-01 CLOSED). "auth-required:" is answered once
743
+ * when this connection can authenticate; anything else is final for this relay.
744
+ */
745
+ onclosed(reason?: string): void;
746
+ private closedByRelay;
747
+ /**
748
+ * Grabs the filters from all the subscriptions
749
+ * and merges them into a single filter.
750
+ */
751
+ private compileFilters;
752
+ }
753
+
754
+ declare class NDKRelayConnectivity {
755
+ private ndkRelay;
756
+ private ws?;
757
+ private _status;
758
+ private timeoutMs?;
759
+ private connectedAt?;
760
+ private _connectionStats;
761
+ private debug;
762
+ netDebug?: NDKNetDebug;
763
+ private connectTimeout;
764
+ private reconnectTimeout;
765
+ private ndk?;
766
+ openSubs: Map<string, NDKRelaySubscription>;
767
+ private openCountRequests;
768
+ private openEventPublishes;
769
+ private pendingAuthPublishes;
770
+ /** Publishes the relay refused with auth-required, held until this connection authenticates.
771
+ * Only these are re-sent after AUTH, or rejected when it fails — not every publish in flight. */
772
+ private authBlocked;
773
+ /** Called when a publish starts waiting on AUTH, so its caller can extend its own timeout. */
774
+ private authWaitHooks;
775
+ /** Something asked to authenticate before the relay sent a challenge, and why. */
776
+ private authWanted?;
777
+ private serial;
778
+ baseEoseTimeout: number;
779
+ /** The latest NIP-42 challenge on the current connection. */
780
+ authChallenge?: string;
781
+ private authInFlight?;
782
+ /** How long to wait for the relay's OK on an AUTH event, and for a signer to sign it. */
783
+ authTimeoutMs: number;
784
+ /** Silence after which the keepalive pings the relay. */
785
+ keepaliveIdleMs: number;
786
+ private pings;
787
+ private pingInFlight?;
788
+ /** Subscriptions running when the last connection dropped; re-sent on the next one. */
789
+ private retiredSubs;
790
+ private keepalive?;
791
+ private wsStateMonitor?;
792
+ private sleepDetector?;
793
+ private lastSleepCheck;
794
+ private lastMessageSent;
795
+ private wasIdle;
796
+ constructor(ndkRelay: NDKRelay, ndk?: NDK);
797
+ /**
798
+ * Sets up keepalive, WebSocket state monitoring, and sleep detection
799
+ */
800
+ private setupMonitoring;
801
+ /**
802
+ * Handles detection of a stale connection by cleaning up and triggering reconnection.
803
+ */
804
+ private handleStaleConnection;
805
+ /**
806
+ * Handles possible system wake event
807
+ */
808
+ private handlePossibleWake;
809
+ /**
810
+ * Resets the reconnection state for system-wide events
811
+ * Used by NDKPool when detecting system sleep/wake
812
+ */
813
+ resetReconnectionState(): void;
814
+ /**
815
+ * Connects to the NDK relay and handles the connection lifecycle.
816
+ *
817
+ * This method attempts to establish a WebSocket connection to the NDK relay specified in the `ndkRelay` object.
818
+ * If the connection is successful, it updates the connection statistics, sets the connection status to `CONNECTED`,
819
+ * and emits `connect` and `ready` events on the `ndkRelay` object.
820
+ *
821
+ * If the connection attempt fails, it handles the error by either initiating a reconnection attempt or emitting a
822
+ * `delayed-connect` event on the `ndkRelay` object, depending on the `reconnect` parameter.
823
+ *
824
+ * @param timeoutMs - The timeout in milliseconds for the connection attempt. If not provided, the default timeout from the `ndkRelay` object is used.
825
+ * @param reconnect - Indicates whether a reconnection should be attempted if the connection fails. Defaults to `true`.
826
+ * @returns A Promise that resolves when the connection is established, or rejects if the connection fails.
827
+ */
828
+ connect(timeoutMs?: number, reconnect?: boolean): Promise<void>;
829
+ /**
830
+ * Disconnects the WebSocket connection to the NDK relay.
831
+ * This method sets the connection status to `NDKRelayStatus.DISCONNECTING`,
832
+ * attempts to close the WebSocket connection, and sets the status to
833
+ * `NDKRelayStatus.DISCONNECTED` if the disconnect operation fails.
834
+ */
835
+ disconnect(): void;
836
+ /**
837
+ * Handles the error that occurred when attempting to connect to the NDK relay.
838
+ * If `reconnect` is `true`, this method will initiate a reconnection attempt.
839
+ * Otherwise, it will emit a `delayed-connect` event on the `ndkRelay` object,
840
+ * indicating that a reconnection should be attempted after a delay.
841
+ *
842
+ * @param reconnect - Indicates whether a reconnection should be attempted.
843
+ */
844
+ onConnectionError(reconnect: boolean): void;
845
+ /**
846
+ * Handles the connection event when the WebSocket connection is established.
847
+ * This method is called when the WebSocket connection is successfully opened.
848
+ * It clears any existing connection and reconnection timeouts, updates the connection statistics,
849
+ * sets the connection status to `CONNECTED`, and emits `connect` and `ready` events on the `ndkRelay` object.
850
+ */
851
+ private onConnect;
852
+ /**
853
+ * Handles the disconnection event when the WebSocket connection is closed.
854
+ * This method is called when the WebSocket connection is successfully closed.
855
+ * It updates the connection statistics, sets the connection status to `DISCONNECTED`,
856
+ * initiates a reconnection attempt if we didn't disconnect ourselves,
857
+ * and emits a `disconnect` event on the `ndkRelay` object.
858
+ */
859
+ private onDisconnect;
860
+ /**
861
+ * Handles incoming messages from the NDK relay WebSocket connection.
862
+ * This method is called whenever a message is received from the relay.
863
+ * It parses the message data and dispatches the appropriate handling logic based on the message type.
864
+ *
865
+ * @param event - The MessageEvent containing the received message data.
866
+ */
867
+ private onMessage;
868
+ /**
869
+ * Handles an authentication request from the NDK relay.
870
+ *
871
+ * If an authentication policy is configured, it will be used to authenticate the connection.
872
+ * Otherwise, the `auth` event will be emitted to allow the application to handle the authentication.
873
+ *
874
+ * @param challenge - The authentication challenge provided by the NDK relay.
875
+ */
876
+ private onAuthRequested;
877
+ private get authPolicy();
878
+ /**
879
+ * Answers the relay's current NIP-42 challenge with the auth policy.
880
+ *
881
+ * Resolves true once the relay accepts the AUTH event (or the connection is
882
+ * already authenticated), false when there is no challenge or policy, the policy
883
+ * declines, or the relay rejects it. Concurrent calls share one attempt.
884
+ */
885
+ authenticate(reason?: NDKAuthReason): Promise<boolean>;
886
+ private runAuth;
887
+ private signAuthEvent;
888
+ private withAuthTimeout;
889
+ /**
890
+ * Handles errors that occur on the WebSocket connection to the relay.
891
+ * @param error - The error or event that occurred.
892
+ */
893
+ private onError;
894
+ /**
895
+ * Gets the current status of the NDK relay connection.
896
+ * @returns {NDKRelayStatus} The current status of the NDK relay connection.
897
+ */
898
+ get status(): NDKRelayStatus;
899
+ /**
900
+ * Checks if the NDK relay connection is currently available.
901
+ * @returns {boolean} `true` if the relay connection is in the `CONNECTED` status, `false` otherwise.
902
+ */
903
+ isAvailable(): boolean;
904
+ /**
905
+ * Checks if the NDK relay connection is flapping, which means the connection is rapidly
906
+ * disconnecting and reconnecting. This is determined by analyzing the durations of the
907
+ * last three connection attempts. If the standard deviation of the durations is less
908
+ * than 1000 milliseconds, the connection is considered to be flapping.
909
+ *
910
+ * @returns {boolean} `true` if the connection is flapping, `false` otherwise.
911
+ */
912
+ private isFlapping;
913
+ /**
914
+ * Handles a notice received from the NDK relay.
915
+ * If the notice indicates the relay is complaining (e.g. "too many" or "maximum"),
916
+ * the method disconnects from the relay and attempts to reconnect after a 2-second delay.
917
+ * A debug message is logged with the relay URL and the notice text.
918
+ * The "notice" event is emitted on the ndkRelay instance with the notice text.
919
+ *
920
+ * @param notice - The notice text received from the NDK relay.
921
+ */
922
+ private onNotice;
923
+ /**
924
+ * Attempts to reconnect to the NDK relay after a connection is lost.
925
+ * This function is called recursively to handle multiple reconnection attempts.
926
+ * It checks if the relay is flapping and emits a "flapping" event if so.
927
+ * It then calculates a delay before the next reconnection attempt based on the number of previous attempts.
928
+ * The function sets a timeout to execute the next reconnection attempt after the calculated delay.
929
+ * If the maximum number of reconnection attempts is reached, a debug message is logged.
930
+ *
931
+ * @param attempt - The current attempt number (default is 0).
932
+ */
933
+ private handleReconnection;
934
+ /**
935
+ * Sends a message to the NDK relay if the connection is in the CONNECTED state and the WebSocket is open.
936
+ * If the connection is not in the CONNECTED state or the WebSocket is not open, logs a debug message and throws an error.
937
+ *
938
+ * @param message - The message to send to the NDK relay.
939
+ * @throws {Error} If attempting to send on a closed relay connection.
940
+ */
941
+ send(message: string): Promise<void>;
942
+ /**
943
+ * Authenticates the NDK event by sending it to the NDK relay and returning a promise that resolves with the result.
944
+ *
945
+ * @param event - The NDK event to authenticate.
946
+ * @returns A promise that resolves with the authentication result.
947
+ */
948
+ private auth;
949
+ /**
950
+ * Clears all pending publish promises by rejecting them with the provided error.
951
+ * This is called on disconnection to prevent memory leaks and ensure promises
952
+ * don't hang indefinitely.
953
+ * @param error The error to reject the promises with
954
+ */
955
+ private clearPendingPublishes;
956
+ /**
957
+ * Retries all pending publishes that failed due to auth-required.
958
+ * Called after successful authentication.
959
+ */
960
+ private retryPendingAuthPublishes;
961
+ /**
962
+ * Rejects all pending publishes that failed due to auth-required.
963
+ * Called when authentication fails.
964
+ */
965
+ private rejectPendingAuthPublishes;
966
+ private forgetPublish;
967
+ /**
968
+ * Publishes an NDK event to the relay and returns a promise that resolves with the result.
969
+ *
970
+ * @param event - The NDK event to publish.
971
+ * @returns A promise that resolves with the result of the event publication.
972
+ * @throws {Error} If attempting to publish on a closed relay connection.
973
+ */
974
+ publish(event: NostrEvent, onAuthWait?: () => void): Promise<string>;
975
+ /**
976
+ * Counts the number of events that match the provided filters.
977
+ *
978
+ * @param filters - The filters to apply to the count request.
979
+ * @param params - An optional object containing a custom id for the count request.
980
+ * @returns A promise that resolves with the count result including optional HLL data.
981
+ * @throws {Error} If attempting to send the count request on a closed relay connection.
982
+ */
983
+ count(filters: NDKFilter[], params: {
984
+ id?: string | null;
985
+ }): Promise<NDKCountResult>;
986
+ close(subId: string, reason?: string): void;
987
+ /**
988
+ * Subscribes to the NDK relay with the provided filters and parameters.
989
+ *
990
+ * @param filters - The filters to apply to the subscription.
991
+ * @param params - The subscription parameters, including an optional custom id.
992
+ * @returns A new NDKRelaySubscription instance.
993
+ */
994
+ /**
995
+ * Asks the relay something it must answer (a REQ for nothing) and resolves true
996
+ * when it answers that REQ — EVENT, EOSE or CLOSED — or false after `timeoutMs`.
997
+ * Other traffic on the socket doesn't count. Concurrent calls share one probe.
998
+ */
999
+ ping(timeoutMs?: number): Promise<boolean>;
1000
+ /**
1001
+ * Replaces the current socket with a new one, also while the old one is still
1002
+ * closing. Running subscriptions are re-sent on the new connection.
1003
+ */
1004
+ reconnect(timeoutMs?: number): Promise<void>;
1005
+ /** Closes the socket without letting its later events reach this connection. */
1006
+ private dropSocket;
1007
+ /** The REQs on this connection end with it; running ones are re-sent on the next one. */
1008
+ private retireConnection;
1009
+ req(relaySub: NDKRelaySubscription): void;
1010
+ /**
1011
+ * Utility functions to update the connection stats.
1012
+ */
1013
+ private updateConnectionStats;
1014
+ /** Returns the connection stats. */
1015
+ get connectionStats(): NDKRelayConnectionStats;
1016
+ /** Returns the relay URL */
1017
+ get url(): WebSocket["url"];
1018
+ get connected(): boolean;
1019
+ }
1020
+
1021
+ /**
1022
+ * NIP-11: Relay Information Document
1023
+ * https://github.com/nostr-protocol/nips/blob/master/11.md
1024
+ */
1025
+ interface NDKRelayInformation {
1026
+ name?: string;
1027
+ description?: string;
1028
+ banner?: string;
1029
+ icon?: string;
1030
+ pubkey?: string;
1031
+ contact?: string;
1032
+ supported_nips?: number[];
1033
+ software?: string;
1034
+ version?: string;
1035
+ privacy_policy?: string;
1036
+ terms_of_service?: string;
1037
+ limitation?: {
1038
+ max_message_length?: number;
1039
+ max_subscriptions?: number;
1040
+ max_subid_length?: number;
1041
+ max_limit?: number;
1042
+ max_event_tags?: number;
1043
+ max_content_length?: number;
1044
+ min_pow_difficulty?: number;
1045
+ auth_required?: boolean;
1046
+ payment_required?: boolean;
1047
+ restricted_writes?: boolean;
1048
+ created_at_lower_limit?: number;
1049
+ created_at_upper_limit?: number;
1050
+ default_limit?: number;
1051
+ };
1052
+ retention?: Array<{
1053
+ kinds?: Array<number | [number, number]>;
1054
+ time?: number | null;
1055
+ count?: number;
1056
+ }>;
1057
+ relay_countries?: string[];
1058
+ language_tags?: string[];
1059
+ tags?: string[];
1060
+ posting_policy?: string;
1061
+ payments_url?: string;
1062
+ fees?: {
1063
+ admission?: Array<{
1064
+ amount: number;
1065
+ unit: string;
1066
+ }>;
1067
+ subscription?: Array<{
1068
+ amount: number;
1069
+ unit: string;
1070
+ period: number;
1071
+ }>;
1072
+ publication?: Array<{
1073
+ kinds?: number[];
1074
+ amount: number;
1075
+ unit: string;
1076
+ }>;
1077
+ };
1078
+ [key: string]: unknown;
1079
+ }
1080
+
1081
+ type NDKRelayScore = number;
1082
+
1083
+ /**
1084
+ * The subscription manager of an NDKRelay is in charge of orchestrating the subscriptions
1085
+ * that are created and closed in a given relay.
1086
+ *
1087
+ * The manager is responsible for:
1088
+ * * restarting subscriptions when they are unexpectedly closed
1089
+ * * scheduling subscriptions that are received before the relay is connected
1090
+ * * grouping similar subscriptions to be compiled into individual REQs
1091
+ */
1092
+ declare class NDKRelaySubscriptionManager {
1093
+ private relay;
1094
+ subscriptions: Map<NDKFilterFingerprint, NDKRelaySubscription[]>;
1095
+ private generalSubManager;
1096
+ /**
1097
+ * @param relay - The relay instance.
1098
+ * @param generalSubManager - The subscription manager instance.
1099
+ */
1100
+ constructor(relay: NDKRelay, generalSubManager: NDKSubscriptionManager);
1101
+ /**
1102
+ * Adds a subscription to the manager.
1103
+ */
1104
+ addSubscription(sub: NDKSubscription, filters: NDKFilter[]): void;
1105
+ createSubscription(_sub: NDKSubscription, _filters: NDKFilter[], fingerprint?: NDKFilterFingerprint): NDKRelaySubscription;
1106
+ private onRelaySubscriptionClose;
1107
+ }
1108
+
1109
+ /**
1110
+ * Protocol handler function type for handling custom relay messages.
1111
+ * @param relay The relay that received the message
1112
+ * @param message The parsed message array from the relay
1113
+ */
1114
+ type NDKProtocolHandler = (relay: NDKRelay, message: unknown[]) => void;
1115
+ declare enum NDKRelayStatus {
1116
+ DISCONNECTING = 0,// 0
1117
+ DISCONNECTED = 1,// 1
1118
+ RECONNECTING = 2,// 2
1119
+ FLAPPING = 3,// 3
1120
+ CONNECTING = 4,// 4
1121
+ CONNECTED = 5,// 5
1122
+ AUTH_REQUESTED = 6,// 6
1123
+ AUTHENTICATING = 7,// 7
1124
+ AUTHENTICATED = 8
1125
+ }
1126
+ interface NDKRelayConnectionStats {
1127
+ /**
1128
+ * The number of times a connection has been attempted.
1129
+ */
1130
+ attempts: number;
1131
+ /**
1132
+ * The number of times a connection has been successfully established.
1133
+ */
1134
+ success: number;
1135
+ /**
1136
+ * The durations of the last 100 connections in milliseconds.
1137
+ */
1138
+ durations: number[];
1139
+ /**
1140
+ * The time the current connection was established in milliseconds.
1141
+ */
1142
+ connectedAt?: number;
1143
+ /**
1144
+ * Timestamp of the next reconnection attempt.
1145
+ */
1146
+ nextReconnectAt?: number;
1147
+ /**
1148
+ * Signature validation ratio for this relay.
1149
+ * @see NDKRelayOptions.validationRatio
1150
+ */
1151
+ validationRatio?: number;
1152
+ }
1153
+ /**
1154
+ * The NDKRelay class represents a connection to a relay.
1155
+ *
1156
+ * @emits NDKRelay#connect
1157
+ * @emits NDKRelay#ready
1158
+ * @emits NDKRelay#disconnect
1159
+ * @emits NDKRelay#notice
1160
+ * @emits NDKRelay#event
1161
+ * @emits NDKRelay#published when an event is published to the relay
1162
+ * @emits NDKRelay#publish:failed when an event fails to publish to the relay
1163
+ * @emits NDKRelay#eose when the relay has reached the end of stored events
1164
+ * @emits NDKRelay#auth when the relay requires authentication
1165
+ * @emits NDKRelay#authed when the relay has authenticated
1166
+ * @emits NDKRelay#delayed-connect when the relay will wait before reconnecting
1167
+ */
1168
+ declare class NDKRelay extends EventEmitter<{
1169
+ connect: () => void;
1170
+ ready: () => void;
1171
+ /**
1172
+ * Emitted when the relay has reached the end of stored events.
1173
+ */
1174
+ disconnect: () => void;
1175
+ flapping: (stats: NDKRelayConnectionStats) => void;
1176
+ notice: (notice: string) => void;
1177
+ auth: (challenge: string) => void;
1178
+ authed: () => void;
1179
+ "auth:failed": (error: Error) => void;
1180
+ published: (event: NDKEvent) => void;
1181
+ "publish:failed": (event: NDKEvent, error: Error) => void;
1182
+ "delayed-connect": (delayInMs: number) => void;
1183
+ }> {
1184
+ readonly url: WebSocket["url"];
1185
+ readonly scores: Map<NDKUser, NDKRelayScore>;
1186
+ connectivity: NDKRelayConnectivity;
1187
+ subs: NDKRelaySubscriptionManager;
1188
+ private publisher;
1189
+ authPolicy?: NDKAuthPolicy;
1190
+ /**
1191
+ * Protocol handlers for custom relay message types (e.g., NEG-OPEN, NEG-MSG).
1192
+ * Allows external packages to handle non-standard relay messages.
1193
+ */
1194
+ private protocolHandlers;
1195
+ /**
1196
+ * Cached relay information from NIP-11.
1197
+ */
1198
+ private _relayInfo?;
1199
+ /**
1200
+ * The lowest validation ratio this relay can reach.
1201
+ */
1202
+ lowestValidationRatio?: number;
1203
+ /**
1204
+ * Current validation ratio this relay is targeting.
1205
+ */
1206
+ targetValidationRatio?: number;
1207
+ validationRatioFn?: (relay: NDKRelay, validatedCount: number, nonValidatedCount: number) => number;
1208
+ /**
1209
+ * This tracks events that have been seen by this relay
1210
+ * with a valid signature.
1211
+ */
1212
+ validatedEventCount: number;
1213
+ /**
1214
+ * This tracks events that have been seen by this relay
1215
+ * but have not been validated.
1216
+ */
1217
+ nonValidatedEventCount: number;
1218
+ /**
1219
+ * Whether this relay is trusted.
1220
+ *
1221
+ * Trusted relay's events do not get their signature verified.
1222
+ */
1223
+ trusted: boolean;
1224
+ complaining: boolean;
1225
+ readonly debug: debug$1.Debugger;
1226
+ static defaultValidationRatioUpdateFn: (relay: NDKRelay, validatedCount: number, _nonValidatedCount: number) => number;
1227
+ constructor(url: WebSocket["url"], authPolicy: NDKAuthPolicy | undefined, ndk: NDK);
1228
+ private updateValidationRatio;
1229
+ get status(): NDKRelayStatus;
1230
+ get connectionStats(): NDKRelayConnectionStats;
1231
+ /**
1232
+ * The NIP-42 challenge the relay sent on the current connection, if any.
1233
+ */
1234
+ get authChallenge(): string | undefined;
1235
+ /**
1236
+ * Answers the relay's NIP-42 challenge with this relay's auth policy (or the
1237
+ * NDK default). Resolves true once the relay accepts, false otherwise.
1238
+ *
1239
+ * With no challenge on the connection yet, the one that comes is answered as soon as it
1240
+ * arrives (the policy sees `reason` rather than an unprompted `challenge`).
1241
+ */
1242
+ authenticate(reason?: NDKAuthReason): Promise<boolean>;
1243
+ /**
1244
+ * Resolves true if the relay answers a probe REQ within `timeoutMs` (default 3s).
1245
+ * Use it to tell a silent-but-alive socket from a dead one.
1246
+ */
1247
+ ping(timeoutMs?: number): Promise<boolean>;
1248
+ /**
1249
+ * Replaces this relay's socket with a new one (also while it is closing) and
1250
+ * resolves once the new one is ready. Running subscriptions are re-sent.
1251
+ */
1252
+ reconnect(timeoutMs?: number): Promise<void>;
1253
+ /**
1254
+ * Connects to the relay.
1255
+ */
1256
+ connect(timeoutMs?: number, reconnect?: boolean): Promise<void>;
1257
+ /**
1258
+ * Disconnects from the relay.
1259
+ */
1260
+ disconnect(): void;
1261
+ /**
1262
+ * Queues or executes the subscription of a specific set of filters
1263
+ * within this relay.
1264
+ *
1265
+ * @param subscription NDKSubscription this filters belong to.
1266
+ * @param filters Filters to execute
1267
+ */
1268
+ subscribe(subscription: NDKSubscription, filters: NDKFilter[]): void;
1269
+ /**
1270
+ * Publishes an event to the relay with an optional timeout.
1271
+ *
1272
+ * If the relay is not connected, the event will be published when the relay connects,
1273
+ * unless the timeout is reached before the relay connects.
1274
+ *
1275
+ * @param event The event to publish
1276
+ * @param timeoutMs The timeout for the publish operation in milliseconds
1277
+ * @returns A promise that resolves when the event has been published or rejects if the operation times out
1278
+ */
1279
+ publish(event: NDKEvent, timeoutMs?: number): Promise<boolean>;
1280
+ referenceTags(): NDKTag[];
1281
+ addValidatedEvent(): void;
1282
+ addNonValidatedEvent(): void;
1283
+ /**
1284
+ * The current validation ratio this relay has achieved.
1285
+ */
1286
+ get validationRatio(): number;
1287
+ shouldValidateEvent(): boolean;
1288
+ get connected(): boolean;
1289
+ req: (relaySub: NDKRelaySubscription) => void;
1290
+ close: (subId: string) => void;
1291
+ /**
1292
+ * Registers a protocol handler for a specific message type.
1293
+ * This allows external packages to handle custom relay messages (e.g., NIP-77 NEG-* messages).
1294
+ *
1295
+ * @param messageType The message type to handle (e.g., "NEG-OPEN", "NEG-MSG")
1296
+ * @param handler The function to call when a message of this type is received
1297
+ *
1298
+ * @example
1299
+ * ```typescript
1300
+ * relay.registerProtocolHandler('NEG-MSG', (relay, message) => {
1301
+ * console.log('Received NEG-MSG:', message);
1302
+ * });
1303
+ * ```
1304
+ */
1305
+ registerProtocolHandler(messageType: string, handler: NDKProtocolHandler): void;
1306
+ /**
1307
+ * Unregisters a protocol handler for a specific message type.
1308
+ *
1309
+ * @param messageType The message type to stop handling
1310
+ */
1311
+ unregisterProtocolHandler(messageType: string): void;
1312
+ /**
1313
+ * Checks if a protocol handler is registered for a message type.
1314
+ * This is used internally by the connectivity layer to route messages.
1315
+ *
1316
+ * @internal
1317
+ * @param messageType The message type to check
1318
+ * @returns The handler function if registered, undefined otherwise
1319
+ */
1320
+ getProtocolHandler(messageType: string): NDKProtocolHandler | undefined;
1321
+ /**
1322
+ * Fetches relay information (NIP-11) from the relay.
1323
+ * Results are cached in persistent storage when cache adapter is available (24-hour TTL).
1324
+ * Falls back to in-memory cache. Pass force=true to bypass all caches.
1325
+ *
1326
+ * @param force Force a fresh fetch, bypassing all caches
1327
+ * @returns The relay information document
1328
+ * @throws Error if the fetch fails
1329
+ *
1330
+ * @example
1331
+ * ```typescript
1332
+ * const info = await relay.fetchInfo();
1333
+ * console.log(`Relay: ${info.name}`);
1334
+ * console.log(`Supported NIPs: ${info.supported_nips?.join(', ')}`);
1335
+ * ```
1336
+ */
1337
+ fetchInfo(force?: boolean): Promise<NDKRelayInformation>;
1338
+ /**
1339
+ * Returns cached relay information if available, undefined otherwise.
1340
+ * Use fetchInfo() to retrieve fresh information.
1341
+ */
1342
+ get info(): NDKRelayInformation | undefined;
1343
+ }
1344
+
1345
+ type NDKSubscriptionInternalId = string;
1346
+
1347
+ type NDKSubscriptionDelayedType = "at-least" | "at-most";
1348
+ type NDKFilter<K extends number = NDKKind> = {
1349
+ ids?: string[];
1350
+ kinds?: K[];
1351
+ authors?: string[];
1352
+ since?: number;
1353
+ until?: number;
1354
+ limit?: number;
1355
+ search?: string;
1356
+ [key: `#${string}`]: string[] | undefined;
1357
+ };
1358
+ declare enum NDKSubscriptionCacheUsage {
1359
+ ONLY_CACHE = "ONLY_CACHE",
1360
+ CACHE_FIRST = "CACHE_FIRST",
1361
+ PARALLEL = "PARALLEL",
1362
+ ONLY_RELAY = "ONLY_RELAY"
1363
+ }
1364
+ interface NDKSubscriptionOptions {
1365
+ /**
1366
+ * Whether to close the subscription when all relays have reached the end of the event stream.
1367
+ * @default false
1368
+ */
1369
+ closeOnEose?: boolean;
1370
+ cacheUsage?: NDKSubscriptionCacheUsage;
1371
+ /**
1372
+ * Whether to skip caching events coming from this subscription
1373
+ **/
1374
+ dontSaveToCache?: boolean;
1375
+ /**
1376
+ * Groupable subscriptions are created with a slight time
1377
+ * delayed to allow similar filters to be grouped together.
1378
+ */
1379
+ groupable?: boolean;
1380
+ /**
1381
+ * The delay to use when grouping subscriptions, specified in milliseconds.
1382
+ * @default 100
1383
+ * @example
1384
+ * const sub1 = ndk.subscribe({ kinds: [1], authors: ["alice"] }, { groupableDelay: 100 });
1385
+ * const sub2 = ndk.subscribe({ kinds: [0], authors: ["alice"] }, { groupableDelay: 1000 });
1386
+ * // sub1 and sub2 will be grouped together and executed 100ms after sub1 was created
1387
+ */
1388
+ groupableDelay?: number;
1389
+ /**
1390
+ * Specifies how this delay should be interpreted.
1391
+ * "at-least" means "wait at least this long before sending the subscription"
1392
+ * "at-most" means "wait at most this long before sending the subscription"
1393
+ * @default "at-most"
1394
+ * @example
1395
+ * const sub1 = ndk.subscribe({ kinds: [1], authors: ["alice"] }, { groupableDelay: 100, groupableDelayType: "at-least" }); // 3 args
1396
+ * const sub2 = ndk.subscribe({ kinds: [0], authors: ["alice"] }, { groupableDelay: 1000, groupableDelayType: "at-most" }); // 3 args
1397
+ * // sub1 and sub2 will be grouped together and executed 1000ms after sub1 was created
1398
+ */
1399
+ groupableDelayType?: NDKSubscriptionDelayedType;
1400
+ /**
1401
+ * The subscription ID to use for the subscription.
1402
+ */
1403
+ subId?: string;
1404
+ /**
1405
+ * Pool to use
1406
+ */
1407
+ pool?: NDKPool;
1408
+ /**
1409
+ * Skip signature verification
1410
+ * @default false
1411
+ */
1412
+ skipVerification?: boolean;
1413
+ /**
1414
+ * Skip event validation. Event validation, checks whether received
1415
+ * kinds conform to what the expected schema of that kind should look like.rtwle
1416
+ * @default false
1417
+ */
1418
+ skipValidation?: boolean;
1419
+ /**
1420
+ * Skip emitting on events before they are received from a relay. (skip optimistic publish)
1421
+ * @default false
1422
+ */
1423
+ skipOptimisticPublishEvent?: boolean;
1424
+ /**
1425
+ * Remove filter constraints when querying the cache.
1426
+ *
1427
+ * This allows setting more aggressive filters that will be removed when hitting the cache.
1428
+ *
1429
+ * Useful uses of this include removing `since` or `until` constraints or `limit` filters.
1430
+ *
1431
+ * @example
1432
+ * ndk.subscribe({ kinds: [1], since: 1710000000, limit: 10 }, { cacheUnconstrainFilter: ['since', 'limit'] }); // 3 args
1433
+ *
1434
+ * This will hit relays with the since and limit constraints, while loading from the cache without them.
1435
+ */
1436
+ cacheUnconstrainFilter?: (keyof NDKFilter)[];
1437
+ /**
1438
+ * Whether to wrap events in kind-specific classes when possible.
1439
+ * @default false
1440
+ */
1441
+ wrap?: boolean;
1442
+ /**
1443
+ * Explicit relay set to use for this subscription instead of calculating it.
1444
+ * If `relayUrls` is also provided in the options, this `relaySet` takes precedence.
1445
+ * @since 2.13.0 Moved from `ndk.subscribe` parameter to options.
1446
+ */
1447
+ relaySet?: NDKRelaySet;
1448
+ /**
1449
+ * Explicit relay URLs to use for this subscription instead of calculating the relay set.
1450
+ * An `NDKRelaySet` will be created internally from these URLs.
1451
+ * If `relaySet` is also provided in the options, the explicit `relaySet` takes precedence over these URLs.
1452
+ * @since 2.13.0
1453
+ */
1454
+ relayUrls?: string[];
1455
+ /**
1456
+ * When set, the cache will be queried first, and, when hitting relays,
1457
+ * a `since` filter will be added to the subscription that is one second
1458
+ * after the last event received from the cache.
1459
+ *
1460
+ * This option implies cacheUsage: CACHE_FIRST.
1461
+ */
1462
+ addSinceFromCache?: boolean;
1463
+ /**
1464
+ * Include muted events in subscription results.
1465
+ * When false (default), events that match ndk.muteFilter are filtered out.
1466
+ * When true, muted events are included.
1467
+ * @default false
1468
+ */
1469
+ includeMuted?: boolean;
1470
+ /**
1471
+ * Number of relays to query for each author in the subscription.
1472
+ * This controls the outbox model relay selection when the filter has authors.
1473
+ * Higher values improve redundancy but increase bandwidth usage.
1474
+ * @default 2
1475
+ * @example
1476
+ * // Query 3 relays for each author
1477
+ * ndk.subscribe(
1478
+ * { kinds: [1], authors: ["alice", "bob"] },
1479
+ * { relayGoalPerAuthor: 3 }
1480
+ * );
1481
+ * @example
1482
+ * // Use all available relays for each author
1483
+ * ndk.subscribe(
1484
+ * { kinds: [1], authors: ["alice", "bob"] },
1485
+ * { relayGoalPerAuthor: Infinity }
1486
+ * );
1487
+ */
1488
+ relayGoalPerAuthor?: number;
1489
+ /**
1490
+ * Called for each event received by the subscription.
1491
+ * This eliminates the race condition of subscribing and then attaching event handlers.
1492
+ * @param event The received NDKEvent.
1493
+ * @param relay The relay the event was received from (undefined if from cache).
1494
+ * @param subscription The subscription that received the event.
1495
+ * @param fromCache Whether the event came from cache.
1496
+ * @param optimisticPublish Whether this is an optimistic publish event.
1497
+ */
1498
+ onEvent?: (event: NDKEvent, relay?: NDKRelay, subscription?: NDKSubscription, fromCache?: boolean, optimisticPublish?: boolean) => void;
1499
+ /**
1500
+ * Called with a batch of events from cache.
1501
+ * When this is provided, cached events are processed in batch instead of individually.
1502
+ * @param events Array of cached events to process in batch.
1503
+ */
1504
+ onEvents?: (events: NDKEvent[]) => void;
1505
+ /**
1506
+ * Called when the subscription receives an EOSE (End of Stored Events) marker
1507
+ * from all connected relays.
1508
+ * @param subscription The subscription that reached EOSE.
1509
+ */
1510
+ onEose?: (subscription: NDKSubscription) => void;
1511
+ /**
1512
+ * Called when a duplicate event is received by the subscription.
1513
+ * @param event The duplicate event received by the subscription.
1514
+ * @param relay The relay that received the event (undefined if from cache).
1515
+ * @param timeSinceFirstSeen The time elapsed since the first time the event was seen.
1516
+ * @param subscription The subscription that received the event.
1517
+ * @param fromCache Whether the event came from cache.
1518
+ * @param optimisticPublish Whether this is an optimistic publish event.
1519
+ */
1520
+ onEventDup?: (event: NDKEvent | NostrEvent, relay: NDKRelay | undefined, timeSinceFirstSeen: number, subscription: NDKSubscription, fromCache: boolean, optimisticPublish: boolean) => void;
1521
+ /**
1522
+ * Called when the subscription is closed.
1523
+ * @param subscription The subscription that was closed.
1524
+ */
1525
+ onClose?: (subscription: NDKSubscription) => void;
1526
+ /**
1527
+ * When true, only accept events from the relays specified in relaySet/relayUrls.
1528
+ * When false (default), events matching the filter from any relay will be delivered
1529
+ * to this subscription (cross-subscription matching behavior).
1530
+ *
1531
+ * This is useful when you need strict relay provenance, such as:
1532
+ * - Fetching events exclusively from a specific relay
1533
+ * - Implementing relay-based isolation or routing
1534
+ * - Testing relay-specific behavior
1535
+ *
1536
+ * @default false
1537
+ * @example
1538
+ * // Only receive events from relay-a.com, ignore matches from other relays
1539
+ * ndk.subscribe(
1540
+ * { kinds: [1] },
1541
+ * { relayUrls: ["wss://relay-a.com"], exclusiveRelay: true }
1542
+ * );
1543
+ */
1544
+ exclusiveRelay?: boolean;
1545
+ }
1546
+ /**
1547
+ * Represents a subscription to an NDK event stream.
1548
+ *
1549
+ * @emits event
1550
+ * Emitted when an event is received by the subscription.
1551
+ * * ({NDKEvent} event - The event received by the subscription,
1552
+ * * {NDKRelay} relay - The relay that received the event,
1553
+ * * {NDKSubscription} subscription - The subscription that received the event.)
1554
+ *
1555
+ * @emits event:dup
1556
+ * Emitted when a duplicate event is received by the subscription.
1557
+ * * {NDKEvent} event - The duplicate event received by the subscription.
1558
+ * * {NDKRelay} relay - The relay that received the event.
1559
+ * * {number} timeSinceFirstSeen - The time elapsed since the first time the event was seen.
1560
+ * * {NDKSubscription} subscription - The subscription that received the event.
1561
+ *
1562
+ * @emits cacheEose - Emitted when the cache adapter has reached the end of the events it had.
1563
+ *
1564
+ * @emits eose - Emitted when all relays have reached the end of the event stream.
1565
+ * * {NDKSubscription} subscription - The subscription that received EOSE.
1566
+ *
1567
+ * @emits close - Emitted when the subscription is closed.
1568
+ * * {NDKSubscription} subscription - The subscription that was closed.
1569
+ *
1570
+ * @example
1571
+ * const sub = ndk.subscribe(
1572
+ * { kinds: [1] }, // Get all kind:1s
1573
+ * {
1574
+ * onEvent: (event) => console.log(event.content), // Show the content
1575
+ * onEose: () => console.log("All relays have reached the end of the event stream"),
1576
+ * onClose: () => console.log("Subscription closed")
1577
+ * }
1578
+ * );
1579
+ * setTimeout(() => sub.stop(), 10000); // Stop the subscription after 10 seconds
1580
+ *
1581
+ * @description
1582
+ * Subscriptions are created using {@link NDK.subscribe}.
1583
+ *
1584
+ * # Event validation
1585
+ * By defaults, subscriptions will validate events to comply with the minimal requirement
1586
+ * of each known NIP.
1587
+ * This can be disabled by setting the `skipValidation` option to `true`.
1588
+ *
1589
+ * @example
1590
+ * const sub = ndk.subscribe(
1591
+ * { kinds: [1] },
1592
+ * {
1593
+ * skipValidation: false,
1594
+ * onEvent: (event) => console.log(event.content) // Only valid events will be received
1595
+ * }
1596
+ * );
1597
+ */
1598
+ declare class NDKSubscription extends EventEmitter<{
1599
+ cacheEose: () => void;
1600
+ eose: (sub: NDKSubscription) => void;
1601
+ /** One relay finished sending what it has (EOSE, or a final CLOSED); again after a re-send. */
1602
+ "relay:eose": (relay: NDKRelay, sub: NDKSubscription) => void;
1603
+ close: (sub: NDKSubscription) => void;
1604
+ /**
1605
+ * Emitted when a duplicate event is received by the subscription.
1606
+ * @param event - The duplicate event received by the subscription.
1607
+ * @param relay - The relay that received the event.
1608
+ * @param timeSinceFirstSeen - The time elapsed since the first time the event was seen.
1609
+ * @param sub - The subscription that received the event.
1610
+ */
1611
+ "event:dup": (event: NDKEvent | NostrEvent, relay: NDKRelay | undefined, timeSinceFirstSeen: number, sub: NDKSubscription, fromCache: boolean, optimisticPublish: boolean) => void;
1612
+ /**
1613
+ * Emitted when an event is received by the subscription.
1614
+ * @param event - The event received by the subscription.
1615
+ * @param relay - The relay that received the event.
1616
+ * @param sub - The subscription that received the event.
1617
+ * @param fromCache - Whether the event was received from the cache.
1618
+ * @param optimisticPublish - Whether the event was received from an optimistic publish.
1619
+ */
1620
+ event: (event: NDKSignedEvent, relay: NDKRelay | undefined, sub: NDKSubscription, fromCache: boolean, optimisticPublish: boolean) => void;
1621
+ /**
1622
+ * Emitted when a relay unilaterally closes the subscription.
1623
+ * @param relay
1624
+ * @param reason
1625
+ * @returns
1626
+ */
1627
+ closed: (relay: NDKRelay, reason: string) => void;
1628
+ }> {
1629
+ readonly subId?: string;
1630
+ readonly filters: NDKFilter[];
1631
+ readonly opts: NDKSubscriptionOptions;
1632
+ readonly pool: NDKPool;
1633
+ readonly skipVerification: boolean;
1634
+ readonly skipValidation: boolean;
1635
+ readonly exclusiveRelay: boolean;
1636
+ /**
1637
+ * Tracks the filters as they are executed on each relay
1638
+ */
1639
+ relayFilters?: Map<WebSocket["url"], NDKFilter[]>;
1640
+ relaySet?: NDKRelaySet;
1641
+ ndk: NDK;
1642
+ debug: debug.Debugger;
1643
+ /**
1644
+ * Events that have been seen by the subscription, with the time they were first seen.
1645
+ */
1646
+ eventFirstSeen: Map<string, number>;
1647
+ /**
1648
+ * Relays that have sent an EOSE.
1649
+ */
1650
+ eosesSeen: Set<NDKRelay>;
1651
+ /**
1652
+ * The time the last event was received by the subscription.
1653
+ * This is used to calculate when EOSE should be emitted.
1654
+ */
1655
+ private lastEventReceivedAt;
1656
+ /**
1657
+ * The most recent event timestamp from cache results.
1658
+ * This is used for addSinceFromCache functionality.
1659
+ */
1660
+ private mostRecentCacheEventTimestamp?;
1661
+ internalId: NDKSubscriptionInternalId;
1662
+ /**
1663
+ * Whether the subscription should close when all relays have reached the end of the event stream.
1664
+ */
1665
+ closeOnEose: boolean;
1666
+ /**
1667
+ * Pool monitor callback
1668
+ */
1669
+ private poolMonitor;
1670
+ skipOptimisticPublishEvent: boolean;
1671
+ /**
1672
+ * Filters to remove when querying the cache.
1673
+ */
1674
+ cacheUnconstrainFilter?: Array<keyof NDKFilter>;
1675
+ constructor(ndk: NDK, filters: NDKFilter | NDKFilter[], opts?: NDKSubscriptionOptions, subId?: string);
1676
+ /**
1677
+ * Returns the relays that have not yet sent an EOSE.
1678
+ */
1679
+ relaysMissingEose(): WebSocket["url"][];
1680
+ /**
1681
+ * Provides access to the first filter of the subscription for
1682
+ * backwards compatibility.
1683
+ */
1684
+ get filter(): NDKFilter;
1685
+ get groupableDelay(): number | undefined;
1686
+ get groupableDelayType(): NDKSubscriptionDelayedType;
1687
+ isGroupable(): boolean;
1688
+ private shouldQueryCache;
1689
+ private shouldQueryRelays;
1690
+ private shouldWaitForCache;
1691
+ /**
1692
+ * Start the subscription. This is the main method that should be called
1693
+ * after creating a subscription.
1694
+ *
1695
+ * @param emitCachedEvents - Whether to emit events coming from a synchronous cache
1696
+ *
1697
+ * When using a synchronous cache, the events will be returned immediately
1698
+ * by this function. If you will use those returned events, you should
1699
+ * set emitCachedEvents to false to prevent seeing them as duplicate events.
1700
+ */
1701
+ start(emitCachedEvents?: boolean): NDKEvent[] | null;
1702
+ /**
1703
+ * We want to monitor for new relays that are coming online, in case
1704
+ * they should be part of this subscription.
1705
+ */
1706
+ private startPoolMonitor;
1707
+ onStopped?: () => void;
1708
+ stop(): void;
1709
+ /**
1710
+ * @returns Whether the subscription has an authors filter.
1711
+ */
1712
+ hasAuthorsFilter(): boolean;
1713
+ private startWithCache;
1714
+ /**
1715
+ * Find available relays that should be part of this subscription and execute in them.
1716
+ *
1717
+ * Note that this is executed in addition to using the pool monitor, so even if the relay set
1718
+ * that is computed (i.e. we don't have any relays available), when relays come online, we will
1719
+ * check if we need to execute in them.
1720
+ */
1721
+ private startWithRelays;
1722
+ /**
1723
+ * Refresh relay connections when outbox data becomes available.
1724
+ * This recalculates which relays should receive this subscription and
1725
+ * connects to any newly discovered relays.
1726
+ */
1727
+ refreshRelayConnections(): void;
1728
+ /**
1729
+ * Called when an event is received from a relay or the cache
1730
+ * @param event
1731
+ * @param relay
1732
+ * @param fromCache Whether the event was received from the cache
1733
+ * @param optimisticPublish Whether this event is coming from an optimistic publish
1734
+ */
1735
+ eventReceived(event: NDKEvent | NostrEvent, relay: NDKRelay | undefined, fromCache?: boolean, optimisticPublish?: boolean): void;
1736
+ /** Caches (relay events), applies the mute filter and emits an accepted event. */
1737
+ private deliverEvent;
1738
+ /**
1739
+ * Optionally wraps, sync or async, and emits the event (if one comes back from the wrapper)
1740
+ */
1741
+ private emitEvent;
1742
+ closedReceived(relay: NDKRelay, reason: string): void;
1743
+ private eoseTimeout;
1744
+ private eosed;
1745
+ /** Relay events held until their signature is verified (verifyBeforeEmit). */
1746
+ private pendingVerifications;
1747
+ private holdUntilVerified;
1748
+ eoseReceived(relay: NDKRelay, afterPendingVerifications?: boolean): void;
1749
+ }
1750
+
1751
+ declare class NDKPublishError extends Error {
1752
+ errors: Map<NDKRelay, Error>;
1753
+ publishedToRelays: Set<NDKRelay>;
1754
+ /**
1755
+ * Intended relay set where the publishing was intended to happen.
1756
+ */
1757
+ intendedRelaySet?: NDKRelaySet;
1758
+ constructor(message: string, errors: Map<NDKRelay, Error>, publishedToRelays: Set<NDKRelay>, intendedRelaySet?: NDKRelaySet);
1759
+ get relayErrors(): string;
1760
+ }
1761
+ /**
1762
+ * A relay set is a group of relays. This grouping can be short-living, for a single
1763
+ * REQ or can be long-lasting, for example for the explicit relay list the user
1764
+ * has specified.
1765
+ *
1766
+ * Requests to relays should be sent through this interface.
1767
+ */
1768
+ declare class NDKRelaySet {
1769
+ readonly relays: Set<NDKRelay>;
1770
+ private debug;
1771
+ private ndk;
1772
+ private pool;
1773
+ constructor(relays: Set<NDKRelay>, ndk: NDK, pool?: NDKPool);
1774
+ /**
1775
+ * Adds a relay to this set.
1776
+ */
1777
+ addRelay(relay: NDKRelay): void;
1778
+ get relayUrls(): WebSocket["url"][];
1779
+ /**
1780
+ * Creates a relay set from a list of relay URLs.
1781
+ *
1782
+ * If no connection to the relay is found in the pool it will temporarily
1783
+ * connect to it.
1784
+ *
1785
+ * @param relayUrls - list of relay URLs to include in this set
1786
+ * @param ndk
1787
+ * @param connect - whether to connect to the relay immediately if it was already in the pool but not connected
1788
+ * @returns NDKRelaySet
1789
+ */
1790
+ static fromRelayUrls(relayUrls: readonly string[], ndk: NDK, connect?: boolean, pool?: NDKPool): NDKRelaySet;
1791
+ /**
1792
+ * Publish an event to all relays in this relay set.
1793
+ *
1794
+ * This method implements a robust mechanism for publishing events to multiple relays with
1795
+ * built-in handling for race conditions, timeouts, and partial failures. The implementation
1796
+ * uses a dual-tracking mechanism to ensure accurate reporting of which relays successfully
1797
+ * received an event.
1798
+ *
1799
+ * Key aspects of this implementation:
1800
+ *
1801
+ * 1. DUAL-TRACKING MECHANISM:
1802
+ * - Promise-based tracking: Records successes/failures from the promises returned by relay.publish()
1803
+ * - Event-based tracking: Listens for 'relay:published' events that indicate successful publishing
1804
+ * This approach ensures we don't miss successful publishes even if there are subsequent errors in
1805
+ * the promise chain.
1806
+ *
1807
+ * 2. RACE CONDITION HANDLING:
1808
+ * - If a relay emits a success event but later fails in the promise chain, we still count it as a success
1809
+ * - If a relay times out after successfully publishing, we still count it as a success
1810
+ * - All relay operations happen in parallel, with proper tracking regardless of completion order
1811
+ *
1812
+ * 3. TIMEOUT MANAGEMENT:
1813
+ * - Individual timeouts for each relay operation
1814
+ * - Proper cleanup of timeouts to prevent memory leaks
1815
+ * - Clear timeout error reporting
1816
+ *
1817
+ * 4. ERROR HANDLING:
1818
+ * - Detailed tracking of specific errors for each failed relay
1819
+ * - Special handling for ephemeral events (which don't expect acknowledgement)
1820
+ * - RequiredRelayCount parameter to control the minimum success threshold
1821
+ *
1822
+ * @param event Event to publish
1823
+ * @param timeoutMs Timeout in milliseconds for each relay publish operation
1824
+ * @param requiredRelayCount The minimum number of relays we expect the event to be published to
1825
+ * @returns A set of relays the event was published to
1826
+ * @throws {NDKPublishError} If the event could not be published to at least `requiredRelayCount` relays
1827
+ * @example
1828
+ * ```typescript
1829
+ * const relaySet = new NDKRelaySet(new Set([relay1, relay2]), ndk);
1830
+ * const publishedToRelays = await relaySet.publish(event);
1831
+ * // publishedToRelays can contain relay1, relay2, both, or none
1832
+ * // depending on which relays the event was successfully published to
1833
+ * if (publishedToRelays.size > 0) {
1834
+ * console.log("Event published to at least one relay");
1835
+ * }
1836
+ * ```
1837
+ */
1838
+ publish(event: NDKEvent, timeoutMs?: number, requiredRelayCount?: number): Promise<Set<NDKRelay>>;
1839
+ get size(): number;
1840
+ /**
1841
+ * Counts events matching the given filters across all relays in this set.
1842
+ *
1843
+ * This method implements NIP-45 COUNT with HyperLogLog (HLL) support for
1844
+ * accurate cardinality estimation across multiple relays.
1845
+ *
1846
+ * When relays return HLL data, the counts are merged using the HLL algorithm
1847
+ * to avoid double-counting events that appear on multiple relays.
1848
+ *
1849
+ * @param filters - The filters to count events for
1850
+ * @param opts - Optional count options (timeout, custom id)
1851
+ * @returns An aggregated count result with the best estimate and per-relay results
1852
+ *
1853
+ * @example
1854
+ * ```typescript
1855
+ * const relaySet = new NDKRelaySet(new Set([relay1, relay2]), ndk);
1856
+ * const result = await relaySet.count([{ kinds: [1], authors: [pubkey] }]);
1857
+ * console.log(`Estimated unique count: ${result.count}`);
1858
+ * console.log(`Relay 1 reported: ${result.relayResults.get(relay1.url)?.count}`);
1859
+ * ```
1860
+ */
1861
+ count(filters: NDKFilter | NDKFilter[], opts?: NDKCountOptions): Promise<NDKAggregatedCountResult>;
1862
+ }
1863
+
1864
+ /**
1865
+ * Options on how to handle when a relay hint doesn't respond
1866
+ * with the requested event.
1867
+ *
1868
+ * When a tag includes a relay hint, and the relay hint doesn't come back
1869
+ * with the event, the fallback options are used to try to fetch the event
1870
+ * from somewhere else.
1871
+ */
1872
+ type NDKFetchFallbackOptions = {
1873
+ /**
1874
+ * Relay set to use as a fallback when the hint relay doesn't respond.
1875
+ * If not provided, the normal NDK calculation is used (whether explicit relays or outbox calculation)
1876
+ * Default is `undefined`.
1877
+ */
1878
+ relaySet?: NDKRelaySet;
1879
+ /**
1880
+ * Type of fallback to use when the hint relay doesn't respond.
1881
+ * - "timeout" will wait for a timeout before falling back
1882
+ * - "eose" will wait for the EOSE before falling back
1883
+ * - "none" will not fall back
1884
+ * Default is "timeout".
1885
+ */
1886
+ type: "timeout" | "eose" | "none";
1887
+ /**
1888
+ * Timeout in milliseconds for the fallback relay.
1889
+ * Default is 1500ms.
1890
+ */
1891
+ timeout?: number;
1892
+ };
1893
+
1894
+ interface AIGuardrailConfig {
1895
+ skip?: Set<string>;
1896
+ }
1897
+ type AIGuardrailsMode = boolean | AIGuardrailConfig;
1898
+
1899
+ /**
1900
+ * AI Guardrails - Runtime validation to catch common mistakes made by LLMs and developers.
1901
+ *
1902
+ * This module provides a flexible system for warning about or preventing common anti-patterns
1903
+ * when using NDK. It's designed to be:
1904
+ * - Off by default (zero performance impact in production)
1905
+ * - Granularly configurable (can disable specific checks)
1906
+ * - Educational (provides actionable error messages)
1907
+ *
1908
+ * Architecture:
1909
+ * - Inline checks for synchronous validation (must block operations)
1910
+ * - Hook methods for observational warnings (async, non-blocking)
1911
+ * - All guardrail logic organized by domain (ndk, event, relay, etc.)
1912
+ * - Core code stays clean - just calls typed hook methods
1913
+ *
1914
+ * @example Enable all guardrails
1915
+ * ```typescript
1916
+ * const ndk = new NDK({ aiGuardrails: true });
1917
+ * ```
1918
+ *
1919
+ * @example Enable with exceptions
1920
+ * ```typescript
1921
+ * const ndk = new NDK({
1922
+ * aiGuardrails: { skip: new Set(['filter-large-limit']) }
1923
+ * });
1924
+ * ```
1925
+ *
1926
+ * @example Programmatic control
1927
+ * ```typescript
1928
+ * ndk.aiGuardrails.skip('filter-large-limit');
1929
+ * ndk.aiGuardrails.enable('filter-bech32-in-array');
1930
+ * ```
1931
+ *
1932
+ * @example Temporarily disable for one call
1933
+ * ```typescript
1934
+ * // Disable all guardrails for one call
1935
+ * ndk.guardrailOff().fetchEvents({ kinds: [1] });
1936
+ *
1937
+ * // Disable specific guardrail for one call
1938
+ * ndk.guardrailOff('fetch-events-usage').fetchEvents({ kinds: [1] });
1939
+ *
1940
+ * // Disable multiple guardrails for one call
1941
+ * ndk.guardrailOff(['fetch-events-usage', 'filter-large-limit'])
1942
+ * .fetchEvents({ kinds: [1], limit: 5000 });
1943
+ *
1944
+ * // Next call has guardrails re-enabled automatically
1945
+ * ndk.fetchEvents({ kinds: [1] }); // Guardrails active again
1946
+ * ```
1947
+ *
1948
+ * @example Hook usage in core code
1949
+ * ```typescript
1950
+ * // Clean, type-safe hook calls
1951
+ * this.aiGuardrails.ndkInstantiated(this);
1952
+ * this.aiGuardrails.eventReceived(event, relay);
1953
+ * ```
1954
+ */
1955
+
1956
+ /**
1957
+ * Central guardrails manager.
1958
+ * Provides both inline validation methods and hook methods for observational checks.
1959
+ */
1960
+ declare class AIGuardrails {
1961
+ private enabled;
1962
+ private skipSet;
1963
+ private extensions;
1964
+ private _nextCallDisabled;
1965
+ private _replyEvents;
1966
+ private _fetchEventsCount;
1967
+ private _subscribeCount;
1968
+ constructor(mode?: AIGuardrailsMode);
1969
+ /**
1970
+ * Register an extension namespace with custom guardrail hooks.
1971
+ * This allows external packages to add their own guardrails.
1972
+ *
1973
+ * @example
1974
+ * ```typescript
1975
+ * // In NDKSvelte package:
1976
+ * ndk.aiGuardrails.register('ndkSvelte', {
1977
+ * constructing: (params) => {
1978
+ * if (!params.session) {
1979
+ * warn('ndksvelte-no-session', 'NDKSvelte instantiated without session parameter...');
1980
+ * }
1981
+ * }
1982
+ * });
1983
+ *
1984
+ * // In NDKSvelte constructor:
1985
+ * this.ndk.aiGuardrails?.ndkSvelte?.constructing(params);
1986
+ * ```
1987
+ */
1988
+ register(namespace: string, hooks: any): void;
1989
+ /**
1990
+ * Set the guardrails mode.
1991
+ */
1992
+ setMode(mode: AIGuardrailsMode): void;
1993
+ /**
1994
+ * Check if guardrails are enabled at all.
1995
+ */
1996
+ isEnabled(): boolean;
1997
+ /**
1998
+ * Check if a specific guardrail check should run.
1999
+ */
2000
+ shouldCheck(id: string): boolean;
2001
+ /**
2002
+ * Disable a specific guardrail check.
2003
+ */
2004
+ skip(id: string): void;
2005
+ /**
2006
+ * Re-enable a specific guardrail check.
2007
+ */
2008
+ enable(id: string): void;
2009
+ /**
2010
+ * Get all currently skipped guardrails.
2011
+ */
2012
+ getSkipped(): string[];
2013
+ /**
2014
+ * Capture the current _nextCallDisabled set and clear it atomically.
2015
+ * This is used by hook methods to handle one-time guardrail disabling.
2016
+ */
2017
+ captureAndClearNextCallDisabled(): Set<string> | "all" | null;
2018
+ /**
2019
+ * Increment fetchEvents call counter for ratio tracking.
2020
+ */
2021
+ incrementFetchEventsCount(): void;
2022
+ /**
2023
+ * Increment subscribe call counter for ratio tracking.
2024
+ */
2025
+ incrementSubscribeCount(): void;
2026
+ /**
2027
+ * Check if fetchEvents usage ratio exceeds the threshold.
2028
+ * Returns true if more than 50% of calls are fetchEvents AND total calls > 6.
2029
+ */
2030
+ shouldWarnAboutFetchEventsRatio(): boolean;
2031
+ /**
2032
+ * Throw an error if the check should run.
2033
+ * Also logs to console.error in case the throw gets swallowed.
2034
+ * @param canDisable - If false, this is a fatal error that cannot be disabled (default: true)
2035
+ */
2036
+ error(id: string, message: string, hint?: string, canDisable?: boolean): never | undefined;
2037
+ /**
2038
+ * Throw a warning if the check should run.
2039
+ * Also logs to console.error in case the throw gets swallowed.
2040
+ * Warnings can always be disabled.
2041
+ */
2042
+ warn(id: string, message: string, hint?: string): never | undefined;
2043
+ /**
2044
+ * Format a guardrail message with helpful metadata.
2045
+ */
2046
+ private formatMessage;
2047
+ /**
2048
+ * Called when NDK instance is created.
2049
+ * Checks for cache presence and other initialization concerns.
2050
+ */
2051
+ ndkInstantiated(ndk: NDK): void;
2052
+ /**
2053
+ * NDK-related guardrails
2054
+ */
2055
+ ndk: {
2056
+ /**
2057
+ * Called when fetchEvents is about to be called
2058
+ */
2059
+ fetchingEvents: (filters: any, opts?: any) => void;
2060
+ };
2061
+ /**
2062
+ * Event-related guardrails
2063
+ */
2064
+ event: {
2065
+ /**
2066
+ * Called when an event is about to be signed
2067
+ */
2068
+ signing: (event: NDKEvent) => void;
2069
+ /**
2070
+ * Called before an event is published
2071
+ */
2072
+ publishing: (event: NDKEvent) => void;
2073
+ /**
2074
+ * Called when an event is received from a relay
2075
+ */
2076
+ received: (_event: NDKEvent, _relay: NDKRelay) => void;
2077
+ /**
2078
+ * Called when a reply event is being created via .reply()
2079
+ * This allows guardrails to track legitimate reply events
2080
+ */
2081
+ creatingReply: (event: NDKEvent) => void;
2082
+ };
2083
+ /**
2084
+ * Subscription-related guardrails
2085
+ */
2086
+ subscription: {
2087
+ /**
2088
+ * Called when a subscription is created
2089
+ */
2090
+ created: (_filters: any[], _opts?: any) => void;
2091
+ };
2092
+ /**
2093
+ * Relay-related guardrails
2094
+ */
2095
+ relay: {
2096
+ /**
2097
+ * Called when a relay connection is established
2098
+ */
2099
+ connected: (_relay: NDKRelay) => void;
2100
+ };
2101
+ }
2102
+
2103
+ type NDKPaymentConfirmationLN = {
2104
+ preimage: string;
2105
+ };
2106
+ type LNPaymentRequest = string;
2107
+ type LnPaymentInfo = {
2108
+ pr: LNPaymentRequest;
2109
+ };
2110
+ type NDKLUD18ServicePayerData = Partial<{
2111
+ name: {
2112
+ mandatory: boolean;
2113
+ };
2114
+ pubkey: {
2115
+ mandatory: boolean;
2116
+ };
2117
+ identifier: {
2118
+ mandatory: boolean;
2119
+ };
2120
+ email: {
2121
+ mandatory: boolean;
2122
+ };
2123
+ auth: {
2124
+ mandatory: boolean;
2125
+ k1: string;
2126
+ };
2127
+ }> & Record<string, unknown>;
2128
+ type NDKLnUrlData = {
2129
+ tag: string;
2130
+ callback: string;
2131
+ minSendable: number;
2132
+ maxSendable: number;
2133
+ metadata: string;
2134
+ payerData?: NDKLUD18ServicePayerData;
2135
+ commentAllowed?: number;
2136
+ /**
2137
+ * Pubkey of the zapper that should publish zap receipts for this user
2138
+ */
2139
+ nostrPubkey?: Hexpubkey;
2140
+ allowsNostr?: boolean;
2141
+ };
2142
+
2143
+ type NDKCacheEntry<T> = T & {
2144
+ cachedAt?: number;
2145
+ };
2146
+ /**
2147
+ * Cache module definition for packages to extend the cache with their own data structures.
2148
+ * Packages define their schemas, indexes, and migrations.
2149
+ */
2150
+ interface CacheModuleDefinition {
2151
+ /**
2152
+ * Unique namespace for this module (e.g., "messages", "wallet", "sync")
2153
+ */
2154
+ namespace: string;
2155
+ /**
2156
+ * Current version of this module's schema
2157
+ */
2158
+ version: number;
2159
+ /**
2160
+ * Collection definitions for this module
2161
+ */
2162
+ collections: {
2163
+ [name: string]: {
2164
+ /**
2165
+ * Primary key field name
2166
+ */
2167
+ primaryKey: string;
2168
+ /**
2169
+ * Fields to create indexes on for efficient querying
2170
+ */
2171
+ indexes?: string[];
2172
+ /**
2173
+ * Optional schema definition (for validation or TypeScript generation)
2174
+ */
2175
+ schema?: Record<string, any>;
2176
+ /**
2177
+ * Compound indexes for multi-field queries
2178
+ */
2179
+ compoundIndexes?: Array<string[]>;
2180
+ };
2181
+ };
2182
+ /**
2183
+ * Migration functions keyed by version number
2184
+ * Version 1 is the initial setup, 2+ are upgrades
2185
+ */
2186
+ migrations: {
2187
+ [version: number]: (adapter: CacheModuleMigrationContext) => Promise<void>;
2188
+ };
2189
+ }
2190
+ /**
2191
+ * Migration context passed to module migration functions
2192
+ */
2193
+ interface CacheModuleMigrationContext {
2194
+ /**
2195
+ * Get a collection by name within the module's namespace
2196
+ */
2197
+ getCollection(name: string): Promise<CacheModuleCollection<any>>;
2198
+ /**
2199
+ * Create a new collection
2200
+ */
2201
+ createCollection(name: string, definition: CacheModuleDefinition["collections"][string]): Promise<void>;
2202
+ /**
2203
+ * Delete a collection
2204
+ */
2205
+ deleteCollection(name: string): Promise<void>;
2206
+ /**
2207
+ * Add an index to a collection
2208
+ */
2209
+ addIndex(collection: string, field: string | string[]): Promise<void>;
2210
+ /**
2211
+ * Current version being migrated from
2212
+ */
2213
+ fromVersion: number;
2214
+ /**
2215
+ * Target version being migrated to
2216
+ */
2217
+ toVersion: number;
2218
+ }
2219
+ /**
2220
+ * Collection interface for module data access
2221
+ */
2222
+ interface CacheModuleCollection<T> {
2223
+ /**
2224
+ * Get an item by its primary key
2225
+ */
2226
+ get(id: string): Promise<T | null>;
2227
+ /**
2228
+ * Get multiple items by their primary keys
2229
+ */
2230
+ getMany(ids: string[]): Promise<T[]>;
2231
+ /**
2232
+ * Save an item (upsert)
2233
+ */
2234
+ save(item: T): Promise<void>;
2235
+ /**
2236
+ * Save multiple items (bulk upsert)
2237
+ */
2238
+ saveMany(items: T[]): Promise<void>;
2239
+ /**
2240
+ * Delete an item by its primary key
2241
+ */
2242
+ delete(id: string): Promise<void>;
2243
+ /**
2244
+ * Delete multiple items by their primary keys
2245
+ */
2246
+ deleteMany(ids: string[]): Promise<void>;
2247
+ /**
2248
+ * Query items by a single field
2249
+ */
2250
+ findBy(field: string, value: any): Promise<T[]>;
2251
+ /**
2252
+ * Query items with multiple conditions
2253
+ */
2254
+ where(conditions: Record<string, any>): Promise<T[]>;
2255
+ /**
2256
+ * Get all items in the collection
2257
+ */
2258
+ all(): Promise<T[]>;
2259
+ /**
2260
+ * Count items matching conditions
2261
+ */
2262
+ count(conditions?: Record<string, any>): Promise<number>;
2263
+ /**
2264
+ * Clear all items from the collection
2265
+ */
2266
+ clear(): Promise<void>;
2267
+ }
2268
+ interface NDKCacheAdapter {
2269
+ /**
2270
+ * Whether this cache adapter is expected to be fast.
2271
+ * If this is true, the cache will be queried before the relays.
2272
+ * When this is false, the cache will be queried in addition to the relays.
2273
+ */
2274
+ locking: boolean;
2275
+ /**
2276
+ * Weather the cache is ready.
2277
+ */
2278
+ ready?: boolean;
2279
+ initializeAsync?(ndk: NDK): Promise<void>;
2280
+ initialize?(ndk: NDK): void;
2281
+ /**
2282
+ * Either synchronously or asynchronously queries the cache.
2283
+ *
2284
+ * Cache adapters that return values synchronously should return an array of events.
2285
+ * Asynchronous cache adapters should call the subscription.eventReceived method for each event.
2286
+ */
2287
+ query(subscription: NDKSubscription): NDKEvent[] | Promise<NDKEvent[]>;
2288
+ setEvent(event: NDKEvent, filters: NDKFilter[], relay?: NDKRelay): Promise<void>;
2289
+ /**
2290
+ * Called when we receive a duplicate event from a relay.
2291
+ * This associates the relay with an existing cached event without re-processing the event data.
2292
+ * @param event - The duplicate event received.
2293
+ * @param relay - The relay that sent the duplicate event.
2294
+ */
2295
+ setEventDup?(event: NDKEvent, relay: NDKRelay): Promise<void> | void;
2296
+ /**
2297
+ * Called when an event is deleted by the client.
2298
+ * Cache adapters should remove the event from their cache.
2299
+ * @param eventIds - The ids of the events that were deleted.
2300
+ */
2301
+ deleteEventIds?(eventIds: NDKEventId[]): Promise<void>;
2302
+ /**
2303
+ * Fetches a profile from the cache synchronously.
2304
+ * @param pubkey - The pubkey of the profile to fetch.
2305
+ * @returns The profile, or null if it is not in the cache.
2306
+ */
2307
+ fetchProfileSync?(pubkey: Hexpubkey): NDKCacheEntry<NDKUserProfile> | null;
2308
+ /**
2309
+ * Retrieve all profiles from the cache synchronously.
2310
+ * @returns A map of pubkeys to profiles.
2311
+ */
2312
+ getAllProfilesSync?(): Map<Hexpubkey, NDKCacheEntry<NDKUserProfile>>;
2313
+ /**
2314
+ * Special purpose
2315
+ */
2316
+ fetchProfile?(pubkey: Hexpubkey): Promise<NDKCacheEntry<NDKUserProfile> | null>;
2317
+ saveProfile?(pubkey: Hexpubkey, profile: NDKUserProfile): void | Promise<void>;
2318
+ /**
2319
+ * Fetches profiles that match the given filter.
2320
+ * @param filter - Either a filter function or a filter descriptor object
2321
+ * @returns NDKUserProfiles that match the filter.
2322
+ * @example
2323
+ * // Using a filter function
2324
+ * const searchFunc = (pubkey, profile) => profile.name.toLowerCase().includes("alice");
2325
+ * const allAliceProfiles = await cache.getProfiles(searchFunc);
2326
+ *
2327
+ * @example
2328
+ * // Using a filter descriptor (supported by some cache adapters like cache-sqlite-wasm)
2329
+ * const aliceProfiles = await cache.getProfiles({ field: 'name', contains: 'alice' });
2330
+ * // Or search multiple fields
2331
+ * const aliceProfiles = await cache.getProfiles({ fields: ['name', 'displayName'], contains: 'alice' });
2332
+ */
2333
+ getProfiles?: (filter: ((pubkey: Hexpubkey, profile: NDKUserProfile) => boolean) | {
2334
+ field?: string;
2335
+ fields?: string[];
2336
+ contains: string;
2337
+ }) => Promise<Map<Hexpubkey, NDKUserProfile> | undefined>;
2338
+ loadNip05?(nip05: string, maxAgeForMissing?: number): Promise<ProfilePointer | null | "missing">;
2339
+ saveNip05?(nip05: string, profile: ProfilePointer | null): void;
2340
+ /**
2341
+ * Fetches a user's LNURL data from the cache.
2342
+ * @param pubkey The pubkey of the user to fetch the LNURL data for.
2343
+ * @param maxAgeInSecs The maximum age of the data in seconds.
2344
+ * @param maxAgeForMissing The maximum age of the data in seconds if it is missing before it returns that it should be refetched.
2345
+ * @returns The LNURL data, null if it is not in the cache and under the maxAgeForMissing, or "missing" if it should be refetched.
2346
+ */
2347
+ loadUsersLNURLDoc?(pubkey: Hexpubkey, maxAgeInSecs?: number, maxAgeForMissing?: number): Promise<NDKLnUrlData | null | "missing">;
2348
+ saveUsersLNURLDoc?(pubkey: Hexpubkey, doc: NDKLnUrlData | null): void;
2349
+ /**
2350
+ * Updates information about the relay.
2351
+ */
2352
+ updateRelayStatus?(relayUrl: WebSocket["url"], info: NDKCacheRelayInfo): void | Promise<void>;
2353
+ /**
2354
+ * Fetches information about the relay.
2355
+ */
2356
+ getRelayStatus?(relayUrl: WebSocket["url"]): NDKCacheRelayInfo | undefined | Promise<NDKCacheRelayInfo | undefined>;
2357
+ /**
2358
+ * Tracks a publishing event.
2359
+ * @param event
2360
+ * @param relayUrls List of relays that the event will be published to.
2361
+ */
2362
+ addUnpublishedEvent?(event: NDKEvent, relayUrls: WebSocket["url"][]): void | Promise<void>;
2363
+ /**
2364
+ * Fetches all unpublished events.
2365
+ */
2366
+ getUnpublishedEvents?(): Promise<{
2367
+ event: NDKEvent;
2368
+ relays?: WebSocket["url"][];
2369
+ lastTryAt?: number;
2370
+ }[]>;
2371
+ /**
2372
+ * Removes an unpublished event.
2373
+ */
2374
+ discardUnpublishedEvent?(eventId: NDKEventId): void | Promise<void>;
2375
+ /**
2376
+ * Called when the cache is ready.
2377
+ */
2378
+ onReady?(callback: () => void): void;
2379
+ /**
2380
+ * Get a decrypted event from the cache by its wrapper ID.
2381
+ * @param wrapperId - The ID of the gift-wrapped event (kind 1059).
2382
+ * @returns The decrypted rumor event, or null if it doesn't exist.
2383
+ */
2384
+ getDecryptedEvent?(wrapperId: NDKEventId): NDKEvent | null | Promise<NDKEvent | null>;
2385
+ /**
2386
+ * Store a decrypted event in the cache.
2387
+ * @param wrapperId - The ID of the gift-wrapped event (kind 1059) to use as the cache key.
2388
+ * @param decryptedEvent - The decrypted rumor event to store.
2389
+ */
2390
+ addDecryptedEvent?(wrapperId: NDKEventId, decryptedEvent: NDKEvent): void | Promise<void>;
2391
+ /**
2392
+ * Cleans up the cache. This is called when the user logs out.
2393
+ */
2394
+ clear?(): Promise<void>;
2395
+ /**
2396
+ * Gets all nutzap states from the cache.
2397
+ * @returns A map of event IDs to nutzap states.
2398
+ */
2399
+ getAllNutzapStates?(): Promise<Map<NDKEventId, NDKNutzapState>>;
2400
+ /**
2401
+ * Sets the state of a nutzap in the cache.
2402
+ * @param id The ID of the nutzap event.
2403
+ * @param stateChange The partial state change to apply.
2404
+ */
2405
+ setNutzapState?(id: NDKEventId, stateChange: Partial<NDKNutzapState>): Promise<void>;
2406
+ /**
2407
+ * Generic key-value cache storage for packages.
2408
+ * Packages should namespace their keys (e.g., "wallet:mint:info:https://mint.url").
2409
+ * @param namespace The namespace for the data (e.g., "wallet", "sync")
2410
+ * @param key The key within the namespace
2411
+ * @param maxAgeInSecs Maximum age of cached data in seconds (optional)
2412
+ * @returns The cached data, or undefined if not cached or expired
2413
+ */
2414
+ getCacheData?<T>(namespace: string, key: string, maxAgeInSecs?: number): Promise<T | undefined>;
2415
+ /**
2416
+ * Generic key-value cache storage for packages.
2417
+ * @param namespace The namespace for the data (e.g., "wallet", "sync")
2418
+ * @param key The key within the namespace
2419
+ * @param data The data to cache
2420
+ */
2421
+ setCacheData?<T>(namespace: string, key: string, data: T): Promise<void>;
2422
+ /**
2423
+ * Cache module support - Register a module with its schema and migrations
2424
+ * @param module Module definition with schema, indexes, and migrations
2425
+ * @returns Promise that resolves when the module is registered and migrations are complete
2426
+ */
2427
+ registerModule?(module: CacheModuleDefinition): Promise<void>;
2428
+ /**
2429
+ * Cache module support - Get a collection from a registered module
2430
+ * @param namespace Module namespace
2431
+ * @param collection Collection name within the module
2432
+ * @returns Collection interface for data operations
2433
+ */
2434
+ getModuleCollection?<T>(namespace: string, collection: string): Promise<CacheModuleCollection<T>>;
2435
+ }
2436
+ /**
2437
+ * Relay metadata and statistics stored in cache.
2438
+ *
2439
+ * This type supports both core connection tracking and extensible package-specific metadata.
2440
+ * Packages can store custom data using the metadata field with namespacing.
2441
+ *
2442
+ * @example
2443
+ * ```typescript
2444
+ * // Core connection tracking
2445
+ * await cache.updateRelayStatus(url, {
2446
+ * lastConnectedAt: Date.now(),
2447
+ * consecutiveFailures: 0
2448
+ * });
2449
+ *
2450
+ * // Package-specific metadata (sync package)
2451
+ * await cache.updateRelayStatus(url, {
2452
+ * metadata: {
2453
+ * sync: {
2454
+ * supportsNegentropy: false,
2455
+ * lastChecked: Date.now()
2456
+ * }
2457
+ * }
2458
+ * });
2459
+ *
2460
+ * // Package-specific metadata (auth/rate limiting)
2461
+ * await cache.updateRelayStatus(url, {
2462
+ * metadata: {
2463
+ * auth: {
2464
+ * token: 'AUTH_TOKEN_HERE',
2465
+ * expiresAt: Date.now() + 3600000
2466
+ * },
2467
+ * rateLimit: {
2468
+ * requestCount: 42,
2469
+ * windowStart: Date.now(),
2470
+ * maxPerWindow: 100
2471
+ * }
2472
+ * }
2473
+ * });
2474
+ *
2475
+ * // NIP-11 caching
2476
+ * await cache.updateRelayStatus(url, {
2477
+ * nip11: {
2478
+ * data: relayInfo,
2479
+ * fetchedAt: Date.now()
2480
+ * }
2481
+ * });
2482
+ * ```
2483
+ */
2484
+ type NDKCacheRelayInfo = {
2485
+ /**
2486
+ * Timestamp of last successful connection
2487
+ */
2488
+ lastConnectedAt?: number;
2489
+ /**
2490
+ * Don't attempt connection before this timestamp
2491
+ */
2492
+ dontConnectBefore?: number;
2493
+ /**
2494
+ * Number of consecutive connection failures
2495
+ */
2496
+ consecutiveFailures?: number;
2497
+ /**
2498
+ * Timestamp of last connection failure
2499
+ */
2500
+ lastFailureAt?: number;
2501
+ /**
2502
+ * Cached NIP-11 relay information document
2503
+ */
2504
+ nip11?: {
2505
+ data: NDKRelayInformation;
2506
+ fetchedAt: number;
2507
+ };
2508
+ /**
2509
+ * Package-specific metadata (namespaced).
2510
+ *
2511
+ * Packages should use their package name as the namespace key.
2512
+ *
2513
+ * @example
2514
+ * ```typescript
2515
+ * metadata: {
2516
+ * sync: { supportsNegentropy: false, lastChecked: 1234567890 },
2517
+ * auth: { token: 'abc123', expiresAt: 1234567890 },
2518
+ * rateLimit: { requestCount: 42, windowStart: 1234567890, maxPerWindow: 100 }
2519
+ * }
2520
+ * ```
2521
+ */
2522
+ metadata?: Record<string, Record<string, unknown>>;
2523
+ };
2524
+
2525
+ type OutboxItemType = "user" | "kind";
2526
+ /**
2527
+ * Tracks outbox scoring of an item. An item can be any of:
2528
+ *
2529
+ * - A user
2530
+ * - A tag
2531
+ */
2532
+ declare class OutboxItem {
2533
+ /**
2534
+ * Type of item
2535
+ */
2536
+ type: OutboxItemType;
2537
+ /**
2538
+ * The relay URLs that are of interest to this item
2539
+ */
2540
+ relayUrlScores: Map<WebSocket["url"], number>;
2541
+ readRelays: Set<WebSocket["url"]>;
2542
+ writeRelays: Set<WebSocket["url"]>;
2543
+ constructor(type: OutboxItemType);
2544
+ }
2545
+ /**
2546
+ * The responsibility of this class is to track relay:outbox-item associations
2547
+ * so that we can intelligently choose which relays to query for which items.
2548
+ *
2549
+ * A single instance of this class should be shared across all subscriptions within
2550
+ * an NDK instance.
2551
+ *
2552
+ * TODO: The state of this tracker needs to be added to cache adapters so that we
2553
+ * can rehydrate-it when a cache is present.
2554
+ */
2555
+ declare class OutboxTracker extends EventEmitter {
2556
+ data: LRUCache<Hexpubkey, OutboxItem>;
2557
+ private ndk;
2558
+ private debug;
2559
+ constructor(ndk: NDK);
2560
+ /**
2561
+ * Adds a list of users to the tracker.
2562
+ * @param items
2563
+ * @param skipCache
2564
+ */
2565
+ trackUsers(items: NDKUser[] | Hexpubkey[], skipCache?: boolean): Promise<void[]>;
2566
+ /**
2567
+ *
2568
+ * @param key
2569
+ * @param score
2570
+ */
2571
+ track(item: NDKUser | Hexpubkey, type?: OutboxItemType, _skipCache?: boolean): OutboxItem;
2572
+ }
2573
+
2574
+ type Proof$1 = {
2575
+ /**
2576
+ * Keyset id, used to link proofs to a mint an its MintKeys.
2577
+ */
2578
+ id: string;
2579
+ /**
2580
+ * Amount denominated in Satoshis. Has to match the amount of the mints signing key.
2581
+ */
2582
+ amount: number;
2583
+ /**
2584
+ * The initial secret that was (randomly) chosen for the creation of this proof.
2585
+ */
2586
+ secret: string;
2587
+ /**
2588
+ * The unblinded signature for this secret, signed by the mints private key.
2589
+ */
2590
+ C: string;
2591
+ };
2592
+
2593
+ declare enum NutzapValidationCode {
2594
+ NO_PROOFS = "NO_PROOFS",
2595
+ INVALID_PROOF_COUNT = "INVALID_PROOF_COUNT",
2596
+ MULTIPLE_RECIPIENTS = "MULTIPLE_RECIPIENTS",
2597
+ NO_RECIPIENT = "NO_RECIPIENT",
2598
+ MULTIPLE_MINTS = "MULTIPLE_MINTS",
2599
+ NO_MINT = "NO_MINT",
2600
+ MULTIPLE_EVENT_TAGS = "MULTIPLE_EVENT_TAGS",
2601
+ MALFORMED_PROOF_SECRET = "MALFORMED_PROOF_SECRET",
2602
+ MISSING_EVENT_TAG_IN_PROOF = "MISSING_EVENT_TAG_IN_PROOF",
2603
+ MISMATCHED_EVENT_TAG_IN_PROOF = "MISMATCHED_EVENT_TAG_IN_PROOF",
2604
+ MISSING_SENDER_TAG_IN_PROOF = "MISSING_SENDER_TAG_IN_PROOF",
2605
+ MISMATCHED_SENDER_TAG_IN_PROOF = "MISMATCHED_SENDER_TAG_IN_PROOF",
2606
+ NO_EVENT_TAG_IN_EVENT = "NO_EVENT_TAG_IN_EVENT"
2607
+ }
2608
+ declare enum NutzapValidationSeverity {
2609
+ ERROR = "ERROR",
2610
+ WARNING = "WARNING"
2611
+ }
2612
+ type NutzapValidationIssue = {
2613
+ code: NutzapValidationCode;
2614
+ severity: NutzapValidationSeverity;
2615
+ message: string;
2616
+ proofIndex?: number;
2617
+ };
2618
+ type NutzapValidationResult = {
2619
+ valid: boolean;
2620
+ issues: NutzapValidationIssue[];
2621
+ };
2622
+
2623
+ /**
2624
+ * Represents a NIP-61 nutzap
2625
+ */
2626
+ declare class NDKNutzap extends NDKEvent {
2627
+ private debug;
2628
+ private _proofs;
2629
+ static kind: NDKKind;
2630
+ static kinds: NDKKind[];
2631
+ constructor(ndk?: NDK, event?: NostrEvent | NDKEvent);
2632
+ static from(event: NDKEvent): NDKNutzap | undefined;
2633
+ set comment(comment: string | undefined);
2634
+ get comment(): string;
2635
+ set proofs(proofs: Proof$1[]);
2636
+ get proofs(): Proof$1[];
2637
+ get rawP2pk(): string | undefined;
2638
+ /**
2639
+ * Gets the p2pk pubkey that is embedded in the first proof.
2640
+ *
2641
+ * Note that this returns a nostr pubkey, not a cashu pubkey (no "02" prefix)
2642
+ */
2643
+ get p2pk(): string | undefined;
2644
+ /**
2645
+ * Get the mint where this nutzap proofs exist
2646
+ */
2647
+ get mint(): string;
2648
+ set mint(value: string);
2649
+ get unit(): string;
2650
+ set unit(value: string | undefined);
2651
+ get amount(): number;
2652
+ sender: NDKUser;
2653
+ /**
2654
+ * Set the target of the nutzap
2655
+ * @param target The target of the nutzap (a user or an event)
2656
+ */
2657
+ set target(target: NDKEvent | NDKUser);
2658
+ set recipientPubkey(pubkey: Hexpubkey);
2659
+ get recipientPubkey(): Hexpubkey;
2660
+ get recipient(): NDKUser;
2661
+ toNostrEvent(): Promise<NostrEvent>;
2662
+ /**
2663
+ * Validates that the nutzap conforms to NIP-61
2664
+ * @deprecated Use validateNIP61() instead for detailed validation results
2665
+ */
2666
+ get isValid(): boolean;
2667
+ /**
2668
+ * Performs comprehensive validation of the nutzap according to NIP-61.
2669
+ * Returns detailed validation results including errors and warnings.
2670
+ *
2671
+ * Errors make the nutzap invalid, warnings are recommendations for best practices.
2672
+ */
2673
+ validateNIP61(): NutzapValidationResult;
2674
+ }
2675
+
2676
+ /**
2677
+ * Provides information that should be used to send a NIP-61 nutzap.
2678
+ * mints: URLs of the mints that can be used.
2679
+ * relays: URLs of the relays where nutzap must be published
2680
+ * p2pk: Optional pubkey to use for P2PK lock
2681
+ */
2682
+ type CashuPaymentInfo = {
2683
+ /**
2684
+ * Mints that must be used for the payment
2685
+ */
2686
+ mints?: string[];
2687
+ /**
2688
+ * Relays where nutzap must be published
2689
+ */
2690
+ relays?: string[];
2691
+ /**
2692
+ * Optional pubkey to use for P2PK lock
2693
+ */
2694
+ p2pk?: string;
2695
+ /**
2696
+ * Tags to include in the proof secrets (e.g., [["e", "event-id"], ["P", "sender-pubkey"]])
2697
+ * These tags will be added to the P2PK lock structure for replay protection and sender verification.
2698
+ */
2699
+ proofTags?: [string, string][];
2700
+ /**
2701
+ * Intramint fallback allowed:
2702
+ *
2703
+ * When set to true, if cross-mint payments fail, we will
2704
+ * fallback to sending an intra-mint payment.
2705
+ */
2706
+ allowIntramintFallback?: boolean;
2707
+ };
2708
+ /**
2709
+ * This is what a wallet implementing Cashu payments should provide back
2710
+ * when a payment has been requested.
2711
+ */
2712
+ type NDKPaymentConfirmationCashu = {
2713
+ /**
2714
+ * Proof of the payment
2715
+ */
2716
+ proofs: Proof$1[];
2717
+ /**
2718
+ * Mint
2719
+ */
2720
+ mint: string;
2721
+ };
2722
+
2723
+ type NDKZapDetails<T> = T & {
2724
+ /**
2725
+ * Target of the zap
2726
+ */
2727
+ target: NDKEvent | NDKUser;
2728
+ /**
2729
+ * Comment for the zap
2730
+ */
2731
+ comment?: string;
2732
+ /**
2733
+ * Tags to add to the zap
2734
+ */
2735
+ tags?: NDKTag[];
2736
+ /**
2737
+ * Pubkey of the user to zap to
2738
+ */
2739
+ recipientPubkey: string;
2740
+ /**
2741
+ * Amount of the payment
2742
+ */
2743
+ amount: number;
2744
+ /**
2745
+ * Unit of the payment (e.g. msat)
2746
+ */
2747
+ unit: string;
2748
+ /**
2749
+ * Description of the payment for the sender's record
2750
+ */
2751
+ paymentDescription?: string;
2752
+ /**
2753
+ * If this payment is for a nip57 zap, this will contain the zap request.
2754
+ */
2755
+ nip57ZapRequest?: NDKEvent;
2756
+ /**
2757
+ * When set to true, when a pubkey is not zappable, we will
2758
+ * automatically fallback to using NIP-61.
2759
+ *
2760
+ * Every pubkey must be able to receive money.
2761
+ *
2762
+ * @default false
2763
+ */
2764
+ nutzapAsFallback?: boolean;
2765
+ };
2766
+ type NDKPaymentConfirmation = NDKPaymentConfirmationLN | NDKNutzap;
2767
+ type NDKZapSplit = {
2768
+ pubkey: string;
2769
+ amount: number;
2770
+ };
2771
+ type NDKZapMethod = "nip57" | "nip61";
2772
+ type NDKLnLudData = {
2773
+ lud06?: string;
2774
+ lud16?: string;
2775
+ };
2776
+ type NDKZapMethodInfo = NDKLnLudData | CashuPaymentInfo;
2777
+ type LnPayCb = (payment: NDKZapDetails<LnPaymentInfo>) => Promise<NDKPaymentConfirmationLN | undefined>;
2778
+ type CashuPayCb = (payment: NDKZapDetails<CashuPaymentInfo>, onLnInvoice?: (pr: string) => void) => Promise<NDKPaymentConfirmationCashu | undefined>;
2779
+
2780
+ type QueueItem<T> = {
2781
+ /**
2782
+ * Deterministic id of the item
2783
+ */
2784
+ id: string;
2785
+ /**
2786
+ * A function to process the item
2787
+ * @returns
2788
+ */
2789
+ func: () => Promise<T>;
2790
+ };
2791
+ declare class Queue<T> {
2792
+ private queue;
2793
+ private maxConcurrency;
2794
+ private processing;
2795
+ private promises;
2796
+ constructor(_name: string, maxConcurrency: number);
2797
+ add(item: QueueItem<T>): Promise<T>;
2798
+ private process;
2799
+ clear(): void;
2800
+ clearProcessing(): void;
2801
+ clearAll(): void;
2802
+ length(): number;
2803
+ }
2804
+
2805
+ type NDKValidationRatioFn = (relay: NDKRelay, validatedCount: number, nonValidatedCount: number) => number;
2806
+ type NDKNetDebug = (msg: string, relay: NDKRelay, direction?: "send" | "recv") => void;
2807
+ /**
2808
+ * An interface compatible with ndk-wallet that allows setting multiple handlers and callbacks.
2809
+ */
2810
+ interface NDKWalletInterface {
2811
+ lnPay?: LnPayCb;
2812
+ cashuPay?: CashuPayCb;
2813
+ onPaymentComplete?: (results: Map<NDKZapSplit, NDKPaymentConfirmation | Error | undefined>) => void;
2814
+ }
2815
+ interface NDKConstructorParams {
2816
+ /**
2817
+ * Relays we should explicitly connect to
2818
+ */
2819
+ explicitRelayUrls?: string[];
2820
+ /**
2821
+ * When this is set, we always write only to this relays.
2822
+ */
2823
+ devWriteRelayUrls?: string[];
2824
+ /**
2825
+ * Outbox relay URLs.
2826
+ */
2827
+ outboxRelayUrls?: string[];
2828
+ /**
2829
+ * Enable outbox model (defaults to true)
2830
+ */
2831
+ enableOutboxModel?: boolean;
2832
+ /**
2833
+ * Auto-connect to main user's relays. The "main" user is determined
2834
+ * by the presence of a signer. Upon connection to the explicit relays,
2835
+ * the user's relays will be fetched and connected to if this is set to true.
2836
+ * @default true
2837
+ */
2838
+ autoConnectUserRelays?: boolean;
2839
+ /**
2840
+ * Signer to use for signing events by default
2841
+ */
2842
+ signer?: NDKSigner;
2843
+ /**
2844
+ * Cache adapter to use for caching events
2845
+ */
2846
+ cacheAdapter?: NDKCacheAdapter;
2847
+ /**
2848
+ * Debug instance to use
2849
+ */
2850
+ debug?: debug$1.Debugger;
2851
+ /**
2852
+ * Provide a caller function to receive all networking traffic from relays
2853
+ */
2854
+ netDebug?: NDKNetDebug;
2855
+ /**
2856
+ * Custom filter function to determine if an event should be muted.
2857
+ * @param event - The event to check
2858
+ * @returns true if the event should be muted
2859
+ */
2860
+ muteFilter?: (event: NDKEvent) => boolean;
2861
+ /**
2862
+ * Custom filter function to determine if a relay connection should be allowed.
2863
+ * @param relayUrl - The relay URL to check
2864
+ * @returns true if the connection should be allowed, false to block it
2865
+ */
2866
+ relayConnectionFilter?: (relayUrl: string) => boolean;
2867
+ /**
2868
+ * Client name to add to events' tag
2869
+ */
2870
+ clientName?: string;
2871
+ /**
2872
+ * Client nip89 to add to events' tag
2873
+ */
2874
+ clientNip89?: string;
2875
+ /**
2876
+ * Default relay-auth policy
2877
+ */
2878
+ relayAuthDefaultPolicy?: NDKAuthPolicy;
2879
+ /**
2880
+ * Set a Web Worker for signature verification.
2881
+ *
2882
+ * @default undefined
2883
+ *
2884
+ * When provided, signature verification will be processed in a web worker.
2885
+ * You should listen for the `event:invalid-sig` event to handle invalid signatures.
2886
+ *
2887
+ * @example
2888
+ * ```typescript
2889
+ * const worker = new Worker("path/to/signature-verification.js");
2890
+ * ndk.signatureVerificationWorker = worker;
2891
+ * ndk.on("event:invalid-sig", (event) => {
2892
+ * console.error("Invalid signature", event);
2893
+ * });
2894
+ * ```
2895
+ */
2896
+ signatureVerificationWorker?: Worker | undefined;
2897
+ /**
2898
+ * The signature verification validation ratio for new relays.
2899
+ */
2900
+ initialValidationRatio?: number;
2901
+ /**
2902
+ * The lowest validation ratio any single relay can have.
2903
+ * Relays will have a sample of events verified based on this ratio.
2904
+ * When using this, you MUST listen for event:invalid-sig events
2905
+ * to handle invalid signatures and disconnect from evil relays.
2906
+ *
2907
+ * @default 0.1
2908
+ */
2909
+ lowestValidationRatio?: number;
2910
+ /**
2911
+ * A function that is invoked to calculate the validation ratio for a relay.
2912
+ */
2913
+ validationRatioFn?: NDKValidationRatioFn;
2914
+ /**
2915
+ * A custom function to verify event signatures.
2916
+ * When provided, this function will be used instead of the default verification logic.
2917
+ * This is particularly useful for platforms like React Native where Web Workers are not available.
2918
+ *
2919
+ * @example
2920
+ * ```typescript
2921
+ * import { verifySignatureAsync } from "@nostr-dev-kit/mobile";
2922
+ *
2923
+ * const ndk = new NDK({
2924
+ * signatureVerificationFunction: verifySignatureAsync
2925
+ * });
2926
+ * ```
2927
+ */
2928
+ signatureVerificationFunction?: (event: NDKEvent) => Promise<boolean>;
2929
+ /**
2930
+ * With async signature verification (a worker or `signatureVerificationFunction`),
2931
+ * hold each relay event until its signature is verified: it is cached and emitted
2932
+ * only once verified, a forged one never is, and EOSE waits for the events before it.
2933
+ * Off by default, where events are emitted first and checked afterwards.
2934
+ */
2935
+ verifyBeforeEmit?: boolean;
2936
+ /**
2937
+ * Filter validation mode for subscriptions.
2938
+ *
2939
+ * @default "validate" - Throws an error when filters contain undefined values
2940
+ * "fix" - Automatically removes undefined values from filters
2941
+ * "ignore" - Skip validation entirely (legacy behavior)
2942
+ */
2943
+ filterValidationMode?: "validate" | "fix" | "ignore";
2944
+ /**
2945
+ * ⚠️ STRONGLY RECOMMENDED: Enable AI Guardrails during development
2946
+ *
2947
+ * AI Guardrails catch 90% of common mistakes before they cause silent failures:
2948
+ * - Using bech32 (npub/note1) in filter arrays instead of hex
2949
+ * - Missing required fields on events (kind, content, etc.)
2950
+ * - Invalid tag formats and duplicate tags
2951
+ * - Performance anti-patterns (fetchEvents abuse, no cache adapter)
2952
+ * - Wrong data types (milliseconds vs seconds for created_at)
2953
+ *
2954
+ * When enabled, you'll get clear, actionable error messages instead of silent failures.
2955
+ *
2956
+ * @default false - Guardrails are disabled (zero performance impact)
2957
+ *
2958
+ * @example RECOMMENDED: Enable during development
2959
+ * ```typescript
2960
+ * const ndk = new NDK({
2961
+ * explicitRelayUrls: ['wss://relay.primal.net'],
2962
+ * aiGuardrails: true // ⚠️ Enable this!
2963
+ * });
2964
+ * ```
2965
+ *
2966
+ * @example Disable in production
2967
+ * ```typescript
2968
+ * const ndk = new NDK({
2969
+ * aiGuardrails: process.env.NODE_ENV !== 'production'
2970
+ * });
2971
+ * ```
2972
+ *
2973
+ * @example Enable with specific checks disabled
2974
+ * ```typescript
2975
+ * const ndk = new NDK({
2976
+ * aiGuardrails: { skip: new Set(['filter-large-limit']) }
2977
+ * });
2978
+ * ```
2979
+ *
2980
+ * @example Programmatic control
2981
+ * ```typescript
2982
+ * ndk.aiGuardrails.skip('fetch-events-usage');
2983
+ * ndk.aiGuardrails.enable('filter-bech32-in-array');
2984
+ * ```
2985
+ *
2986
+ * @see https://github.com/nostr-dev-kit/ndk/tree/master/ndk/src/ai-guardrails
2987
+ */
2988
+ aiGuardrails?: boolean | {
2989
+ skip?: Set<string>;
2990
+ };
2991
+ /**
2992
+ * Optional grace period (in seconds) for future timestamps.
2993
+ *
2994
+ * When set, subscriptions will automatically discard events where
2995
+ * `created_at` is more than this many seconds ahead of the current time.
2996
+ * This helps protect against malicious relays sending events with
2997
+ * manipulated timestamps.
2998
+ *
2999
+ * Set to `undefined` (default) to disable this check and accept all events
3000
+ * regardless of timestamp.
3001
+ *
3002
+ * @default undefined
3003
+ *
3004
+ * @example Reject events more than 5 minutes in the future
3005
+ * ```typescript
3006
+ * const ndk = new NDK({
3007
+ * explicitRelayUrls: ['wss://relay.primal.net'],
3008
+ * futureTimestampGrace: 300 // 5 minutes
3009
+ * });
3010
+ * ```
3011
+ */
3012
+ futureTimestampGrace?: number;
3013
+ }
3014
+ interface GetUserParams extends NDKUserParams {
3015
+ npub?: string;
3016
+ pubkey?: string;
3017
+ /**
3018
+ * @deprecated Use `pubkey` instead
3019
+ */
3020
+ hexpubkey?: string;
3021
+ }
3022
+ /**
3023
+ * Defines handlers that can be passed to `ndk.subscribe` via the `autoStart` parameter
3024
+ * to react to subscription lifecycle events.
3025
+ */
3026
+ interface NDKSubscriptionEventHandlers {
3027
+ /**
3028
+ * Called for each individual event received from relays *after* the initial cache load (if `onEvents` is provided),
3029
+ * or for *all* events (including cached ones) if `onEvents` is not provided.
3030
+ * @param event The received NDKEvent.
3031
+ * @param relay The relay the event was received from (undefined if from cache).
3032
+ */
3033
+ onEvent?: (event: NDKEvent, relay?: NDKRelay) => void;
3034
+ /**
3035
+ * Called *once* with an array of all events found synchronously in the cache when the subscription starts.
3036
+ * If this handler is provided, `onEvent` will *not* be called for this initial batch of cached events.
3037
+ * This is useful for bulk processing or batching UI updates based on the initial cached state.
3038
+ * @param events An array of NDKEvents loaded synchronously from the cache.
3039
+ */
3040
+ onEvents?: (events: NDKEvent[]) => void;
3041
+ /**
3042
+ * Called when the subscription receives an EOSE (End of Stored Events) marker
3043
+ * from all connected relays involved in this subscription request.
3044
+ * @param sub The NDKSubscription instance that reached EOSE.
3045
+ */
3046
+ onEose?: (sub: NDKSubscription) => void;
3047
+ /**
3048
+ * Called when the subscription is closed.
3049
+ * @param sub The NDKSubscription instance that was closed.
3050
+ */
3051
+ onClose?: (sub: NDKSubscription) => void;
3052
+ }
3053
+ /**
3054
+ * The NDK class is the main entry point to the library.
3055
+ *
3056
+ * @emits signer:ready when a signer is ready
3057
+ * @emits activeUser:change when the active user changes
3058
+ * @emits invalid-signature when an event with an invalid signature is received
3059
+ */
3060
+ declare class NDK extends EventEmitter<{
3061
+ "signer:ready": (signer: NDKSigner) => void;
3062
+ "signer:required": () => void;
3063
+ /**
3064
+ * Emitted when the active user changes.
3065
+ * This can happen when a signer is set or when activeUser is set directly.
3066
+ */
3067
+ "activeUser:change": (user: NDKUser | undefined) => void;
3068
+ /**
3069
+ * Emitted when an event with an invalid signature is received.
3070
+ * Includes the relay that provided the invalid signature.
3071
+ */
3072
+ "event:invalid-sig": (event: NDKEvent, relay?: NDKRelay) => void;
3073
+ /**
3074
+ * Emitted when an event fails to publish.
3075
+ * @param event The event that failed to publish
3076
+ * @param error The error that caused the event to fail to publish
3077
+ * @param relays The relays that the event was attempted to be published to
3078
+ */
3079
+ "event:publish-failed": (event: NDKEvent, error: NDKPublishError, relays: WebSocket["url"][]) => void;
3080
+ }> {
3081
+ private _explicitRelayUrls?;
3082
+ pool: NDKPool;
3083
+ outboxPool?: NDKPool;
3084
+ private _signer?;
3085
+ private _activeUser?;
3086
+ cacheAdapter?: NDKCacheAdapter;
3087
+ debug: debug$1.Debugger;
3088
+ devWriteRelaySet?: NDKRelaySet;
3089
+ outboxTracker?: OutboxTracker;
3090
+ muteFilter?: (event: NDKEvent) => boolean;
3091
+ relayConnectionFilter?: (relayUrl: string) => boolean;
3092
+ clientName?: string;
3093
+ clientNip89?: string;
3094
+ queuesZapConfig: Queue<NDKLnUrlData | undefined>;
3095
+ queuesNip05: Queue<ProfilePointer | null>;
3096
+ asyncSigVerification: boolean;
3097
+ /** See {@link NDKConstructorParams.verifyBeforeEmit}. */
3098
+ verifyBeforeEmit: boolean;
3099
+ initialValidationRatio: number;
3100
+ lowestValidationRatio: number;
3101
+ validationRatioFn?: NDKValidationRatioFn;
3102
+ filterValidationMode: "validate" | "fix" | "ignore";
3103
+ subManager: NDKSubscriptionManager;
3104
+ aiGuardrails: AIGuardrails;
3105
+ futureTimestampGrace?: number;
3106
+ /**
3107
+ * Private storage for the signature verification function
3108
+ */
3109
+ private _signatureVerificationFunction?;
3110
+ /**
3111
+ * Private storage for the signature verification worker
3112
+ */
3113
+ private _signatureVerificationWorker?;
3114
+ /**
3115
+ * Rolling total of time spent (in ms) performing signature verifications.
3116
+ * Users can read this to monitor or display aggregate verification cost.
3117
+ */
3118
+ signatureVerificationTimeMs: number;
3119
+ publishingFailureHandled: boolean;
3120
+ pools: NDKPool[];
3121
+ /**
3122
+ * Default relay-auth policy that will be used when a relay requests authentication,
3123
+ * if no other policy is specified for that relay.
3124
+ *
3125
+ * @example Disconnect from relays that request authentication:
3126
+ * ```typescript
3127
+ * ndk.relayAuthDefaultPolicy = NDKAuthPolicies.disconnect(ndk.pool);
3128
+ * ```
3129
+ *
3130
+ * @example Sign in to relays that request authentication:
3131
+ * ```typescript
3132
+ * ndk.relayAuthDefaultPolicy = NDKAuthPolicies.signIn({ndk})
3133
+ * ```
3134
+ *
3135
+ * @example Sign in to relays that request authentication, asking the user for confirmation:
3136
+ * ```typescript
3137
+ * ndk.relayAuthDefaultPolicy = (relay: NDKRelay) => {
3138
+ * const signIn = NDKAuthPolicies.signIn({ndk});
3139
+ * if (confirm(`Relay ${relay.url} is requesting authentication, do you want to sign in?`)) {
3140
+ * signIn(relay);
3141
+ * }
3142
+ * }
3143
+ * ```
3144
+ */
3145
+ relayAuthDefaultPolicy?: NDKAuthPolicy;
3146
+ /**
3147
+ * Fetch function to use for HTTP requests.
3148
+ *
3149
+ * @example
3150
+ * ```typescript
3151
+ * import fetch from "node-fetch";
3152
+ *
3153
+ * ndk.httpFetch = fetch;
3154
+ * ```
3155
+ */
3156
+ httpFetch: typeof fetch | undefined;
3157
+ /**
3158
+ * Provide a caller function to receive all networking traffic from relays
3159
+ */
3160
+ readonly netDebug?: NDKNetDebug;
3161
+ autoConnectUserRelays: boolean;
3162
+ private _wallet?;
3163
+ walletConfig?: NDKWalletInterface;
3164
+ constructor(opts?: NDKConstructorParams);
3165
+ set explicitRelayUrls(urls: WebSocket["url"][]);
3166
+ get explicitRelayUrls(): WebSocket["url"][];
3167
+ /**
3168
+ * Set a Web Worker for signature verification.
3169
+ *
3170
+ * This method initializes the worker and sets the asyncSigVerification flag.
3171
+ * The actual verification is handled by the verifySignatureAsync function in signature.ts,
3172
+ * which will use the worker if available.
3173
+ */
3174
+ set signatureVerificationWorker(worker: Worker | undefined);
3175
+ /**
3176
+ * Set a custom signature verification function.
3177
+ *
3178
+ * This method is particularly useful for platforms that don't support Web Workers,
3179
+ * such as React Native.
3180
+ *
3181
+ * When a function is provided, it will be used for signature verification
3182
+ * instead of the default worker-based verification. This enables signature
3183
+ * verification on platforms where Web Workers are not available.
3184
+ *
3185
+ * @example
3186
+ * ```typescript
3187
+ * import { verifySignatureAsync } from "@nostr-dev-kit/mobile";
3188
+ *
3189
+ * ndk.signatureVerificationFunction = verifySignatureAsync;
3190
+ * ```
3191
+ */
3192
+ set signatureVerificationFunction(fn: ((event: NDKEvent) => Promise<boolean>) | undefined);
3193
+ /**
3194
+ * Get the custom signature verification function
3195
+ */
3196
+ get signatureVerificationFunction(): ((event: NDKEvent) => Promise<boolean>) | undefined;
3197
+ /**
3198
+ * Adds an explicit relay to the pool.
3199
+ * @param url
3200
+ * @param relayAuthPolicy Authentication policy to use if different from the default
3201
+ * @param connect Whether to connect to the relay automatically
3202
+ * @returns
3203
+ */
3204
+ addExplicitRelay(urlOrRelay: string | NDKRelay, relayAuthPolicy?: NDKAuthPolicy, connect?: boolean): NDKRelay;
3205
+ toJSON(): string;
3206
+ get activeUser(): NDKUser | undefined;
3207
+ /**
3208
+ * Sets the active user for this NDK instance, typically this will be
3209
+ * called when assigning a signer to the NDK instance.
3210
+ *
3211
+ * This function will automatically connect to the user's relays if
3212
+ * `autoConnectUserRelays` is set to true.
3213
+ */
3214
+ set activeUser(user: NDKUser | undefined);
3215
+ get signer(): NDKSigner | undefined;
3216
+ set signer(newSigner: NDKSigner | undefined);
3217
+ /**
3218
+ * Connect to relays with optional timeout.
3219
+ * If the timeout is reached, the connection will be continued to be established in the background.
3220
+ */
3221
+ connect(timeoutMs?: number): Promise<void>;
3222
+ /**
3223
+ * Centralized method to report an invalid signature, identifying the relay that provided it.
3224
+ * A single invalid signature means the relay is considered malicious.
3225
+ * All invalid signature detections (synchronous or asynchronous) should delegate to this method.
3226
+ *
3227
+ * @param event The event with an invalid signature
3228
+ * @param relay The relay that provided the invalid signature
3229
+ */
3230
+ reportInvalidSignature(event: NDKEvent, relay?: NDKRelay): void;
3231
+ /**
3232
+ * Default function to calculate validation ratio based on historical validation results.
3233
+ * The more events validated successfully, the lower the ratio goes (down to the minimum).
3234
+ */
3235
+ private defaultValidationRatioFn;
3236
+ /**
3237
+ * Get a NDKUser object
3238
+ *
3239
+ * @deprecated Use `fetchUser` instead - this method will be removed in the next major version
3240
+ * @param opts - User parameters object or a string (npub, nprofile, or hex pubkey)
3241
+ * @returns NDKUser instance
3242
+ *
3243
+ * @example
3244
+ * ```typescript
3245
+ * // Using parameters object
3246
+ * const user1 = ndk.getUser({ pubkey: "hex..." });
3247
+ *
3248
+ * // Using npub string
3249
+ * const user2 = ndk.getUser("npub1...");
3250
+ *
3251
+ * // Using nprofile string (includes relay hints)
3252
+ * const user3 = ndk.getUser("nprofile1...");
3253
+ *
3254
+ * // Using hex pubkey directly
3255
+ * const user4 = ndk.getUser("deadbeef...");
3256
+ * ```
3257
+ */
3258
+ getUser(opts: GetUserParams | string): NDKUser;
3259
+ /**
3260
+ * Get a NDKUser from a NIP05
3261
+ * @deprecated Use `fetchUser` instead - this method will be removed in the next major version
3262
+ * @param nip05 NIP-05 ID
3263
+ * @param skipCache Skip cache
3264
+ * @returns
3265
+ */
3266
+ getUserFromNip05(nip05: string, skipCache?: boolean): Promise<NDKUser | undefined>;
3267
+ /**
3268
+ * Fetch a NDKUser from a string identifier
3269
+ *
3270
+ * Supports multiple input formats:
3271
+ * - NIP-05 identifiers (e.g., "pablo@test.com" or "test.com")
3272
+ * - npub (NIP-19 encoded public key)
3273
+ * - nprofile (NIP-19 encoded profile with optional relay hints)
3274
+ * - Hex public key
3275
+ *
3276
+ * @param input - String identifier for the user (NIP-05, npub, nprofile, or hex pubkey)
3277
+ * @param skipCache - Skip cache when resolving NIP-05 (only applies to NIP-05 lookups)
3278
+ * @returns Promise resolving to NDKUser or undefined if not found
3279
+ *
3280
+ * @example
3281
+ * ```typescript
3282
+ * // Using NIP-05
3283
+ * const user1 = await ndk.fetchUser("pablo@test.com");
3284
+ * const user2 = await ndk.fetchUser("test.com"); // defaults to _@test.com
3285
+ *
3286
+ * // Using npub
3287
+ * const user3 = await ndk.fetchUser("npub1...");
3288
+ *
3289
+ * // Using nprofile (includes relay hints)
3290
+ * const user4 = await ndk.fetchUser("nprofile1...");
3291
+ *
3292
+ * // Using hex pubkey
3293
+ * const user5 = await ndk.fetchUser("deadbeef...");
3294
+ * ```
3295
+ */
3296
+ fetchUser(input: string, skipCache?: boolean): Promise<NDKUser | undefined>;
3297
+ /**
3298
+ * Creates and starts a new subscription.
3299
+ *
3300
+ * Subscriptions automatically start unless `autoStart` is set to `false`.
3301
+ * You can control automatic closing on EOSE via `opts.closeOnEose`.
3302
+ *
3303
+ * @param filters - A single NDKFilter object or an array of filters.
3304
+ * @param opts - Optional NDKSubscriptionOptions to customize behavior (e.g., caching, grouping).
3305
+ * @param handlers - Optional handlers for subscription events. Passing handlers is the preferred method of using ndk.subscribe.
3306
+ * - `onEvent`: Called for each event received.
3307
+ * - `onEvents`: Called once with an array of events when the subscription starts (from the cache).
3308
+ * - `onEose`: Called when the subscription receives EOSE.
3309
+ * For backwards compatibility, this third parameter also accepts a relaySet, the relaySet should be passed via `opts.relaySet`.
3310
+ *
3311
+ * @param _autoStart - For backwards compatibility, this can be a boolean indicating whether to start the subscription immediately.
3312
+ * This parameter is deprecated and will be removed in a future version.
3313
+ * - `false`: Creates the subscription but does not start it (call `subscription.start()` manually).
3314
+ * @returns The created NDKSubscription instance.
3315
+ *
3316
+ * @example Basic subscription
3317
+ * ```typescript
3318
+ * const sub = ndk.subscribe(
3319
+ * { kinds: [1], authors: [pubkey] },
3320
+ * {
3321
+ * onEvent: (event) => console.log("Kind 1 event:", event.content)
3322
+ * }
3323
+ * );
3324
+ * ```
3325
+ *
3326
+ * @example Subscription with options and direct handlers
3327
+ * ```typescript
3328
+ * const sub = ndk.subscribe(
3329
+ * { kinds: [0], authors: [pubkey] },
3330
+ * {
3331
+ * closeOnEose: true,
3332
+ * cacheUsage: NDKSubscriptionCacheUsage.PARALLEL,
3333
+ * onEvents: (events) => console.log(`Got ${events.length} profile events from cache:`, events[0].content),
3334
+ * onEvent: (event) => console.log("Got profile update from relay:", event.content),
3335
+ * onEose: () => console.log("Profile subscription finished.")
3336
+ * }
3337
+ * );
3338
+ * ```
3339
+ *
3340
+ * @since 2.13.0 `relaySet` parameter removed; pass `relaySet` or `relayUrls` via `opts`.
3341
+ */
3342
+ subscribe(filters: NDKFilter | NDKFilter[], opts?: NDKSubscriptionOptions, autoStartOrRelaySet?: NDKRelaySet | boolean | NDKSubscriptionEventHandlers, _autoStart?: boolean): NDKSubscription;
3343
+ /**
3344
+ * Attempts to fetch an event from a tag, following relay hints and
3345
+ * other best practices.
3346
+ * @param tag Tag to fetch the event from
3347
+ * @param originalEvent Event where the tag came from
3348
+ * @param subOpts Subscription options to use when fetching the event
3349
+ * @param fallback Fallback options to use when the hint relay doesn't respond
3350
+ * @returns
3351
+ */
3352
+ fetchEventFromTag: (tag: NDKTag, originalEvent: NDKEvent, subOpts?: NDKSubscriptionOptions | undefined, fallback?: NDKFetchFallbackOptions | undefined) => Promise<NDKEvent | null>;
3353
+ /**
3354
+ * Fetch an event from the cache synchronously.
3355
+ * @param idOrFilter event id in bech32 format or filter
3356
+ * @returns events from the cache or null if the cache is empty
3357
+ */
3358
+ fetchEventSync(idOrFilter: string | NDKFilter[]): NDKEvent[] | null;
3359
+ /**
3360
+ * Fetch a single event.
3361
+ *
3362
+ * @param idOrFilter event id in bech32 format or filter
3363
+ * @param opts subscription options
3364
+ * @param relaySetOrRelay explicit relay set to use
3365
+ */
3366
+ fetchEvent(idOrFilter: string | NDKFilter | NDKFilter[], opts?: NDKSubscriptionOptions, relaySetOrRelay?: NDKRelaySet | NDKRelay): Promise<NDKEvent | null>;
3367
+ /**
3368
+ * Fetch events
3369
+ */
3370
+ fetchEvents(filters: NDKFilter | NDKFilter[], opts?: NDKSubscriptionOptions, relaySet?: NDKRelaySet): Promise<Set<NDKEvent>>;
3371
+ /**
3372
+ * Count events matching the given filters using NIP-45.
3373
+ *
3374
+ * This method queries multiple relays and aggregates their COUNT responses.
3375
+ * When relays return HyperLogLog (HLL) data, it uses the HLL algorithm to
3376
+ * provide accurate cardinality estimation without double-counting events
3377
+ * that appear on multiple relays.
3378
+ *
3379
+ * @param filters - The filters to count events for
3380
+ * @param opts - Optional count options (timeout, custom id)
3381
+ * @param relaySet - Optional relay set to use for the count request
3382
+ * @returns An aggregated count result with the best estimate and per-relay results
3383
+ *
3384
+ * @example Basic count
3385
+ * ```typescript
3386
+ * const result = await ndk.count([{ kinds: [1], authors: [pubkey] }]);
3387
+ * console.log(`Found approximately ${result.count} events`);
3388
+ * ```
3389
+ *
3390
+ * @example Count with specific relays
3391
+ * ```typescript
3392
+ * const relaySet = NDKRelaySet.fromRelayUrls(['wss://relay1.com', 'wss://relay2.com'], ndk);
3393
+ * const result = await ndk.count([{ kinds: [7], "#e": [eventId] }], {}, relaySet);
3394
+ * console.log(`Approximately ${result.count} reactions`);
3395
+ * ```
3396
+ *
3397
+ * @example Using HLL data for further analysis
3398
+ * ```typescript
3399
+ * const result = await ndk.count([{ kinds: [3] }]);
3400
+ * if (result.mergedHll) {
3401
+ * console.log('HLL data available for further merging');
3402
+ * }
3403
+ * ```
3404
+ */
3405
+ count(filters: NDKFilter | NDKFilter[], opts?: NDKCountOptions, relaySet?: NDKRelaySet): Promise<NDKAggregatedCountResult>;
3406
+ /**
3407
+ * Ensures that a signer is available to sign an event.
3408
+ */
3409
+ assertSigner(): void;
3410
+ getEntity: (entity: string) => NDKUser | nip19.DecodedNevent | nip19.DecodedNaddr | nip19.DecodedNsec | nip19.DecodedNote | null;
3411
+ /**
3412
+ * Temporarily disable AI guardrails for the next method call.
3413
+ *
3414
+ * @param ids - Optional guardrail IDs to disable. If omitted, all guardrails are disabled for the next call.
3415
+ * Can be a single string or an array of strings.
3416
+ * @returns This NDK instance for method chaining
3417
+ *
3418
+ * @example Disable all guardrails for one call
3419
+ * ```typescript
3420
+ * ndk.guardrailOff().fetchEvents({ kinds: [1] });
3421
+ * ```
3422
+ *
3423
+ * @example Disable specific guardrail
3424
+ * ```typescript
3425
+ * ndk.guardrailOff('fetch-events-usage').fetchEvents({ kinds: [1] });
3426
+ * ```
3427
+ *
3428
+ * @example Disable multiple guardrails
3429
+ * ```typescript
3430
+ * ndk.guardrailOff(['fetch-events-usage', 'filter-large-limit']).fetchEvents({ kinds: [1], limit: 5000 });
3431
+ * ```
3432
+ */
3433
+ guardrailOff(ids?: string | string[]): this;
3434
+ set wallet(wallet: NDKWalletInterface | undefined);
3435
+ get wallet(): NDKWalletInterface | undefined;
3436
+ }
3437
+
3438
+ type ContentTag = {
3439
+ tags: NDKTag[];
3440
+ content: string;
3441
+ };
3442
+
3443
+ /**
3444
+ * NIP-73 entity types
3445
+ */
3446
+ type NIP73EntityType = "url" | "hashtag" | "geohash" | "isbn" | "podcast:guid" | "podcast:item:guid" | "podcast:publisher:guid" | "isan" | "doi";
3447
+
3448
+ type NDKEventSerialized = string;
3449
+
3450
+ type NDKEventId = string;
3451
+ type NDKTag = string[];
3452
+ type ContentTaggingOptions = {
3453
+ skipContentTagging?: boolean;
3454
+ pTagOnQTags?: boolean;
3455
+ pTagOnATags?: boolean;
3456
+ pTags?: boolean;
3457
+ copyPTagsFromTarget?: boolean;
3458
+ filters?: {
3459
+ includeTypes?: Array<"npub" | "nprofile" | "note" | "nevent" | "naddr" | "hashtag">;
3460
+ excludeTypes?: Array<"npub" | "nprofile" | "note" | "nevent" | "naddr" | "hashtag">;
3461
+ };
3462
+ };
3463
+ type NostrEvent = {
3464
+ created_at: number;
3465
+ content: string;
3466
+ tags: NDKTag[];
3467
+ kind?: NDKKind | number;
3468
+ pubkey: string;
3469
+ id?: string;
3470
+ sig?: string;
3471
+ };
3472
+ /**
3473
+ * A finalized event
3474
+ */
3475
+ type NDKRawEvent = {
3476
+ created_at: number;
3477
+ content: string;
3478
+ tags: NDKTag[];
3479
+ kind: NDKKind | number;
3480
+ pubkey: string;
3481
+ id: string;
3482
+ sig: string;
3483
+ };
3484
+ /**
3485
+ * NDKEvent is the basic building block of NDK; most things
3486
+ * you do with NDK will revolve around writing or consuming NDKEvents.
3487
+ */
3488
+ declare class NDKEvent extends EventEmitter {
3489
+ ndk?: NDK;
3490
+ created_at?: number;
3491
+ content: string;
3492
+ tags: NDKTag[];
3493
+ kind: NDKKind | number;
3494
+ id: string;
3495
+ sig?: string;
3496
+ pubkey: string;
3497
+ signatureVerified?: boolean;
3498
+ private _author;
3499
+ /**
3500
+ * The relay that this event was first received from.
3501
+ */
3502
+ relay: NDKRelay | undefined;
3503
+ /**
3504
+ * The relays that this event was received from and/or successfully published to.
3505
+ */
3506
+ get onRelays(): NDKRelay[];
3507
+ /**
3508
+ * The status of the publish operation.
3509
+ */
3510
+ publishStatus?: "pending" | "success" | "error";
3511
+ publishError?: Error;
3512
+ constructor(ndk?: NDK, event?: Partial<NDKRawEvent> | NDKEvent);
3513
+ /**
3514
+ * Deserialize an NDKEvent from a serialized payload.
3515
+ * @param ndk
3516
+ * @param event
3517
+ * @returns
3518
+ */
3519
+ static deserialize(ndk: NDK | undefined, event: NDKEventSerialized): NDKEvent;
3520
+ /**
3521
+ * Returns the event as is.
3522
+ */
3523
+ rawEvent(): NDKRawEvent;
3524
+ set author(user: NDKUser);
3525
+ /**
3526
+ * Returns an NDKUser for the author of the event.
3527
+ */
3528
+ get author(): NDKUser;
3529
+ /**
3530
+ * NIP-73 tagging of external entities
3531
+ * @param entity to be tagged
3532
+ * @param type of the entity
3533
+ * @param markerUrl to be used as the marker URL
3534
+ *
3535
+ * @example
3536
+ * ```typescript
3537
+ * event.tagExternal("https://example.com/article/123#nostr", "url");
3538
+ * event.tags => [["i", "https://example.com/123"], ["k", "https://example.com"]]
3539
+ * ```
3540
+ *
3541
+ * @example tag a podcast:item:guid
3542
+ * ```typescript
3543
+ * event.tagExternal("e32b4890-b9ea-4aef-a0bf-54b787833dc5", "podcast:item:guid");
3544
+ * event.tags => [["i", "podcast:item:guid:e32b4890-b9ea-4aef-a0bf-54b787833dc5"], ["k", "podcast:item:guid"]]
3545
+ * ```
3546
+ *
3547
+ * @see https://github.com/nostr-protocol/nips/blob/master/73.md
3548
+ */
3549
+ tagExternal(entity: string, type: NIP73EntityType, markerUrl?: string): void;
3550
+ /**
3551
+ * Tag a user with an optional marker.
3552
+ * @param target What is to be tagged. Can be an NDKUser, NDKEvent, or an NDKTag.
3553
+ * @param marker The marker to use in the tag.
3554
+ * @param skipAuthorTag Whether to explicitly skip adding the author tag of the event.
3555
+ * @param forceTag Force a specific tag to be used instead of the default "e" or "a" tag.
3556
+ * @param opts Optional content tagging options to control p tag behavior.
3557
+ * @example
3558
+ * ```typescript
3559
+ * reply.tag(opEvent, "reply");
3560
+ * // reply.tags => [["e", <id>, <relay>, "reply"]]
3561
+ * ```
3562
+ */
3563
+ tag(target: NDKTag | NDKUser | NDKEvent, marker?: string, skipAuthorTag?: boolean, forceTag?: string, opts?: ContentTaggingOptions): void;
3564
+ /**
3565
+ * Return a NostrEvent object, trying to fill in missing fields
3566
+ * when possible, adding tags when necessary.
3567
+ * @param pubkey {string} The pubkey of the user who the event belongs to.
3568
+ * @param opts {ContentTaggingOptions} Options for content tagging.
3569
+ * @returns {Promise<NostrEvent>} A promise that resolves to a NostrEvent.
3570
+ */
3571
+ toNostrEvent(pubkey?: string, opts?: ContentTaggingOptions): Promise<NostrEvent>;
3572
+ serialize: (includeSig?: boolean | undefined, includeId?: boolean | undefined) => string;
3573
+ getEventHash: () => string;
3574
+ validate: () => boolean;
3575
+ verifySignature: (persist: boolean) => boolean | undefined;
3576
+ /**
3577
+ * Is this event replaceable (whether parameterized or not)?
3578
+ *
3579
+ * This will return true for kind 0, 3, 10k-20k and 30k-40k
3580
+ */
3581
+ isReplaceable: () => boolean;
3582
+ isEphemeral: () => boolean;
3583
+ isDvm: () => boolean | 0;
3584
+ /**
3585
+ * Is this event parameterized replaceable?
3586
+ *
3587
+ * This will return true for kind 30k-40k
3588
+ */
3589
+ isParamReplaceable: () => boolean;
3590
+ /**
3591
+ * Encodes a bech32 id.
3592
+ *
3593
+ * @param relays {string[]} The relays to encode in the id
3594
+ * @returns {string} - Encoded naddr, note or nevent.
3595
+ */
3596
+ encode: (maxRelayCount?: number | undefined) => string;
3597
+ encrypt: (recipient?: NDKUser | undefined, signer?: NDKSigner | undefined, scheme?: NDKEncryptionScheme | undefined) => Promise<void>;
3598
+ decrypt: (sender?: NDKUser | undefined, signer?: NDKSigner | undefined, scheme?: NDKEncryptionScheme | undefined) => Promise<void>;
3599
+ /**
3600
+ * Get all tags with the given name
3601
+ * @param tagName {string} The name of the tag to search for
3602
+ * @returns {NDKTag[]} An array of the matching tags
3603
+ */
3604
+ getMatchingTags(tagName: string, marker?: string): NDKTag[];
3605
+ /**
3606
+ * Check if the event has a tag with the given name
3607
+ * @param tagName
3608
+ * @param marker
3609
+ * @returns
3610
+ */
3611
+ hasTag(tagName: string, marker?: string): boolean;
3612
+ /**
3613
+ * Get the first tag with the given name
3614
+ * @param tagName Tag name to search for
3615
+ * @returns The value of the first tag with the given name, or undefined if no such tag exists
3616
+ */
3617
+ tagValue(tagName: string, marker?: string): string | undefined;
3618
+ /**
3619
+ * Gets the NIP-31 "alt" tag of the event.
3620
+ */
3621
+ get alt(): string | undefined;
3622
+ /**
3623
+ * Sets the NIP-31 "alt" tag of the event. Use this to set an alt tag so
3624
+ * clients that don't handle a particular event kind can display something
3625
+ * useful for users.
3626
+ */
3627
+ set alt(alt: string | undefined);
3628
+ /**
3629
+ * Gets the NIP-33 "d" tag of the event.
3630
+ */
3631
+ get dTag(): string | undefined;
3632
+ /**
3633
+ * Sets the NIP-33 "d" tag of the event.
3634
+ */
3635
+ set dTag(value: string | undefined);
3636
+ /**
3637
+ * Remove all tags with the given name (e.g. "d", "a", "p")
3638
+ * @param tagName Tag name(s) to search for and remove
3639
+ * @param marker Optional marker to check for too
3640
+ *
3641
+ * @example
3642
+ * Remove a tags with a "defer" marker
3643
+ * ```typescript
3644
+ * event.tags = [
3645
+ * ["a", "....", "defer"],
3646
+ * ["a", "....", "no-defer"],
3647
+ * ]
3648
+ *
3649
+ * event.removeTag("a", "defer");
3650
+ *
3651
+ * // event.tags => [["a", "....", "no-defer"]]
3652
+ *
3653
+ * @returns {void}
3654
+ */
3655
+ removeTag(tagName: string | string[], marker?: string): void;
3656
+ /**
3657
+ * Replace a tag with a new value. If not found, it will be added.
3658
+ * @param tag The tag to replace.
3659
+ * @param value The new value for the tag.
3660
+ */
3661
+ replaceTag(tag: NDKTag): void;
3662
+ /**
3663
+ * Sign the event if a signer is present.
3664
+ *
3665
+ * It will generate tags.
3666
+ * Repleacable events will have their created_at field set to the current time.
3667
+ * @param signer {NDKSigner} The NDKSigner to use to sign the event
3668
+ * @param opts {ContentTaggingOptions} Options for content tagging.
3669
+ * @returns {Promise<string>} A Promise that resolves to the signature of the signed event.
3670
+ */
3671
+ sign(signer?: NDKSigner, opts?: ContentTaggingOptions): Promise<string>;
3672
+ /**
3673
+ *
3674
+ * @param relaySet
3675
+ * @param timeoutMs
3676
+ * @param requiredRelayCount
3677
+ * @returns
3678
+ */
3679
+ publishReplaceable(relaySet?: NDKRelaySet, timeoutMs?: number, requiredRelayCount?: number): Promise<Set<NDKRelay>>;
3680
+ /**
3681
+ * Attempt to sign and then publish an NDKEvent to a given relaySet.
3682
+ * If no relaySet is provided, the relaySet will be calculated by NDK.
3683
+ * @param relaySet {NDKRelaySet} The relaySet to publish the even to.
3684
+ * @param timeoutM {number} The timeout for the publish operation in milliseconds.
3685
+ * @param requiredRelayCount The number of relays that must receive the event for the publish to be considered successful.
3686
+ * @param opts {ContentTaggingOptions} Options for content tagging.
3687
+ * @returns A promise that resolves to the relays the event was published to.
3688
+ */
3689
+ publish(relaySet?: NDKRelaySet, timeoutMs?: number, requiredRelayCount?: number, opts?: ContentTaggingOptions): Promise<Set<NDKRelay>>;
3690
+ /**
3691
+ * Generates tags for users, notes, and other events tagged in content.
3692
+ * Will also generate random "d" tag for parameterized replaceable events where needed.
3693
+ * @param opts {ContentTaggingOptions} Options for content tagging.
3694
+ * @returns {ContentTag} The tags and content of the event.
3695
+ */
3696
+ generateTags(opts?: ContentTaggingOptions): Promise<ContentTag>;
3697
+ get shouldAddClientTag(): boolean;
3698
+ get shouldStripClientTag(): boolean;
3699
+ muted(): string | null;
3700
+ /**
3701
+ * Returns the "d" tag of a parameterized replaceable event or throws an error if the event isn't
3702
+ * a parameterized replaceable event.
3703
+ * @returns {string} the "d" tag of the event.
3704
+ *
3705
+ * @deprecated Use `dTag` instead.
3706
+ */
3707
+ replaceableDTag(): string;
3708
+ /**
3709
+ * Provides a deduplication key for the event.
3710
+ *
3711
+ * For kinds 0, 3, 10k-20k this will be the event <kind>:<pubkey>
3712
+ * For kinds 30k-40k this will be the event <kind>:<pubkey>:<d-tag>
3713
+ * For all other kinds this will be the event id
3714
+ */
3715
+ deduplicationKey(): string;
3716
+ /**
3717
+ * Returns the id of the event or, if it's a parameterized event, the generated id of the event using "d" tag, pubkey, and kind.
3718
+ * @returns {string} The id
3719
+ */
3720
+ tagId(): string;
3721
+ /**
3722
+ * Returns a stable reference value for a replaceable event.
3723
+ *
3724
+ * Param replaceable events are returned in the expected format of `<kind>:<pubkey>:<d-tag>`.
3725
+ * Kind-replaceable events are returned in the format of `<kind>:<pubkey>:`.
3726
+ *
3727
+ * @returns {string} A stable reference value for replaceable events
3728
+ */
3729
+ tagAddress(): string;
3730
+ /**
3731
+ * Determines the type of tag that can be used to reference this event from another event.
3732
+ * @returns {string} The tag type
3733
+ * @example
3734
+ * event = new NDKEvent(ndk, { kind: 30000, pubkey: 'pubkey', tags: [ ["d", "d-code"] ] });
3735
+ * event.tagType(); // "a"
3736
+ */
3737
+ tagType(): "e" | "a";
3738
+ /**
3739
+ * Get the tag that can be used to reference this event from another event.
3740
+ *
3741
+ * Consider using referenceTags() instead (unless you have a good reason to use this)
3742
+ *
3743
+ * @example
3744
+ * event = new NDKEvent(ndk, { kind: 30000, pubkey: 'pubkey', tags: [ ["d", "d-code"] ] });
3745
+ * event.tagReference(); // ["a", "30000:pubkey:d-code"]
3746
+ *
3747
+ * event = new NDKEvent(ndk, { kind: 1, pubkey: 'pubkey', id: "eventid" });
3748
+ * event.tagReference(); // ["e", "eventid"]
3749
+ * @returns {NDKTag} The NDKTag object referencing this event
3750
+ */
3751
+ tagReference(marker?: string): NDKTag;
3752
+ /**
3753
+ * Get the tags that can be used to reference this event from another event
3754
+ * @param marker The marker to use in the tag
3755
+ * @param skipAuthorTag Whether to explicitly skip adding the author tag of the event
3756
+ * @param forceTag Force a specific tag to be used instead of the default "e" or "a" tag
3757
+ * @example
3758
+ * event = new NDKEvent(ndk, { kind: 30000, pubkey: 'pubkey', tags: [ ["d", "d-code"] ] });
3759
+ * event.referenceTags(); // [["a", "30000:pubkey:d-code"], ["e", "parent-id"]]
3760
+ *
3761
+ * event = new NDKEvent(ndk, { kind: 1, pubkey: 'pubkey', id: "eventid" });
3762
+ * event.referenceTags(); // [["e", "parent-id"]]
3763
+ * @returns {NDKTag} The NDKTag object referencing this event
3764
+ */
3765
+ referenceTags(marker?: string, skipAuthorTag?: boolean, forceTag?: string, opts?: ContentTaggingOptions): NDKTag[];
3766
+ /**
3767
+ * Provides the filter that will return matching events for this event.
3768
+ *
3769
+ * @example
3770
+ * event = new NDKEvent(ndk, { kind: 30000, pubkey: 'pubkey', tags: [ ["d", "d-code"] ] });
3771
+ * event.filter(); // { "#a": ["30000:pubkey:d-code"] }
3772
+ * @example
3773
+ * event = new NDKEvent(ndk, { kind: 1, pubkey: 'pubkey', id: "eventid" });
3774
+ * event.filter(); // { "#e": ["eventid"] }
3775
+ *
3776
+ * @returns The filter that will return matching events for this event
3777
+ */
3778
+ filter(): NDKFilter;
3779
+ nip22Filter(): NDKFilter;
3780
+ /**
3781
+ * Generates a deletion event of the current event
3782
+ *
3783
+ * @param reason The reason for the deletion
3784
+ * @param publish Whether to publish the deletion event automatically
3785
+ * @returns The deletion event
3786
+ */
3787
+ delete(reason?: string, publish?: boolean): Promise<NDKEvent>;
3788
+ /**
3789
+ * Establishes whether this is a NIP-70-protectede event.
3790
+ * @@satisfies NIP-70
3791
+ */
3792
+ set isProtected(val: boolean);
3793
+ /**
3794
+ * Whether this is a NIP-70-protected event.
3795
+ * @@satisfies NIP-70
3796
+ */
3797
+ get isProtected(): boolean;
3798
+ /**
3799
+ * Fetch an event tagged with the given tag following relay hints if provided.
3800
+ * @param tag The tag to search for
3801
+ * @param marker The marker to use in the tag (e.g. "root")
3802
+ * @returns The fetched event or null if no event was found, undefined if no matching tag was found in the event
3803
+ * * @example
3804
+ * const replyEvent = await ndk.fetchEvent("nevent1qqs8x8vnycyha73grv380gmvlury4wtmx0nr9a5ds2dngqwgu87wn6gpzemhxue69uhhyetvv9ujuurjd9kkzmpwdejhgq3ql2vyh47mk2p0qlsku7hg0vn29faehy9hy34ygaclpn66ukqp3afqz4cwjd")
3805
+ * const originalEvent = await replyEvent.fetchTaggedEvent("e", "reply");
3806
+ * console.log(replyEvent.encode() + " is a reply to event " + originalEvent?.encode());
3807
+ */
3808
+ fetchTaggedEvent: (tag: string, marker?: string | undefined) => Promise<NDKEvent | null | undefined>;
3809
+ /**
3810
+ * Fetch the root event of the current event.
3811
+ * @returns The fetched root event or null if no event was found
3812
+ * @example
3813
+ * const replyEvent = await ndk.fetchEvent("nevent1qqs8x8vnycyha73grv380gmvlury4wtmx0nr9a5ds2dngqwgu87wn6gpzemhxue69uhhyetvv9ujuurjd9kkzmpwdejhgq3ql2vyh47mk2p0qlsku7hg0vn29faehy9hy34ygaclpn66ukqp3afqz4cwjd")
3814
+ * const rootEvent = await replyEvent.fetchRootEvent();
3815
+ * console.log(replyEvent.encode() + " is a reply in the thread " + rootEvent?.encode());
3816
+ */
3817
+ fetchRootEvent: (subOpts?: NDKSubscriptionOptions | undefined) => Promise<NDKEvent | null | undefined>;
3818
+ /**
3819
+ * Fetch the event the current event is replying to.
3820
+ * @returns The fetched reply event or null if no event was found
3821
+ */
3822
+ fetchReplyEvent: (subOpts?: NDKSubscriptionOptions | undefined) => Promise<NDKEvent | null | undefined>;
3823
+ /**
3824
+ * NIP-18 reposting event.
3825
+ *
3826
+ * @param publish Whether to publish the reposted event automatically @default true
3827
+ * @param signer The signer to use for signing the reposted event
3828
+ * @returns The reposted event
3829
+ *
3830
+ * @function
3831
+ */
3832
+ repost: (publish?: boolean | undefined, signer?: NDKSigner | undefined) => Promise<NDKEvent>;
3833
+ /**
3834
+ * React to an existing event
3835
+ *
3836
+ * @param content The content of the reaction
3837
+ */
3838
+ react(content: string, publish?: boolean): Promise<NDKEvent>;
3839
+ /**
3840
+ * Checks whether the event is valid per underlying NIPs.
3841
+ *
3842
+ * This method is meant to be overridden by subclasses that implement specific NIPs
3843
+ * to allow the enforcement of NIP-specific validation rules.
3844
+ *
3845
+ * Otherwise, it will only check for basic event properties.
3846
+ *
3847
+ */
3848
+ get isValid(): boolean;
3849
+ get inspect(): string;
3850
+ /**
3851
+ * Dump the event to console for debugging purposes.
3852
+ * Prints a JSON stringified version of rawEvent() with indentation
3853
+ * and also lists all relay URLs for onRelays.
3854
+ */
3855
+ dump(): void;
3856
+ /**
3857
+ * Creates a reply event for the current event.
3858
+ *
3859
+ * This function will use NIP-22 when appropriate (i.e. replies to non-kind:1 events).
3860
+ * This function does not have side-effects; it will just return an event with the appropriate tags
3861
+ * to generate the reply event; the caller is responsible for publishing the event.
3862
+ *
3863
+ * @param forceNip22 - Optional flag to force NIP-22 style replies (kind 1111) regardless of the original event's kind
3864
+ * @param opts - Optional content tagging options
3865
+ */
3866
+ reply(forceNip22?: boolean, opts?: ContentTaggingOptions): NDKEvent;
3867
+ }
3868
+ /**
3869
+ * Discriminated union types for signed and unsigned events
3870
+ */
3871
+ /**
3872
+ * An NDKEvent that has been signed and has all required fields for relay transmission
3873
+ */
3874
+ type NDKSignedEvent = NDKEvent & {
3875
+ readonly signed: true;
3876
+ id: string;
3877
+ sig: string;
3878
+ created_at: number;
3879
+ };
3880
+
3881
+ type NDKEncryptionScheme = "nip04" | "nip44";
3882
+
3883
+ declare enum NdkNutzapStatus {
3884
+ INITIAL = "initial",
3885
+ PROCESSING = "processing",
3886
+ REDEEMED = "redeemed",
3887
+ SPENT = "spent",
3888
+ MISSING_PRIVKEY = "missing_privkey",
3889
+ TEMPORARY_ERROR = "temporary_error",
3890
+ PERMANENT_ERROR = "permanent_error",
3891
+ INVALID_NUTZAP = "invalid_nutzap"
3892
+ }
3893
+ interface NDKNutzapState {
3894
+ nutzap?: NDKNutzap;
3895
+ status: NdkNutzapStatus;
3896
+ redeemedById?: NDKEventId;
3897
+ errorMessage?: string;
3898
+ redeemedAmount?: number;
3899
+ }
3900
+
3901
+ /**
3902
+ * A signer that uses an in-memory private key (nsec).
3903
+ *
3904
+ * @example
3905
+ * ```ts
3906
+ * const signer = NDKPrivateKeySigner.generate();
3907
+ * console.log('your nsec is', signer.nsec);
3908
+ * console.log('your pubkey is', signer.pubkey);
3909
+ * console.log('your npub is', signer.npub);
3910
+ * ```
3911
+ *
3912
+ * @example
3913
+ * ```ts
3914
+ * const signer = new NDKPrivateKeySigner(nsec);
3915
+ * ```
3916
+ */
3917
+ declare class NDKPrivateKeySigner implements NDKSigner {
3918
+ private _user;
3919
+ private _privateKey;
3920
+ private _pubkey?;
3921
+ /**
3922
+ * Create a new signer from a private key.
3923
+ * @param privateKey - The private key to use in hex form or nsec.
3924
+ * @param ndk - The NDK instance to use.
3925
+ *
3926
+ * @ai-guardrail
3927
+ * If you have an nsec (bech32-encoded private key starting with "nsec1"), you can pass it directly
3928
+ * to this constructor without decoding it first. The constructor handles both hex and nsec formats automatically.
3929
+ * DO NOT use nip19.decode() to convert nsec to hex before passing it here - just pass the nsec string directly.
3930
+ */
3931
+ constructor(privateKeyOrNsec: Uint8Array | string, ndk?: NDK);
3932
+ /**
3933
+ * Get the private key in hex form.
3934
+ */
3935
+ get privateKey(): string;
3936
+ /**
3937
+ * Get the public key in hex form.
3938
+ */
3939
+ get pubkey(): string;
3940
+ /**
3941
+ * Get the private key in nsec form.
3942
+ */
3943
+ get nsec(): string;
3944
+ /**
3945
+ * Get the public key in npub form.
3946
+ */
3947
+ get npub(): string;
3948
+ /**
3949
+ * Encrypt the private key with a password to ncryptsec format.
3950
+ * @param password - The password to encrypt the private key.
3951
+ * @param logn - The log2 of the scrypt N parameter (default: 16).
3952
+ * @param ksb - The key security byte (0x00, 0x01, or 0x02, default: 0x02).
3953
+ * @returns The encrypted private key in ncryptsec format.
3954
+ *
3955
+ * @example
3956
+ * ```ts
3957
+ * const signer = new NDKPrivateKeySigner(nsec);
3958
+ * const ncryptsec = signer.encryptToNcryptsec("my-password");
3959
+ * console.log('encrypted key:', ncryptsec);
3960
+ * ```
3961
+ */
3962
+ encryptToNcryptsec(password: string, logn?: number, ksb?: 0x00 | 0x01 | 0x02): string;
3963
+ /**
3964
+ * Generate a new private key.
3965
+ */
3966
+ static generate(): NDKPrivateKeySigner;
3967
+ /**
3968
+ * Create a signer from an encrypted private key (ncryptsec) using a password.
3969
+ * @param ncryptsec - The encrypted private key in ncryptsec format.
3970
+ * @param password - The password to decrypt the private key.
3971
+ * @param ndk - Optional NDK instance.
3972
+ * @returns A new NDKPrivateKeySigner instance.
3973
+ *
3974
+ * @example
3975
+ * ```ts
3976
+ * const signer = NDKPrivateKeySigner.fromNcryptsec(
3977
+ * "ncryptsec1qgg9947rlpvqu76pj5ecreduf9jxhselq2nae2kghhvd5g7dgjtcxfqtd67p9m0w57lspw8gsq6yphnm8623nsl8xn9j4jdzz84zm3frztj3z7s35vpzmqf6ksu8r89qk5z2zxfmu5gv8th8wclt0h4p",
3978
+ * "my-password"
3979
+ * );
3980
+ * console.log('your pubkey is', signer.pubkey);
3981
+ * ```
3982
+ */
3983
+ static fromNcryptsec(ncryptsec: string, password: string, ndk?: NDK): NDKPrivateKeySigner;
3984
+ /**
3985
+ * Noop in NDKPrivateKeySigner.
3986
+ */
3987
+ blockUntilReady(): Promise<NDKUser>;
3988
+ /**
3989
+ * Get the user.
3990
+ */
3991
+ user(): Promise<NDKUser>;
3992
+ /**
3993
+ * Get the user.
3994
+ */
3995
+ get userSync(): NDKUser;
3996
+ sign(event: NostrEvent): Promise<string>;
3997
+ encryptionEnabled(scheme?: NDKEncryptionScheme): Promise<NDKEncryptionScheme[]>;
3998
+ encrypt(recipient: NDKUser, value: string, scheme?: NDKEncryptionScheme): Promise<string>;
3999
+ decrypt(sender: NDKUser, value: string, scheme?: NDKEncryptionScheme): Promise<string>;
4000
+ /**
4001
+ * Serializes the signer's private key into a storable format.
4002
+ * @returns A JSON string containing the type and the hex private key.
4003
+ */
4004
+ toPayload(): string;
4005
+ /**
4006
+ * Deserializes the signer from a payload string.
4007
+ * @param payloadString The JSON string obtained from toPayload().
4008
+ * @param ndk Optional NDK instance.
4009
+ * @returns An instance of NDKPrivateKeySigner.
4010
+ */
4011
+ static fromPayload(payloadString: string, ndk?: NDK): Promise<NDKPrivateKeySigner>;
4012
+ }
4013
+
4014
+ type Nip07RelayMap = {
4015
+ [key: string]: {
4016
+ read: boolean;
4017
+ write: boolean;
4018
+ };
4019
+ };
4020
+ type Nip44 = {
4021
+ encrypt: (recipient: Hexpubkey, value: string) => Promise<string>;
4022
+ decrypt: (sender: Hexpubkey, value: string) => Promise<string>;
4023
+ };
4024
+ declare global {
4025
+ interface Window {
4026
+ nostr?: {
4027
+ getPublicKey(): Promise<string>;
4028
+ signEvent(event: NostrEvent): Promise<{
4029
+ sig: string;
4030
+ }>;
4031
+ getRelays?: () => Promise<Nip07RelayMap>;
4032
+ nip04?: {
4033
+ encrypt(recipientHexPubKey: string, value: string): Promise<string>;
4034
+ decrypt(senderHexPubKey: string, value: string): Promise<string>;
4035
+ };
4036
+ nip44?: Nip44;
4037
+ };
4038
+ }
4039
+ }
4040
+
4041
+ type Names = "alice" | "bob" | "carol" | "dave" | "eve";
4042
+ /**
4043
+ * Generates deterministic test users for consistent, reproducible testing.
4044
+ *
4045
+ * Provides predefined users (alice, bob, carol, dave, eve) with static keypairs,
4046
+ * ensuring your tests produce the same results every time. Perfect for testing
4047
+ * multi-user interactions in your Nostr application.
4048
+ *
4049
+ * @example
4050
+ * ```typescript
4051
+ * // Get a deterministic test user
4052
+ * const alice = await UserGenerator.getUser('alice', ndk);
4053
+ * const bob = await UserGenerator.getUser('bob', ndk);
4054
+ *
4055
+ * // Use in your app tests
4056
+ * const dm = await myApp.sendMessage(alice, bob, 'Hello!');
4057
+ * ```
4058
+ */
4059
+ declare class UserGenerator {
4060
+ static privateKeys: Record<string, string>;
4061
+ /**
4062
+ * Get a deterministic test user by name.
4063
+ *
4064
+ * Returns a test user with a predefined keypair, ensuring consistent behavior
4065
+ * across test runs. Use this when testing features that involve specific users.
4066
+ *
4067
+ * @param name The name of the user (alice, bob, carol, dave, eve)
4068
+ * @param ndk Optional NDK instance to attach to the user
4069
+ * @returns The NDK user with a deterministic keypair
4070
+ *
4071
+ * @example
4072
+ * ```typescript
4073
+ * const alice = await UserGenerator.getUser('alice', ndk);
4074
+ * expect(alice.pubkey).toBe('e9e4276490374a0daf7759fd5f475deff6ffb9b0fc5fa98c902b5f4b2fe3bba1');
4075
+ * ```
4076
+ */
4077
+ static getUser(name: Names, ndk?: NDK): Promise<NDKUser>;
4078
+ /**
4079
+ * Get the private key for a specific test user
4080
+ * @param name The name of the user (alice, bob, carol, dave, eve)
4081
+ * @returns The private key hex string
4082
+ */
4083
+ static getPrivateKey(name: Names): string;
4084
+ /**
4085
+ * Get a user with a random private key
4086
+ * @param ndk The NDK instance to use for the user
4087
+ * @returns The NDK user
4088
+ */
4089
+ static getRandomUser(ndk?: NDK): Promise<NDKUser>;
4090
+ }
4091
+ /**
4092
+ * Generates signers for test users to sign events in your application tests.
4093
+ *
4094
+ * Provides signers for predefined test users, allowing you to test event signing,
4095
+ * publishing, and authentication flows in your Nostr application.
4096
+ *
4097
+ * @example
4098
+ * ```typescript
4099
+ * // Get a signer for a test user
4100
+ * const aliceSigner = SignerGenerator.getSigner('alice');
4101
+ * ndk.signer = aliceSigner;
4102
+ *
4103
+ * // Now alice can sign events in your app
4104
+ * await myApp.publishNote('Hello, Nostr!');
4105
+ * ```
4106
+ */
4107
+ declare class SignerGenerator {
4108
+ /**
4109
+ * Get a signer for a specific test user
4110
+ * @param name The name of the user (alice, bob, carol, dave, eve)
4111
+ * @returns The NDK signer
4112
+ */
4113
+ static getSigner(name: Names): NDKPrivateKeySigner;
4114
+ static sign(event: NDKEvent, user: Names): Promise<NDKEvent>;
4115
+ /**
4116
+ * Generate a random signer
4117
+ * @returns The NDK signer
4118
+ */
4119
+ static getRandomSigner(): NDKPrivateKeySigner;
4120
+ }
4121
+ /**
4122
+ * High-level event factory for creating test events with proper relationships and tagging.
4123
+ *
4124
+ * Provides convenient methods for creating common event patterns like notes, DMs,
4125
+ * replies, and conversation threads. Automatically handles proper NIP-10 tagging
4126
+ * and event relationships for testing your app's event handling logic.
4127
+ *
4128
+ * @example
4129
+ * ```typescript
4130
+ * const factory = new TestEventFactory(ndk);
4131
+ * const alice = await UserGenerator.getUser('alice', ndk);
4132
+ * const bob = await UserGenerator.getUser('bob', ndk);
4133
+ *
4134
+ * // Create a note
4135
+ * const note = await factory.createSignedTextNote('Hello!', alice);
4136
+ *
4137
+ * // Create a reply
4138
+ * const reply = await factory.createReply(note, 'Hi back!', bob);
4139
+ *
4140
+ * // Create a DM
4141
+ * const dm = await factory.createDirectMessage('Secret message', alice, bob);
4142
+ *
4143
+ * // Create a conversation thread
4144
+ * const thread = await factory.createEventChain('Original post', alice, [
4145
+ * { author: bob, content: 'First reply' },
4146
+ * { author: alice, content: 'Response' }
4147
+ * ]);
4148
+ * ```
4149
+ */
4150
+ declare class TestEventFactory {
4151
+ private ndk;
4152
+ constructor(ndk: NDK);
4153
+ /**
4154
+ * Create a signed text note from a specific user
4155
+ * @param content The content of the note
4156
+ * @param user The user that authored the note, or name of predefined test user
4157
+ * @param kind The kind of the event (defaults to 1)
4158
+ * @returns The signed event
4159
+ */
4160
+ createSignedTextNote(content: string, user: NDKUser | Names | undefined, kind?: number): Promise<any>;
4161
+ /**
4162
+ * Create a direct message from one user to another
4163
+ * @param content The content of the message
4164
+ * @param fromUser The sender (author)
4165
+ * @param toUser The recipient
4166
+ * @returns The created event (not necessarily signed)
4167
+ */
4168
+ createDirectMessage(content: string, fromUser: NDKUser | Names, toUser: NDKUser | Names): Promise<any>;
4169
+ /**
4170
+ * Create a reply to an event
4171
+ * @param originalEvent The event being replied to
4172
+ * @param content The content of the reply
4173
+ * @param fromUser The author of the reply
4174
+ * @param kind The kind of the reply (defaults to same as original for kind 1, or 1111 for other kinds)
4175
+ * @returns The created reply event (not necessarily signed)
4176
+ */
4177
+ createReply(originalEvent: any, content: string, fromUser: NDKUser | Names, kind?: number): Promise<any>;
4178
+ /**
4179
+ * Creates a chain of events (e.g., a thread)
4180
+ * @param initialContent Content of the first message
4181
+ * @param replies Array of {content, author} objects for each reply
4182
+ * @returns Array of events in the chain
4183
+ */
4184
+ createEventChain(initialContent: string, initialAuthor: NDKUser | Names, replies: Array<{
4185
+ content: string;
4186
+ author: NDKUser | Names;
4187
+ }>): Promise<any[]>;
4188
+ }
4189
+ /**
4190
+ * Complete test environment with NDK, users, and event factory pre-configured.
4191
+ *
4192
+ * Provides a ready-to-use test environment that combines NDK instance, event factory,
4193
+ * and convenient access to test users and signers. Reduces boilerplate in your tests.
4194
+ *
4195
+ * @example
4196
+ * ```typescript
4197
+ * const fixture = new TestFixture();
4198
+ *
4199
+ * // Access NDK instance
4200
+ * fixture.ndk.connect();
4201
+ *
4202
+ * // Get test users
4203
+ * const alice = await fixture.getUser('alice');
4204
+ *
4205
+ * // Setup signer
4206
+ * fixture.setupSigner('alice');
4207
+ *
4208
+ * // Use event factory
4209
+ * const note = await fixture.eventFactory.createSignedTextNote('Test', alice);
4210
+ *
4211
+ * // Test your app with this environment
4212
+ * ```
4213
+ */
4214
+ declare class TestFixture {
4215
+ ndk: NDK;
4216
+ eventFactory: TestEventFactory;
4217
+ constructor();
4218
+ /**
4219
+ * Get a predefined test user
4220
+ * @param name The name of the user (alice, bob, carol, dave, eve)
4221
+ * @returns The NDK user
4222
+ */
4223
+ getUser(name: Names): Promise<NDKUser>;
4224
+ /**
4225
+ * Get a signer for a predefined test user
4226
+ * @param name The name of the user
4227
+ * @returns The NDK signer
4228
+ */
4229
+ getSigner(name: Names): NDKPrivateKeySigner;
4230
+ /**
4231
+ * Set up the NDK instance with a specific signer
4232
+ * @param name The name of the predefined user to use as signer
4233
+ */
4234
+ setupSigner(name: Names): void;
4235
+ }
4236
+
4237
+ /**
4238
+ * Controls time in tests for testing time-dependent application logic.
4239
+ *
4240
+ * Provides utilities to advance fake timers, control async operations, and test
4241
+ * features like retries, delays, and scheduled tasks in your Nostr application.
4242
+ * Works with Vitest's fake timer system.
4243
+ *
4244
+ * @example
4245
+ * ```typescript
4246
+ * import { vi } from 'vitest';
4247
+ * import { TimeController } from '@nostr-dev-kit/ndk/test';
4248
+ *
4249
+ * beforeEach(() => {
4250
+ * vi.useFakeTimers();
4251
+ * TimeController.setViObject(vi);
4252
+ * });
4253
+ *
4254
+ * it('should retry after delay', async () => {
4255
+ * const promise = myApp.retryPublish(event); // retries after 5 seconds
4256
+ *
4257
+ * // Advance time by 5 seconds
4258
+ * await TimeController.tickAsync(5000);
4259
+ *
4260
+ * await expect(promise).resolves.toBeTruthy();
4261
+ * });
4262
+ *
4263
+ * afterEach(() => {
4264
+ * TimeController.reset();
4265
+ * vi.useRealTimers();
4266
+ * });
4267
+ * ```
4268
+ */
4269
+ declare class TimeController {
4270
+ private static viObject;
4271
+ /**
4272
+ * Set the Vitest object to use for time control
4273
+ */
4274
+ static setViObject(vi: any): void;
4275
+ /**
4276
+ * Advance timers by a specified number of milliseconds
4277
+ */
4278
+ static advanceTime(ms: number): void;
4279
+ /**
4280
+ * Advance timers asynchronously by a specified number of milliseconds
4281
+ */
4282
+ static tickAsync(ms?: number): Promise<void>;
4283
+ /**
4284
+ * Clear all timers
4285
+ */
4286
+ static reset(): void;
4287
+ /**
4288
+ * Wait for the next tick of the event loop
4289
+ */
4290
+ static waitForNextTick(): Promise<void>;
4291
+ }
4292
+ /**
4293
+ * Helper function to create a TimeController with automatic setup/teardown.
4294
+ *
4295
+ * Convenience wrapper that automatically sets up fake timers before your test
4296
+ * and restores real timers after, reducing boilerplate in your test files.
4297
+ *
4298
+ * @param viObject The Vitest `vi` object
4299
+ * @returns A TimeController instance configured for your test
4300
+ *
4301
+ * @example
4302
+ * ```typescript
4303
+ * import { vi } from 'vitest';
4304
+ * import { withTimeControl } from '@nostr-dev-kit/ndk/test';
4305
+ *
4306
+ * const timeController = withTimeControl(vi);
4307
+ *
4308
+ * it('should handle delays', async () => {
4309
+ * const promise = myApp.delayedOperation();
4310
+ * await timeController.tickAsync(1000);
4311
+ * await expect(promise).resolves.toBeTruthy();
4312
+ * });
4313
+ * ```
4314
+ */
4315
+ declare function withTimeControl(viObject: any): (fn: (timeController: typeof TimeController) => Promise<void>) => (() => Promise<void>);
4316
+
4317
+ /** biome-ignore-all lint/complexity/noStaticOnlyClass: <test purposes> */
4318
+ /** biome-ignore-all lint/suspicious/noExplicitAny: <test purposes> */
4319
+
4320
+ /**
4321
+ * Low-level event generator for creating test events in your Nostr application tests.
4322
+ *
4323
+ * Provides simple methods to create various types of Nostr events with automatic signing.
4324
+ * Must call `setNDK()` once before using any event creation methods.
4325
+ *
4326
+ * @example
4327
+ * ```typescript
4328
+ * import { EventGenerator, UserGenerator } from '@nostr-dev-kit/ndk/test';
4329
+ *
4330
+ * // Initialize once in your test setup
4331
+ * EventGenerator.setNDK(ndk);
4332
+ *
4333
+ * // Create events
4334
+ * const alice = await UserGenerator.getUser('alice', ndk);
4335
+ * const note = await EventGenerator.createSignedTextNote('Hello!', alice.pubkey);
4336
+ * const dm = await EventGenerator.createEncryptedDirectMessage('Secret', alice.pubkey, bob.pubkey);
4337
+ *
4338
+ * // Use these events to test your app's event handling
4339
+ * ```
4340
+ */
4341
+ declare class EventGenerator {
4342
+ private static ndk;
4343
+ static setNDK(ndk: NDK): void;
4344
+ static createEvent(kind?: number, content?: string, pubkey?: string): NDKEvent;
4345
+ static createSignedTextNote(content: string, pubkey?: string): Promise<NDKEvent>;
4346
+ static createEncryptedDirectMessage(content: string, from: string, to: string): Promise<NDKEvent>;
4347
+ static createRepost(originalEvent: NDKEvent, pubkey?: string): Promise<NDKEvent>;
4348
+ static createParameterizedReplaceable(kind: number, content: string, pubkey?: string, dTag?: string): Promise<NDKEvent>;
4349
+ private static requireNDK;
4350
+ private static resolvePubkey;
4351
+ }
4352
+
4353
+ type Proof = {
4354
+ id: string;
4355
+ amount: number;
4356
+ secret: string;
4357
+ C: string;
4358
+ };
4359
+ /**
4360
+ * Creates a mock Cashu nutzap for testing zap/payment features in your application.
4361
+ *
4362
+ * Generates a complete NIP-61 nutzap event with Cashu tokens, perfect for testing
4363
+ * payment flows, zap handling, and wallet integration in your Nostr app without
4364
+ * requiring real mints or tokens.
4365
+ *
4366
+ * @param mint The mint URL
4367
+ * @param amount The amount in satoshis
4368
+ * @param ndk The NDK instance
4369
+ * @param opts Configuration options
4370
+ * @param opts.senderPk The private key signer of the sender (defaults to random)
4371
+ * @param opts.recipientPubkey The nostr pubkey of the recipient
4372
+ * @param opts.content Optional comment/message with the nutzap
4373
+ * @param opts.eventId Optional event ID being zapped (for replay protection)
4374
+ * @returns A signed nutzap event ready for testing
4375
+ *
4376
+ * @example
4377
+ * ```typescript
4378
+ * import { mockNutzap, UserGenerator } from '@nostr-dev-kit/ndk/test';
4379
+ *
4380
+ * const alice = await UserGenerator.getUser('alice', ndk);
4381
+ * const bob = await UserGenerator.getUser('bob', ndk);
4382
+ *
4383
+ * // Create a nutzap from alice to bob
4384
+ * const nutzap = await mockNutzap(
4385
+ * 'https://mint.example.com',
4386
+ * 1000, // 1000 sats
4387
+ * ndk,
4388
+ * {
4389
+ * recipientPubkey: bob.pubkey,
4390
+ * content: 'Great post!',
4391
+ * eventId: originalEvent.id
4392
+ * }
4393
+ * );
4394
+ *
4395
+ * // Test your app's nutzap handling
4396
+ * await myApp.handleNutzap(nutzap);
4397
+ * ```
4398
+ */
4399
+ declare function mockNutzap(mint: string, amount: number, ndk: any, { senderPk, recipientPubkey, content, eventId, }?: {
4400
+ senderPk?: any;
4401
+ recipientPubkey?: string;
4402
+ content?: string;
4403
+ eventId?: string;
4404
+ }): Promise<NDKNutzap>;
4405
+ /**
4406
+ * Creates a mock Cashu proof for testing token handling in your application.
4407
+ *
4408
+ * Generates individual Cashu proofs with optional P2PK locking, useful for testing
4409
+ * token validation, redemption, and wallet operations without real Cashu tokens.
4410
+ *
4411
+ * @param C The commitment point (usually mint URL for testing)
4412
+ * @param amount The amount in satoshis
4413
+ * @param p2pk Optional pubkey for P2PK locking the proof
4414
+ * @param proofTags Optional tags for proof secret (e.g., [["e", "event-id"], ["P", "sender-pubkey"]])
4415
+ * @returns A mock Cashu proof object
4416
+ *
4417
+ * @example
4418
+ * ```typescript
4419
+ * import { mockProof } from '@nostr-dev-kit/ndk/test';
4420
+ *
4421
+ * // Create a simple proof
4422
+ * const proof = mockProof('https://mint.example.com', 100);
4423
+ *
4424
+ * // Create a P2PK-locked proof
4425
+ * const lockedProof = mockProof(
4426
+ * 'https://mint.example.com',
4427
+ * 500,
4428
+ * bobPubkey, // locked to bob
4429
+ * [['P', alicePubkey]] // from alice
4430
+ * );
4431
+ *
4432
+ * // Test your app's proof validation
4433
+ * const isValid = await myApp.validateProof(lockedProof);
4434
+ * ```
4435
+ */
4436
+ declare function mockProof(C: string, amount: number, p2pk?: string, proofTags?: [string, string][]): Proof;
4437
+
4438
+ interface RelayMockOptions {
4439
+ simulateDisconnect?: boolean;
4440
+ disconnectAfter?: number;
4441
+ connectionDelay?: number;
4442
+ autoConnect?: boolean;
4443
+ failNextPublish?: boolean;
4444
+ }
4445
+ /**
4446
+ * Mock Nostr relay for testing your application without real relay connections.
4447
+ *
4448
+ * Simulates a full Nostr relay with configurable behavior including connection delays,
4449
+ * disconnections, and publish failures. Perfect for testing your app's relay interaction
4450
+ * logic without network dependencies.
4451
+ *
4452
+ * @example
4453
+ * ```typescript
4454
+ * import { RelayMock } from '@nostr-dev-kit/ndk/test';
4455
+ *
4456
+ * // Create a mock relay
4457
+ * const relay = new RelayMock('wss://relay.example.com', {
4458
+ * connectionDelay: 100, // Simulate 100ms connection delay
4459
+ * simulateDisconnect: true, // Randomly disconnect
4460
+ * disconnectAfter: 5000 // Disconnect after 5 seconds
4461
+ * });
4462
+ *
4463
+ * // Use it in your NDK instance
4464
+ * ndk.pool.relays.set(relay.url, relay);
4465
+ *
4466
+ * // Simulate events from relay
4467
+ * const event = await EventGenerator.createSignedTextNote('Hello!', alice.pubkey);
4468
+ * relay.simulateEvent(event);
4469
+ * relay.simulateEOSE();
4470
+ *
4471
+ * // Test publish failures
4472
+ * relay.failNextPublish = true;
4473
+ * await myApp.publishNote('This will fail');
4474
+ * ```
4475
+ */
4476
+ declare class RelayMock extends EventEmitter$1 {
4477
+ url: string;
4478
+ private _status;
4479
+ messageLog: Array<{
4480
+ direction: "in" | "out";
4481
+ message: string;
4482
+ }>;
4483
+ private activeSubscriptions;
4484
+ validatedEvents: number;
4485
+ nonValidatedEvents: number;
4486
+ options: Required<RelayMockOptions>;
4487
+ constructor(url?: string, options?: RelayMockOptions);
4488
+ connect(): Promise<void>;
4489
+ disconnect(): Promise<void>;
4490
+ get status(): NDKRelayStatus;
4491
+ send(message: string): void;
4492
+ publish(event: NDKEvent): Promise<boolean>;
4493
+ subscribe(subscription: NDKSubscription, filters: NDKFilter[]): void;
4494
+ shouldValidateEvent(): boolean;
4495
+ /**
4496
+ * Track the number of validated events (used in tests)
4497
+ */
4498
+ addValidatedEvent(): void;
4499
+ /**
4500
+ * Track the number of non-validated events (used in tests)
4501
+ */
4502
+ addNonValidatedEvent(): void;
4503
+ /**
4504
+ * Simulate receiving a raw message
4505
+ */
4506
+ simulateReceiveMessage(message: string): void;
4507
+ /**
4508
+ * Simulate receiving an event
4509
+ */
4510
+ simulateEvent(event: NDKEvent, subId?: string): Promise<void>;
4511
+ /**
4512
+ * Simulate end of stored events
4513
+ */
4514
+ simulateEOSE(subId: string): void;
4515
+ /**
4516
+ * Simulate a NOTICE message from the relay
4517
+ */
4518
+ simulateNotice(message: string): void;
4519
+ reset(): void;
4520
+ }
4521
+
4522
+ /**
4523
+ * Mock relay pool for testing applications with multiple Nostr relays.
4524
+ *
4525
+ * Manages multiple mock relays and provides convenient methods to simulate
4526
+ * events across all or specific relays. Perfect for testing your app's
4527
+ * multi-relay behavior, redundancy, and relay selection logic.
4528
+ *
4529
+ * @example
4530
+ * ```typescript
4531
+ * import { RelayPoolMock, EventGenerator, UserGenerator } from '@nostr-dev-kit/ndk/test';
4532
+ *
4533
+ * const pool = new RelayPoolMock();
4534
+ * const ndk = new NDK({ explicitRelayUrls: [] });
4535
+ * ndk.pool = pool;
4536
+ *
4537
+ * // Add mock relays
4538
+ * pool.addMockRelay('wss://relay1.example.com');
4539
+ * pool.addMockRelay('wss://relay2.example.com', {
4540
+ * connectionDelay: 200
4541
+ * });
4542
+ *
4543
+ * // Simulate event on all relays
4544
+ * const alice = await UserGenerator.getUser('alice', ndk);
4545
+ * const event = await EventGenerator.createSignedTextNote('Hello!', alice.pubkey);
4546
+ * pool.simulateEventOnAll(event);
4547
+ *
4548
+ * // Simulate event on specific relays
4549
+ * pool.simulateEventOn(['wss://relay1.example.com'], event);
4550
+ *
4551
+ * // Send EOSE to all relays
4552
+ * pool.simulateEOSEOnAll(subscriptionId);
4553
+ *
4554
+ * // Cleanup
4555
+ * pool.disconnectAll();
4556
+ * pool.resetAll();
4557
+ * ```
4558
+ */
4559
+ declare class RelayPoolMock {
4560
+ mockRelays: Map<string, RelayMock>;
4561
+ relays: Set<RelayMock>;
4562
+ private eventListeners;
4563
+ private onceListeners;
4564
+ addMockRelay(url: string, options?: {}): RelayMock;
4565
+ getMockRelay(url: string): RelayMock | undefined;
4566
+ addRelay(relay: RelayMock): void;
4567
+ removeRelay(relay: RelayMock): void;
4568
+ simulateEventOnAll(event: NDKEvent): void;
4569
+ simulateEventOn(relayUrls: string[], event: NDKEvent): void;
4570
+ simulateEOSEOnAll(subscriptionId: string): void;
4571
+ disconnectAll(): void;
4572
+ resetAll(): void;
4573
+ permanentAndConnectedRelays(): RelayMock[];
4574
+ connectedRelays(): RelayMock[];
4575
+ getRelay(url: string, connect?: boolean, createIfNotExists?: boolean, _filters?: NDKFilter[]): RelayMock;
4576
+ on(eventName: string, callback: Function): void;
4577
+ once(eventName: string, callback: Function): void;
4578
+ off(eventName: string, callback: Function): void;
4579
+ emit(eventName: string, ...args: any[]): void;
4580
+ useTemporaryRelay(_relay: RelayMock, _filters?: NDKFilter[], _subscription?: any): void;
4581
+ blacklistRelayUrls: Set<string>;
4582
+ }
4583
+
4584
+ export { EventGenerator, type Proof, RelayMock, RelayPoolMock, SignerGenerator, TestEventFactory, TestFixture, TimeController, UserGenerator, mockNutzap, mockProof, withTimeControl };