sdk

Radroots SDK and bindings
git clone https://radroots.dev/git/sdk.git
Log | Files | Refs | README

commit 3edb09c0088a5d37d496515ee7cbbe1aadb57904
parent 47dabd049d57be6efd9741d966adabb01bd8b433
Author: triesap <tyson@radroots.org>
Date:   Thu, 30 Jul 2026 23:04:03 +0000

transport: migrate workspace consumers

- Consume canonical transport identities, targets, and final sink contracts.
- Route Nostr outbox publication through the final delivery request and receipt model.
- Keep Reticulum preview policy private to its adapter-owned contract constants.
- Update source boundaries, runtime tests, and the exact alpha dependency lock.

Diffstat:
MCargo.lock | 4++++
Mcrates/sdk/src/lib.rs | 4++--
Mcrates/sdk/src/sync_runtime.rs | 23++++++++++++-----------
Mcrates/sdk/src/transport.rs | 75+++++++++++++++++++++++++++++++++++++--------------------------------------
Mcrates/sdk/src/workflow_runtime.rs | 28+++++++++++++---------------
Mcrates/sdk/tests/source_boundary.rs | 28++++++++++++++++++++++++++++
Mcrates/sdk/tests/sync_runtime.rs | 20++++++++++----------
Mcrates/sdk/tests/unit/adapters_radrootsd_tests.rs | 2+-
Mcrates/sdk/tests/unit/sync_runtime_tests.rs | 64+++++++++++++++++++++++++++++++++-------------------------------
Mcrates/sdk/tests/unit/transport_tests.rs | 16+++++++---------
10 files changed, 147 insertions(+), 117 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -2171,6 +2171,7 @@ dependencies = [ "hex", "radroots_event", "radroots_event_store", + "radroots_protocol", "radroots_transport", "serde", "serde_json", @@ -2446,6 +2447,9 @@ version = "0.1.0-alpha" name = "radroots_transport" version = "0.1.0-alpha" dependencies = [ + "radroots_event", + "radroots_identity", + "radroots_protocol", "serde", "sha2", ] diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs @@ -193,9 +193,9 @@ pub use crate::trade_runtime::{ #[cfg(feature = "runtime")] pub use crate::transport::{ MeshScopeId, MultiTargetProfile, NostrProfile, NostrRelayUrlPolicy, PublishMode, - RadrootsTransportDeliveryReceipt, RadrootsTransportDeliveryTargetStatus, RadrootsTransportKind, + RadrootsTransportDeliveryReceipt, RadrootsTransportDeliveryTargetStatus, RadrootsTransportOutcome, RadrootsTransportSatisfactionClass, RadrootsTransportTargetReceipt, RadrootsdExecutionAuth, RadrootsdExecutionProfile, ReticulumAgentEndpoint, ReticulumBehavior, ReticulumProfile, SDK_TRANSPORT_TARGET_MAX_COUNT, SatisfactionPolicy, TargetPolicy, TargetSet, - TransportProfile, TransportReceipt, + TransportId, TransportProfile, TransportReceipt, }; diff --git a/crates/sdk/src/sync_runtime.rs b/crates/sdk/src/sync_runtime.rs @@ -34,13 +34,12 @@ use radroots_protocol::radrootsd::transport_publish::v5::{ #[cfg(feature = "runtime")] use radroots_trade::reducer::{RADROOTS_TRADE_REDUCER_CONTRACT_ID, RADROOTS_TRADE_REDUCER_VERSION}; #[cfg(all(feature = "runtime", feature = "radrootsd-execution"))] -use radroots_transport::RadrootsTransportTargetFingerprint; +use radroots_transport::target::TargetFingerprint; #[cfg(feature = "runtime")] use radroots_transport::{ - RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE, RadrootsTransportCapabilityAvailability, - RadrootsTransportCapabilityMaturity, RadrootsTransportImplementationState, - RadrootsTransportKind, RadrootsTransportOutcomeKind, RadrootsTransportStatus, - RadrootsTransportTarget, + RadrootsTransportCapabilityAvailability, RadrootsTransportCapabilityMaturity, + RadrootsTransportImplementationState, RadrootsTransportOutcomeKind, RadrootsTransportStatus, + Target, TransportId, }; #[cfg(all(feature = "runtime", feature = "radrootsd-execution"))] use radroots_transport::{RadrootsTransportSatisfactionClass, RadrootsTransportSatisfactionPolicy}; @@ -51,6 +50,7 @@ use radroots_transport_nostr::{ RadrootsOutboxPublishPolicy, RadrootsOutboxPublishReceipt, RadrootsOutboxPublishTargetReceipt, RadrootsRelayOutcomeKind, publish_claimed_outbox_event_with_transport, }; +use radroots_transport_reticulum::RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE; #[cfg(feature = "runtime")] use sha2::{Digest, Sha256}; @@ -214,7 +214,7 @@ pub struct SyncTransportTargetSummary { #[cfg(feature = "runtime")] impl SyncTransportTargetSummary { - fn from_transport_target(target: &RadrootsTransportTarget) -> Self { + fn from_transport_target(target: &Target) -> Self { Self { transport_kind: target.kind().canonical_label(), endpoint_uri: target.uri().as_str().to_owned(), @@ -279,6 +279,7 @@ fn transport_implementation_label(state: RadrootsTransportImplementationState) - #[cfg(feature = "runtime")] fn transport_maturity_label(maturity: RadrootsTransportCapabilityMaturity) -> &'static str { match maturity { + RadrootsTransportCapabilityMaturity::Experimental => "experimental", RadrootsTransportCapabilityMaturity::Preview => "preview", RadrootsTransportCapabilityMaturity::Stable => "stable", } @@ -816,7 +817,7 @@ impl<'sdk> SyncClient<'sdk> { request: PushOutboxRequest, ) -> Result<PushOutboxReceipt, RadrootsSdkError> where - T: radroots_transport::RadrootsTransport + ?Sized, + T: radroots_transport::EventSink + ?Sized, { request.validate()?; let recovery_now_ms = sdk_now_ms(self.sdk)?; @@ -1313,7 +1314,7 @@ async fn radrootsd_delivery_policy( fn radrootsd_delivery_policy_from_remaining( ready_target_count: usize, required_remaining: usize, - required_remaining_targets: Option<&[RadrootsTransportTargetFingerprint]>, + required_remaining_targets: Option<&[TargetFingerprint]>, satisfaction_policy: &RadrootsTransportSatisfactionPolicy, ) -> Result<TransportPublishDeliveryPolicy, RadrootsSdkError> { reject_non_accepted_radrootsd_satisfaction(satisfaction_policy)?; @@ -1373,7 +1374,7 @@ fn radrootsd_delivery_policy_from_remaining( fn radrootsd_required_remaining_targets( satisfaction_policy: &RadrootsTransportSatisfactionPolicy, active_targets: &[&RadrootsOutboxDeliveryTargetRecord], -) -> Result<Option<Vec<RadrootsTransportTargetFingerprint>>, RadrootsSdkError> { +) -> Result<Option<Vec<TargetFingerprint>>, RadrootsSdkError> { let RadrootsTransportSatisfactionPolicy::RequiredTargets { class, targets } = satisfaction_policy else { @@ -1535,7 +1536,7 @@ fn radrootsd_transport_publish_target_policy( fn transport_publish_target_from_outbox_target( target: &RadrootsOutboxDeliveryTargetRecord, ) -> Result<TransportPublishTarget, RadrootsSdkError> { - if target.transport_kind != RadrootsTransportKind::Nostr { + if target.transport_kind != TransportId::NOSTR { return Err(RadrootsSdkError::InvalidRequest { message: format!( "radrootsd execution explicit targets are Nostr-only and cannot publish {} target {}", @@ -1930,7 +1931,7 @@ fn push_receipt_event_id(value: &str, field: &str) -> Result<EventId, RadrootsSd #[cfg(feature = "runtime")] fn push_target_receipt(target: RadrootsOutboxPublishTargetReceipt) -> PushOutboxTargetReceipt { PushOutboxTargetReceipt { - transport_kind: RadrootsTransportKind::Nostr.canonical_label(), + transport_kind: TransportId::NOSTR.canonical_label(), endpoint_uri: target.endpoint_uri, target_scope: target.target_scope, target_label: target.target_label, diff --git a/crates/sdk/src/transport.rs b/crates/sdk/src/transport.rs @@ -1,18 +1,22 @@ use crate::RadrootsSdkError; +use radroots_transport::target::{TargetFingerprint, TargetScope, TargetSet as TransportTargetSet}; use radroots_transport::{ - RADROOTS_RETICULUM_ENDPOINT_URI, RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE, RadrootsTransportCapabilityAvailability, RadrootsTransportCapabilityMaturity, - RadrootsTransportImplementationState, RadrootsTransportMeshScopeId, - RadrootsTransportSatisfactionPolicy, RadrootsTransportStatus, RadrootsTransportTarget, - RadrootsTransportTargetFingerprint, RadrootsTransportTargetSet, + RadrootsTransportImplementationState, RadrootsTransportSatisfactionPolicy, + RadrootsTransportStatus, Target, }; use radroots_transport_nostr::{RadrootsRelayUrlPolicy, RelayUrl}; +use radroots_transport_reticulum::{ + RADROOTS_RETICULUM_ENDPOINT_URI, RADROOTS_RETICULUM_SCOPE_ID, + RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE, +}; use serde::ser::{SerializeStruct, Serializer}; use std::collections::BTreeSet; pub use radroots_transport::{ - RadrootsTransportDeliveryReceipt, RadrootsTransportDeliveryTargetStatus, RadrootsTransportKind, + RadrootsTransportDeliveryReceipt, RadrootsTransportDeliveryTargetStatus, RadrootsTransportOutcome, RadrootsTransportSatisfactionClass, RadrootsTransportTargetReceipt, + TransportId, }; pub const SDK_TRANSPORT_TARGET_MAX_COUNT: usize = 20; @@ -43,10 +47,10 @@ pub enum SatisfactionPolicy { threshold: u16, }, RequiredAcceptedTargets { - target_fingerprints: Vec<RadrootsTransportTargetFingerprint>, + target_fingerprints: Vec<TargetFingerprint>, }, RequiredDeliveredTargets { - target_fingerprints: Vec<RadrootsTransportTargetFingerprint>, + target_fingerprints: Vec<TargetFingerprint>, }, } @@ -127,14 +131,14 @@ fn validate_satisfaction_threshold(threshold: u16) -> Result<(), RadrootsSdkErro fn required_target_fingerprints<I, S>( targets: I, -) -> Result<Vec<RadrootsTransportTargetFingerprint>, RadrootsSdkError> +) -> Result<Vec<TargetFingerprint>, RadrootsSdkError> where I: IntoIterator<Item = S>, S: AsRef<str>, { let fingerprints = targets .into_iter() - .map(|target| RadrootsTransportTargetFingerprint::parse(target.as_ref())) + .map(|target| TargetFingerprint::parse(target.as_ref())) .collect::<Result<Vec<_>, _>>()?; RadrootsTransportSatisfactionPolicy::required_targets( RadrootsTransportSatisfactionClass::Accepted, @@ -233,29 +237,29 @@ impl serde::Serialize for TargetPolicy { #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] #[serde(transparent)] -pub struct MeshScopeId(RadrootsTransportMeshScopeId); +pub struct MeshScopeId(TargetScope); impl MeshScopeId { pub fn parse(raw: impl AsRef<str>) -> Result<Self, RadrootsSdkError> { - Ok(Self(RadrootsTransportMeshScopeId::parse(raw)?)) + Ok(Self(TargetScope::parse(raw)?)) } pub fn local_reticulum() -> Self { - Self(RadrootsTransportMeshScopeId::local_reticulum()) + Self(TargetScope::parse(RADROOTS_RETICULUM_SCOPE_ID).expect("Reticulum scope")) } pub fn as_str(&self) -> &str { self.0.as_str() } - pub(crate) fn transport_scope(&self) -> RadrootsTransportMeshScopeId { + pub(crate) fn transport_scope(&self) -> TargetScope { self.0.clone() } } #[derive(Clone, Debug, PartialEq, Eq)] pub struct TargetSet { - targets: Vec<RadrootsTransportTarget>, + targets: Vec<Target>, canonical_targets: Vec<String>, } @@ -271,18 +275,16 @@ impl TargetSet { let mut targets = Vec::new(); for relay in relays { let normalized = normalized_nostr_relay_url(relay.as_ref(), policy)?; - targets.push(RadrootsTransportTarget::nostr_relay(normalized)?); + targets.push(Target::new(TransportId::NOSTR, normalized)?); } Self::from_transport_targets(targets) } - pub fn transport_targets( - targets: Vec<RadrootsTransportTarget>, - ) -> Result<Self, RadrootsSdkError> { + pub fn transport_targets(targets: Vec<Target>) -> Result<Self, RadrootsSdkError> { Self::from_transport_targets(targets) } - pub fn targets(&self) -> &[RadrootsTransportTarget] { + pub fn targets(&self) -> &[Target] { self.targets.as_slice() } @@ -290,19 +292,19 @@ impl TargetSet { self.canonical_targets.as_slice() } - pub fn transport_target_set(&self) -> Result<RadrootsTransportTargetSet, RadrootsSdkError> { - Ok(RadrootsTransportTargetSet::new(self.targets.clone())?) + pub fn transport_target_set(&self) -> Result<TransportTargetSet, RadrootsSdkError> { + Ok(TransportTargetSet::new(self.targets.clone())?) } pub fn nostr_relay_urls(&self) -> Vec<String> { self.targets .iter() - .filter(|target| target.kind() == &RadrootsTransportKind::Nostr) + .filter(|target| target.kind() == &TransportId::NOSTR) .map(|target| target.uri().as_str().to_owned()) .collect() } - pub fn into_targets(self) -> Vec<RadrootsTransportTarget> { + pub fn into_targets(self) -> Vec<Target> { self.targets } @@ -314,9 +316,7 @@ impl TargetSet { self.targets.is_empty() } - fn from_transport_targets( - targets: Vec<RadrootsTransportTarget>, - ) -> Result<Self, RadrootsSdkError> { + fn from_transport_targets(targets: Vec<Target>) -> Result<Self, RadrootsSdkError> { if targets.is_empty() { return Err(RadrootsSdkError::empty_transport_targets( "sdk transport target set", @@ -329,7 +329,7 @@ impl TargetSet { )); } for target in &targets { - if target.kind() == &RadrootsTransportKind::Reticulum + if target.kind() == &TransportId::RETICULUM && target.uri().as_str() != RADROOTS_RETICULUM_ENDPOINT_URI { return Err(RadrootsSdkError::InvalidRequest { @@ -339,7 +339,7 @@ impl TargetSet { }); } } - RadrootsTransportTargetSet::new(targets.clone())?; + TransportTargetSet::new(targets.clone())?; let canonical_targets = targets .iter() .map(|target| target.fingerprint().to_string()) @@ -440,10 +440,11 @@ impl ReticulumProfile { } pub fn target_set(&self) -> Result<TargetSet, RadrootsSdkError> { - if self.endpoint_uri.as_str() != radroots_transport::RADROOTS_RETICULUM_ENDPOINT_URI { + if self.endpoint_uri.as_str() != RADROOTS_RETICULUM_ENDPOINT_URI { return Err(radroots_transport::RadrootsTransportError::InvalidTargetUri.into()); } - TargetSet::transport_targets(vec![RadrootsTransportTarget::reticulum_with_metadata( + TargetSet::transport_targets(vec![Target::new_with_metadata( + TransportId::RETICULUM, self.endpoint_uri.as_str(), Some(self.scope.transport_scope()), None, @@ -639,9 +640,7 @@ impl TransportProfile { } } - pub(crate) fn configured_transport_targets( - &self, - ) -> Result<Vec<RadrootsTransportTarget>, RadrootsSdkError> { + pub(crate) fn configured_transport_targets(&self) -> Result<Vec<Target>, RadrootsSdkError> { Ok(self .target_set()? .map(TargetSet::into_targets) @@ -652,7 +651,7 @@ impl TransportProfile { match self { Self::LocalOnly => vec![ RadrootsTransportStatus::new( - RadrootsTransportKind::Local, + TransportId::LOCAL, true, RadrootsTransportImplementationState::Real, false, @@ -688,7 +687,7 @@ impl TransportProfile { fn nostr_transport_status(profile_id: &str) -> RadrootsTransportStatus { RadrootsTransportStatus::new( - RadrootsTransportKind::Nostr, + TransportId::NOSTR, true, RadrootsTransportImplementationState::Real, true, @@ -699,7 +698,7 @@ fn nostr_transport_status(profile_id: &str) -> RadrootsTransportStatus { fn reticulum_transport_status(profile_id: &str, endpoint_uri: &str) -> RadrootsTransportStatus { RadrootsTransportStatus::new( - RadrootsTransportKind::Reticulum, + TransportId::RETICULUM, true, RadrootsTransportImplementationState::Real, false, @@ -724,7 +723,7 @@ impl From<RadrootsTransportDeliveryReceipt> for TransportReceipt { #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] pub struct TransportReceipt { request_id: String, - target_set: RadrootsTransportTargetSet, + target_set: TransportTargetSet, target_receipts: Vec<RadrootsTransportTargetReceipt>, } @@ -733,7 +732,7 @@ impl TransportReceipt { self.request_id.as_str() } - pub fn target_set(&self) -> &RadrootsTransportTargetSet { + pub fn target_set(&self) -> &TransportTargetSet { &self.target_set } diff --git a/crates/sdk/src/workflow_runtime.rs b/crates/sdk/src/workflow_runtime.rs @@ -23,9 +23,8 @@ use radroots_signing::{ Actor, SignRequest, Signer, request::{CancellationPolicy, SignPolicy}, }; -use radroots_transport::{ - RADROOTS_RETICULUM_ENDPOINT_URI, RadrootsTransportKind, RadrootsTransportTarget, -}; +use radroots_transport::{Target, TransportId}; +use radroots_transport_reticulum::RADROOTS_RETICULUM_ENDPOINT_URI; use sha2::{Digest, Sha256}; use sqlx::Row; @@ -221,7 +220,7 @@ async fn enqueue_signed_workflow_event( })?; ensure_runtime_operation_can_commit(&mut tx, request, &idempotency_key).await?; let local_import_observation = RadrootsTransportObservation::new( - RadrootsTransportKind::Local, + TransportId::LOCAL, SDK_LOCAL_EVENT_ENDPOINT_URI, RadrootsTransportObservationType::LocalImport, observed_at_ms, @@ -300,7 +299,7 @@ async fn enqueue_signed_trade_workflow_event( })?; ensure_runtime_operation_can_commit(&mut tx, request, &idempotency_key).await?; let local_import_observation = RadrootsTransportObservation::new( - RadrootsTransportKind::Local, + TransportId::LOCAL, SDK_LOCAL_EVENT_ENDPOINT_URI, RadrootsTransportObservationType::LocalImport, observed_at_ms, @@ -411,13 +410,12 @@ fn resolved_delivery_plan( ) } TargetPolicy::MeshScope(scope) => { - let target_set = TargetSet::transport_targets(vec![ - RadrootsTransportTarget::reticulum_with_metadata( - RADROOTS_RETICULUM_ENDPOINT_URI, - Some(scope.transport_scope()), - None, - )?, - ])?; + let target_set = TargetSet::transport_targets(vec![Target::new_with_metadata( + TransportId::RETICULUM, + RADROOTS_RETICULUM_ENDPOINT_URI, + Some(scope.transport_scope()), + None, + )?])?; delivery_plan_from_targets( "mesh_scope", target_set.into_targets(), @@ -430,7 +428,7 @@ fn resolved_delivery_plan( fn delivery_plan_from_targets( transport_profile_id: impl Into<String>, - targets: Vec<RadrootsTransportTarget>, + targets: Vec<Target>, satisfaction_policy: &SatisfactionPolicy, reticulum_behavior: RadrootsOutboxReticulumBehavior, ) -> Result<SdkResolvedDeliveryPlan, RadrootsSdkError> { @@ -446,11 +444,11 @@ fn delivery_plan_from_targets( fn reticulum_behavior_for_targets( transport_profile: &TransportProfile, - targets: &[RadrootsTransportTarget], + targets: &[Target], ) -> RadrootsOutboxReticulumBehavior { if targets .iter() - .any(|target| target.kind() == &RadrootsTransportKind::Reticulum) + .any(|target| target.kind() == &TransportId::RETICULUM) { outbox_reticulum_behavior(transport_profile) } else { diff --git a/crates/sdk/tests/source_boundary.rs b/crates/sdk/tests/source_boundary.rs @@ -113,6 +113,34 @@ fn active_sources_do_not_import_retired_listing_contracts() { } #[test] +fn active_sources_use_canonical_transport_type_names() { + for path in active_source_files() { + let source = read_source(&path); + for retired in [ + "RadrootsTransportKind", + "RadrootsTransportMeshScopeId", + "RadrootsTransportTarget", + "RadrootsTransportTargetFingerprint", + "RadrootsTransportTargetLabel", + "RadrootsTransportTargetSet", + ] { + let restores_identifier = source.match_indices(retired).any(|(index, _)| { + let before = source[..index].chars().next_back(); + let after = source[index + retired.len()..].chars().next(); + before.is_none_or(|character| !(character.is_alphanumeric() || character == '_')) + && after + .is_none_or(|character| !(character.is_alphanumeric() || character == '_')) + }); + assert!( + !restores_identifier, + "{} must use the canonical transport type instead of `{retired}`", + path.display() + ); + } + } +} + +#[test] fn active_sources_do_not_describe_compatibility_paths() { for path in active_source_files() { let source = read_source(&path).to_lowercase(); diff --git a/crates/sdk/tests/sync_runtime.rs b/crates/sdk/tests/sync_runtime.rs @@ -31,15 +31,14 @@ use radroots_sdk::{ StorageStatusRequest, SyncStatusRequest, SyncStatusSource, TargetPolicy, TransportProfile, }; use radroots_signing::{Actor, actor::ActorSource}; -use radroots_transport::{ - RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE, RadrootsTransportMeshScopeId, - RadrootsTransportSatisfactionPolicy, RadrootsTransportTarget, RadrootsTransportTargetLabel, -}; +use radroots_transport::target::{TargetLabel, TargetScope}; +use radroots_transport::{RadrootsTransportSatisfactionPolicy, Target, TransportId}; use radroots_transport_nostr::{ RadrootsMockRelayPublishAdapter, RadrootsNostrTransport, RadrootsRelayOutcome, RadrootsRelayPublishAdapter, RadrootsRelayPublishRelayReceipt, RadrootsRelayPublishRequest, RadrootsRelayTransportError, }; +use radroots_transport_reticulum::RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE; #[cfg(feature = "radrootsd-execution")] use std::io::{Read, Write}; #[cfg(feature = "radrootsd-execution")] @@ -602,11 +601,12 @@ fn scoped_duplicate_relay_delivery_plan( ) } -fn scoped_nostr_target(relay: &str, scope: &str, label: &str) -> RadrootsTransportTarget { - RadrootsTransportTarget::nostr_relay_with_metadata( +fn scoped_nostr_target(relay: &str, scope: &str, label: &str) -> Target { + Target::new_with_metadata( + TransportId::NOSTR, relay, - Some(RadrootsTransportMeshScopeId::parse(scope).expect("target scope")), - Some(RadrootsTransportTargetLabel::parse(label).expect("target label")), + Some(TargetScope::parse(scope).expect("target scope")), + Some(TargetLabel::parse(label).expect("target label")), ) .expect("scoped Nostr target") } @@ -1746,7 +1746,7 @@ async fn product_push_outbox_uses_radrootsd_execution_transport_with_daemon_reso assert_eq!(pre_push_targets.len(), 1); assert_eq!( pre_push_targets[0].transport_kind, - radroots_sdk::RadrootsTransportKind::Nostr + radroots_sdk::TransportId::NOSTR ); assert_eq!( pre_push_targets[0].status, @@ -2753,7 +2753,7 @@ async fn push_outbox_with_transport_scopes_duplicate_endpoint_sibling_plans() { 1, radroots_transport::RadrootsTransportSatisfactionPolicy::all_accepted(), vec![ - radroots_transport::RadrootsTransportTarget::nostr_relay(RELAY_A) + radroots_transport::Target::new(TransportId::NOSTR, RELAY_A) .expect("second target"), ], ), diff --git a/crates/sdk/tests/unit/adapters_radrootsd_tests.rs b/crates/sdk/tests/unit/adapters_radrootsd_tests.rs @@ -10,7 +10,7 @@ use radroots_protocol::radrootsd::transport_publish::v5::{ TargetOutcome as TransportPublishTargetOutcome, TargetPolicy as TransportPublishTargetPolicy, TargetSource as TransportPublishTargetSource, }; -use radroots_transport::RADROOTS_RETICULUM_ENDPOINT_URI; +use radroots_transport_reticulum::RADROOTS_RETICULUM_ENDPOINT_URI; use std::io::{Read, Write}; use std::net::TcpListener; use std::thread::JoinHandle; diff --git a/crates/sdk/tests/unit/sync_runtime_tests.rs b/crates/sdk/tests/unit/sync_runtime_tests.rs @@ -51,10 +51,8 @@ use radroots_signing::{ Actor, Error as SigningError, SignReceipt, SignRequest, Signer, SignerStatus, actor::ActorSource, error::Kind as SigningErrorKind, signer::BoxFuture as SigningFuture, }; -use radroots_transport::{ - RadrootsTransportDeliveryTargetStatus, RadrootsTransportMeshScopeId, RadrootsTransportTarget, - RadrootsTransportTargetLabel, -}; +use radroots_transport::target::{TargetLabel, TargetScope}; +use radroots_transport::{RadrootsTransportDeliveryTargetStatus, Target, TransportId}; #[cfg(feature = "radrootsd-execution")] use radroots_transport::{RadrootsTransportSatisfactionClass, RadrootsTransportSatisfactionPolicy}; use radroots_transport_nostr::{ @@ -233,7 +231,7 @@ async fn claimed_uningested_radrootsd_event_with_satisfaction( .expect("sdk"); let draft = radrootsd_frozen_draft(d_tag); let radrootsd_target = - RadrootsTransportTarget::nostr_relay("wss://relay.example.com").expect("Nostr target"); + Target::new(TransportId::NOSTR, "wss://relay.example.com").expect("Nostr target"); let enqueue = sdk ._outbox .enqueue_operation( @@ -313,12 +311,12 @@ fn assert_no_transport_publish_request(listener: &TcpListener) { fn delivery_target_record( delivery_target_id: i64, delivery_plan_id: i64, - target: &RadrootsTransportTarget, + target: &Target, ) -> RadrootsOutboxDeliveryTargetRecord { RadrootsOutboxDeliveryTargetRecord { delivery_target_id, delivery_plan_id, - transport_kind: target.kind().clone(), + transport_kind: *target.kind(), endpoint_uri: target.uri().clone(), target_scope: target.scope().cloned(), target_label: target.label().cloned(), @@ -869,12 +867,12 @@ async fn radrootsd_push_empty_queue_and_private_helpers_are_deterministic() { .expect("any-target radrootsd policy"), TransportPublishDeliveryPolicy::Any ); - let first_required = RadrootsTransportTarget::nostr_relay("wss://required-a.example.com") + let first_required = Target::new(TransportId::NOSTR, "wss://required-a.example.com") .expect("first required target"); - let second_required = RadrootsTransportTarget::nostr_relay("wss://required-b.example.com") + let second_required = Target::new(TransportId::NOSTR, "wss://required-b.example.com") .expect("second required target"); - let optional = RadrootsTransportTarget::nostr_relay("wss://optional.example.com") - .expect("optional target"); + let optional = + Target::new(TransportId::NOSTR, "wss://optional.example.com").expect("optional target"); let policy = RadrootsTransportSatisfactionPolicy::required_targets( RadrootsTransportSatisfactionClass::Accepted, vec![ @@ -1011,11 +1009,11 @@ async fn radrootsd_delivery_policy_rejects_non_accepted_satisfaction_before_daem #[cfg(feature = "radrootsd-execution")] #[test] fn radrootsd_outbox_target_conversion_rejects_reticulum_targets_before_behavior_loss() { - let target = RadrootsTransportTarget::reticulum().expect("Reticulum target"); + let target = Target::reticulum().expect("Reticulum target"); let record = RadrootsOutboxDeliveryTargetRecord { delivery_target_id: 1, delivery_plan_id: 1, - transport_kind: target.kind().clone(), + transport_kind: *target.kind(), endpoint_uri: target.uri().clone(), target_scope: target.scope().cloned(), target_label: target.label().cloned(), @@ -1043,10 +1041,11 @@ fn radrootsd_outbox_target_conversion_rejects_reticulum_targets_before_behavior_ #[cfg(feature = "radrootsd-execution")] #[test] fn radrootsd_outbox_target_conversion_preserves_nostr_scope_and_label() { - let target = RadrootsTransportTarget::nostr_relay_with_metadata( + let target = Target::new_with_metadata( + TransportId::NOSTR, "wss://relay.example.com", - Some(RadrootsTransportMeshScopeId::parse("farm.local").expect("scope")), - Some(RadrootsTransportTargetLabel::parse("Farm relay").expect("label")), + Some(TargetScope::parse("farm.local").expect("scope")), + Some(TargetLabel::parse("Farm relay").expect("label")), ) .expect("scoped Nostr target"); let record = delivery_target_record(1, 1, &target); @@ -1191,8 +1190,8 @@ async fn radrootsd_local_validation_errors_release_claim_before_daemon_publish() .expect("stored before"); assert!(!stored_before.event_store_ingested); assert_eq!(stored_before.event_store_ingested_at_ms, None); - let reticulum_target = RadrootsTransportTarget::reticulum().expect("Reticulum target"); - claimed.delivery_targets[0].transport_kind = reticulum_target.kind().clone(); + let reticulum_target = Target::reticulum().expect("Reticulum target"); + claimed.delivery_targets[0].transport_kind = *reticulum_target.kind(); claimed.delivery_targets[0].endpoint_uri = reticulum_target.uri().clone(); claimed.delivery_targets[0].endpoint_fingerprint = reticulum_target.fingerprint().clone(); let sync = sdk.sync(); @@ -1259,7 +1258,7 @@ async fn radrootsd_local_validation_failure_keeps_sibling_plan_ready_and_claimab 1, RadrootsTransportSatisfactionPolicy::all_accepted(), vec![ - RadrootsTransportTarget::nostr_relay("wss://active.example.com") + Target::new(TransportId::NOSTR, "wss://active.example.com") .expect("active target"), ], ), @@ -1283,7 +1282,7 @@ async fn radrootsd_local_validation_failure_keeps_sibling_plan_ready_and_claimab 1, RadrootsTransportSatisfactionPolicy::all_accepted(), vec![ - RadrootsTransportTarget::nostr_relay("wss://sibling.example.com") + Target::new(TransportId::NOSTR, "wss://sibling.example.com") .expect("sibling target"), ], ), @@ -1321,8 +1320,8 @@ async fn radrootsd_local_validation_failure_keeps_sibling_plan_ready_and_claimab .expect("stored before"); let ingested_before = stored_before.event_store_ingested; let ingested_at_before = stored_before.event_store_ingested_at_ms; - let reticulum_target = RadrootsTransportTarget::reticulum().expect("Reticulum target"); - claimed.delivery_targets[0].transport_kind = reticulum_target.kind().clone(); + let reticulum_target = Target::reticulum().expect("Reticulum target"); + claimed.delivery_targets[0].transport_kind = *reticulum_target.kind(); claimed.delivery_targets[0].endpoint_uri = reticulum_target.uri().clone(); claimed.delivery_targets[0].endpoint_fingerprint = reticulum_target.fingerprint().clone(); let sync = sdk.sync(); @@ -1526,16 +1525,18 @@ async fn radrootsd_completion_matches_duplicate_endpoint_targets_by_scope() { let signed_event = RadrootsdFixtureSigner::new() .sign_frozen_draft(&draft) .expect("signed event"); - let farm_a = RadrootsTransportTarget::nostr_relay_with_metadata( + let farm_a = Target::new_with_metadata( + TransportId::NOSTR, "wss://relay.example.com", - Some(RadrootsTransportMeshScopeId::parse("farm.a").expect("farm a scope")), - Some(RadrootsTransportTargetLabel::parse("Farm A").expect("farm a label")), + Some(TargetScope::parse("farm.a").expect("farm a scope")), + Some(TargetLabel::parse("Farm A").expect("farm a label")), ) .expect("farm a target"); - let farm_b = RadrootsTransportTarget::nostr_relay_with_metadata( + let farm_b = Target::new_with_metadata( + TransportId::NOSTR, "wss://relay.example.com", - Some(RadrootsTransportMeshScopeId::parse("farm.b").expect("farm b scope")), - Some(RadrootsTransportTargetLabel::parse("Farm B").expect("farm b label")), + Some(TargetScope::parse("farm.b").expect("farm b scope")), + Some(TargetLabel::parse("Farm B").expect("farm b label")), ) .expect("farm b target"); let enqueue = sdk @@ -1736,10 +1737,11 @@ impl OutboxPublishReceiptFixture for RadrootsOutboxPublishReceipt { .push(RadrootsOutboxPublishTargetReceipt { delivery_target_id: 10, endpoint_uri: "wss://relay.example.com".to_owned(), - endpoint_fingerprint: RadrootsTransportTarget::nostr_relay_with_metadata( + endpoint_fingerprint: Target::new_with_metadata( + TransportId::NOSTR, "wss://relay.example.com", - Some(RadrootsTransportMeshScopeId::parse("farm.local").expect("scope")), - Some(RadrootsTransportTargetLabel::parse("Farm relay").expect("label")), + Some(TargetScope::parse("farm.local").expect("scope")), + Some(TargetLabel::parse("Farm relay").expect("label")), ) .expect("target") .fingerprint() diff --git a/crates/sdk/tests/unit/transport_tests.rs b/crates/sdk/tests/unit/transport_tests.rs @@ -4,10 +4,8 @@ use super::{ TransportProfile, }; use crate::{RadrootsSdkError, SDK_TRANSPORT_TARGET_MAX_COUNT}; -use radroots_transport::{ - RADROOTS_RETICULUM_ENDPOINT_URI, RadrootsTransportError, RadrootsTransportKind, - RadrootsTransportTarget, -}; +use radroots_transport::{RadrootsTransportError, Target, TransportId}; +use radroots_transport_reticulum::RADROOTS_RETICULUM_ENDPOINT_URI; use crate::serializer_failure::assert_struct_serialize_error_paths; @@ -208,10 +206,10 @@ fn target_sets_reject_duplicate_transport_fingerprints() { if message == "transport target set contains duplicate fingerprints" )); - let first = RadrootsTransportTarget::nostr_relay("wss://relay-a.example.com/path") - .expect("first target"); - let second = RadrootsTransportTarget::nostr_relay("WSS://RELAY-A.EXAMPLE.COM/path") - .expect("second target"); + let first = + Target::new(TransportId::NOSTR, "wss://relay-a.example.com/path").expect("first target"); + let second = + Target::new(TransportId::NOSTR, "WSS://RELAY-A.EXAMPLE.COM/path").expect("second target"); let duplicate_targets = TargetSet::transport_targets(vec![first, second]).expect_err("duplicate targets"); @@ -306,7 +304,7 @@ fn explicit_target_sets_reject_noncanonical_reticulum_endpoints() { "reticulum:custom".to_owned(), ] { assert_eq!( - RadrootsTransportTarget::new(RadrootsTransportKind::Reticulum, invalid.as_str()) + Target::new(TransportId::RETICULUM, invalid.as_str()) .expect_err("invalid Reticulum target"), RadrootsTransportError::InvalidTargetUri );