commit d19a688128087c9c62b767b9fdd9e571a3e9add9
parent 4f6a1033b2e7a79ebb136fb752f6a9eda0ff2605
Author: triesap <tyson@radroots.org>
Date: Fri, 31 Jul 2026 20:32:58 +0000
nostr-connect: migrate workspace consumers
- drive SDK remote signing through the final client state machine
- adapt host relay IO behind the canonical transport contract
- migrate examples, tests, and adapter exports to final protocol paths
- verify SDK tests, strict Clippy, and architecture policy
Diffstat:
5 files changed, 231 insertions(+), 155 deletions(-)
diff --git a/crates/sdk/examples/sdk_v1_myc_nip46_signer_setup.rs b/crates/sdk/examples/sdk_v1_myc_nip46_signer_setup.rs
@@ -1,8 +1,8 @@
use nostr::Keys as RadrootsNostrKeys;
use radroots_event::envelope::kind::KIND_TRADE_PROPOSAL;
use radroots_nostr::event::Event as RadrootsNostrEvent;
-use radroots_nostr_connect::prelude::{
- RadrootsNostrConnectClientTarget, RadrootsNostrConnectError,
+use radroots_nostr_connect::{
+ Error as NostrConnectError, client::Target, uri::RelayUrl as ConnectRelayUrl,
};
use radroots_sdk::{
RadrootsClient, RadrootsSdkMycNip46Signer, RadrootsSdkNip46ClientKey,
@@ -24,7 +24,7 @@ impl RadrootsSdkNip46Transport for ExampleNip46Transport {
fn next_response_event<'a>(
&'a self,
) -> RadrootsSdkNip46TransportFuture<'a, RadrootsNostrEvent> {
- Box::pin(async { Err(RadrootsNostrConnectError::RequestTimedOut) })
+ Box::pin(async { Err(NostrConnectError::RequestTimedOut) })
}
}
@@ -33,10 +33,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client_key = RadrootsSdkNip46ClientKey::generate();
let remote_signer_keys = RadrootsNostrKeys::generate();
let user_keys = RadrootsNostrKeys::generate();
- let target = RadrootsNostrConnectClientTarget::new(
- remote_signer_keys.public_key(),
- vec![nostr::RelayUrl::parse("wss://relay.example.com")?],
- );
+ let remote_signer_public_key =
+ radroots_nostr::key::public_key_from_nostr(remote_signer_keys.public_key())?;
+ let target = Target::try_new(
+ remote_signer_public_key,
+ vec![ConnectRelayUrl::parse("wss://relay.example.com")?],
+ )?;
let signer = RadrootsSdkMycNip46Signer::new(
client_key,
target,
diff --git a/crates/sdk/src/adapters/signer.rs b/crates/sdk/src/adapters/signer.rs
@@ -1,11 +1,11 @@
-pub use radroots_nostr_connect::prelude::{
- RADROOTS_NOSTR_CONNECT_PENDING_CONNECTION_ERROR, RADROOTS_NOSTR_CONNECT_RPC_KIND,
- RadrootsNostrConnectBunkerUri, RadrootsNostrConnectClientMetadata,
- RadrootsNostrConnectClientUri, RadrootsNostrConnectError, RadrootsNostrConnectMethod,
- RadrootsNostrConnectPendingConnectionPollOutcome, RadrootsNostrConnectPermission,
- RadrootsNostrConnectPermissions, RadrootsNostrConnectRemoteSessionCapability,
- RadrootsNostrConnectRequest, RadrootsNostrConnectRequestMessage, RadrootsNostrConnectResponse,
- RadrootsNostrConnectResponseEnvelope, RadrootsNostrConnectUri,
+pub use radroots_nostr_connect::{
+ BunkerUri, ClientUri, Error, Method, Permission, Request, Response,
+ message::{
+ PENDING_CONNECTION_ERROR, PendingConnectionOutcome, RPC_KIND, RemoteSessionCapability,
+ RequestMessage, ResponseEnvelope,
+ },
+ permission::Permissions,
+ uri::{ClientMetadata, Uri},
};
pub use radroots_nostr_signer::prelude::{
RadrootsNostrEmbeddedSignerBackend, RadrootsNostrLocalSignerAvailability,
diff --git a/crates/sdk/src/signer_provider.rs b/crates/sdk/src/signer_provider.rs
@@ -10,12 +10,14 @@ use radroots_event::envelope::kind::{
use radroots_event::wire::Nip01EventWire;
use radroots_identity::PublicKey;
use radroots_nostr::event::Event as RadrootsNostrEvent;
-use radroots_nostr_connect::prelude::{
- RadrootsNostrConnectClientRequest, RadrootsNostrConnectClientTarget,
- RadrootsNostrConnectClientTransport, RadrootsNostrConnectClientTransportFuture,
- RadrootsNostrConnectError, RadrootsNostrConnectMethod, RadrootsNostrConnectPermission,
- RadrootsNostrConnectPermissions, RadrootsNostrConnectRequest, RadrootsNostrConnectResponse,
- UnsignedEvent as ConnectUnsignedEvent, execute_request_with_transport,
+use radroots_nostr_connect::{
+ Error as NostrConnectError, Method, Permission, Request, Response,
+ client::{
+ CancellationToken, Client, ClientEvent, Completion, Progress, Receive, Target, Transport,
+ TransportFuture,
+ },
+ message::{RequestId, UnsignedEvent as ConnectUnsignedEvent},
+ permission::Permissions,
};
use radroots_signing::{
Actor, SignReceipt, SignRequest, Signer,
@@ -26,7 +28,7 @@ use std::time::Duration;
use tokio::time::timeout;
use uuid::Uuid;
-pub type RadrootsSdkNip46TransportFuture<'a, T> = RadrootsNostrConnectClientTransportFuture<'a, T>;
+pub type RadrootsSdkNip46TransportFuture<'a, T> = TransportFuture<'a, T>;
pub type RadrootsSdkLocalSignerCapability = dyn Signer;
pub const RADROOTS_SDK_MYC_NIP46_PRODUCT_SIGN_EVENT_KINDS: [u32; 7] = [
@@ -381,8 +383,7 @@ impl Default for RadrootsSdkMycNip46RequestPolicy {
#[derive(Clone)]
pub struct RadrootsSdkMycNip46Signer {
- client_keys: RadrootsNostrKeys,
- target: RadrootsNostrConnectClientTarget,
+ client: Arc<Client>,
user_pubkey: PublicKey,
transport: Arc<dyn RadrootsSdkNip46Transport>,
request_policy: RadrootsSdkMycNip46RequestPolicy,
@@ -392,7 +393,7 @@ pub struct RadrootsSdkMycNip46Signer {
impl RadrootsSdkMycNip46Signer {
pub fn new(
client_key: RadrootsSdkNip46ClientKey,
- target: RadrootsNostrConnectClientTarget,
+ target: Target,
user_pubkey: impl AsRef<str>,
transport: Arc<dyn RadrootsSdkNip46Transport>,
) -> Result<Self, RadrootsSdkError> {
@@ -407,7 +408,7 @@ impl RadrootsSdkMycNip46Signer {
pub fn new_with_request_policy(
client_key: RadrootsSdkNip46ClientKey,
- target: RadrootsNostrConnectClientTarget,
+ target: Target,
user_pubkey: impl AsRef<str>,
transport: Arc<dyn RadrootsSdkNip46Transport>,
request_policy: RadrootsSdkMycNip46RequestPolicy,
@@ -424,21 +425,23 @@ impl RadrootsSdkMycNip46Signer {
fn new_with_request_id_generator(
client_key: RadrootsSdkNip46ClientKey,
- target: RadrootsNostrConnectClientTarget,
+ target: Target,
user_pubkey: impl AsRef<str>,
transport: Arc<dyn RadrootsSdkNip46Transport>,
request_policy: RadrootsSdkMycNip46RequestPolicy,
request_id_generator: Arc<dyn RadrootsSdkMycNip46RequestIdGenerator>,
) -> Result<Self, RadrootsSdkError> {
RadrootsSdkMycNip46RequestPolicy::new(request_policy.request_timeout())?;
+ let client_secret = client_key.into_keys().secret_key().to_secret_hex();
+ let client = Client::from_secret(client_secret.as_str(), target)
+ .map_err(sdk_error_from_nip46_error)?;
let user_pubkey = PublicKey::from_hex(user_pubkey.as_ref()).map_err(|error| {
RadrootsSdkError::InvalidRequest {
message: format!("myc_nip46 user pubkey is invalid: {error}"),
}
})?;
Ok(Self {
- client_keys: client_key.into_keys(),
- target,
+ client: Arc::new(client),
user_pubkey,
transport,
request_policy,
@@ -451,8 +454,8 @@ impl RadrootsSdkMycNip46Signer {
mode: RadrootsSdkSignerMode::MycNip46,
state: RadrootsSdkSignerState::Ready,
signer_pubkey: self.user_pubkey.to_hex(),
- remote_signer_pubkey: Some(self.target.remote_signer_public_key.to_hex()),
- relay_count: self.target.relays.len(),
+ remote_signer_pubkey: Some(self.client.target().remote_signer_public_key().to_hex()),
+ relay_count: self.client.target().relays().len(),
}
}
@@ -460,8 +463,14 @@ impl RadrootsSdkMycNip46Signer {
RadrootsSdkSignerCapability {
mode: RadrootsSdkSignerMode::MycNip46,
signer_pubkey: self.user_pubkey.to_hex(),
- remote_signer_pubkey: Some(self.target.remote_signer_public_key.to_hex()),
- relays: self.target.relays.iter().map(ToString::to_string).collect(),
+ remote_signer_pubkey: Some(self.client.target().remote_signer_public_key().to_hex()),
+ relays: self
+ .client
+ .target()
+ .relays()
+ .iter()
+ .map(ToString::to_string)
+ .collect(),
can_sign_events: true,
nip46_permissions: radroots_sdk_myc_nip46_product_permission_strings(),
}
@@ -487,42 +496,52 @@ impl RadrootsSdkMycNip46Signer {
.into());
}
let sign_event_request = sign_event_request_from_frozen_draft(sign_request.draft())?;
- let request_id = self.next_request_id();
+ let request_id =
+ RequestId::parse(self.next_request_id()).map_err(sdk_error_from_nip46_error)?;
let mut adapter = RadrootsSdkNip46TransportAdapter {
transport: self.transport.as_ref(),
+ request_timeout: self.request_policy.request_timeout(),
};
let mut progress_error = None;
- let request_future = execute_request_with_transport(
- &self.client_keys,
- &self.target,
- RadrootsNostrConnectClientRequest::new(request_id, sign_event_request),
- &mut adapter,
- |progress| {
- let sdk_progress = match progress {
- radroots_nostr_connect::prelude::RadrootsNostrConnectClientProgress::AuthChallenge {
- url,
- } => RadrootsSdkSignerProgress::AuthChallenge {
- mode: RadrootsSdkSignerMode::MycNip46,
- url,
- },
- };
- if let Err(error) = request.emit_progress(sdk_progress) {
- progress_error = Some(error);
- return Err(RadrootsNostrConnectError::Transport {
- reason: "SDK signer progress sink failed".to_owned(),
- });
- }
- Ok(())
- },
- );
- let response = timeout(self.request_policy.request_timeout(), request_future)
- .await
- .map_err(|_| RadrootsNostrConnectError::RequestTimedOut)
- .and_then(|response| response);
+ let cancellation = CancellationToken::new();
+ let completion = self
+ .client
+ .execute(
+ request_id,
+ sign_event_request,
+ &mut adapter,
+ &cancellation,
+ |progress| {
+ let sdk_progress = match progress {
+ Progress::AuthChallenge { url } => {
+ RadrootsSdkSignerProgress::AuthChallenge {
+ mode: RadrootsSdkSignerMode::MycNip46,
+ url,
+ }
+ }
+ };
+ if let Err(error) = request.emit_progress(sdk_progress) {
+ progress_error = Some(error);
+ return Err(NostrConnectError::Transport {
+ reason: "SDK signer progress sink failed".to_owned(),
+ });
+ }
+ Ok(())
+ },
+ )
+ .await;
if let Some(error) = progress_error {
return Err(error);
}
- let response = response.map_err(sdk_error_from_nip46_error)?;
+ let response = match completion.map_err(sdk_error_from_nip46_error)? {
+ Completion::Response(response) => *response,
+ Completion::Cancelled(phase) => {
+ return Err(RadrootsSdkError::SignerTransport {
+ mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(),
+ reason: format!("NIP-46 request cancelled {phase:?}"),
+ });
+ }
+ };
let signed_event = signed_event_from_nip46_response(operation_kind.as_str(), response)?;
let receipt = SignReceipt::from_signed_event(&sign_request, signed_event, unix_time_now()?)
.map_err(|error| match error.kind() {
@@ -541,7 +560,7 @@ impl RadrootsSdkMycNip46Signer {
operation_kind.as_str(),
RadrootsSdkSignerMode::MycNip46,
self.user_pubkey.to_hex(),
- Some(self.target.remote_signer_public_key.to_hex()),
+ Some(self.client.target().remote_signer_public_key().to_hex()),
receipt,
))
}
@@ -563,15 +582,10 @@ impl RadrootsSdkMycNip46RequestIdGenerator for RadrootsSdkUuidNip46RequestIdGene
}
}
-pub fn radroots_sdk_myc_nip46_product_permissions() -> RadrootsNostrConnectPermissions {
+pub fn radroots_sdk_myc_nip46_product_permissions() -> Permissions {
RADROOTS_SDK_MYC_NIP46_PRODUCT_SIGN_EVENT_KINDS
.iter()
- .map(|kind| {
- RadrootsNostrConnectPermission::with_parameter(
- RadrootsNostrConnectMethod::SignEvent,
- kind.to_string(),
- )
- })
+ .map(|kind| Permission::with_parameter(Method::SignEvent, kind.to_string()))
.collect::<Vec<_>>()
.into()
}
@@ -586,26 +600,49 @@ pub fn radroots_sdk_myc_nip46_product_permission_strings() -> Vec<String> {
struct RadrootsSdkNip46TransportAdapter<'a> {
transport: &'a dyn RadrootsSdkNip46Transport,
+ request_timeout: Duration,
}
-impl RadrootsNostrConnectClientTransport for RadrootsSdkNip46TransportAdapter<'_> {
- fn publish_request_event<'a>(
- &'a mut self,
- event: RadrootsNostrEvent,
- ) -> RadrootsNostrConnectClientTransportFuture<'a, ()> {
+impl Transport for RadrootsSdkNip46TransportAdapter<'_> {
+ fn publish<'a>(&'a mut self, event: ClientEvent) -> TransportFuture<'a, ()> {
+ let event = match RadrootsNostrEvent::from_json(event.as_json()) {
+ Ok(event) => event,
+ Err(error) => {
+ return Box::pin(async move {
+ Err(NostrConnectError::Transport {
+ reason: format!("invalid SDK NIP-46 publication: {error}"),
+ })
+ });
+ }
+ };
self.transport.publish_request_event(event)
}
- fn next_response_event<'a>(
+ fn receive<'a>(
&'a mut self,
- ) -> RadrootsNostrConnectClientTransportFuture<'a, RadrootsNostrEvent> {
- self.transport.next_response_event()
+ cancellation: &'a CancellationToken,
+ ) -> TransportFuture<'a, Receive> {
+ if cancellation.is_cancelled() {
+ return Box::pin(async { Ok(Receive::Cancelled) });
+ }
+ let next = self.transport.next_response_event();
+ let request_timeout = self.request_timeout;
+ Box::pin(async move {
+ match timeout(request_timeout, next).await {
+ Ok(Ok(event)) => {
+ if cancellation.is_cancelled() {
+ return Ok(Receive::Cancelled);
+ }
+ ClientEvent::from_json(event.as_json().as_str()).map(Receive::event)
+ }
+ Ok(Err(error)) => Err(error),
+ Err(_) => Ok(Receive::TimedOut),
+ }
+ })
}
}
-fn sign_event_request_from_frozen_draft(
- draft: &EventDraft,
-) -> Result<RadrootsNostrConnectRequest, RadrootsSdkError> {
+fn sign_event_request_from_frozen_draft(draft: &EventDraft) -> Result<Request, RadrootsSdkError> {
let public_key = nip46_unsigned_event_pubkey(draft)?;
let kind = nip46_unsigned_event_kind(draft)?;
let tags = nip46_unsigned_event_tags(draft)?;
@@ -619,7 +656,7 @@ fn sign_event_request_from_frozen_draft(
};
let unsigned_event = ConnectUnsignedEvent::from_json(&unsigned_event.as_json())
.map_err(|error| nip46_sign_event_protocol_error(error.to_string()))?;
- Ok(RadrootsNostrConnectRequest::SignEvent(unsigned_event))
+ Ok(Request::SignEvent(unsigned_event))
}
fn nip46_unsigned_event_pubkey(draft: &EventDraft) -> Result<NostrPublicKey, RadrootsSdkError> {
@@ -662,10 +699,10 @@ fn nip46_sign_event_protocol_error(reason: String) -> RadrootsSdkError {
fn signed_event_from_nip46_response(
operation_kind: &str,
- response: RadrootsNostrConnectResponse,
+ response: Response,
) -> Result<SignedEvent, RadrootsSdkError> {
match response {
- RadrootsNostrConnectResponse::SignedEvent(event) => {
+ Response::SignedEvent(event) => {
let raw_json = event.as_json();
let wire = Nip01EventWire::parse_json(raw_json.as_str()).map_err(|error| {
RadrootsSdkError::SignerProtocol {
@@ -687,18 +724,14 @@ fn signed_event_from_nip46_response(
reason: format!("remote signed event signature is invalid: {error}"),
})
}
- RadrootsNostrConnectResponse::Error { error, .. } => {
- Err(RadrootsSdkError::SignerRequestRejected {
- mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(),
- reason: error,
- })
- }
- RadrootsNostrConnectResponse::PendingConnection => {
- Err(RadrootsSdkError::SignerAuthChallengePending {
- mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(),
- auth_url: None,
- })
- }
+ Response::Error { error, .. } => Err(RadrootsSdkError::SignerRequestRejected {
+ mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(),
+ reason: error,
+ }),
+ Response::PendingConnection => Err(RadrootsSdkError::SignerAuthChallengePending {
+ mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(),
+ auth_url: None,
+ }),
other => Err(RadrootsSdkError::SignerProtocol {
mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(),
reason: format!("unexpected NIP-46 response for {operation_kind}: {other:?}"),
@@ -706,21 +739,21 @@ fn signed_event_from_nip46_response(
}
}
-fn sdk_error_from_nip46_error(error: RadrootsNostrConnectError) -> RadrootsSdkError {
+fn sdk_error_from_nip46_error(error: NostrConnectError) -> RadrootsSdkError {
match error {
- RadrootsNostrConnectError::RequestTimedOut => RadrootsSdkError::SignerRequestTimedOut {
+ NostrConnectError::RequestTimedOut => RadrootsSdkError::SignerRequestTimedOut {
mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(),
},
- RadrootsNostrConnectError::Transport { reason } => RadrootsSdkError::SignerTransport {
+ NostrConnectError::Transport { reason } => RadrootsSdkError::SignerTransport {
mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(),
reason,
},
- RadrootsNostrConnectError::Encrypt { reason }
- | RadrootsNostrConnectError::Decrypt { reason }
- | RadrootsNostrConnectError::Sign { reason }
- | RadrootsNostrConnectError::Json(reason)
- | RadrootsNostrConnectError::InvalidRequestPayload { reason, .. }
- | RadrootsNostrConnectError::InvalidResponsePayload { reason, .. } => {
+ NostrConnectError::Encrypt { reason }
+ | NostrConnectError::Decrypt { reason }
+ | NostrConnectError::Sign { reason }
+ | NostrConnectError::Json(reason)
+ | NostrConnectError::InvalidRequestPayload { reason, .. }
+ | NostrConnectError::InvalidResponsePayload { reason, .. } => {
RadrootsSdkError::SignerProtocol {
mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(),
reason,
diff --git a/crates/sdk/tests/source_boundary.rs b/crates/sdk/tests/source_boundary.rs
@@ -280,3 +280,33 @@ fn signer_transition_surface_is_private_hidden_and_scheduled_for_removal() {
assert!(transition_record.contains("oss/cli"));
assert!(transition_record.contains("oss/studio_app"));
}
+
+#[test]
+fn signer_consumers_use_the_final_nostr_connect_state_machine() {
+ let manifest = manifest_dir();
+ for relative in [
+ "src/signer_provider.rs",
+ "src/adapters/signer.rs",
+ "examples/sdk_v1_myc_nip46_signer_setup.rs",
+ ] {
+ let source = read_source(&manifest.join(relative));
+ for retired in [
+ "radroots_nostr_connect::prelude",
+ "RadrootsNostrConnectClient",
+ "RadrootsNostrConnectMethod",
+ "RadrootsNostrConnectPermission",
+ "RadrootsNostrConnectRequest",
+ "RadrootsNostrConnectResponse",
+ "RADROOTS_NOSTR_CONNECT_",
+ ] {
+ assert!(
+ !source.contains(retired),
+ "{relative} retains retired Nostr Connect surface `{retired}`"
+ );
+ }
+ }
+
+ let provider = read_source(&manifest.join("src/signer_provider.rs"));
+ assert!(provider.contains("impl Transport for RadrootsSdkNip46TransportAdapter"));
+ assert!(provider.contains(".client\n .execute("));
+}
diff --git a/crates/sdk/tests/unit/signer_provider_tests.rs b/crates/sdk/tests/unit/signer_provider_tests.rs
@@ -8,10 +8,11 @@ use radroots_event::envelope::kind::{
};
use radroots_nostr::signing::sign_frozen_draft;
use radroots_nostr::{event::Event as RadrootsNostrEvent, signing::LocalSigner};
-use radroots_nostr_connect::prelude::{
- RADROOTS_NOSTR_CONNECT_RPC_KIND, RadrootsNostrConnectClientTarget, RadrootsNostrConnectError,
- RadrootsNostrConnectRequest, RadrootsNostrConnectRequestMessage, RadrootsNostrConnectResponse,
- SignedEvent as ConnectSignedEvent,
+use radroots_nostr_connect::{
+ Error as NostrConnectError, Request, Response,
+ client::Target,
+ message::{RPC_KIND, RequestMessage, SignedEvent as ConnectSignedEvent},
+ uri::RelayUrl as ConnectRelayUrl,
};
use radroots_signing::actor::ActorSource;
use std::collections::VecDeque;
@@ -54,6 +55,16 @@ fn remote_keys() -> RadrootsNostrKeys {
REMOTE_KEYS.clone()
}
+fn nip46_target(remote_public_key: nostr::PublicKey, relays: Vec<nostr::RelayUrl>) -> Target {
+ let remote_public_key =
+ radroots_nostr::key::public_key_from_nostr(remote_public_key).expect("identity public key");
+ let relays = relays
+ .into_iter()
+ .map(|relay| ConnectRelayUrl::parse(relay.to_string().as_str()).expect("connect relay"))
+ .collect();
+ Target::try_new(remote_public_key, relays).expect("NIP-46 target")
+}
+
fn client_keys() -> RadrootsSdkNip46ClientKey {
RadrootsSdkNip46ClientKey::generate()
}
@@ -134,7 +145,7 @@ fn response_event(
remote_keys: &RadrootsNostrKeys,
client_public_key: nostr::PublicKey,
request_id: &str,
- response: RadrootsNostrConnectResponse,
+ response: Response,
) -> RadrootsNostrEvent {
let envelope = response
.into_envelope(request_id)
@@ -147,7 +158,7 @@ fn response_event(
Version::V2,
)
.expect("ciphertext");
- EventBuilder::new(Kind::Custom(RADROOTS_NOSTR_CONNECT_RPC_KIND), ciphertext)
+ EventBuilder::new(Kind::Custom(RPC_KIND), ciphertext)
.tag(Tag::public_key(client_public_key))
.sign_with_keys(remote_keys)
.expect("response event")
@@ -158,7 +169,7 @@ fn myc_signer_with_responses(
) -> (RadrootsSdkMycNip46Signer, Arc<MockNip46Transport>) {
let remote_keys = remote_keys();
let transport = Arc::new(MockNip46Transport::new(remote_keys.clone(), responses));
- let target = RadrootsNostrConnectClientTarget::new(
+ let target = nip46_target(
remote_keys.public_key(),
vec![nostr::RelayUrl::parse("wss://relay.example.com").expect("relay")],
);
@@ -176,7 +187,7 @@ struct MockNip46Transport {
}
enum MockNip46Response {
- Respond(RadrootsNostrConnectResponse),
+ Respond(Response),
}
impl MockNip46Transport {
@@ -193,7 +204,7 @@ impl MockNip46Transport {
self.published.lock().expect("published lock").clone()
}
- fn published_request_messages(&self) -> Vec<RadrootsNostrConnectRequestMessage> {
+ fn published_request_messages(&self) -> Vec<RequestMessage> {
self.published()
.iter()
.map(|event| request_message_from_event(&self.remote_keys, event))
@@ -204,7 +215,7 @@ impl MockNip46Transport {
fn request_message_from_event(
remote_keys: &RadrootsNostrKeys,
event: &RadrootsNostrEvent,
-) -> RadrootsNostrConnectRequestMessage {
+) -> RequestMessage {
let payload = nip44::decrypt(remote_keys.secret_key(), &event.pubkey, &event.content)
.expect("request payload");
serde_json::from_str(payload.as_str()).expect("request message")
@@ -239,7 +250,7 @@ impl RadrootsSdkNip46Transport for MockNip46Transport {
&'a self,
) -> RadrootsSdkNip46TransportFuture<'a, RadrootsNostrEvent> {
let next = self.inbound.lock().expect("inbound lock").pop_front();
- Box::pin(async move { next.ok_or(RadrootsNostrConnectError::RequestTimedOut) })
+ Box::pin(async move { next.ok_or(NostrConnectError::RequestTimedOut) })
}
}
@@ -268,7 +279,7 @@ impl RadrootsSdkNip46Transport for HangingNip46Transport {
&'a self,
) -> RadrootsSdkNip46TransportFuture<'a, RadrootsNostrEvent> {
Box::pin(future::pending::<
- Result<RadrootsNostrEvent, RadrootsNostrConnectError>,
+ Result<RadrootsNostrEvent, NostrConnectError>,
>())
}
}
@@ -409,7 +420,7 @@ fn signer_provider_reports_myc_status_capability_and_constructor_errors() {
nostr::RelayUrl::parse("wss://relay-a.example.com").expect("relay a"),
nostr::RelayUrl::parse("wss://relay-b.example.com").expect("relay b"),
];
- let target = RadrootsNostrConnectClientTarget::new(remote_keys.public_key(), relays);
+ let target = nip46_target(remote_keys.public_key(), relays);
let transport = Arc::new(MockNip46Transport::new(remote_keys.clone(), Vec::new()));
let signer =
RadrootsSdkMycNip46Signer::new(client_keys(), target, user_pubkey(), transport.clone())
@@ -442,7 +453,7 @@ fn signer_provider_reports_myc_status_capability_and_constructor_errors() {
}
);
- let target = RadrootsNostrConnectClientTarget::new(remote_keys.public_key(), Vec::new());
+ let target = nip46_target(remote_keys.public_key(), Vec::new());
let error =
match RadrootsSdkMycNip46Signer::new(client_keys(), target, "not-a-pubkey", transport) {
Ok(_) => panic!("expected invalid pubkey"),
@@ -460,7 +471,7 @@ fn nip46_private_helpers_map_identity_adapter_and_response_edges() {
assert!(matches!(
signed_event_from_nip46_response(
"farm.publish",
- RadrootsNostrConnectResponse::Error {
+ Response::Error {
result: None,
error: "operator rejected".to_owned(),
},
@@ -469,42 +480,42 @@ fn nip46_private_helpers_map_identity_adapter_and_response_edges() {
if mode == "myc_nip46" && reason == "operator rejected"
));
assert!(matches!(
- signed_event_from_nip46_response("farm.publish", RadrootsNostrConnectResponse::PendingConnection),
+ signed_event_from_nip46_response("farm.publish", Response::PendingConnection),
Err(RadrootsSdkError::SignerAuthChallengePending { ref mode, auth_url: None })
if mode == "myc_nip46"
));
assert!(matches!(
- signed_event_from_nip46_response("farm.publish", RadrootsNostrConnectResponse::Pong),
+ signed_event_from_nip46_response("farm.publish", Response::Pong),
Err(RadrootsSdkError::SignerProtocol { ref mode, ref reason })
if mode == "myc_nip46" && reason.contains("farm.publish")
));
assert!(matches!(
- sdk_error_from_nip46_error(RadrootsNostrConnectError::Transport {
+ sdk_error_from_nip46_error(NostrConnectError::Transport {
reason: "relay offline".to_owned(),
}),
RadrootsSdkError::SignerTransport { ref mode, ref reason }
if mode == "myc_nip46" && reason == "relay offline"
));
assert!(matches!(
- sdk_error_from_nip46_error(RadrootsNostrConnectError::Json("bad json".to_owned())),
+ sdk_error_from_nip46_error(NostrConnectError::Json("bad json".to_owned())),
RadrootsSdkError::SignerProtocol { ref mode, ref reason }
if mode == "myc_nip46" && reason == "bad json"
));
for error in [
- RadrootsNostrConnectError::Encrypt {
+ NostrConnectError::Encrypt {
reason: "encrypt failed".to_owned(),
},
- RadrootsNostrConnectError::Decrypt {
+ NostrConnectError::Decrypt {
reason: "decrypt failed".to_owned(),
},
- RadrootsNostrConnectError::Sign {
+ NostrConnectError::Sign {
reason: "sign failed".to_owned(),
},
- RadrootsNostrConnectError::InvalidRequestPayload {
+ NostrConnectError::InvalidRequestPayload {
method: "sign_event".to_owned(),
reason: "request payload failed".to_owned(),
},
- RadrootsNostrConnectError::InvalidResponsePayload {
+ NostrConnectError::InvalidResponsePayload {
method: "sign_event".to_owned(),
reason: "response payload failed".to_owned(),
},
@@ -515,7 +526,7 @@ fn nip46_private_helpers_map_identity_adapter_and_response_edges() {
));
}
assert!(matches!(
- sdk_error_from_nip46_error(RadrootsNostrConnectError::InvalidMethod("ping".to_owned())),
+ sdk_error_from_nip46_error(NostrConnectError::InvalidMethod("ping".to_owned())),
RadrootsSdkError::SignerProtocol { ref mode, ref reason }
if mode == "myc_nip46" && reason.contains("invalid NIP-46 method")
));
@@ -527,17 +538,18 @@ async fn nip46_transport_adapter_delegates_publish_and_response_poll() {
let event = sign_event(&user_keys(), &frozen_draft());
let mut adapter = RadrootsSdkNip46TransportAdapter {
transport: transport.as_ref(),
+ request_timeout: Duration::from_millis(10),
};
adapter
- .publish_request_event(event)
+ .publish(ClientEvent::from_json(event.as_json().as_str()).expect("client event"))
.await
.expect("publish request");
assert_eq!(transport.published().len(), 1);
assert!(matches!(
- adapter.next_response_event().await,
- Err(RadrootsNostrConnectError::RequestTimedOut)
+ adapter.receive(&CancellationToken::new()).await,
+ Err(NostrConnectError::RequestTimedOut)
));
}
@@ -573,11 +585,11 @@ async fn myc_nip46_provider_signs_and_validates_remote_event() {
let signed_event = RadrootsNostrEvent::from_json(signed.raw_json()).expect("event");
let transport = Arc::new(MockNip46Transport::new(
remote_keys.clone(),
- vec![MockNip46Response::Respond(
- RadrootsNostrConnectResponse::SignedEvent(connect_signed_event(signed_event)),
- )],
+ vec![MockNip46Response::Respond(Response::SignedEvent(
+ connect_signed_event(signed_event),
+ ))],
));
- let target = RadrootsNostrConnectClientTarget::new(
+ let target = nip46_target(
remote_keys.public_key(),
vec![nostr::RelayUrl::parse("wss://relay.example.com").expect("relay")],
);
@@ -614,7 +626,7 @@ async fn myc_nip46_provider_signs_and_validates_remote_event() {
assert_eq!(transport.published().len(), 1);
let request_messages = transport.published_request_messages();
let sign_event_request = match &request_messages[0].request {
- RadrootsNostrConnectRequest::SignEvent(unsigned_event) => unsigned_event,
+ Request::SignEvent(unsigned_event) => unsigned_event,
other => panic!("unexpected NIP-46 request: {other:?}"),
};
let sign_event_request: nostr::UnsignedEvent =
@@ -708,8 +720,7 @@ async fn myc_nip46_provider_reports_preflight_and_progress_sink_edges() {
let remote_keys = remote_keys();
let mismatch_transport = Arc::new(MockNip46Transport::new(remote_keys.clone(), Vec::new()));
- let mismatch_target =
- RadrootsNostrConnectClientTarget::new(remote_keys.public_key(), Vec::new());
+ let mismatch_target = nip46_target(remote_keys.public_key(), Vec::new());
let mismatch_signer = RadrootsSdkMycNip46Signer::new(
client_keys(),
mismatch_target,
@@ -735,7 +746,7 @@ async fn myc_nip46_provider_returns_completion_progress_errors_after_remote_sign
let signed = sign_frozen_draft(&user_keys, &draft).expect("signed");
let signed_event = RadrootsNostrEvent::from_json(signed.raw_json()).expect("event");
let (signer, transport) = myc_signer_with_responses(vec![MockNip46Response::Respond(
- RadrootsNostrConnectResponse::SignedEvent(connect_signed_event(signed_event)),
+ Response::SignedEvent(connect_signed_event(signed_event)),
)]);
let actor = actor();
let mut observed = Vec::new();
@@ -787,11 +798,11 @@ async fn myc_nip46_provider_reports_auth_challenge_progress_and_timeout() {
let remote_keys = remote_keys();
let transport = Arc::new(MockNip46Transport::new(
remote_keys.clone(),
- vec![MockNip46Response::Respond(
- RadrootsNostrConnectResponse::AuthUrl("https://auth.example.com/challenge".to_owned()),
- )],
+ vec![MockNip46Response::Respond(Response::AuthUrl(
+ "https://auth.example.com/challenge".to_owned(),
+ ))],
));
- let target = RadrootsNostrConnectClientTarget::new(remote_keys.public_key(), Vec::new());
+ let target = nip46_target(remote_keys.public_key(), Vec::new());
let signer = RadrootsSdkMycNip46Signer::new(client_keys, target, user_pubkey(), transport)
.expect("signer");
let mut progress = Vec::new();
@@ -834,11 +845,11 @@ async fn myc_nip46_provider_returns_progress_sink_errors_from_auth_challenge() {
let remote_keys = remote_keys();
let transport = Arc::new(MockNip46Transport::new(
remote_keys.clone(),
- vec![MockNip46Response::Respond(
- RadrootsNostrConnectResponse::AuthUrl("https://auth.example.com/challenge".to_owned()),
- )],
+ vec![MockNip46Response::Respond(Response::AuthUrl(
+ "https://auth.example.com/challenge".to_owned(),
+ ))],
));
- let target = RadrootsNostrConnectClientTarget::new(remote_keys.public_key(), Vec::new());
+ let target = nip46_target(remote_keys.public_key(), Vec::new());
let signer = RadrootsSdkMycNip46Signer::new(client_keys, target, user_pubkey(), transport)
.expect("signer");
let draft = frozen_draft();
@@ -886,7 +897,7 @@ async fn myc_nip46_provider_rejects_zero_timeout_policy() {
if mode == "myc_nip46" && reason.contains("timeout")
));
- let target = RadrootsNostrConnectClientTarget::new(remote_keys().public_key(), Vec::new());
+ let target = nip46_target(remote_keys().public_key(), Vec::new());
let transport = Arc::new(MockNip46Transport::new(remote_keys(), Vec::new()));
let constructor_error = match RadrootsSdkMycNip46Signer::new_with_request_policy(
client_keys(),
@@ -911,7 +922,7 @@ async fn myc_nip46_provider_rejects_zero_timeout_policy() {
async fn myc_nip46_provider_times_out_hanging_transport() {
let client_keys = client_keys();
let remote_keys = remote_keys();
- let target = RadrootsNostrConnectClientTarget::new(remote_keys.public_key(), Vec::new());
+ let target = nip46_target(remote_keys.public_key(), Vec::new());
let transport = Arc::new(HangingNip46Transport::new());
let policy = RadrootsSdkMycNip46RequestPolicy::new(Duration::from_millis(5)).expect("policy");
let signer = RadrootsSdkMycNip46Signer::new_with_request_policy(
@@ -1022,11 +1033,11 @@ async fn myc_nip46_provider_rejects_returned_event_drift() {
let signed_event = sign_event(&signing_keys, &drifted_draft);
let transport = Arc::new(MockNip46Transport::new(
remote_keys.clone(),
- vec![MockNip46Response::Respond(
- RadrootsNostrConnectResponse::SignedEvent(connect_signed_event(signed_event)),
- )],
+ vec![MockNip46Response::Respond(Response::SignedEvent(
+ connect_signed_event(signed_event),
+ ))],
));
- let target = RadrootsNostrConnectClientTarget::new(remote_keys.public_key(), Vec::new());
+ let target = nip46_target(remote_keys.public_key(), Vec::new());
let signer = RadrootsSdkMycNip46Signer::new(client_keys, target, user_pubkey(), transport)
.expect("signer");
let actor = actor();