commit 2c5927503fd34e3110906b3bbff46c42eabcffa7
parent 9002c272e4973d72d571d3787b2a3b65abd51f15
Author: triesap <tyson@radroots.org>
Date: Sat, 1 Aug 2026 07:14:41 +0000
nostr-connect: quarantine superseded package surface
- Keep the canonical client and transport surface while hiding the publish-frozen bridge.
- Move package coverage and protocol tests off the transitional prelude.
- Record the exact CLI, Myc, residual-consumer, and final-removal steps.
- Verify package checks, tests, clippy, architecture policy, and the public API baseline.
Diffstat:
9 files changed, 389 insertions(+), 431 deletions(-)
diff --git a/contracts/releases/api_boundaries.toml b/contracts/releases/api_boundaries.toml
@@ -117,8 +117,8 @@ observed_paths = [
"nostr::RelayUrl",
]
adr = "docs/decisions/0001-public-api-leakage-migration-baseline.md"
-removal_step = 140
-rationale = "Legacy client state-machine signatures retain exact protocol types until the Nostr Connect transport split and conformance gate."
+removal_step = 313
+rationale = "Hidden, publish-frozen client signatures remain only for CLI, Myc, and residual first-party cutovers in Steps 271, 288, and 293."
[[exception]]
id = "RCRV1-API-007"
@@ -138,8 +138,8 @@ observed_paths = [
"nostr::UnsignedEvent",
]
adr = "docs/decisions/0001-public-api-leakage-migration-baseline.md"
-removal_step = 140
-rationale = "Legacy request and response envelopes retain exact Nostr values until canonical package-owned envelopes are complete."
+removal_step = 313
+rationale = "Hidden, publish-frozen aliases remain only for CLI, Myc, and residual first-party cutovers in Steps 271, 288, and 293."
[[exception]]
id = "RCRV1-API-008"
@@ -152,5 +152,5 @@ items = [
]
observed_paths = ["nostr::PublicKey", "nostr::RelayUrl"]
adr = "docs/decisions/0001-public-api-leakage-migration-baseline.md"
-removal_step = 140
-rationale = "Legacy URI wrappers retain exact upstream value types until URI normalization and the package conformance gate."
+removal_step = 313
+rationale = "Hidden, publish-frozen URI aliases remain only for CLI, Myc, and residual first-party cutovers in Steps 271, 288, and 293."
diff --git a/crates/nostr_connect/src/client.rs b/crates/nostr_connect/src/client.rs
@@ -457,15 +457,18 @@ fn build_request_event_for(
.map_err(sign_error)
}
+#[doc(hidden)]
pub type RadrootsNostrConnectClientTransportFuture<'a, T> =
Pin<Box<dyn Future<Output = Result<T, RadrootsNostrConnectError>> + Send + 'a>>;
+#[doc(hidden)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RadrootsNostrConnectClientTarget {
pub remote_signer_public_key: PublicKey,
pub relays: Vec<RelayUrl>,
}
+#[doc(hidden)]
impl RadrootsNostrConnectClientTarget {
pub fn new(remote_signer_public_key: PublicKey, relays: Vec<RelayUrl>) -> Self {
Self {
@@ -475,12 +478,14 @@ impl RadrootsNostrConnectClientTarget {
}
}
+#[doc(hidden)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RadrootsNostrConnectClientRequest {
pub request_id: String,
pub request: Request,
}
+#[doc(hidden)]
impl RadrootsNostrConnectClientRequest {
pub fn new(request_id: impl Into<String>, request: Request) -> Self {
Self {
@@ -498,11 +503,13 @@ impl RadrootsNostrConnectClientRequest {
}
}
+#[doc(hidden)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RadrootsNostrConnectClientProgress {
AuthChallenge { url: String },
}
+#[doc(hidden)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RadrootsNostrConnectClientEventOutcome {
Ignore,
@@ -510,6 +517,7 @@ pub enum RadrootsNostrConnectClientEventOutcome {
Response(Response),
}
+#[doc(hidden)]
pub trait RadrootsNostrConnectClientTransport {
fn publish_request_event<'a>(
&'a mut self,
@@ -521,6 +529,7 @@ pub trait RadrootsNostrConnectClientTransport {
) -> RadrootsNostrConnectClientTransportFuture<'a, Event>;
}
+#[doc(hidden)]
pub fn build_request_event(
client_keys: &Keys,
target: &RadrootsNostrConnectClientTarget,
@@ -541,6 +550,7 @@ pub fn build_request_event(
.map_err(sign_error)
}
+#[doc(hidden)]
pub fn parse_response_event(
client_keys: &Keys,
target: &RadrootsNostrConnectClientTarget,
@@ -551,11 +561,9 @@ pub fn parse_response_event(
if event.kind != Kind::Custom(RPC_KIND) {
return Ok(RadrootsNostrConnectClientEventOutcome::Ignore);
}
-
if event.pubkey != target.remote_signer_public_key {
return Ok(RadrootsNostrConnectClientEventOutcome::Ignore);
}
-
let client_public_key = client_keys.public_key();
if !event
.tags
@@ -567,7 +575,6 @@ pub fn parse_response_event(
event
.verify()
.map_err(|_| RadrootsNostrConnectError::InvalidClientEvent)?;
-
let decrypted = nip44::decrypt(
client_keys.secret_key(),
&target.remote_signer_public_key,
@@ -576,13 +583,11 @@ pub fn parse_response_event(
.map_err(|error| RadrootsNostrConnectError::Decrypt {
reason: error.to_string(),
})?;
-
let envelope: ResponseEnvelope =
serde_json::from_str(&decrypted).map_err(RadrootsNostrConnectError::from)?;
if envelope.id != request_id {
return Ok(RadrootsNostrConnectClientEventOutcome::Ignore);
}
-
let response = Response::from_envelope(method, envelope)?;
Ok(match response {
Response::AuthUrl(url) => RadrootsNostrConnectClientEventOutcome::Progress(
@@ -592,6 +597,7 @@ pub fn parse_response_event(
})
}
+#[doc(hidden)]
pub async fn execute_request_with_transport<T, F>(
client_keys: &Keys,
target: &RadrootsNostrConnectClientTarget,
@@ -607,7 +613,6 @@ where
let request_id = request.request_id.clone();
let event = build_request_event(client_keys, target, request.into_message())?;
transport.publish_request_event(event).await?;
-
loop {
let event = transport.next_response_event().await?;
match parse_response_event(client_keys, target, &request_id, &method, &event)? {
diff --git a/crates/nostr_connect/src/lib.rs b/crates/nostr_connect/src/lib.rs
@@ -19,8 +19,11 @@ pub use permission::Permission;
pub use server::Server;
pub use uri::{BunkerUri, ClientUri};
-// Transitional compatibility surface for consumers migrated in Step 141.
-// Publication remains disabled, and Step 143 removes this module.
+/// Private migration surface for separate first-party repositories.
+///
+/// This module is excluded from the reviewed public API baseline, the package
+/// remains `publish = false`, consumers cut over in Steps 271, 288, and 293,
+/// and Step 313 removes the shim in full.
#[doc(hidden)]
pub mod prelude {
pub use crate::client::{
@@ -49,25 +52,20 @@ pub mod prelude {
Response as RadrootsNostrConnectResponse,
ResponseEnvelope as RadrootsNostrConnectResponseEnvelope,
};
- pub use crate::method::Method;
- pub use crate::method::Method as RadrootsNostrConnectMethod;
- pub use crate::permission::{Permission, Permissions};
+ pub use crate::method::{Method, Method as RadrootsNostrConnectMethod};
pub use crate::permission::{
- Permission as RadrootsNostrConnectPermission,
+ Permission, Permission as RadrootsNostrConnectPermission, Permissions,
Permissions as RadrootsNostrConnectPermissions,
};
pub use crate::uri::{
- BUNKER_URI_SCHEME, BunkerUri, CLIENT_METADATA_JSON_MAX_BYTES, CLIENT_NAME_MAX_BYTES,
- CLIENT_URL_MAX_BYTES, ClientMetadata, ClientUri, URI_SCHEME, Uri,
- };
- pub use crate::uri::{
- BUNKER_URI_SCHEME as RADROOTS_NOSTR_CONNECT_BUNKER_URI_SCHEME,
- BunkerUri as RadrootsNostrConnectBunkerUri,
+ BUNKER_URI_SCHEME, BUNKER_URI_SCHEME as RADROOTS_NOSTR_CONNECT_BUNKER_URI_SCHEME,
+ BunkerUri, BunkerUri as RadrootsNostrConnectBunkerUri, CLIENT_METADATA_JSON_MAX_BYTES,
CLIENT_METADATA_JSON_MAX_BYTES as RADROOTS_NOSTR_CONNECT_CLIENT_METADATA_JSON_MAX_BYTES,
+ CLIENT_NAME_MAX_BYTES,
CLIENT_NAME_MAX_BYTES as RADROOTS_NOSTR_CONNECT_CLIENT_NAME_MAX_BYTES,
- CLIENT_URL_MAX_BYTES as RADROOTS_NOSTR_CONNECT_CLIENT_URL_MAX_BYTES,
- ClientMetadata as RadrootsNostrConnectClientMetadata,
- ClientUri as RadrootsNostrConnectClientUri,
- URI_SCHEME as RADROOTS_NOSTR_CONNECT_URI_SCHEME, Uri as RadrootsNostrConnectUri,
+ CLIENT_URL_MAX_BYTES, CLIENT_URL_MAX_BYTES as RADROOTS_NOSTR_CONNECT_CLIENT_URL_MAX_BYTES,
+ ClientMetadata, ClientMetadata as RadrootsNostrConnectClientMetadata, ClientUri,
+ ClientUri as RadrootsNostrConnectClientUri, URI_SCHEME,
+ URI_SCHEME as RADROOTS_NOSTR_CONNECT_URI_SCHEME, Uri, Uri as RadrootsNostrConnectUri,
};
}
diff --git a/crates/nostr_connect/tests/client.rs b/crates/nostr_connect/tests/client.rs
@@ -372,7 +372,6 @@ async fn executes_request_through_transport_with_auth_progress() {
)
);
}
-
#[tokio::test]
async fn ignores_events_not_addressed_by_expected_signer_and_client() {
let client_keys = client_keys();
diff --git a/crates/nostr_connect/tests/coverage.rs b/crates/nostr_connect/tests/coverage.rs
@@ -2,15 +2,13 @@
mod test_fixtures;
use nostr::{Event, EventBuilder, JsonUtil, Keys, SecretKey, Timestamp, UnsignedEvent};
-use radroots_nostr_connect::prelude::{
- CLIENT_URL_MAX_BYTES, ClientMetadata, Method, Permission, Permissions,
- RADROOTS_NOSTR_CONNECT_PENDING_CONNECTION_ERROR, RadrootsNostrConnectError,
- RadrootsNostrConnectPendingConnectionPollOutcome, RadrootsNostrConnectRequest,
- RadrootsNostrConnectRequestMessage, RadrootsNostrConnectResponse,
- RadrootsNostrConnectResponseEnvelope, SignedEvent as ConnectSignedEvent,
- UnsignedEvent as ConnectUnsignedEvent, Uri,
+use radroots_nostr_connect::message::{
+ PENDING_CONNECTION_ERROR, PendingConnectionOutcome, RemoteSessionCapability, RequestMessage,
+ ResponseEnvelope, SignedEvent as ConnectSignedEvent, UnsignedEvent as ConnectUnsignedEvent,
};
-use radroots_nostr_connect::uri::RelayUrl;
+use radroots_nostr_connect::permission::Permissions;
+use radroots_nostr_connect::uri::{CLIENT_URL_MAX_BYTES, ClientMetadata, RelayUrl, Uri};
+use radroots_nostr_connect::{Error, Method, Permission, Request, Response};
use serde_json::{Value, json};
use std::str::FromStr;
use test_fixtures::{
@@ -61,8 +59,8 @@ fn relay(value: &str) -> RelayUrl {
fn error_method_and_permission_surfaces_cover_public_paths() {
let json_error = serde_json::from_str::<Value>("{").expect_err("invalid json");
assert!(matches!(
- RadrootsNostrConnectError::from(json_error),
- RadrootsNostrConnectError::Json(message) if !message.is_empty()
+ Error::from(json_error),
+ Error::Json(message) if !message.is_empty()
));
let methods = [
@@ -88,7 +86,7 @@ fn error_method_and_permission_surfaces_cover_public_paths() {
);
assert!(matches!(
Method::from_str(" "),
- Err(RadrootsNostrConnectError::InvalidMethod(value)) if value == " "
+ Err(Error::InvalidMethod(value)) if value == " "
));
assert_eq!(
serde_json::from_str::<Method>("\"do_work\"").expect("deserialize custom method"),
@@ -117,15 +115,15 @@ fn error_method_and_permission_surfaces_cover_public_paths() {
);
assert!(matches!(
Permission::from_str(" "),
- Err(RadrootsNostrConnectError::InvalidPermission(value)) if value == " "
+ Err(Error::InvalidPermission(value)) if value == " "
));
assert!(matches!(
Permission::from_str("sign_event:"),
- Err(RadrootsNostrConnectError::InvalidPermission(value)) if value == "sign_event:"
+ Err(Error::InvalidPermission(value)) if value == "sign_event:"
));
assert!(matches!(
Permission::from_str(" :kind"),
- Err(RadrootsNostrConnectError::InvalidMethod(_))
+ Err(Error::InvalidMethod(_))
));
let empty = Permissions::new();
@@ -159,7 +157,7 @@ fn error_method_and_permission_surfaces_cover_public_paths() {
);
assert!(matches!(
Permissions::from_str("sign_event:,ping"),
- Err(RadrootsNostrConnectError::InvalidPermission(value)) if value == "sign_event:"
+ Err(Error::InvalidPermission(value)) if value == "sign_event:"
));
let all_sign_events = Permission::new(Method::SignEvent);
@@ -246,22 +244,22 @@ fn uri_surface_covers_rendering_ignored_queries_and_error_paths() {
assert!(matches!(
Uri::parse("not a uri"),
- Err(RadrootsNostrConnectError::InvalidUrl { .. })
+ Err(Error::InvalidUrl { .. })
));
assert!(matches!(
Uri::parse("nostrconnect:///path?relay=wss%3A%2F%2Frelay.example.com&secret=abc"),
- Err(RadrootsNostrConnectError::MissingPublicKey)
+ Err(Error::MissingPublicKey)
));
assert!(matches!(
Uri::parse(&format!("bunker://{}", FIXTURE_ALICE.public_key_hex)),
- Err(RadrootsNostrConnectError::MissingRelay)
+ Err(Error::MissingRelay)
));
assert!(matches!(
Uri::parse(&format!(
"nostrconnect://{}?secret=abc",
FIXTURE_ALICE.public_key_hex
)),
- Err(RadrootsNostrConnectError::MissingRelay)
+ Err(Error::MissingRelay)
));
assert!(matches!(
Uri::parse(&format!(
@@ -269,22 +267,22 @@ fn uri_surface_covers_rendering_ignored_queries_and_error_paths() {
FIXTURE_ALICE.public_key_hex,
encode_uri_component(RELAY_PRIMARY_WSS),
)),
- Err(RadrootsNostrConnectError::MissingSecret)
+ Err(Error::MissingSecret)
));
assert!(matches!(
Uri::parse("https://example.com"),
- Err(RadrootsNostrConnectError::InvalidUriScheme(value)) if value == "https"
+ Err(Error::InvalidUriScheme(value)) if value == "https"
));
assert!(matches!(
Uri::parse("nostrconnect://bad-key?relay=wss%3A%2F%2Frelay.example.com&secret=abc"),
- Err(RadrootsNostrConnectError::InvalidPublicKey { .. })
+ Err(Error::InvalidPublicKey { .. })
));
assert!(matches!(
Uri::parse(&format!(
"nostrconnect://{}?relay=http%3A%2F%2Frelay.example.com&secret=abc",
FIXTURE_ALICE.public_key_hex
)),
- Err(RadrootsNostrConnectError::InvalidRelayUrl { .. })
+ Err(Error::InvalidRelayUrl { .. })
));
assert!(matches!(
Uri::parse(&format!(
@@ -292,18 +290,18 @@ fn uri_surface_covers_rendering_ignored_queries_and_error_paths() {
FIXTURE_ALICE.public_key_hex,
encode_uri_component(RELAY_PRIMARY_WSS),
)),
- Err(RadrootsNostrConnectError::InvalidClientMetadata { field: "url", .. })
+ Err(Error::InvalidClientMetadata { field: "url", .. })
));
assert!(matches!(
Uri::parse("bunker://bad-key?relay=wss%3A%2F%2Frelay.example.com"),
- Err(RadrootsNostrConnectError::InvalidPublicKey { .. })
+ Err(Error::InvalidPublicKey { .. })
));
assert!(matches!(
Uri::parse(&format!(
"bunker://{}?relay=http%3A%2F%2Frelay.example.com",
FIXTURE_ALICE.public_key_hex
)),
- Err(RadrootsNostrConnectError::InvalidRelayUrl { .. })
+ Err(Error::InvalidRelayUrl { .. })
));
assert!(matches!(
Uri::parse(&format!(
@@ -311,7 +309,7 @@ fn uri_surface_covers_rendering_ignored_queries_and_error_paths() {
FIXTURE_ALICE.public_key_hex,
encode_uri_component(RELAY_PRIMARY_WSS),
)),
- Err(RadrootsNostrConnectError::InvalidPermission(value)) if value == "sign_event:"
+ Err(Error::InvalidPermission(value)) if value == "sign_event:"
));
assert!(matches!(
Uri::parse(&format!(
@@ -319,7 +317,7 @@ fn uri_surface_covers_rendering_ignored_queries_and_error_paths() {
FIXTURE_ALICE.public_key_hex,
encode_uri_component(RELAY_PRIMARY_WSS),
)),
- Err(RadrootsNostrConnectError::InvalidClientMetadata { field: "image", .. })
+ Err(Error::InvalidClientMetadata { field: "image", .. })
));
assert!(matches!(
Uri::parse(&format!(
@@ -327,7 +325,7 @@ fn uri_surface_covers_rendering_ignored_queries_and_error_paths() {
FIXTURE_ALICE.public_key_hex,
encode_uri_component(RELAY_PRIMARY_WSS),
)),
- Err(RadrootsNostrConnectError::MissingSecret)
+ Err(Error::MissingSecret)
));
}
@@ -372,7 +370,7 @@ fn client_metadata_rejects_malformed_and_unsafe_display_fields() {
assert!(matches!(
ClientMetadata::from_connect_param("{"),
- Err(RadrootsNostrConnectError::InvalidClientMetadata {
+ Err(Error::InvalidClientMetadata {
field: "payload",
..
})
@@ -391,7 +389,7 @@ fn client_metadata_rejects_malformed_and_unsafe_display_fields() {
};
assert!(matches!(
metadata.normalized(),
- Err(RadrootsNostrConnectError::InvalidClientMetadata {
+ Err(Error::InvalidClientMetadata {
field: actual,
..
}) if actual == field
@@ -405,7 +403,7 @@ fn request_surface_covers_variant_methods_serialization_and_validation() {
let requests = vec![
(
- RadrootsNostrConnectRequest::Connect {
+ Request::Connect {
remote_signer_public_key: test_public_key(),
secret: None,
requested_permissions: Permissions::default(),
@@ -415,7 +413,7 @@ fn request_surface_covers_variant_methods_serialization_and_validation() {
vec![test_public_key().to_hex()],
),
(
- RadrootsNostrConnectRequest::Connect {
+ Request::Connect {
remote_signer_public_key: test_public_key(),
secret: None,
requested_permissions: ping_permission.clone(),
@@ -424,18 +422,14 @@ fn request_surface_covers_variant_methods_serialization_and_validation() {
Method::Connect,
vec![test_public_key().to_hex(), String::new(), "ping".to_owned()],
),
+ (Request::GetPublicKey, Method::GetPublicKey, Vec::new()),
(
- RadrootsNostrConnectRequest::GetPublicKey,
- Method::GetPublicKey,
- Vec::new(),
- ),
- (
- RadrootsNostrConnectRequest::GetSessionCapability,
+ Request::GetSessionCapability,
Method::GetSessionCapability,
Vec::new(),
),
(
- RadrootsNostrConnectRequest::SignEvent(
+ Request::SignEvent(
ConnectUnsignedEvent::from_json(&unsigned_event().as_json())
.expect("unsigned event payload"),
),
@@ -443,7 +437,7 @@ fn request_surface_covers_variant_methods_serialization_and_validation() {
vec![serde_json::to_string(&unsigned_event()).expect("serialize unsigned event")],
),
(
- RadrootsNostrConnectRequest::Nip04Encrypt {
+ Request::Nip04Encrypt {
public_key: test_public_key(),
plaintext: "hello".to_owned(),
},
@@ -451,7 +445,7 @@ fn request_surface_covers_variant_methods_serialization_and_validation() {
vec![test_public_key().to_hex(), "hello".to_owned()],
),
(
- RadrootsNostrConnectRequest::Nip04Decrypt {
+ Request::Nip04Decrypt {
public_key: test_public_key(),
ciphertext: "cipher".to_owned(),
},
@@ -459,7 +453,7 @@ fn request_surface_covers_variant_methods_serialization_and_validation() {
vec![test_public_key().to_hex(), "cipher".to_owned()],
),
(
- RadrootsNostrConnectRequest::Nip44Encrypt {
+ Request::Nip44Encrypt {
public_key: test_public_key(),
plaintext: "hello".to_owned(),
},
@@ -467,26 +461,18 @@ fn request_surface_covers_variant_methods_serialization_and_validation() {
vec![test_public_key().to_hex(), "hello".to_owned()],
),
(
- RadrootsNostrConnectRequest::Nip44Decrypt {
+ Request::Nip44Decrypt {
public_key: test_public_key(),
ciphertext: "cipher".to_owned(),
},
Method::Nip44Decrypt,
vec![test_public_key().to_hex(), "cipher".to_owned()],
),
- (RadrootsNostrConnectRequest::Ping, Method::Ping, Vec::new()),
- (
- RadrootsNostrConnectRequest::SwitchRelays,
- Method::SwitchRelays,
- Vec::new(),
- ),
+ (Request::Ping, Method::Ping, Vec::new()),
+ (Request::SwitchRelays, Method::SwitchRelays, Vec::new()),
+ (Request::Logout, Method::Logout, Vec::new()),
(
- RadrootsNostrConnectRequest::Logout,
- Method::Logout,
- Vec::new(),
- ),
- (
- RadrootsNostrConnectRequest::Custom {
+ Request::Custom {
method: Method::custom("publish_note").expect("valid custom NIP-46 method"),
params: vec!["one".to_owned(), "two".to_owned()],
},
@@ -500,9 +486,9 @@ fn request_surface_covers_variant_methods_serialization_and_validation() {
}
assert_eq!(
- RadrootsNostrConnectRequest::from_parts(Method::Connect, vec![test_public_key().to_hex()],)
+ Request::from_parts(Method::Connect, vec![test_public_key().to_hex()],)
.expect("connect without secret or perms"),
- RadrootsNostrConnectRequest::Connect {
+ Request::Connect {
remote_signer_public_key: test_public_key(),
secret: None,
requested_permissions: Permissions::default(),
@@ -510,12 +496,12 @@ fn request_surface_covers_variant_methods_serialization_and_validation() {
}
);
assert_eq!(
- RadrootsNostrConnectRequest::from_parts(
+ Request::from_parts(
Method::Connect,
vec![test_public_key().to_hex(), String::new(), "ping".to_owned()],
)
.expect("connect with empty secret"),
- RadrootsNostrConnectRequest::Connect {
+ Request::Connect {
remote_signer_public_key: test_public_key(),
secret: None,
requested_permissions: Permissions::from(vec![Permission::new(Method::Ping),]),
@@ -523,67 +509,65 @@ fn request_surface_covers_variant_methods_serialization_and_validation() {
}
);
assert_eq!(
- RadrootsNostrConnectRequest::from_parts(Method::GetPublicKey, Vec::new(),)
- .expect("get_public_key from parts"),
- RadrootsNostrConnectRequest::GetPublicKey
+ Request::from_parts(Method::GetPublicKey, Vec::new(),).expect("get_public_key from parts"),
+ Request::GetPublicKey
);
assert_eq!(
- RadrootsNostrConnectRequest::from_parts(Method::GetSessionCapability, Vec::new(),)
+ Request::from_parts(Method::GetSessionCapability, Vec::new(),)
.expect("get_session_capability from parts"),
- RadrootsNostrConnectRequest::GetSessionCapability
+ Request::GetSessionCapability
);
assert_eq!(
- RadrootsNostrConnectRequest::from_parts(
+ Request::from_parts(
Method::Nip04Encrypt,
vec![test_public_key().to_hex(), "hello".to_owned()],
)
.expect("nip04 encrypt from parts"),
- RadrootsNostrConnectRequest::Nip04Encrypt {
+ Request::Nip04Encrypt {
public_key: test_public_key(),
plaintext: "hello".to_owned(),
}
);
assert_eq!(
- RadrootsNostrConnectRequest::from_parts(
+ Request::from_parts(
Method::Nip04Decrypt,
vec![test_public_key().to_hex(), "cipher".to_owned()],
)
.expect("nip04 decrypt from parts"),
- RadrootsNostrConnectRequest::Nip04Decrypt {
+ Request::Nip04Decrypt {
public_key: test_public_key(),
ciphertext: "cipher".to_owned(),
}
);
assert_eq!(
- RadrootsNostrConnectRequest::from_parts(
+ Request::from_parts(
Method::Nip44Encrypt,
vec![test_public_key().to_hex(), "hello".to_owned()],
)
.expect("nip44 encrypt from parts"),
- RadrootsNostrConnectRequest::Nip44Encrypt {
+ Request::Nip44Encrypt {
public_key: test_public_key(),
plaintext: "hello".to_owned(),
}
);
assert_eq!(
- RadrootsNostrConnectRequest::from_parts(
+ Request::from_parts(
Method::Nip44Decrypt,
vec![test_public_key().to_hex(), "cipher".to_owned()],
)
.expect("nip44 decrypt from parts"),
- RadrootsNostrConnectRequest::Nip44Decrypt {
+ Request::Nip44Decrypt {
public_key: test_public_key(),
ciphertext: "cipher".to_owned(),
}
);
assert_eq!(
- RadrootsNostrConnectRequest::from_parts(Method::Ping, Vec::new()).expect("ping from parts"),
- RadrootsNostrConnectRequest::Ping
+ Request::from_parts(Method::Ping, Vec::new()).expect("ping from parts"),
+ Request::Ping
);
assert_eq!(
- RadrootsNostrConnectRequest::from_parts(Method::SwitchRelays, Vec::new(),)
- .expect("switch relays from parts"),
- RadrootsNostrConnectRequest::SwitchRelays
+ Request::from_parts(Method::SwitchRelays, Vec::new(),).expect("switch relays from parts"),
+ Request::SwitchRelays
);
for (method, params, expected_error) in [
@@ -619,28 +603,28 @@ fn request_surface_covers_variant_methods_serialization_and_validation() {
(Method::Logout, vec!["oops".to_owned()], "no params"),
] {
assert!(matches!(
- RadrootsNostrConnectRequest::from_parts(method, params),
- Err(RadrootsNostrConnectError::InvalidParams { expected, .. }) if expected == expected_error
+ Request::from_parts(method, params),
+ Err(Error::InvalidParams { expected, .. }) if expected == expected_error
));
}
assert!(matches!(
- RadrootsNostrConnectRequest::from_parts(Method::Connect, Vec::new()),
- Err(RadrootsNostrConnectError::InvalidParams { expected, received, .. })
+ Request::from_parts(Method::Connect, Vec::new()),
+ Err(Error::InvalidParams { expected, received, .. })
if expected == "1 to 4 params" && received == 0
));
assert!(matches!(
- RadrootsNostrConnectRequest::from_parts(Method::Connect, vec!["bad-key".to_owned()],),
- Err(RadrootsNostrConnectError::InvalidPublicKey { .. })
+ Request::from_parts(Method::Connect, vec!["bad-key".to_owned()],),
+ Err(Error::InvalidPublicKey { .. })
));
assert!(matches!(
- RadrootsNostrConnectRequest::from_parts(
+ Request::from_parts(
Method::Connect,
vec![test_public_key().to_hex(), "secret".to_owned(), "sign_event:".to_owned()],
),
- Err(RadrootsNostrConnectError::InvalidPermission(value)) if value == "sign_event:"
+ Err(Error::InvalidPermission(value)) if value == "sign_event:"
));
assert!(matches!(
- RadrootsNostrConnectRequest::from_parts(
+ Request::from_parts(
Method::Connect,
vec![
test_public_key().to_hex(),
@@ -650,61 +634,61 @@ fn request_surface_covers_variant_methods_serialization_and_validation() {
"too-many".to_owned(),
],
),
- Err(RadrootsNostrConnectError::InvalidParams { expected, received, .. })
+ Err(Error::InvalidParams { expected, received, .. })
if expected == "1 to 4 params" && received == 5
));
assert!(matches!(
- RadrootsNostrConnectRequest::from_parts(Method::SignEvent, vec!["not-json".to_owned()],),
- Err(RadrootsNostrConnectError::InvalidRequestPayload { .. })
+ Request::from_parts(Method::SignEvent, vec!["not-json".to_owned()],),
+ Err(Error::InvalidRequestPayload { .. })
));
assert!(matches!(
- RadrootsNostrConnectRequest::from_parts(
+ Request::from_parts(
Method::Nip04Encrypt,
vec!["bad-key".to_owned(), "hello".to_owned()],
),
- Err(RadrootsNostrConnectError::InvalidPublicKey { .. })
+ Err(Error::InvalidPublicKey { .. })
));
assert!(matches!(
- RadrootsNostrConnectRequest::from_parts(
+ Request::from_parts(
Method::Nip04Decrypt,
vec!["bad-key".to_owned(), "cipher".to_owned()],
),
- Err(RadrootsNostrConnectError::InvalidPublicKey { .. })
+ Err(Error::InvalidPublicKey { .. })
));
assert!(matches!(
- RadrootsNostrConnectRequest::from_parts(
+ Request::from_parts(
Method::Nip44Encrypt,
vec!["bad-key".to_owned(), "hello".to_owned()],
),
- Err(RadrootsNostrConnectError::InvalidPublicKey { .. })
+ Err(Error::InvalidPublicKey { .. })
));
assert!(matches!(
- RadrootsNostrConnectRequest::from_parts(
+ Request::from_parts(
Method::Nip44Decrypt,
vec!["bad-key".to_owned(), "cipher".to_owned()],
),
- Err(RadrootsNostrConnectError::InvalidPublicKey { .. })
+ Err(Error::InvalidPublicKey { .. })
));
- let custom_message = RadrootsNostrConnectRequestMessage::new(
+ let custom_message = RequestMessage::new(
"req-custom",
- RadrootsNostrConnectRequest::Custom {
+ Request::Custom {
method: Method::custom("publish_note").expect("valid custom NIP-46 method"),
params: vec!["a".to_owned()],
},
);
let encoded = serde_json::to_string(&custom_message).expect("serialize custom request");
- let decoded: RadrootsNostrConnectRequestMessage =
+ let decoded: RequestMessage =
serde_json::from_str(&encoded).expect("deserialize custom request");
assert_eq!(decoded, custom_message);
assert!(
- serde_json::from_str::<RadrootsNostrConnectRequestMessage>("{")
+ serde_json::from_str::<RequestMessage>("{")
.expect_err("invalid request message json")
.to_string()
.contains("EOF")
);
assert!(
- serde_json::from_str::<RadrootsNostrConnectRequestMessage>(
+ serde_json::from_str::<RequestMessage>(
"{\"id\":\"req\",\"method\":\"get_public_key\",\"params\":[\"oops\"]}",
)
.expect_err("invalid request params")
@@ -716,104 +700,88 @@ fn request_surface_covers_variant_methods_serialization_and_validation() {
#[test]
fn response_surface_covers_success_and_error_paths() {
let event = signed_event();
- let remote_session_capability =
- radroots_nostr_connect::prelude::RadrootsNostrConnectRemoteSessionCapability {
- user_public_key: test_public_key(),
- relays: vec![relay(RELAY_PRIMARY_WSS), relay(RELAY_SECONDARY_WSS)],
- permissions: Permissions::from(vec![
- Permission::new(Method::Ping),
- Permission::with_parameter(Method::SignEvent, "kind:1"),
- ]),
- };
+ let remote_session_capability = RemoteSessionCapability {
+ user_public_key: test_public_key(),
+ relays: vec![relay(RELAY_PRIMARY_WSS), relay(RELAY_SECONDARY_WSS)],
+ permissions: Permissions::from(vec![
+ Permission::new(Method::Ping),
+ Permission::with_parameter(Method::SignEvent, "kind:1"),
+ ]),
+ };
let cases = vec![
(
- RadrootsNostrConnectResponse::ConnectAcknowledged,
+ Response::ConnectAcknowledged,
Method::Connect,
- RadrootsNostrConnectResponse::ConnectAcknowledged,
+ Response::ConnectAcknowledged,
),
(
- RadrootsNostrConnectResponse::ConnectSecretEcho("secret".to_owned()),
+ Response::ConnectSecretEcho("secret".to_owned()),
Method::Connect,
- RadrootsNostrConnectResponse::ConnectSecretEcho("secret".to_owned()),
+ Response::ConnectSecretEcho("secret".to_owned()),
),
(
- RadrootsNostrConnectResponse::UserPublicKey(test_public_key()),
+ Response::UserPublicKey(test_public_key()),
Method::GetPublicKey,
- RadrootsNostrConnectResponse::UserPublicKey(test_public_key()),
+ Response::UserPublicKey(test_public_key()),
),
(
- RadrootsNostrConnectResponse::PendingConnection,
+ Response::PendingConnection,
Method::GetSessionCapability,
- RadrootsNostrConnectResponse::PendingConnection,
+ Response::PendingConnection,
),
(
- RadrootsNostrConnectResponse::RemoteSessionCapability(
- remote_session_capability.clone(),
- ),
+ Response::RemoteSessionCapability(remote_session_capability.clone()),
Method::GetSessionCapability,
- RadrootsNostrConnectResponse::RemoteSessionCapability(
- remote_session_capability.clone(),
- ),
+ Response::RemoteSessionCapability(remote_session_capability.clone()),
),
(
- RadrootsNostrConnectResponse::SignedEvent(
+ Response::SignedEvent(
ConnectSignedEvent::from_json(&event.as_json()).expect("signed event payload"),
),
Method::SignEvent,
- RadrootsNostrConnectResponse::SignedEvent(
+ Response::SignedEvent(
ConnectSignedEvent::from_json(&event.as_json()).expect("signed event payload"),
),
),
+ (Response::Pong, Method::Ping, Response::Pong),
(
- RadrootsNostrConnectResponse::Pong,
- Method::Ping,
- RadrootsNostrConnectResponse::Pong,
- ),
- (
- RadrootsNostrConnectResponse::Nip04Encrypt("cipher".to_owned()),
+ Response::Nip04Encrypt("cipher".to_owned()),
Method::Nip04Encrypt,
- RadrootsNostrConnectResponse::Nip04Encrypt("cipher".to_owned()),
+ Response::Nip04Encrypt("cipher".to_owned()),
),
(
- RadrootsNostrConnectResponse::Nip04Decrypt("plain".to_owned()),
+ Response::Nip04Decrypt("plain".to_owned()),
Method::Nip04Decrypt,
- RadrootsNostrConnectResponse::Nip04Decrypt("plain".to_owned()),
+ Response::Nip04Decrypt("plain".to_owned()),
),
(
- RadrootsNostrConnectResponse::Nip44Encrypt("cipher".to_owned()),
+ Response::Nip44Encrypt("cipher".to_owned()),
Method::Nip44Encrypt,
- RadrootsNostrConnectResponse::Nip44Encrypt("cipher".to_owned()),
+ Response::Nip44Encrypt("cipher".to_owned()),
),
(
- RadrootsNostrConnectResponse::Nip44Decrypt("plain".to_owned()),
+ Response::Nip44Decrypt("plain".to_owned()),
Method::Nip44Decrypt,
- RadrootsNostrConnectResponse::Nip44Decrypt("plain".to_owned()),
+ Response::Nip44Decrypt("plain".to_owned()),
),
(
- RadrootsNostrConnectResponse::RelayList(vec![
- relay(RELAY_SECONDARY_WSS),
- relay(RELAY_TERTIARY_WSS),
- ]),
+ Response::RelayList(vec![relay(RELAY_SECONDARY_WSS), relay(RELAY_TERTIARY_WSS)]),
Method::SwitchRelays,
- RadrootsNostrConnectResponse::RelayList(vec![
- relay(RELAY_SECONDARY_WSS),
- relay(RELAY_TERTIARY_WSS),
- ]),
+ Response::RelayList(vec![relay(RELAY_SECONDARY_WSS), relay(RELAY_TERTIARY_WSS)]),
),
(
- RadrootsNostrConnectResponse::RelayListUnchanged,
+ Response::RelayListUnchanged,
Method::SwitchRelays,
- RadrootsNostrConnectResponse::RelayListUnchanged,
+ Response::RelayListUnchanged,
),
];
for (response, method, expected) in cases {
let envelope = response.into_envelope("req").expect("serialize response");
- let parsed =
- RadrootsNostrConnectResponse::from_envelope(&method, envelope).expect("parse response");
+ let parsed = Response::from_envelope(&method, envelope).expect("parse response");
assert_eq!(parsed, expected);
}
- let error_envelope = RadrootsNostrConnectResponse::Error {
+ let error_envelope = Response::Error {
result: Some(json!("partial")),
error: "denied".to_owned(),
}
@@ -821,7 +789,7 @@ fn response_surface_covers_success_and_error_paths() {
.expect("serialize error response");
assert_eq!(error_envelope.error.as_deref(), Some("denied"));
- let custom_envelope = RadrootsNostrConnectResponse::Custom {
+ let custom_envelope = Response::Custom {
result: Some(json!({"ok": true})),
error: Some("warning".to_owned()),
}
@@ -829,116 +797,114 @@ fn response_surface_covers_success_and_error_paths() {
.expect("serialize custom response");
assert_eq!(custom_envelope.error.as_deref(), Some("warning"));
- let auth_envelope =
- RadrootsNostrConnectResponse::AuthUrl("https://auth.example.com/challenge".to_owned())
- .into_envelope("req-auth")
- .expect("serialize auth_url");
+ let auth_envelope = Response::AuthUrl("https://auth.example.com/challenge".to_owned())
+ .into_envelope("req-auth")
+ .expect("serialize auth_url");
assert_eq!(
- RadrootsNostrConnectResponse::from_envelope(&Method::SignEvent, auth_envelope,)
- .expect("parse auth_url"),
- RadrootsNostrConnectResponse::AuthUrl("https://auth.example.com/challenge".to_owned())
+ Response::from_envelope(&Method::SignEvent, auth_envelope,).expect("parse auth_url"),
+ Response::AuthUrl("https://auth.example.com/challenge".to_owned())
);
assert_eq!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::custom("publish_note").expect("valid custom NIP-46 method"),
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-custom".to_owned(),
result: Some(json!("ok")),
error: None,
},
)
.expect("parse custom response without error"),
- RadrootsNostrConnectResponse::Custom {
+ Response::Custom {
result: Some(json!("ok")),
error: None,
}
);
assert_eq!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::custom("publish_note").expect("valid custom NIP-46 method"),
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-custom".to_owned(),
result: Some(json!({"ok": true})),
error: Some("warning".to_owned()),
},
)
.expect("parse custom response"),
- RadrootsNostrConnectResponse::Custom {
+ Response::Custom {
result: Some(json!({"ok": true})),
error: Some("warning".to_owned()),
}
);
assert_eq!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::GetPublicKey,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-pending".to_owned(),
result: None,
- error: Some(RADROOTS_NOSTR_CONNECT_PENDING_CONNECTION_ERROR.to_owned()),
+ error: Some(PENDING_CONNECTION_ERROR.to_owned()),
},
)
.expect("parse typed pending response"),
- RadrootsNostrConnectResponse::PendingConnection
+ Response::PendingConnection
);
assert_eq!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::GetSessionCapability,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-pending-capability".to_owned(),
result: None,
- error: Some(RADROOTS_NOSTR_CONNECT_PENDING_CONNECTION_ERROR.to_owned()),
+ error: Some(PENDING_CONNECTION_ERROR.to_owned()),
},
)
.expect("parse typed pending capability response"),
- RadrootsNostrConnectResponse::PendingConnection
+ Response::PendingConnection
);
assert_eq!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::GetPublicKey,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-nonpending-public-key".to_owned(),
result: None,
error: Some("denied".to_owned()),
},
)
.expect("parse non-pending public key error"),
- RadrootsNostrConnectResponse::Error {
+ Response::Error {
result: None,
error: "denied".to_owned(),
}
);
assert_eq!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::GetSessionCapability,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-capability-error-with-result".to_owned(),
result: Some(json!({"code": "retry"})),
error: Some("denied".to_owned()),
},
)
.expect("parse capability error with result"),
- RadrootsNostrConnectResponse::Error {
+ Response::Error {
result: Some(json!({"code": "retry"})),
error: "denied".to_owned(),
}
);
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::GetSessionCapability,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-capability-invalid-result".to_owned(),
result: Some(json!({"permissions": "ping"})),
error: None,
},
),
- Err(RadrootsNostrConnectError::InvalidResponsePayload { method, .. })
+ Err(Error::InvalidResponsePayload { method, .. })
if method == "get_session_capability"
));
assert_eq!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::GetSessionCapability,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-capability-string-result".to_owned(),
result: Some(json!(
serde_json::to_string(&remote_session_capability)
@@ -948,350 +914,346 @@ fn response_surface_covers_success_and_error_paths() {
},
)
.expect("parse stringified capability result"),
- RadrootsNostrConnectResponse::RemoteSessionCapability(remote_session_capability.clone(),)
+ Response::RemoteSessionCapability(remote_session_capability.clone(),)
);
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::GetSessionCapability,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-capability-invalid-string".to_owned(),
result: Some(json!("{")),
error: None,
},
),
- Err(RadrootsNostrConnectError::InvalidResponsePayload { method, .. })
+ Err(Error::InvalidResponsePayload { method, .. })
if method == "get_session_capability"
));
assert_eq!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::Ping,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-error".to_owned(),
result: Some(json!("partial")),
error: Some("denied".to_owned()),
},
)
.expect("parse error response"),
- RadrootsNostrConnectResponse::Error {
+ Response::Error {
result: Some(json!("partial")),
error: "denied".to_owned(),
}
);
assert_eq!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::SignEvent,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-event".to_owned(),
result: Some(serde_json::to_value(&event).expect("event value")),
error: None,
},
)
.expect("parse object event"),
- RadrootsNostrConnectResponse::SignedEvent(
+ Response::SignedEvent(
ConnectSignedEvent::from_json(&event.as_json()).expect("signed event payload")
)
);
assert_eq!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::SwitchRelays,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-switch".to_owned(),
result: Some(json!("null")),
error: None,
},
)
.expect("parse string null"),
- RadrootsNostrConnectResponse::RelayListUnchanged
+ Response::RelayListUnchanged
);
assert_eq!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::SwitchRelays,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-switch".to_owned(),
result: Some(json!(format!("[\"{RELAY_SECONDARY_WSS}\"]"))),
error: None,
},
)
.expect("parse stringified relay list"),
- RadrootsNostrConnectResponse::RelayList(vec![relay(RELAY_SECONDARY_WSS)])
+ Response::RelayList(vec![relay(RELAY_SECONDARY_WSS)])
);
assert!(matches!(
- RadrootsNostrConnectResponse::AuthUrl("not-a-url".to_owned()).into_envelope("req"),
- Err(RadrootsNostrConnectError::InvalidUrl { value, .. }) if value == "[redacted auth URL]"
+ Response::AuthUrl("not-a-url".to_owned()).into_envelope("req"),
+ Err(Error::InvalidUrl { value, .. }) if value == "[redacted auth URL]"
));
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::SignEvent,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-auth".to_owned(),
result: Some(json!("auth_url")),
error: Some("not-a-url".to_owned()),
},
),
- Err(RadrootsNostrConnectError::InvalidUrl { value, .. }) if value == "[redacted auth URL]"
+ Err(Error::InvalidUrl { value, .. }) if value == "[redacted auth URL]"
));
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::GetPublicKey,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-key".to_owned(),
result: Some(json!("bad-key")),
error: None,
},
),
- Err(RadrootsNostrConnectError::InvalidPublicKey { .. })
+ Err(Error::InvalidPublicKey { .. })
));
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::Connect,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-connect".to_owned(),
result: None,
error: None,
},
),
- Err(RadrootsNostrConnectError::MissingResult)
+ Err(Error::MissingResult)
));
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::GetPublicKey,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-key".to_owned(),
result: None,
error: None,
},
),
- Err(RadrootsNostrConnectError::MissingResult)
+ Err(Error::MissingResult)
));
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::Ping,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-ping".to_owned(),
result: Some(json!("nope")),
error: None,
},
),
- Err(RadrootsNostrConnectError::InvalidResponsePayload { .. })
+ Err(Error::InvalidResponsePayload { .. })
));
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::Ping,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-ping".to_owned(),
result: None,
error: None,
},
),
- Err(RadrootsNostrConnectError::MissingResult)
+ Err(Error::MissingResult)
));
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::Nip04Encrypt,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-nip04".to_owned(),
result: Some(json!(5)),
error: None,
},
),
- Err(RadrootsNostrConnectError::InvalidResponsePayload { .. })
+ Err(Error::InvalidResponsePayload { .. })
));
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::Nip04Encrypt,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-nip04".to_owned(),
result: None,
error: None,
},
),
- Err(RadrootsNostrConnectError::MissingResult)
+ Err(Error::MissingResult)
));
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::SignEvent,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-event".to_owned(),
result: Some(json!("not-json")),
error: None,
},
),
- Err(RadrootsNostrConnectError::InvalidResponsePayload { .. })
+ Err(Error::InvalidResponsePayload { .. })
));
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::SignEvent,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-event".to_owned(),
result: Some(json!(5)),
error: None,
},
),
- Err(RadrootsNostrConnectError::InvalidResponsePayload { .. })
+ Err(Error::InvalidResponsePayload { .. })
));
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::SignEvent,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-event".to_owned(),
result: None,
error: None,
},
),
- Err(RadrootsNostrConnectError::MissingResult)
+ Err(Error::MissingResult)
));
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::Nip04Decrypt,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-nip04d".to_owned(),
result: None,
error: None,
},
),
- Err(RadrootsNostrConnectError::MissingResult)
+ Err(Error::MissingResult)
));
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::Nip44Encrypt,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-nip44e".to_owned(),
result: None,
error: None,
},
),
- Err(RadrootsNostrConnectError::MissingResult)
+ Err(Error::MissingResult)
));
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::Nip44Decrypt,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-nip44d".to_owned(),
result: None,
error: None,
},
),
- Err(RadrootsNostrConnectError::MissingResult)
+ Err(Error::MissingResult)
));
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::SwitchRelays,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-switch".to_owned(),
result: Some(json!("[invalid")),
error: None,
},
),
- Err(RadrootsNostrConnectError::InvalidResponsePayload { .. })
+ Err(Error::InvalidResponsePayload { .. })
));
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::SwitchRelays,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-switch".to_owned(),
result: Some(json!([1])),
error: None,
},
),
- Err(RadrootsNostrConnectError::InvalidResponsePayload { .. })
+ Err(Error::InvalidResponsePayload { .. })
));
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::SwitchRelays,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-switch".to_owned(),
result: Some(json!(["http://relay.example.com"])),
error: None,
},
),
- Err(RadrootsNostrConnectError::InvalidRelayUrl { .. })
+ Err(Error::InvalidRelayUrl { .. })
));
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::SwitchRelays,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-switch".to_owned(),
result: Some(json!(5)),
error: None,
},
),
- Err(RadrootsNostrConnectError::InvalidResponsePayload { .. })
+ Err(Error::InvalidResponsePayload { .. })
));
assert!(matches!(
- RadrootsNostrConnectResponse::from_envelope(
+ Response::from_envelope(
&Method::Logout,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-logout".to_owned(),
result: Some(json!("not-ack")),
error: None,
},
),
- Err(RadrootsNostrConnectError::InvalidResponsePayload { method, .. })
+ Err(Error::InvalidResponsePayload { method, .. })
if method == "logout"
));
}
#[test]
fn pending_connection_poll_outcome_uses_typed_variants() {
- let remote_session_capability =
- radroots_nostr_connect::prelude::RadrootsNostrConnectRemoteSessionCapability {
- user_public_key: test_public_key(),
- relays: vec![relay(RELAY_PRIMARY_WSS), relay(RELAY_SECONDARY_WSS)],
- permissions: Permissions::from(vec![
- Permission::new(Method::Ping),
- Permission::with_parameter(Method::SignEvent, "kind:1"),
- ]),
- };
+ let remote_session_capability = RemoteSessionCapability {
+ user_public_key: test_public_key(),
+ relays: vec![relay(RELAY_PRIMARY_WSS), relay(RELAY_SECONDARY_WSS)],
+ permissions: Permissions::from(vec![
+ Permission::new(Method::Ping),
+ Permission::with_parameter(Method::SignEvent, "kind:1"),
+ ]),
+ };
assert_eq!(
- RadrootsNostrConnectResponse::PendingConnection.into_pending_connection_poll_outcome(),
- RadrootsNostrConnectPendingConnectionPollOutcome::PendingApproval
+ Response::PendingConnection.into_pending_connection_poll_outcome(),
+ PendingConnectionOutcome::PendingApproval
);
assert_eq!(
- RadrootsNostrConnectResponse::UserPublicKey(test_public_key())
- .into_pending_connection_poll_outcome(),
- RadrootsNostrConnectPendingConnectionPollOutcome::Approved(test_public_key())
+ Response::UserPublicKey(test_public_key()).into_pending_connection_poll_outcome(),
+ PendingConnectionOutcome::Approved(test_public_key())
);
assert_eq!(
- RadrootsNostrConnectResponse::RemoteSessionCapability(remote_session_capability.clone())
+ Response::RemoteSessionCapability(remote_session_capability.clone())
.into_pending_connection_poll_outcome(),
- RadrootsNostrConnectPendingConnectionPollOutcome::ApprovedCapability(
- remote_session_capability
- )
+ PendingConnectionOutcome::ApprovedCapability(remote_session_capability)
);
assert_eq!(
- RadrootsNostrConnectResponse::Error {
+ Response::Error {
result: Some(json!("partial")),
error: "rejected".to_owned(),
}
.into_pending_connection_poll_outcome(),
- RadrootsNostrConnectPendingConnectionPollOutcome::Rejected {
+ PendingConnectionOutcome::Rejected {
message: "rejected".to_owned(),
}
);
assert_eq!(
- RadrootsNostrConnectResponse::Error {
+ Response::Error {
result: None,
- error: RADROOTS_NOSTR_CONNECT_PENDING_CONNECTION_ERROR.to_owned(),
+ error: PENDING_CONNECTION_ERROR.to_owned(),
}
.into_pending_connection_poll_outcome(),
- RadrootsNostrConnectPendingConnectionPollOutcome::PendingApproval
+ PendingConnectionOutcome::PendingApproval
);
assert_eq!(
- RadrootsNostrConnectResponse::AuthUrl("https://auth.example.com/challenge".to_owned())
+ Response::AuthUrl("https://auth.example.com/challenge".to_owned())
.into_pending_connection_poll_outcome(),
- RadrootsNostrConnectPendingConnectionPollOutcome::AuthChallenge {
+ PendingConnectionOutcome::AuthChallenge {
url: "https://auth.example.com/challenge".to_owned(),
}
);
assert!(matches!(
- RadrootsNostrConnectResponse::Pong.into_pending_connection_poll_outcome(),
- RadrootsNostrConnectPendingConnectionPollOutcome::UnexpectedResponse { response }
+ Response::Pong.into_pending_connection_poll_outcome(),
+ PendingConnectionOutcome::UnexpectedResponse { response }
if response == "pong"
));
}
diff --git a/crates/nostr_connect/tests/package_boundary.rs b/crates/nostr_connect/tests/package_boundary.rs
@@ -98,7 +98,7 @@ fn manifest_has_final_identity_feature_vocabulary_and_radroots_dependencies() {
#[test]
fn crate_root_contains_the_approved_module_skeleton() {
let final_root = ROOT
- .split("// Transitional compatibility surface")
+ .split("/// Private migration surface")
.next()
.expect("final root declarations");
assert_eq!(
@@ -133,10 +133,8 @@ fn crate_root_contains_the_approved_module_skeleton() {
assert!(SERVER.starts_with("//! Relay- and persistence-independent NIP-46 server state."));
assert!(ROOT.contains("pub use server::Server;"));
assert!(ROOT.contains("#[doc(hidden)]\npub mod prelude"));
- assert!(
- ROOT.contains("Step 143 removes this module"),
- "the temporary prelude must carry an exact removal checkpoint"
- );
+ assert!(ROOT.contains("Steps 271, 288, and 293"));
+ assert!(ROOT.contains("Step 313 removes the shim"));
}
#[test]
@@ -167,7 +165,7 @@ fn approved_root_exports_and_transport_trait_compile() {
"pub trait RadrootsNostrConnectClientTransport {",
"pub trait Transport: Send {",
]),
- "only the final host transport SPI and Step 143 compatibility trait may remain"
+ "only the final host transport SPI and private migration shim may remain"
);
for forbidden in [
"Relay", "Runtime", "Session", "Storage", "Secret", "Approval",
@@ -235,6 +233,39 @@ fn client_root_and_transport_use_package_owned_state_machine_types() {
}
#[test]
+fn separate_repository_compatibility_is_hidden_unpublished_and_scheduled() {
+ assert!(MANIFEST.contains("publish = false"));
+ for item in [
+ "pub type RadrootsNostrConnectClientTransportFuture",
+ "pub struct RadrootsNostrConnectClientTarget",
+ "pub struct RadrootsNostrConnectClientRequest",
+ "pub enum RadrootsNostrConnectClientProgress",
+ "pub enum RadrootsNostrConnectClientEventOutcome",
+ "pub trait RadrootsNostrConnectClientTransport",
+ "pub fn build_request_event",
+ "pub fn parse_response_event",
+ "pub async fn execute_request_with_transport",
+ ] {
+ let position = CLIENT
+ .find(item)
+ .unwrap_or_else(|| panic!("missing `{item}`"));
+ assert!(
+ CLIENT[position.saturating_sub(100)..position].contains("#[doc(hidden)]"),
+ "compatibility item `{item}` must remain hidden"
+ );
+ }
+ for legacy in [
+ "RadrootsNostrConnectClient",
+ "radroots_nostr_connect::prelude",
+ ] {
+ assert!(
+ !PUBLIC_API.contains(legacy),
+ "compatibility identity `{legacy}` leaked into the public API baseline"
+ );
+ }
+}
+
+#[test]
fn protocol_transport_boundary_has_no_relay_pool_or_runtime_owner() {
for forbidden in [
"nostr-sdk",
diff --git a/crates/nostr_connect/tests/protocol.rs b/crates/nostr_connect/tests/protocol.rs
@@ -2,14 +2,16 @@
mod test_fixtures;
use nostr::{EventBuilder, JsonUtil, Keys, PublicKey, SecretKey, Timestamp, UnsignedEvent};
-use radroots_nostr_connect::prelude::{
- CLIENT_METADATA_JSON_MAX_BYTES, CLIENT_NAME_MAX_BYTES, ClientMetadata, Method, Permission,
- Permissions, RADROOTS_NOSTR_CONNECT_PENDING_CONNECTION_ERROR, RadrootsNostrConnectError,
- RadrootsNostrConnectRequest, RadrootsNostrConnectRequestMessage, RadrootsNostrConnectResponse,
- RadrootsNostrConnectResponseEnvelope, SignedEvent as ConnectSignedEvent,
- UnsignedEvent as ConnectUnsignedEvent, Uri,
+use radroots_nostr_connect::message::{
+ PENDING_CONNECTION_ERROR, RemoteSessionCapability, RequestMessage, ResponseEnvelope,
+ SignedEvent as ConnectSignedEvent, UnsignedEvent as ConnectUnsignedEvent,
};
-use radroots_nostr_connect::uri::RelayUrl as ConnectRelayUrl;
+use radroots_nostr_connect::permission::Permissions;
+use radroots_nostr_connect::uri::{
+ CLIENT_METADATA_JSON_MAX_BYTES, CLIENT_NAME_MAX_BYTES, ClientMetadata,
+ RelayUrl as ConnectRelayUrl, Uri,
+};
+use radroots_nostr_connect::{Error, Method, Permission, Request, Response};
use serde_json::{Value, json};
use test_fixtures::{
APP_PRIMARY_HTTPS, CDN_PRIMARY_HTTPS, FIXTURE_ALICE, RELAY_PRIMARY_WSS, RELAY_SECONDARY_WSS,
@@ -38,9 +40,8 @@ fn logo_url() -> String {
format!("{CDN_PRIMARY_HTTPS}/logo.png")
}
-fn remote_session_capability()
--> radroots_nostr_connect::prelude::RadrootsNostrConnectRemoteSessionCapability {
- radroots_nostr_connect::prelude::RadrootsNostrConnectRemoteSessionCapability {
+fn remote_session_capability() -> RemoteSessionCapability {
+ RemoteSessionCapability {
user_public_key: test_identity_public_key(),
relays: vec![
ConnectRelayUrl::parse(RELAY_PRIMARY_WSS).expect("relay 1"),
@@ -129,7 +130,7 @@ fn requested_permissions_roundtrip_as_csv() {
#[test]
fn connect_request_roundtrips_requested_permissions() {
- let request = RadrootsNostrConnectRequest::Connect {
+ let request = Request::Connect {
remote_signer_public_key: test_identity_public_key(),
secret: Some("abcd".to_owned()),
requested_permissions: Permissions::from(vec![
@@ -138,7 +139,7 @@ fn connect_request_roundtrips_requested_permissions() {
]),
client_metadata: None,
};
- let message = RadrootsNostrConnectRequestMessage::new("req-1", request);
+ let message = RequestMessage::new("req-1", request);
let encoded = serde_json::to_value(&message).expect("serialize request");
assert_eq!(
encoded,
@@ -153,14 +154,13 @@ fn connect_request_roundtrips_requested_permissions() {
})
);
- let decoded: RadrootsNostrConnectRequestMessage =
- serde_json::from_value(encoded).expect("deserialize request");
+ let decoded: RequestMessage = serde_json::from_value(encoded).expect("deserialize request");
assert_eq!(decoded, message);
}
#[test]
fn connect_request_roundtrips_client_metadata_in_fourth_parameter() {
- let request = RadrootsNostrConnectRequest::Connect {
+ let request = Request::Connect {
remote_signer_public_key: test_identity_public_key(),
secret: None,
requested_permissions: Permissions::default(),
@@ -171,7 +171,7 @@ fn connect_request_roundtrips_client_metadata_in_fourth_parameter() {
image: Some(logo_url()),
}),
};
- let message = RadrootsNostrConnectRequestMessage::new("req-metadata", request);
+ let message = RequestMessage::new("req-metadata", request);
let encoded = serde_json::to_value(&message).expect("serialize metadata request");
assert_eq!(encoded["params"][1], "");
assert_eq!(encoded["params"][2], "");
@@ -190,10 +190,10 @@ fn connect_request_roundtrips_client_metadata_in_fourth_parameter() {
})
);
- let decoded: RadrootsNostrConnectRequestMessage =
+ let decoded: RequestMessage =
serde_json::from_value(encoded.clone()).expect("deserialize metadata request");
match &decoded.request {
- RadrootsNostrConnectRequest::Connect {
+ Request::Connect {
client_metadata: Some(metadata),
..
} => {
@@ -210,23 +210,22 @@ fn connect_request_roundtrips_client_metadata_in_fourth_parameter() {
#[test]
fn logout_request_and_acknowledgement_roundtrip() {
- let message =
- RadrootsNostrConnectRequestMessage::new("req-logout", RadrootsNostrConnectRequest::Logout);
+ let message = RequestMessage::new("req-logout", Request::Logout);
assert_eq!(
serde_json::to_value(&message).expect("serialize logout"),
json!({"id": "req-logout", "method": "logout", "params": []})
);
- let response = RadrootsNostrConnectResponse::from_envelope(
+ let response = Response::from_envelope(
&Method::Logout,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-logout".to_owned(),
result: Some(Value::String("ack".to_owned())),
error: None,
},
)
.expect("parse logout acknowledgement");
- assert_eq!(response, RadrootsNostrConnectResponse::LogoutAcknowledged);
+ assert_eq!(response, Response::LogoutAcknowledged);
assert_eq!(
response
.into_envelope("req-logout")
@@ -248,7 +247,7 @@ fn rejects_invalid_client_metadata() {
serde_json::to_string(&json!({"name": "line\nbreak"})).expect("metadata")
]
});
- assert!(serde_json::from_value::<RadrootsNostrConnectRequestMessage>(invalid_name).is_err());
+ assert!(serde_json::from_value::<RequestMessage>(invalid_name).is_err());
let invalid_scheme = format!(
"nostrconnect://{}?relay={}&secret=secret&url={}",
@@ -266,12 +265,12 @@ fn rejects_invalid_client_metadata() {
};
assert!(matches!(
oversized_name.to_connect_param(),
- Err(RadrootsNostrConnectError::InvalidClientMetadata { field: "name", .. })
+ Err(Error::InvalidClientMetadata { field: "name", .. })
));
let oversized_payload = "x".repeat(CLIENT_METADATA_JSON_MAX_BYTES + 1);
assert!(matches!(
- RadrootsNostrConnectRequest::from_parts(
+ Request::from_parts(
Method::Connect,
vec![
test_public_key().to_hex(),
@@ -280,7 +279,7 @@ fn rejects_invalid_client_metadata() {
oversized_payload,
],
),
- Err(RadrootsNostrConnectError::ClientMetadataTooLarge { .. })
+ Err(Error::ClientMetadataTooLarge { .. })
));
}
@@ -295,9 +294,9 @@ fn sign_event_request_roundtrips_unsigned_event_payload() {
}))
.expect("unsigned event");
- let message = RadrootsNostrConnectRequestMessage::new(
+ let message = RequestMessage::new(
"req-sign",
- RadrootsNostrConnectRequest::SignEvent(
+ Request::SignEvent(
ConnectUnsignedEvent::from_json(&unsigned_event.as_json())
.expect("unsigned event payload"),
),
@@ -305,12 +304,12 @@ fn sign_event_request_roundtrips_unsigned_event_payload() {
let encoded = serde_json::to_value(&message).expect("serialize sign request");
assert_eq!(encoded["method"], "sign_event");
- let decoded: RadrootsNostrConnectRequestMessage =
+ let decoded: RequestMessage =
serde_json::from_value(encoded).expect("deserialize sign request");
assert_eq!(decoded, message);
assert_eq!(
decoded.request,
- RadrootsNostrConnectRequest::SignEvent(
+ Request::SignEvent(
ConnectUnsignedEvent::from_json(&unsigned_event.as_json())
.expect("unsigned event payload"),
)
@@ -319,66 +318,59 @@ fn sign_event_request_roundtrips_unsigned_event_payload() {
#[test]
fn switch_relays_response_accepts_array_or_null() {
- let relays_response = RadrootsNostrConnectResponseEnvelope {
+ let relays_response = ResponseEnvelope {
id: "req-switch".to_owned(),
result: Some(json!([RELAY_SECONDARY_WSS, RELAY_TERTIARY_WSS])),
error: None,
};
let parsed =
- RadrootsNostrConnectResponse::from_envelope(&Method::SwitchRelays, relays_response)
- .expect("parse relay list");
+ Response::from_envelope(&Method::SwitchRelays, relays_response).expect("parse relay list");
assert_eq!(
parsed,
- RadrootsNostrConnectResponse::RelayList(vec![
+ Response::RelayList(vec![
ConnectRelayUrl::parse(RELAY_SECONDARY_WSS).expect("relay 1"),
ConnectRelayUrl::parse(RELAY_TERTIARY_WSS).expect("relay 2"),
])
);
- let unchanged = RadrootsNostrConnectResponse::from_envelope(
+ let unchanged = Response::from_envelope(
&Method::SwitchRelays,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-switch".to_owned(),
result: Some(Value::Null),
error: None,
},
)
.expect("parse null relay result");
- assert_eq!(unchanged, RadrootsNostrConnectResponse::RelayListUnchanged);
+ assert_eq!(unchanged, Response::RelayListUnchanged);
}
#[test]
fn get_session_capability_request_and_response_roundtrip() {
- let request_message = RadrootsNostrConnectRequestMessage::new(
- "req-cap",
- RadrootsNostrConnectRequest::GetSessionCapability,
- );
+ let request_message = RequestMessage::new("req-cap", Request::GetSessionCapability);
let encoded_request = serde_json::to_value(&request_message).expect("serialize request");
- let decoded_request: RadrootsNostrConnectRequestMessage =
+ let decoded_request: RequestMessage =
serde_json::from_value(encoded_request).expect("deserialize request");
assert_eq!(decoded_request, request_message);
let capability = remote_session_capability();
- let response_envelope =
- RadrootsNostrConnectResponse::RemoteSessionCapability(capability.clone())
- .into_envelope("resp-cap")
- .expect("serialize response");
- let decoded_response = RadrootsNostrConnectResponse::from_envelope(
- &Method::GetSessionCapability,
- response_envelope,
- )
- .expect("deserialize response");
+ let response_envelope = Response::RemoteSessionCapability(capability.clone())
+ .into_envelope("resp-cap")
+ .expect("serialize response");
+ let decoded_response =
+ Response::from_envelope(&Method::GetSessionCapability, response_envelope)
+ .expect("deserialize response");
assert_eq!(
decoded_response,
- RadrootsNostrConnectResponse::RemoteSessionCapability(capability)
+ Response::RemoteSessionCapability(capability)
);
}
#[test]
fn auth_url_response_parses_from_result_and_error_fields() {
- let response = RadrootsNostrConnectResponse::from_envelope(
+ let response = Response::from_envelope(
&Method::SignEvent,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-auth".to_owned(),
result: Some(json!("auth_url")),
error: Some("https://auth.example.com/challenge".to_owned()),
@@ -388,23 +380,23 @@ fn auth_url_response_parses_from_result_and_error_fields() {
assert_eq!(
response,
- RadrootsNostrConnectResponse::AuthUrl("https://auth.example.com/challenge".to_owned())
+ Response::AuthUrl("https://auth.example.com/challenge".to_owned())
);
}
#[test]
fn get_public_key_pending_response_parses_as_typed_pending_connection() {
- let response = RadrootsNostrConnectResponse::from_envelope(
+ let response = Response::from_envelope(
&Method::GetPublicKey,
- RadrootsNostrConnectResponseEnvelope {
+ ResponseEnvelope {
id: "req-pending".to_owned(),
result: None,
- error: Some(RADROOTS_NOSTR_CONNECT_PENDING_CONNECTION_ERROR.to_owned()),
+ error: Some(PENDING_CONNECTION_ERROR.to_owned()),
},
)
.expect("parse pending get_public_key response");
- assert_eq!(response, RadrootsNostrConnectResponse::PendingConnection);
+ assert_eq!(response, Response::PendingConnection);
}
#[test]
@@ -415,17 +407,17 @@ fn sign_event_response_roundtrips_signed_event_json_string() {
.sign_with_keys(&keys)
.expect("sign event");
- let envelope = RadrootsNostrConnectResponse::SignedEvent(
+ let envelope = Response::SignedEvent(
ConnectSignedEvent::from_json(&event.as_json()).expect("signed event payload"),
)
.into_envelope("req-sign")
.expect("serialize response");
- let parsed = RadrootsNostrConnectResponse::from_envelope(&Method::SignEvent, envelope)
- .expect("parse signed event response");
+ let parsed =
+ Response::from_envelope(&Method::SignEvent, envelope).expect("parse signed event response");
assert_eq!(
parsed,
- RadrootsNostrConnectResponse::SignedEvent(
+ Response::SignedEvent(
ConnectSignedEvent::from_json(&event.as_json()).expect("signed event payload")
)
);
@@ -448,18 +440,15 @@ fn checked_in_current_session_vectors_match_protocol_behavior() {
match kind {
"nip46.request.valid" => {
- let message: RadrootsNostrConnectRequestMessage =
- serde_json::from_value(input["message"].clone())
- .unwrap_or_else(|error| panic!("{id}: parse request: {error}"));
+ let message: RequestMessage = serde_json::from_value(input["message"].clone())
+ .unwrap_or_else(|error| panic!("{id}: parse request: {error}"));
let normalized = serde_json::to_value(message)
.unwrap_or_else(|error| panic!("{id}: serialize request: {error}"));
assert_eq!(normalized, expected["normalized_message"], "{id}");
}
"nip46.request.invalid" => {
- let error = serde_json::from_value::<RadrootsNostrConnectRequestMessage>(
- input["message"].clone(),
- )
- .expect_err("invalid request vector");
+ let error = serde_json::from_value::<RequestMessage>(input["message"].clone())
+ .expect_err("invalid request vector");
assert_vector_error(id, expected, error);
}
"nip46.metadata.invalid" => {
@@ -489,11 +478,10 @@ fn checked_in_current_session_vectors_match_protocol_behavior() {
.expect("response method")
.parse::<Method>()
.expect("typed response method");
- let envelope: RadrootsNostrConnectResponseEnvelope =
- serde_json::from_value(input["envelope"].clone())
- .unwrap_or_else(|error| panic!("{id}: parse envelope: {error}"));
+ let envelope: ResponseEnvelope = serde_json::from_value(input["envelope"].clone())
+ .unwrap_or_else(|error| panic!("{id}: parse envelope: {error}"));
let request_id = envelope.id.clone();
- let response = RadrootsNostrConnectResponse::from_envelope(&method, envelope)
+ let response = Response::from_envelope(&method, envelope)
.unwrap_or_else(|error| panic!("{id}: parse response: {error}"));
let normalized = response
.into_envelope(request_id)
@@ -508,10 +496,9 @@ fn checked_in_current_session_vectors_match_protocol_behavior() {
.expect("response method")
.parse::<Method>()
.expect("typed response method");
- let envelope: RadrootsNostrConnectResponseEnvelope =
- serde_json::from_value(input["envelope"].clone())
- .unwrap_or_else(|error| panic!("{id}: parse envelope: {error}"));
- let error = RadrootsNostrConnectResponse::from_envelope(&method, envelope)
+ let envelope: ResponseEnvelope = serde_json::from_value(input["envelope"].clone())
+ .unwrap_or_else(|error| panic!("{id}: parse envelope: {error}"));
+ let error = Response::from_envelope(&method, envelope)
.expect_err("invalid response vector");
assert_vector_error(id, expected, error);
}
diff --git a/docs/api/radroots_nostr_connect.txt b/docs/api/radroots_nostr_connect.txt
@@ -17,13 +17,6 @@ pub radroots_nostr_connect::client::Progress::AuthChallenge
pub radroots_nostr_connect::client::Progress::AuthChallenge::url: alloc::string::String
impl core::fmt::Debug for radroots_nostr_connect::client::Progress
pub fn radroots_nostr_connect::client::Progress::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-pub enum radroots_nostr_connect::client::RadrootsNostrConnectClientEventOutcome
-pub radroots_nostr_connect::client::RadrootsNostrConnectClientEventOutcome::Ignore
-pub radroots_nostr_connect::client::RadrootsNostrConnectClientEventOutcome::Progress(radroots_nostr_connect::client::RadrootsNostrConnectClientProgress)
-pub radroots_nostr_connect::client::RadrootsNostrConnectClientEventOutcome::Response(radroots_nostr_connect::message::Response)
-pub enum radroots_nostr_connect::client::RadrootsNostrConnectClientProgress
-pub radroots_nostr_connect::client::RadrootsNostrConnectClientProgress::AuthChallenge
-pub radroots_nostr_connect::client::RadrootsNostrConnectClientProgress::AuthChallenge::url: alloc::string::String
pub enum radroots_nostr_connect::client::Receive
pub radroots_nostr_connect::client::Receive::Cancelled
pub radroots_nostr_connect::client::Receive::Event(alloc::boxed::Box<radroots_nostr_connect::client::ClientEvent>)
@@ -59,34 +52,15 @@ pub fn radroots_nostr_connect::client::Operation<'_>::publication(&self) -> core
pub fn radroots_nostr_connect::client::Operation<'_>::select(&mut self, &radroots_nostr_connect::client::ClientEvent) -> core::result::Result<radroots_nostr_connect::client::EventOutcome, radroots_nostr_connect::error::RadrootsNostrConnectError>
impl core::fmt::Debug for radroots_nostr_connect::client::Operation<'_>
pub fn radroots_nostr_connect::client::Operation<'_>::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-pub struct radroots_nostr_connect::client::RadrootsNostrConnectClientRequest
-pub radroots_nostr_connect::client::RadrootsNostrConnectClientRequest::request: radroots_nostr_connect::message::Request
-pub radroots_nostr_connect::client::RadrootsNostrConnectClientRequest::request_id: alloc::string::String
-impl radroots_nostr_connect::client::RadrootsNostrConnectClientRequest
-pub fn radroots_nostr_connect::client::RadrootsNostrConnectClientRequest::into_message(self) -> radroots_nostr_connect::message::RequestMessage
-pub fn radroots_nostr_connect::client::RadrootsNostrConnectClientRequest::method(&self) -> radroots_nostr_connect::method::Method
-pub fn radroots_nostr_connect::client::RadrootsNostrConnectClientRequest::new(impl core::convert::Into<alloc::string::String>, radroots_nostr_connect::message::Request) -> Self
-pub struct radroots_nostr_connect::client::RadrootsNostrConnectClientTarget
-pub radroots_nostr_connect::client::RadrootsNostrConnectClientTarget::relays: alloc::vec::Vec<nostr::types::url::RelayUrl>
-pub radroots_nostr_connect::client::RadrootsNostrConnectClientTarget::remote_signer_public_key: nostr::key::public_key::PublicKey
-impl radroots_nostr_connect::client::RadrootsNostrConnectClientTarget
-pub fn radroots_nostr_connect::client::RadrootsNostrConnectClientTarget::new(nostr::key::public_key::PublicKey, alloc::vec::Vec<nostr::types::url::RelayUrl>) -> Self
pub struct radroots_nostr_connect::client::Target
impl radroots_nostr_connect::client::Target
pub fn radroots_nostr_connect::client::Target::relays(&self) -> &[radroots_nostr_connect::uri::RelayUrl]
pub const fn radroots_nostr_connect::client::Target::remote_signer_public_key(&self) -> radroots_identity::key::PublicKey
pub fn radroots_nostr_connect::client::Target::try_new(radroots_identity::key::PublicKey, alloc::vec::Vec<radroots_nostr_connect::uri::RelayUrl>) -> core::result::Result<Self, radroots_nostr_connect::error::RadrootsNostrConnectError>
pub const radroots_nostr_connect::client::CLIENT_EVENT_MAX_BYTES: usize
-pub trait radroots_nostr_connect::client::RadrootsNostrConnectClientTransport
-pub fn radroots_nostr_connect::client::RadrootsNostrConnectClientTransport::next_response_event<'a>(&'a mut self) -> radroots_nostr_connect::client::RadrootsNostrConnectClientTransportFuture<'a, nostr::event::Event>
-pub fn radroots_nostr_connect::client::RadrootsNostrConnectClientTransport::publish_request_event<'a>(&'a mut self, nostr::event::Event) -> radroots_nostr_connect::client::RadrootsNostrConnectClientTransportFuture<'a, ()>
pub trait radroots_nostr_connect::client::Transport: core::marker::Send
pub fn radroots_nostr_connect::client::Transport::publish<'a>(&'a mut self, radroots_nostr_connect::client::ClientEvent) -> radroots_nostr_connect::client::TransportFuture<'a, ()>
pub fn radroots_nostr_connect::client::Transport::receive<'a>(&'a mut self, &'a radroots_nostr_connect::client::CancellationToken) -> radroots_nostr_connect::client::TransportFuture<'a, radroots_nostr_connect::client::Receive>
-pub fn radroots_nostr_connect::client::build_request_event(&nostr::key::Keys, &radroots_nostr_connect::client::RadrootsNostrConnectClientTarget, radroots_nostr_connect::message::RequestMessage) -> core::result::Result<nostr::event::Event, radroots_nostr_connect::error::RadrootsNostrConnectError>
-pub async fn radroots_nostr_connect::client::execute_request_with_transport<T, F>(&nostr::key::Keys, &radroots_nostr_connect::client::RadrootsNostrConnectClientTarget, radroots_nostr_connect::client::RadrootsNostrConnectClientRequest, &mut T, F) -> core::result::Result<radroots_nostr_connect::message::Response, radroots_nostr_connect::error::RadrootsNostrConnectError> where T: radroots_nostr_connect::client::RadrootsNostrConnectClientTransport, F: core::ops::function::FnMut(radroots_nostr_connect::client::RadrootsNostrConnectClientProgress) -> core::result::Result<(), radroots_nostr_connect::error::RadrootsNostrConnectError>
-pub fn radroots_nostr_connect::client::parse_response_event(&nostr::key::Keys, &radroots_nostr_connect::client::RadrootsNostrConnectClientTarget, &str, &radroots_nostr_connect::method::Method, &nostr::event::Event) -> core::result::Result<radroots_nostr_connect::client::RadrootsNostrConnectClientEventOutcome, radroots_nostr_connect::error::RadrootsNostrConnectError>
-pub type radroots_nostr_connect::client::RadrootsNostrConnectClientTransportFuture<'a, T> = core::pin::Pin<alloc::boxed::Box<(dyn core::future::future::Future<Output = core::result::Result<T, radroots_nostr_connect::error::RadrootsNostrConnectError>> + core::marker::Send + 'a)>>
pub type radroots_nostr_connect::client::TransportFuture<'a, T> = core::pin::Pin<alloc::boxed::Box<(dyn core::future::future::Future<Output = core::result::Result<T, radroots_nostr_connect::error::RadrootsNostrConnectError>> + core::marker::Send + 'a)>>
pub mod radroots_nostr_connect::error
pub enum radroots_nostr_connect::error::RadrootsNostrConnectError
diff --git a/docs/implementation/COMPATIBILITY_SHIMS.md b/docs/implementation/COMPATIBILITY_SHIMS.md
@@ -9,9 +9,11 @@ public crate identity or a second contract authority.
| --- | --- | --- | --- | --- |
| `radroots_authority` | `radroots_signing` | `oss/cli`, `oss/studio_app` | downstream Steps 269-293; matrix Step 294 | Step 313 |
| `radroots_nostr_signer` | `radroots_signing`, `radroots_nostr_connect`, Myc-private state | `radroots_net`, `radroots_nostr_accounts`, `oss/sdk`, `oss/myc`, `oss/cli` | crate Steps 109-143; SDK Step 248; downstream Steps 269-293; matrix Step 294 | Step 313 |
+| hidden `radroots_nostr_connect::prelude` and prefixed client bridge | final `radroots_nostr_connect` modules and client state machine | `oss/cli`, `oss/myc`, enterprise NIP-46 adapters, integration harnesses | CLI Step 271; Myc Step 288; residual consumers Step 293; matrix Step 294 | Step 313 |
-Both package manifests keep `publish = false`. Release policy classifies both
-as private and excludes both from the exact 19-package public inventory. The
+Both compatibility package manifests and `radroots_nostr_connect` keep
+`publish = false`. Release policy classifies the shims as private and excludes
+them from the exact 19-package public API inventory. The
`radroots_nostr_signer` manifest intentionally has no docs.rs URL. No new
consumer, feature, public contract, or behavior may be added before removal.