contextvm_sdk/core/
constants.rs1pub const CTXVM_MESSAGES_KIND: u16 = 25910;
8
9pub const GIFT_WRAP_KIND: u16 = 1059;
11
12pub const EPHEMERAL_GIFT_WRAP_KIND: u16 = 21059;
17
18pub const RELAY_LIST_METADATA_KIND: u16 = 10002;
20
21pub const SERVER_ANNOUNCEMENT_KIND: u16 = 11316;
23
24pub const TOOLS_LIST_KIND: u16 = 11317;
26
27pub const RESOURCES_LIST_KIND: u16 = 11318;
29
30pub const RESOURCETEMPLATES_LIST_KIND: u16 = 11319;
32
33pub const PROMPTS_LIST_KIND: u16 = 11320;
35
36pub mod tags {
38 pub const PUBKEY: &str = "p";
40
41 pub const RELAY: &str = "r";
43
44 pub const EVENT_ID: &str = "e";
46
47 pub const CAPABILITY: &str = "cap";
49
50 pub const NAME: &str = "name";
52
53 pub const WEBSITE: &str = "website";
55
56 pub const PICTURE: &str = "picture";
58
59 pub const ABOUT: &str = "about";
61
62 pub const SUPPORT_ENCRYPTION: &str = "support_encryption";
64
65 pub const SUPPORT_ENCRYPTION_EPHEMERAL: &str = "support_encryption_ephemeral";
67
68 pub const SUPPORT_OVERSIZED_TRANSFER: &str = "support_oversized_transfer";
70}
71
72pub const MAX_MESSAGE_SIZE: usize = 1024 * 1024;
74
75pub const DEFAULT_LRU_SIZE: usize = 5000;
77
78pub const DEFAULT_TIMEOUT_MS: u64 = 30_000;
80
81pub const DEFAULT_BOOTSTRAP_RELAY_URLS: &[&str] = &[
86 "wss://relay.damus.io",
87 "wss://relay.primal.net",
88 "wss://nos.lol",
89 "wss://relay.snort.social/",
90 "wss://nostr.mom/",
91 "wss://nostr.oxtr.dev/",
92];
93
94pub const INITIALIZE_METHOD: &str = "initialize";
96
97pub const NOTIFICATIONS_INITIALIZED_METHOD: &str = "notifications/initialized";
99
100pub const UNENCRYPTED_KINDS: &[u16] = &[
102 SERVER_ANNOUNCEMENT_KIND,
103 TOOLS_LIST_KIND,
104 RESOURCES_LIST_KIND,
105 RESOURCETEMPLATES_LIST_KIND,
106 PROMPTS_LIST_KIND,
107];
108
109#[cfg(feature = "rmcp")]
110pub fn mcp_protocol_version() -> &'static str {
111 use std::sync::OnceLock;
112 static VERSION: OnceLock<String> = OnceLock::new();
113 VERSION
114 .get_or_init(|| rmcp::model::ProtocolVersion::LATEST.to_string())
115 .as_str()
116}
117
118#[cfg(not(feature = "rmcp"))]
119pub const fn mcp_protocol_version() -> &'static str {
120 "2025-11-25"
121}
122
123const _: () = {
126 assert!(EPHEMERAL_GIFT_WRAP_KIND >= 20000);
128 assert!(EPHEMERAL_GIFT_WRAP_KIND < 30000);
129 assert!(CTXVM_MESSAGES_KIND >= 20000);
130 assert!(CTXVM_MESSAGES_KIND < 30000);
131 assert!(RELAY_LIST_METADATA_KIND >= 10000);
133 assert!(RELAY_LIST_METADATA_KIND < 20000);
134};
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 #[test]
141 fn test_event_kind_values_match_spec() {
142 assert_eq!(CTXVM_MESSAGES_KIND, 25910);
143 assert_eq!(GIFT_WRAP_KIND, 1059);
144 assert_eq!(EPHEMERAL_GIFT_WRAP_KIND, 21059);
145 assert_eq!(RELAY_LIST_METADATA_KIND, 10002);
146 assert_eq!(SERVER_ANNOUNCEMENT_KIND, 11316);
147 assert_eq!(TOOLS_LIST_KIND, 11317);
148 assert_eq!(RESOURCES_LIST_KIND, 11318);
149 assert_eq!(RESOURCETEMPLATES_LIST_KIND, 11319);
150 assert_eq!(PROMPTS_LIST_KIND, 11320);
151 }
152
153 #[test]
154 fn test_tag_values_match_ts_sdk() {
155 assert_eq!(tags::PUBKEY, "p");
156 assert_eq!(tags::RELAY, "r");
157 assert_eq!(tags::EVENT_ID, "e");
158 assert_eq!(tags::CAPABILITY, "cap");
159 assert_eq!(tags::NAME, "name");
160 assert_eq!(tags::WEBSITE, "website");
161 assert_eq!(tags::PICTURE, "picture");
162 assert_eq!(tags::ABOUT, "about");
163 assert_eq!(tags::SUPPORT_ENCRYPTION, "support_encryption");
164 assert_eq!(
165 tags::SUPPORT_ENCRYPTION_EPHEMERAL,
166 "support_encryption_ephemeral"
167 );
168 assert_eq!(
169 tags::SUPPORT_OVERSIZED_TRANSFER,
170 "support_oversized_transfer"
171 );
172 }
173
174 #[test]
175 fn test_announcement_kinds_in_addressable_range() {
176 for &kind in UNENCRYPTED_KINDS {
180 assert!(kind >= 11316);
181 assert!(kind <= 11320);
182 }
183 }
184
185 #[test]
186 fn test_bootstrap_relays_are_wss() {
187 for url in DEFAULT_BOOTSTRAP_RELAY_URLS {
188 assert!(
189 url.starts_with("wss://"),
190 "Bootstrap relay must use wss: {url}"
191 );
192 }
193 }
194
195 #[test]
196 fn test_bootstrap_relays_nonempty() {
197 assert!(
198 !DEFAULT_BOOTSTRAP_RELAY_URLS.is_empty(),
199 "Must have at least one bootstrap relay"
200 );
201 }
202
203 #[test]
204 fn test_mcp_method_constants() {
205 assert_eq!(INITIALIZE_METHOD, "initialize");
206 assert_eq!(
207 NOTIFICATIONS_INITIALIZED_METHOD,
208 "notifications/initialized"
209 );
210 }
211
212 #[test]
213 fn test_unencrypted_kinds_contains_all_announcements() {
214 assert!(UNENCRYPTED_KINDS.contains(&SERVER_ANNOUNCEMENT_KIND));
215 assert!(UNENCRYPTED_KINDS.contains(&TOOLS_LIST_KIND));
216 assert!(UNENCRYPTED_KINDS.contains(&RESOURCES_LIST_KIND));
217 assert!(UNENCRYPTED_KINDS.contains(&RESOURCETEMPLATES_LIST_KIND));
218 assert!(UNENCRYPTED_KINDS.contains(&PROMPTS_LIST_KIND));
219 }
220
221 #[test]
222 fn test_gift_wrap_not_in_unencrypted() {
223 assert!(!UNENCRYPTED_KINDS.contains(&GIFT_WRAP_KIND));
224 assert!(!UNENCRYPTED_KINDS.contains(&EPHEMERAL_GIFT_WRAP_KIND));
225 }
226}