commit c866c00b0fc3e591d9f32d176c606ba7b9e54fd3
parent c926ccad3662685142029431c48ef7b9b6013ed8
Author: triesap <tyson@radroots.org>
Date: Fri, 31 Jul 2026 09:03:21 +0000
nostr: remove live relay-client dependencies
- Route SDK client adapters through radroots_transport_nostr.
- Replace portable-client features with transport-owned feature wiring.
- Normalize adapter tests against the owned transport error contract.
- Refresh lockfile and API-boundary expectations for the move.
Diffstat:
7 files changed, 58 insertions(+), 81 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -1029,7 +1029,7 @@ dependencies = [
"futures-channel",
"futures-io",
"futures-util",
- "idna",
+ "idna 1.1.0",
"ipnet",
"once_cell",
"rand 0.9.4",
@@ -1283,6 +1283,16 @@ checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
[[package]]
name = "idna"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "idna"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
@@ -1587,6 +1597,7 @@ dependencies = [
"serde_json",
"unicode-normalization",
"url",
+ "url-fork",
]
[[package]]
@@ -2125,7 +2136,6 @@ name = "radroots_nostr"
version = "0.1.0-alpha"
dependencies = [
"nostr",
- "nostr-sdk",
"radroots_event",
"radroots_event_codec",
"radroots_identity",
@@ -2460,6 +2470,7 @@ version = "0.1.0-alpha"
dependencies = [
"futures",
"nostr",
+ "nostr-sdk",
"radroots_event",
"radroots_event_store",
"radroots_nostr",
@@ -3529,6 +3540,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
[[package]]
+name = "unicode-bidi"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
+
+[[package]]
name = "unicode-general-category"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3584,13 +3601,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
dependencies = [
"form_urlencoded",
- "idna",
+ "idna 1.1.0",
"percent-encoding",
"serde",
"serde_derive",
]
[[package]]
+name = "url-fork"
+version = "3.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fa3323c39b8e786154d3000b70ae9af0e9bd746c9791456da0d4a1f68ad89d6"
+dependencies = [
+ "form_urlencoded",
+ "idna 0.5.0",
+ "percent-encoding",
+ "serde",
+]
+
+[[package]]
name = "utf-8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/contracts/releases/api_boundaries.toml b/contracts/releases/api_boundaries.toml
@@ -98,63 +98,6 @@ allowed_public_paths = []
name = "radroots"
allowed_public_paths = []
[[exception]]
-id = "RCRV1-API-003"
-package = "radroots_nostr"
-source = "src/client.rs"
-forbidden_path = "nostr_sdk"
-items = [
- "client::RadrootsNostrClient::from_inner",
- "client::RadrootsNostrClient::into_inner",
-]
-observed_paths = ["nostr_sdk::Client"]
-adr = "docs/decisions/0001-public-api-leakage-migration-baseline.md"
-removal_step = 124
-rationale = "Legacy client ownership remains visible only until the Nostr package removes live relay-client dependencies."
-
-[[exception]]
-id = "RCRV1-API-004"
-package = "radroots_nostr"
-source = "src/error.rs"
-forbidden_path = "nostr_sdk"
-items = ["error::RadrootsNostrError"]
-observed_paths = [
- "nostr_sdk::client::Error",
- "nostr_sdk::prelude::DatabaseError",
-]
-adr = "docs/decisions/0001-public-api-leakage-migration-baseline.md"
-removal_step = 124
-rationale = "Legacy SDK error variants remain exact-scoped until normalized adapter errors replace them."
-
-[[exception]]
-id = "RCRV1-API-005"
-package = "radroots_nostr"
-source = "src/types.rs"
-forbidden_path = "nostr_sdk"
-items = [
- "types::RadrootsNostrEventStream",
- "types::RadrootsNostrMonitor",
- "types::RadrootsNostrMonitorNotification",
- "types::RadrootsNostrOutput",
- "types::RadrootsNostrRelay",
- "types::RadrootsNostrRelayPoolNotification",
- "types::RadrootsNostrRelayStatus",
- "types::RadrootsNostrSubscribeAutoCloseOptions",
-]
-observed_paths = [
- "nostr_sdk::Relay",
- "nostr_sdk::RelayPoolNotification",
- "nostr_sdk::RelayStatus",
- "nostr_sdk::SubscribeAutoCloseOptions",
- "nostr_sdk::pool::stream::BoxedStream",
- "nostr_sdk::prelude::Monitor",
- "nostr_sdk::prelude::MonitorNotification",
- "nostr_sdk::prelude::Output",
-]
-adr = "docs/decisions/0001-public-api-leakage-migration-baseline.md"
-removal_step = 124
-rationale = "Broad live-client aliases are frozen and must be removed with the Nostr client dependency at Step 124."
-
-[[exception]]
id = "RCRV1-API-006"
package = "radroots_nostr_connect"
source = "src/client.rs"
diff --git a/crates/sdk/Cargo.toml b/crates/sdk/Cargo.toml
@@ -52,7 +52,13 @@ signing = [
"radroots_protocol/std",
"radroots_signing/std",
]
-transport-nostr-client = ["signing", "std", "serde_json", "radroots_nostr/client"]
+transport-nostr-client = [
+ "signing",
+ "std",
+ "serde_json",
+ "dep:radroots_transport_nostr",
+ "radroots_transport_nostr/client",
+]
radrootsd-execution = [
"std",
"serde_json",
@@ -112,7 +118,6 @@ local-signer = ["runtime", "signing", "radroots_nostr/signing"]
transport-nostr-runtime = [
"runtime",
"dep:radroots_nostr",
- "radroots_nostr/client",
"radroots_transport_nostr/client",
]
local-runtime = [
diff --git a/crates/sdk/src/adapters/nostr.rs b/crates/sdk/src/adapters/nostr.rs
@@ -1,17 +1,16 @@
use core::time::Duration;
-use radroots_nostr::prelude::{
- RadrootsNostrClient, RadrootsNostrClientOptions, RadrootsNostrError, RadrootsNostrEvent,
- RadrootsNostrEventId, RadrootsNostrKeys, RadrootsNostrOutput,
+use radroots_nostr::prelude::{RadrootsNostrEvent, RadrootsNostrEventId, RadrootsNostrKeys};
+use radroots_transport_nostr::{
+ RadrootsNostrClient, RadrootsNostrClientOptions, RadrootsNostrOutput,
+ RadrootsRelayTransportError,
};
pub fn signerless_client() -> RadrootsNostrClient {
RadrootsNostrClient::new_signerless()
}
-pub fn signerless_client_with_options(
- options: RadrootsNostrClientOptions,
-) -> Result<RadrootsNostrClient, RadrootsNostrError> {
+pub fn signerless_client_with_options(options: RadrootsNostrClientOptions) -> RadrootsNostrClient {
RadrootsNostrClient::new_signerless_with_options(options)
}
@@ -23,7 +22,7 @@ pub async fn configure_write_relays(
client: &RadrootsNostrClient,
relay_urls: &[String],
connect_timeout: Duration,
-) -> Result<(), RadrootsNostrError> {
+) -> Result<(), RadrootsRelayTransportError> {
for relay_url in relay_urls {
client.add_write_relay(relay_url).await?;
}
@@ -36,7 +35,7 @@ pub async fn connected_client_from_keys(
keys: RadrootsNostrKeys,
relay_urls: &[String],
connect_timeout: Duration,
-) -> Result<RadrootsNostrClient, RadrootsNostrError> {
+) -> Result<RadrootsNostrClient, RadrootsRelayTransportError> {
let client = client_from_keys(keys);
configure_write_relays(&client, relay_urls, connect_timeout).await?;
Ok(client)
@@ -57,7 +56,7 @@ pub async fn connected_relay_urls(client: &RadrootsNostrClient) -> Vec<String> {
pub async fn publish_signed_event(
client: &RadrootsNostrClient,
event: &RadrootsNostrEvent,
-) -> Result<RadrootsNostrOutput<RadrootsNostrEventId>, RadrootsNostrError> {
+) -> Result<RadrootsNostrOutput<RadrootsNostrEventId>, RadrootsRelayTransportError> {
client.send_event(event).await
}
diff --git a/crates/sdk/src/sync_runtime.rs b/crates/sdk/src/sync_runtime.rs
@@ -15,8 +15,6 @@ use crate::{RadrootsdExecutionAuth, RadrootsdExecutionProfile};
use radroots_event::id::EventId;
#[cfg(feature = "runtime")]
use radroots_event_store::{RADROOTS_EVENT_STORE_QUERY_LIMIT_MAX, RadrootsEventStoreStatusSummary};
-#[cfg(all(feature = "runtime", feature = "transport-nostr-runtime"))]
-use radroots_nostr::prelude::RadrootsNostrClient;
#[cfg(all(feature = "runtime", feature = "radrootsd-execution"))]
use radroots_outbox::RadrootsOutboxClaimedEvent;
#[cfg(feature = "runtime")]
@@ -44,7 +42,9 @@ use radroots_transport::{
#[cfg(all(feature = "runtime", feature = "radrootsd-execution"))]
use radroots_transport::{RadrootsTransportSatisfactionClass, RadrootsTransportSatisfactionPolicy};
#[cfg(all(feature = "runtime", feature = "transport-nostr-runtime"))]
-use radroots_transport_nostr::{RadrootsNostrClientPublishAdapter, RadrootsNostrTransport};
+use radroots_transport_nostr::{
+ RadrootsNostrClient, RadrootsNostrClientPublishAdapter, RadrootsNostrTransport,
+};
#[cfg(feature = "runtime")]
use radroots_transport_nostr::{
RadrootsOutboxPublishPolicy, RadrootsOutboxPublishReceipt, RadrootsOutboxPublishTargetReceipt,
diff --git a/crates/sdk/tests/unit/adapters_nostr_tests.rs b/crates/sdk/tests/unit/adapters_nostr_tests.rs
@@ -4,7 +4,7 @@ use super::{
};
use core::time::Duration;
use nostr::{EventBuilder, Keys, Kind};
-use radroots_nostr::prelude::RadrootsNostrClientOptions;
+use radroots_transport_nostr::{RadrootsNostrClientOptions, RadrootsRelayTransportError};
use tokio::runtime::Runtime;
#[test]
@@ -13,8 +13,7 @@ fn client_constructors_build_without_runtime_net() {
let _client = client_from_keys(keys);
let _signerless = signerless_client();
let _signerless_with_options =
- signerless_client_with_options(RadrootsNostrClientOptions::new())
- .expect("signerless client with options");
+ signerless_client_with_options(RadrootsNostrClientOptions::new());
}
#[test]
@@ -42,7 +41,7 @@ fn relay_helpers_accept_empty_relay_sets_without_network_endpoints() {
let error = configure_write_relays(&client, &invalid_relays, Duration::from_millis(1))
.await
.expect_err("invalid relay");
- assert!(format!("{error:?}").contains("Url"));
+ assert!(matches!(error, RadrootsRelayTransportError::Client(_)));
let connected_error = match connected_client_from_keys(
keys.clone(),
&invalid_relays,
@@ -53,7 +52,10 @@ fn relay_helpers_accept_empty_relay_sets_without_network_endpoints() {
Ok(_) => panic!("expected invalid connected relay"),
Err(error) => error,
};
- assert!(format!("{connected_error:?}").contains("Url"));
+ assert!(matches!(
+ connected_error,
+ RadrootsRelayTransportError::Client(_)
+ ));
let disconnected = client_from_keys(keys.clone());
disconnected
@@ -78,6 +80,6 @@ fn relay_helpers_accept_empty_relay_sets_without_network_endpoints() {
let error = publish_signed_event(&connected, &signed)
.await
.expect_err("publish without relays");
- assert!(format!("{error:?}").contains("NoRelaysSpecified"));
+ assert!(matches!(error, RadrootsRelayTransportError::Client(_)));
});
}
diff --git a/tools/xtask/src/check.rs b/tools/xtask/src/check.rs
@@ -564,7 +564,6 @@ fn check_sdk_feature_matrix(root: &Path) -> Result<(), String> {
for entry in [
"runtime",
"dep:radroots_nostr",
- "radroots_nostr/client",
"radroots_transport_nostr/client",
] {
require_feature_entry(&nostr_runtime, "transport-nostr-runtime", entry)?;