lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

commit c83fff8939521ded3f013ba3887433e31ce436cc
parent fcd644e80c3e7a94308b640c300271d1ca682e3a
Author: triesap <tyson@radroots.org>
Date:   Mon, 13 Apr 2026 01:49:04 +0000

sdk: add sdk-first publish acceptance proofs

Diffstat:
Mcrates/sdk/src/adapters/radrootsd.rs | 26++++++++++++++++++++++----
Mcrates/sdk/src/client.rs | 27+++++++++++++++++++++++++++
Mcrates/sdk/tests/radrootsd.rs | 36+++++++++++++++++++++++++-----------
Mcrates/sdk/tests/relay_direct.rs | 5+++--
4 files changed, 77 insertions(+), 17 deletions(-)

diff --git a/crates/sdk/src/adapters/radrootsd.rs b/crates/sdk/src/adapters/radrootsd.rs @@ -1,6 +1,8 @@ use core::time::Duration; +use crate::RadrootsNostrEvent; use crate::config::RadrootsdAuth; +use crate::listing; use crate::listing::RadrootsListing; use reqwest::header::{AUTHORIZATION, CONTENT_TYPE, HeaderMap, HeaderValue}; use serde::{Deserialize, Serialize}; @@ -26,6 +28,23 @@ pub struct SdkRadrootsdListingPublishRequest { pub idempotency_key: Option<String>, } +impl SdkRadrootsdListingPublishRequest { + pub fn from_event( + event: &RadrootsNostrEvent, + signer_session_id: impl Into<String>, + signer_authority: Option<SdkRadrootsdSignerAuthority>, + idempotency_key: Option<String>, + ) -> Result<Self, listing::RadrootsTradeListingParseError> { + Ok(Self { + listing: listing::parse_event(event)?, + kind: Some(event.kind), + signer_session_id: signer_session_id.into(), + signer_authority, + idempotency_key, + }) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] pub struct SdkRadrootsdBridgePublishResponse { pub deduplicated: bool, @@ -108,10 +127,9 @@ pub async fn publish_listing( request_builder = request_builder.header(CONTENT_TYPE, "application/json"); - let response = request_builder - .send() - .await - .map_err(|err| RadrootsdError::Http(format!("send radrootsd listing publish request: {err}")))?; + let response = request_builder.send().await.map_err(|err| { + RadrootsdError::Http(format!("send radrootsd listing publish request: {err}")) + })?; let status = response.status(); let body = response .text() diff --git a/crates/sdk/src/client.rs b/crates/sdk/src/client.rs @@ -199,6 +199,14 @@ impl RadrootsSdkClient { TradeClient { client: self } } + #[cfg(any( + feature = "radrootsd-client", + all( + feature = "identity-models", + feature = "relay-client", + feature = "signing" + ) + ))] fn require_signer_mode( &self, required: SignerConfig, @@ -391,6 +399,25 @@ impl<'a> ListingClient<'a> { .await } + #[cfg(all( + feature = "identity-models", + feature = "relay-client", + feature = "signing" + ))] + pub async fn publish_draft_with_identity( + &self, + identity: &RadrootsIdentity, + draft: WireEventParts, + ) -> Result<SdkPublishReceipt, SdkPublishError> { + self.client + .publish_parts_via_relay_with_identity( + identity, + draft, + "listing.publish_draft_with_identity", + ) + .await + } + #[cfg(feature = "radrootsd-client")] pub async fn publish_via_radrootsd( &self, diff --git a/crates/sdk/tests/radrootsd.rs b/crates/sdk/tests/radrootsd.rs @@ -10,9 +10,9 @@ use radroots_sdk::listing::{ RadrootsListingProduct, RadrootsListingStatus, }; use radroots_sdk::{ - RadrootsSdkClient, RadrootsSdkConfig, RadrootsdAuth, RadrootsdConfig, SdkEnvironment, - SdkPublishError, SdkRadrootsdListingPublishRequest, SdkTransportMode, SdkTransportReceipt, - SignerConfig, + RadrootsNostrEvent, RadrootsSdkClient, RadrootsSdkConfig, RadrootsdAuth, RadrootsdConfig, + SdkEnvironment, SdkPublishError, SdkRadrootsdListingPublishRequest, SdkTransportMode, + SdkTransportReceipt, SignerConfig, WireEventParts, }; use serde_json::{Value, json}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; @@ -238,8 +238,20 @@ fn sample_listing() -> RadrootsListing { } } +fn sdk_event(author: &str, created_at: u32, parts: WireEventParts) -> RadrootsNostrEvent { + RadrootsNostrEvent { + id: "event-1".to_owned(), + author: author.to_owned(), + created_at, + kind: parts.kind, + tags: parts.tags, + content: parts.content, + sig: "f".repeat(128), + } +} + #[tokio::test] -async fn radrootsd_listing_publish_returns_normalized_receipt() -> TestResult<()> { +async fn radrootsd_listing_publish_accepts_sdk_built_draft() -> TestResult<()> { let (server, request_rx) = JsonRpcServer::spawn( Some("Bearer sdk-secret"), json!({ @@ -274,13 +286,14 @@ async fn radrootsd_listing_publish_returns_normalized_receipt() -> TestResult<() auth: RadrootsdAuth::BearerToken("sdk-secret".to_owned()), }; let client = RadrootsSdkClient::from_config(config)?; - let request = SdkRadrootsdListingPublishRequest { - listing: sample_listing(), - kind: None, - signer_session_id: "session-123".to_owned(), - signer_authority: None, - idempotency_key: Some("idem-1".to_owned()), - }; + let draft = client.listing().build_draft(&sample_listing())?; + let event = sdk_event("seller", 1_720_000_000, draft); + let request = SdkRadrootsdListingPublishRequest::from_event( + &event, + "session-123", + None, + Some("idem-1".to_owned()), + )?; let receipt = client.listing().publish_via_radrootsd(&request).await?; let request_json = request_rx.await?; @@ -288,6 +301,7 @@ async fn radrootsd_listing_publish_returns_normalized_receipt() -> TestResult<() assert_eq!(request_json["method"], "bridge.listing.publish"); assert_eq!(request_json["params"]["signer_session_id"], "session-123"); assert_eq!(request_json["params"]["idempotency_key"], "idem-1"); + assert_eq!(request_json["params"]["kind"], 30402); assert_eq!( request_json["params"]["listing"]["d_tag"], "AAAAAAAAAAAAAAAAAAAAAg" diff --git a/crates/sdk/tests/relay_direct.rs b/crates/sdk/tests/relay_direct.rs @@ -161,7 +161,7 @@ fn sample_listing() -> RadrootsListing { } #[tokio::test] -async fn relay_direct_listing_publish_returns_normalized_receipt() -> TestResult<()> { +async fn relay_direct_listing_publish_accepts_sdk_built_draft() -> TestResult<()> { let relay = AckRelay::spawn().await?; let identity = RadrootsIdentity::generate(); let mut config = RadrootsSdkConfig::for_environment(SdkEnvironment::Custom); @@ -175,10 +175,11 @@ async fn relay_direct_listing_publish_returns_normalized_receipt() -> TestResult auth: RadrootsdAuth::None, }; let client = RadrootsSdkClient::from_config(config)?; + let draft = client.listing().build_draft(&sample_listing())?; let receipt = client .listing() - .publish_with_identity(&identity, &sample_listing()) + .publish_draft_with_identity(&identity, draft) .await?; assert_eq!(receipt.transport, SdkTransportMode::RelayDirect);