lib

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

commit 93ca97a75b53d83a4c4fcc8d23e7b5437d5dbab5
parent 731029342394b7253a20818d07806f06a7c68f29
Author: triesap <tyson@radroots.org>
Date:   Thu, 16 Jul 2026 12:46:45 +0000

sdk: harden release product bindings

- remove retired order operations and DTO roots from active package contracts
- publish canonical trade capability and error catalog surfaces
- switch MYC NIP-46 permissions to canonical trade mutation kinds
- regenerate TypeScript bindings with canonical trade counters

Diffstat:
Mcrates/event_bindings/src/lib.rs | 5+++--
Mcrates/event_bindings/src/model.rs | 18+++++++++++++-----
Mcrates/sdk/README | 31++++++++++++++++---------------
Mcrates/sdk/examples/sdk_v1_myc_nip46_signer_setup.rs | 7+++++++
Mcrates/sdk/src/error.rs | 347+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcrates/sdk/src/lib.rs | 22++++++++++++++--------
Mcrates/sdk/src/signer_provider.rs | 13++++++++-----
Mcrates/sdk/src/trade_runtime.rs | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mcrates/sdk/tests/unit/error_tests.rs | 71++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mcrates/sdk/tests/unit/signer_provider_tests.rs | 12+++++++++---
Mcrates/sdk/tests/unit/trade_runtime_tests.rs | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mcrates/trade_bindings/src/dto.rs | 20++++++++++----------
Mcrates/trade_bindings/src/lib.rs | 24++++++++++++------------
Mtools/sdk_xtask_import/src/dto_roots.rs | 47+++++++++++++++++++++++++++++++----------------
14 files changed, 733 insertions(+), 82 deletions(-)

diff --git a/crates/event_bindings/src/lib.rs b/crates/event_bindings/src/lib.rs @@ -18,7 +18,8 @@ mod tests { assert!(constants.contains(RADROOTS_LISTING_PRODUCT_TAG_KEYS[0])); assert!(kinds_ts.contains("KIND_LISTING")); assert!(kinds_ts.contains(&kinds::KIND_LISTING.to_string())); - assert!(kinds_ts.contains("KIND_ORDER_REQUEST")); - assert!(kinds_ts.contains(&kinds::KIND_ORDER_REQUEST.to_string())); + assert!(kinds_ts.contains("KIND_TRADE_PROPOSAL")); + assert!(kinds_ts.contains(&kinds::KIND_TRADE_PROPOSAL.to_string())); + assert!(!kinds_ts.contains("KIND_ORDER_REQUEST")); } } diff --git a/crates/event_bindings/src/model.rs b/crates/event_bindings/src/model.rs @@ -113,12 +113,20 @@ const EVENT_KIND_EXPORTS: &[(&str, u32)] = &[ ("KIND_APP_DATA", kinds::KIND_APP_DATA), ("KIND_LISTING", kinds::KIND_LISTING), ("KIND_APPLICATION_HANDLER", kinds::KIND_APPLICATION_HANDLER), - ("KIND_ORDER_REQUEST", kinds::KIND_ORDER_REQUEST), - ("KIND_ORDER_DECISION", kinds::KIND_ORDER_DECISION), - ("KIND_ORDER_CANCELLATION", kinds::KIND_ORDER_CANCELLATION), + ("KIND_TRADE_PROPOSAL", kinds::KIND_TRADE_PROPOSAL), + ("KIND_TRADE_DECISION", kinds::KIND_TRADE_DECISION), ( - "KIND_TRADE_FORBIDDEN_3431", - kinds::KIND_TRADE_FORBIDDEN_3431, + "KIND_TRADE_REVISION_PROPOSAL", + kinds::KIND_TRADE_REVISION_PROPOSAL, + ), + ( + "KIND_TRADE_REVISION_DECISION", + kinds::KIND_TRADE_REVISION_DECISION, + ), + ("KIND_TRADE_CANCELLATION", kinds::KIND_TRADE_CANCELLATION), + ( + "KIND_TRADE_SELLER_RESERVATION_ASSERTION", + kinds::KIND_TRADE_SELLER_RESERVATION_ASSERTION, ), ( "KIND_TRADE_VALIDATION_RECEIPT", diff --git a/crates/sdk/README b/crates/sdk/README @@ -41,18 +41,17 @@ and radrootsd execution consume signed outbox events; neither path owns signing. `push_outbox_with_transport(...)` remains available for tests and controlled transport-level substrate checks. `radrootsd-execution` adds daemon-resolved publishing through `publish.event`. -`sdk.trades()` exposes the local trade runtime surface. With `runtime`, callers can ingest local trade -evidence, read `sdk.trades().status(...)`, resync through `sdk.trades().resync()`, inspect -validation receipts through `sdk.trades().validation_receipts()`, and read seller inbox projections -through `sdk.trades().seller()`. -`sdk.trades().status(...)` accepts `TradeStatusRequest` and reads local projections; it returns typed -source, event count, limit state, event IDs, ambiguity candidates, eligibility, next-action, and -reducer issue data. Status is not a network fetch. - -Configured-signer trade writes compile when both `runtime` and `signer-adapters` are enabled. Buyer -write workflows use `sdk.trades().buyer()` for propose and cancel actions. Seller write workflows -use `sdk.trades().seller()` for accept and decline actions. Runtime-only builds intentionally expose -no buyer write handle and no trade mutation request DTOs. +`sdk.trades()` exposes the local trade runtime surface. With `runtime`, callers can read +`sdk.trades().capabilities()`, seal/open/delete protected private artifacts, issue semantic trade +commands through `sdk.trades().commands()`, and read semantic projections through +`sdk.trades().queries()`. Query methods read local projections and evidence; they are not network +fetches. + +Configured-signer trade writes compile when both `runtime` and `signer-adapters` are enabled. +Trade write workflows use `SubmitProposalRequest`, `ProposeRevisionRequest`, +`DecideCandidateRequest`, `CancelTradeRequest`, and `ResumeOperationRequest` through the command +service. Runtime-only builds keep explicit-signer methods available and do not expose a parallel +buyer/seller workflow namespace. The `local-runtime` feature is the curated feature bundle for local product runtime consumers. It enables `std`, `serde`, `serde_json`, `runtime`, `signer-adapters`, `transport-nostr-runtime`, and @@ -64,7 +63,7 @@ targets Nostr relay URLs. `local-runtime-radrootsd-execution` uses daemon-resolv `radroots_sdk_myc_nip46_product_permissions()` and `radroots_sdk_myc_nip46_product_permission_strings()` expose the SDK product NIP-46 `sign_event:<kind>` permission set for Myc connection setup. The set is derived from the farm, -listing, and trade event kinds the SDK can write. +listing, and canonical trade mutation event kinds the SDK can write. Relay URL policy is explicit. Public relay URLs must use `wss://`. Local development `ws://` relay URLs are accepted only under `NostrRelayUrlPolicy::Localhost` and only for `localhost`, `127.0.0.1`, @@ -92,7 +91,7 @@ preparation, signed-event verification, decoded event matching, and manifest has local runtime storage. `sdk_v1_local_enqueue_and_mock_sync` shows localhost Nostr target selection, configured local-key signing, prepared listing enqueue, `push_outbox_with_transport(...)` with a Nostr transport facade, and -`TradeStatusRequest`. `sdk_v1_myc_nip46_signer_setup` shows Myc NIP-46 signer provider setup and +queued outbox sync. `sdk_v1_myc_nip46_signer_setup` shows Myc NIP-46 signer provider setup and product permission derivation at the SDK boundary. The examples stay on product APIs and do not use wire-event internals. @@ -118,7 +117,9 @@ stable method surface: `code`, `class`, `retryable`, `detail_json`, and `recover ## Runtime DTO Stability Runtime request DTOs are constructor-led and marked non-exhaustive where they carry public fields: -`ListingPreparePublishRequest`, `ListingEnqueuePublishRequest`, `TradeStatusRequest`, +`ListingPreparePublishRequest`, `ListingEnqueuePublishRequest`, `SubmitProposalRequest`, +`ProposeRevisionRequest`, `DecideCandidateRequest`, `CancelTradeRequest`, `ResumeOperationRequest`, +`GetTradeRequest`, `ListTradesRequest`, `RefreshTradeEvidenceRequest`, `InspectEvidenceRequest`, `StorageStatusRequest`, `BackupRequest`, `IntegrityRequest`, `SyncStatusRequest`, and `PushOutboxRequest`. Restore uses the same request posture through `RestoreRequest`. Use `new`, `parse`, `default`, and `with_*` methods rather than struct literals. 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,3 +1,4 @@ +use radroots_event::kinds::KIND_TRADE_PROPOSAL; use radroots_nostr::prelude::{RadrootsNostrEvent, RadrootsNostrKeys}; use radroots_nostr_connect::prelude::{ RadrootsNostrConnectClientTarget, RadrootsNostrConnectError, @@ -50,6 +51,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { assert_eq!(status.mode, RadrootsSdkSignerMode::MycNip46); assert!(permissions.iter().any(|value| value == "sign_event:30340")); + assert!( + permissions + .iter() + .any(|value| value == &format!("sign_event:{KIND_TRADE_PROPOSAL}")) + ); + assert!(!permissions.iter().any(|value| value == "sign_event:3422")); println!("configured signer mode: {}", status.mode.as_str()); println!("requested permissions: {}", permissions.join(",")); Ok(()) diff --git a/crates/sdk/src/error.rs b/crates/sdk/src/error.rs @@ -88,6 +88,353 @@ impl RadrootsSdkTradeErrorKind { } #[cfg(feature = "runtime")] +const RECOVERY_INSPECT_LOCAL_STORES: &[RadrootsSdkRecoveryAction] = + &[RadrootsSdkRecoveryAction::InspectLocalStores]; +#[cfg(feature = "runtime")] +const RECOVERY_INSPECT_GEONAMES_ASSET: &[RadrootsSdkRecoveryAction] = + &[RadrootsSdkRecoveryAction::InspectGeoNamesAsset]; +#[cfg(feature = "runtime")] +const RECOVERY_RETRY_OPERATION_WITH_SAME_IDEMPOTENCY_KEY: &[RadrootsSdkRecoveryAction] = + &[RadrootsSdkRecoveryAction::RetryOperationWithSameIdempotencyKey]; +#[cfg(feature = "runtime")] +const RECOVERY_CONFIGURE_TRANSPORT_TARGETS: &[RadrootsSdkRecoveryAction] = + &[RadrootsSdkRecoveryAction::ConfigureTransportTargets]; +#[cfg(feature = "runtime")] +const RECOVERY_CONFIGURE_GEONAMES_CACHE: &[RadrootsSdkRecoveryAction] = + &[RadrootsSdkRecoveryAction::ConfigureGeoNamesCache]; +#[cfg(feature = "runtime")] +const RECOVERY_CONFIGURE_SIGNER: &[RadrootsSdkRecoveryAction] = + &[RadrootsSdkRecoveryAction::ConfigureSigner]; +#[cfg(feature = "runtime")] +const RECOVERY_FIX_REQUEST: &[RadrootsSdkRecoveryAction] = &[RadrootsSdkRecoveryAction::FixRequest]; +#[cfg(feature = "runtime")] +const RECOVERY_SELECT_AUTHORIZED_ACTOR: &[RadrootsSdkRecoveryAction] = + &[RadrootsSdkRecoveryAction::SelectAuthorizedActor]; +#[cfg(feature = "runtime")] +const RECOVERY_COMPLETE_SIGNER_AUTHENTICATION: &[RadrootsSdkRecoveryAction] = + &[RadrootsSdkRecoveryAction::CompleteSignerAuthentication]; +#[cfg(feature = "runtime")] +const RECOVERY_RETRY_AFTER_TRANSPORT_FAILURE: &[RadrootsSdkRecoveryAction] = + &[RadrootsSdkRecoveryAction::RetryAfterTransportFailure]; +#[cfg(feature = "runtime")] +const RECOVERY_RETRY_GEONAMES_DOWNLOAD: &[RadrootsSdkRecoveryAction] = + &[RadrootsSdkRecoveryAction::RetryGeoNamesDownload]; +#[cfg(feature = "runtime")] +const RECOVERY_ENABLE_REQUIRED_FEATURE: &[RadrootsSdkRecoveryAction] = + &[RadrootsSdkRecoveryAction::EnableRequiredFeature]; + +#[cfg(feature = "runtime")] +#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)] +pub struct RadrootsSdkErrorCatalogEntry { + pub code: &'static str, + pub class: RadrootsSdkErrorClass, + pub retryable: bool, + pub recovery_actions: &'static [RadrootsSdkRecoveryAction], +} + +#[cfg(feature = "runtime")] +impl RadrootsSdkErrorCatalogEntry { + const fn new( + code: &'static str, + class: RadrootsSdkErrorClass, + retryable: bool, + recovery_actions: &'static [RadrootsSdkRecoveryAction], + ) -> Self { + Self { + code, + class, + retryable, + recovery_actions, + } + } +} + +#[cfg(feature = "runtime")] +pub const RADROOTS_SDK_ERROR_CATALOG: &[RadrootsSdkErrorCatalogEntry] = &[ + RadrootsSdkErrorCatalogEntry::new( + "io", + RadrootsSdkErrorClass::Storage, + true, + RECOVERY_INSPECT_LOCAL_STORES, + ), + RadrootsSdkErrorCatalogEntry::new( + "clock_before_unix_epoch", + RadrootsSdkErrorClass::Clock, + false, + RECOVERY_FIX_REQUEST, + ), + RadrootsSdkErrorCatalogEntry::new( + "timestamp_out_of_range", + RadrootsSdkErrorClass::Clock, + false, + RECOVERY_FIX_REQUEST, + ), + RadrootsSdkErrorCatalogEntry::new( + "unauthorized_actor", + RadrootsSdkErrorClass::Authorization, + false, + RECOVERY_SELECT_AUTHORIZED_ACTOR, + ), + RadrootsSdkErrorCatalogEntry::new( + "signer_pubkey_mismatch", + RadrootsSdkErrorClass::Authorization, + false, + RECOVERY_SELECT_AUTHORIZED_ACTOR, + ), + RadrootsSdkErrorCatalogEntry::new( + "signer_unavailable", + RadrootsSdkErrorClass::Configuration, + false, + RECOVERY_CONFIGURE_SIGNER, + ), + RadrootsSdkErrorCatalogEntry::new( + "signer_request_rejected", + RadrootsSdkErrorClass::Authorization, + false, + RECOVERY_SELECT_AUTHORIZED_ACTOR, + ), + RadrootsSdkErrorCatalogEntry::new( + "signer_request_timed_out", + RadrootsSdkErrorClass::Transport, + true, + RECOVERY_RETRY_AFTER_TRANSPORT_FAILURE, + ), + RadrootsSdkErrorCatalogEntry::new( + "signer_auth_challenge_pending", + RadrootsSdkErrorClass::Request, + false, + RECOVERY_COMPLETE_SIGNER_AUTHENTICATION, + ), + RadrootsSdkErrorCatalogEntry::new( + "signer_transport", + RadrootsSdkErrorClass::Transport, + true, + RECOVERY_RETRY_AFTER_TRANSPORT_FAILURE, + ), + RadrootsSdkErrorCatalogEntry::new( + "signer_protocol", + RadrootsSdkErrorClass::Request, + false, + RECOVERY_FIX_REQUEST, + ), + RadrootsSdkErrorCatalogEntry::new( + "signer_returned_event_drift", + RadrootsSdkErrorClass::Authorization, + false, + RECOVERY_SELECT_AUTHORIZED_ACTOR, + ), + RadrootsSdkErrorCatalogEntry::new( + "empty_transport_targets", + RadrootsSdkErrorClass::Configuration, + false, + RECOVERY_CONFIGURE_TRANSPORT_TARGETS, + ), + RadrootsSdkErrorCatalogEntry::new( + "transport_target_limit_exceeded", + RadrootsSdkErrorClass::Configuration, + false, + RECOVERY_CONFIGURE_TRANSPORT_TARGETS, + ), + RadrootsSdkErrorCatalogEntry::new( + "invalid_relay_url", + RadrootsSdkErrorClass::Configuration, + false, + RECOVERY_CONFIGURE_TRANSPORT_TARGETS, + ), + RadrootsSdkErrorCatalogEntry::new( + "idempotency_conflict", + RadrootsSdkErrorClass::Request, + false, + RECOVERY_RETRY_OPERATION_WITH_SAME_IDEMPOTENCY_KEY, + ), + RadrootsSdkErrorCatalogEntry::new( + "trade_invalid_envelope", + RadrootsSdkErrorClass::Request, + false, + RECOVERY_FIX_REQUEST, + ), + RadrootsSdkErrorCatalogEntry::new( + "trade_invalid_command_body", + RadrootsSdkErrorClass::Request, + false, + RECOVERY_FIX_REQUEST, + ), + RadrootsSdkErrorCatalogEntry::new( + "trade_private_artifact_missing", + RadrootsSdkErrorClass::Request, + false, + RECOVERY_FIX_REQUEST, + ), + RadrootsSdkErrorCatalogEntry::new( + "trade_private_artifact_commitment_mismatch", + RadrootsSdkErrorClass::Request, + false, + RECOVERY_FIX_REQUEST, + ), + RadrootsSdkErrorCatalogEntry::new( + "trade_private_artifact_acknowledgement_missing", + RadrootsSdkErrorClass::Request, + false, + RECOVERY_FIX_REQUEST, + ), + RadrootsSdkErrorCatalogEntry::new( + "trade_not_found", + RadrootsSdkErrorClass::Request, + false, + RECOVERY_FIX_REQUEST, + ), + RadrootsSdkErrorCatalogEntry::new( + "trade_query_limit_invalid", + RadrootsSdkErrorClass::Request, + false, + RECOVERY_FIX_REQUEST, + ), + RadrootsSdkErrorCatalogEntry::new( + "trade_cursor_invalid", + RadrootsSdkErrorClass::Request, + false, + RECOVERY_FIX_REQUEST, + ), + RadrootsSdkErrorCatalogEntry::new( + "privacy_preflight", + RadrootsSdkErrorClass::Request, + false, + RECOVERY_FIX_REQUEST, + ), + RadrootsSdkErrorCatalogEntry::new( + "product_sync_unsupported", + RadrootsSdkErrorClass::Unsupported, + false, + RECOVERY_ENABLE_REQUIRED_FEATURE, + ), + RadrootsSdkErrorCatalogEntry::new( + "reticulum_transport_unavailable", + RadrootsSdkErrorClass::Unsupported, + false, + RECOVERY_CONFIGURE_TRANSPORT_TARGETS, + ), + RadrootsSdkErrorCatalogEntry::new( + "reticulum_transport_deferred", + RadrootsSdkErrorClass::Unsupported, + false, + RECOVERY_CONFIGURE_TRANSPORT_TARGETS, + ), + RadrootsSdkErrorCatalogEntry::new( + "product_sync_transport_setup_failure", + RadrootsSdkErrorClass::Transport, + true, + RECOVERY_RETRY_AFTER_TRANSPORT_FAILURE, + ), + RadrootsSdkErrorCatalogEntry::new( + "authority", + RadrootsSdkErrorClass::Authorization, + false, + RECOVERY_SELECT_AUTHORIZED_ACTOR, + ), + RadrootsSdkErrorCatalogEntry::new( + "event_store", + RadrootsSdkErrorClass::Storage, + true, + RECOVERY_INSPECT_LOCAL_STORES, + ), + RadrootsSdkErrorCatalogEntry::new( + "invalid_request", + RadrootsSdkErrorClass::Request, + false, + RECOVERY_FIX_REQUEST, + ), + RadrootsSdkErrorCatalogEntry::new( + "unsupported_profile_schema", + RadrootsSdkErrorClass::Request, + false, + RECOVERY_INSPECT_LOCAL_STORES, + ), + RadrootsSdkErrorCatalogEntry::new( + "listing_edit", + RadrootsSdkErrorClass::Request, + false, + RECOVERY_FIX_REQUEST, + ), + RadrootsSdkErrorCatalogEntry::new( + "listing_mutation", + RadrootsSdkErrorClass::Request, + false, + RECOVERY_FIX_REQUEST, + ), + RadrootsSdkErrorCatalogEntry::new( + "outbox", + RadrootsSdkErrorClass::Storage, + true, + RECOVERY_INSPECT_LOCAL_STORES, + ), + RadrootsSdkErrorCatalogEntry::new( + "private_store", + RadrootsSdkErrorClass::Storage, + true, + RECOVERY_INSPECT_LOCAL_STORES, + ), + RadrootsSdkErrorCatalogEntry::new( + "studio_store", + RadrootsSdkErrorClass::Storage, + true, + RECOVERY_INSPECT_LOCAL_STORES, + ), + RadrootsSdkErrorCatalogEntry::new( + "geonames_configuration", + RadrootsSdkErrorClass::Configuration, + false, + RECOVERY_CONFIGURE_GEONAMES_CACHE, + ), + RadrootsSdkErrorCatalogEntry::new( + "geonames_download", + RadrootsSdkErrorClass::Transport, + true, + RECOVERY_RETRY_GEONAMES_DOWNLOAD, + ), + RadrootsSdkErrorCatalogEntry::new( + "geonames_cache", + RadrootsSdkErrorClass::Storage, + true, + RECOVERY_INSPECT_GEONAMES_ASSET, + ), + RadrootsSdkErrorCatalogEntry::new( + "geonames_integrity", + RadrootsSdkErrorClass::Storage, + false, + RECOVERY_INSPECT_GEONAMES_ASSET, + ), + RadrootsSdkErrorCatalogEntry::new( + "geonames_schema", + RadrootsSdkErrorClass::Storage, + false, + RECOVERY_INSPECT_GEONAMES_ASSET, + ), + RadrootsSdkErrorCatalogEntry::new( + "geonames_lookup", + RadrootsSdkErrorClass::Request, + false, + RECOVERY_FIX_REQUEST, + ), + RadrootsSdkErrorCatalogEntry::new( + "transport", + RadrootsSdkErrorClass::Transport, + true, + RECOVERY_RETRY_AFTER_TRANSPORT_FAILURE, + ), + RadrootsSdkErrorCatalogEntry::new( + "projection", + RadrootsSdkErrorClass::Storage, + true, + RECOVERY_INSPECT_LOCAL_STORES, + ), +]; + +#[cfg(feature = "runtime")] +pub fn radroots_sdk_error_catalog() -> &'static [RadrootsSdkErrorCatalogEntry] { + RADROOTS_SDK_ERROR_CATALOG +} + +#[cfg(feature = "runtime")] #[derive(Debug)] #[non_exhaustive] pub enum RadrootsSdkError { diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs @@ -60,8 +60,9 @@ pub use radroots_runtime_contract_v1 as runtime_contract_v1; #[cfg(feature = "runtime")] pub use crate::error::{ - RadrootsSdkError, RadrootsSdkErrorClass, RadrootsSdkGeoNamesErrorKind, - RadrootsSdkRecoveryAction, RadrootsSdkTradeErrorKind, + RADROOTS_SDK_ERROR_CATALOG, RadrootsSdkError, RadrootsSdkErrorCatalogEntry, + RadrootsSdkErrorClass, RadrootsSdkGeoNamesErrorKind, RadrootsSdkRecoveryAction, + RadrootsSdkTradeErrorKind, radroots_sdk_error_catalog, }; #[cfg(feature = "runtime")] pub use crate::farms_runtime::{ @@ -178,12 +179,17 @@ pub use crate::trade_runtime::{ RefreshTradeEvidenceRequest, ResumeOperationRequest, SubmitProposalRequest, TRADE_CANCEL_OPERATION_KIND, TRADE_DECIDE_CANDIDATE_OPERATION_KIND, TRADE_PROPOSE_REVISION_OPERATION_KIND, TRADE_QUERY_DEFAULT_LIMIT, TRADE_QUERY_MAX_LIMIT, - TRADE_RESUME_OPERATION_KIND, TRADE_SUBMIT_PROPOSAL_OPERATION_KIND, TradeCommandLifecycleState, - TradeCommandReceipt, TradeCommandService, TradeListAnyOf, TradeListFilter, TradeListSort, - TradePrivateArtifactDeleteReceipt, TradePrivateArtifactDeleteRequest, TradePrivateArtifactKind, - TradePrivateArtifactOpenReceipt, TradePrivateArtifactOpenRequest, - TradePrivateArtifactSealReceipt, TradePrivateArtifactSealRequest, - TradePrivateTermsAvailabilityView, TradeQueryService, TradeStatusView, TradeSummaryView, + TRADE_RESUME_OPERATION_KIND, TRADE_RUNTIME_CAPABILITY_API_VERSION, + TRADE_RUNTIME_PRIVATE_STORAGE_PROFILE_ID, TRADE_RUNTIME_PROTOCOL_PROFILE_ID, + TRADE_RUNTIME_STORAGE_PROFILE_ID, TRADE_RUNTIME_WIRE_PROFILE_ID, + TRADE_SUBMIT_PROPOSAL_OPERATION_KIND, TradeCommandLifecycleState, TradeCommandReceipt, + TradeCommandService, TradeCoreMvpCapabilityReport, TradeListAnyOf, TradeListFilter, + TradeListSort, TradeOptionalIntegrationCapabilityReport, TradePrivateArtifactDeleteReceipt, + TradePrivateArtifactDeleteRequest, TradePrivateArtifactKind, TradePrivateArtifactOpenReceipt, + TradePrivateArtifactOpenRequest, TradePrivateArtifactSealReceipt, + TradePrivateArtifactSealRequest, TradePrivateTermsAvailabilityView, + TradeProtocolCapabilityReport, TradeQueryService, TradeRuntimeCapabilityReport, + TradeStatusView, TradeStorageCapabilityReport, TradeSummaryView, }; #[cfg(feature = "runtime")] pub use crate::transport::{ diff --git a/crates/sdk/src/signer_provider.rs b/crates/sdk/src/signer_provider.rs @@ -7,7 +7,8 @@ use radroots_authority::{ use radroots_event::draft::{RadrootsEventDraft, RadrootsSignedEvent}; use radroots_event::ids::RadrootsPublicKey; use radroots_event::kinds::{ - KIND_FARM, KIND_LISTING, KIND_ORDER_CANCELLATION, KIND_ORDER_DECISION, KIND_ORDER_REQUEST, + KIND_FARM, KIND_LISTING, KIND_TRADE_CANCELLATION, KIND_TRADE_DECISION, KIND_TRADE_PROPOSAL, + KIND_TRADE_REVISION_DECISION, KIND_TRADE_REVISION_PROPOSAL, }; use radroots_event::wire::RadrootsNip01EventWire; use radroots_nostr::prelude::{RadrootsNostrEvent, RadrootsNostrKeys}; @@ -26,12 +27,14 @@ use uuid::Uuid; pub type RadrootsSdkNip46TransportFuture<'a, T> = RadrootsNostrConnectClientTransportFuture<'a, T>; pub type RadrootsSdkLocalSignerCapability = dyn RadrootsEventSigner + Send + Sync; -pub const RADROOTS_SDK_MYC_NIP46_PRODUCT_SIGN_EVENT_KINDS: [u32; 5] = [ +pub const RADROOTS_SDK_MYC_NIP46_PRODUCT_SIGN_EVENT_KINDS: [u32; 7] = [ KIND_FARM, KIND_LISTING, - KIND_ORDER_REQUEST, - KIND_ORDER_DECISION, - KIND_ORDER_CANCELLATION, + KIND_TRADE_PROPOSAL, + KIND_TRADE_DECISION, + KIND_TRADE_REVISION_PROPOSAL, + KIND_TRADE_REVISION_DECISION, + KIND_TRADE_CANCELLATION, ]; pub const RADROOTS_SDK_MYC_NIP46_DEFAULT_REQUEST_TIMEOUT_MS: u64 = 30_000; diff --git a/crates/sdk/src/trade_runtime.rs b/crates/sdk/src/trade_runtime.rs @@ -5,7 +5,8 @@ use crate::{ RadrootsClient, RadrootsSdkError, RadrootsSdkRecoveryAction, RadrootsSdkTradeErrorKind, SatisfactionPolicy, SdkIdempotencyKey, SdkMutationState, TargetPolicy, TradesClient, private_store::{ - SdkPrivateTradeArtifactInput, SdkPrivateTradeArtifactKind, SdkPrivateTradeArtifactMetadata, + SDK_PRIVATE_STORE_SCHEMA_VERSION, SdkPrivateTradeArtifactInput, + SdkPrivateTradeArtifactKind, SdkPrivateTradeArtifactMetadata, }, runtime::sdk_now_ms, workflow_runtime::{ @@ -20,9 +21,12 @@ use radroots_authority::{RadrootsActorContext, RadrootsEventSigner}; use radroots_event::{ draft::RadrootsEventDraft, ids::{RadrootsEventId, RadrootsTradeCandidateId, RadrootsTradeId, RadrootsTradeMutationId}, + kinds::TRADE_MUTATION_EVENT_KINDS, trade::{ - RadrootsTradeDecisionV1, RadrootsTradeMutationBodyV1, RadrootsTradeMutationEnvelopeV1, - RadrootsTradePrivateTermsRefV1, trade_mutation_from_canonical_content, + RADROOTS_TRADE_MAX_PRIVATE_ARTIFACT_BYTES, RADROOTS_TRADE_MUTATION_CONTRACT_IDS, + RADROOTS_TRADE_SCHEMA_VERSION, RadrootsTradeDecisionV1, RadrootsTradeMutationBodyV1, + RadrootsTradeMutationEnvelopeV1, RadrootsTradePrivateTermsRefV1, + trade_mutation_from_canonical_content, }, }; #[cfg(feature = "runtime")] @@ -62,6 +66,17 @@ pub const TRADE_QUERY_DEFAULT_LIMIT: u32 = 50; #[cfg(feature = "runtime")] pub const TRADE_QUERY_MAX_LIMIT: u32 = 100; #[cfg(feature = "runtime")] +pub const TRADE_RUNTIME_CAPABILITY_API_VERSION: u16 = 1; +#[cfg(feature = "runtime")] +pub const TRADE_RUNTIME_PROTOCOL_PROFILE_ID: &str = "radroots.trade.protocol.v1"; +#[cfg(feature = "runtime")] +pub const TRADE_RUNTIME_WIRE_PROFILE_ID: &str = "radroots.trade.nostr_regular_immutable_jcs.v1"; +#[cfg(feature = "runtime")] +pub const TRADE_RUNTIME_STORAGE_PROFILE_ID: &str = "radroots.sdk.trade.sqlite.v1"; +#[cfg(feature = "runtime")] +pub const TRADE_RUNTIME_PRIVATE_STORAGE_PROFILE_ID: &str = + "radroots.sdk.trade.private_artifacts.v1"; +#[cfg(feature = "runtime")] const TRADE_MUTATION_QUERY_LIMIT: u32 = 1_000; #[cfg(feature = "runtime")] const TRADE_LIST_CURSOR_VERSION: u8 = 1; @@ -244,6 +259,10 @@ impl<'client> TradeQueryService<'client> { #[cfg(feature = "runtime")] impl<'client> TradesClient<'client> { + pub fn capabilities(&self) -> TradeRuntimeCapabilityReport { + trade_runtime_capabilities() + } + pub fn commands(&self) -> TradeCommandService<'client> { TradeCommandService::new(self.sdk) } @@ -666,6 +685,109 @@ pub struct TradePrivateArtifactDeleteReceipt { } #[cfg(feature = "runtime")] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +#[non_exhaustive] +pub struct TradeRuntimeCapabilityReport { + pub api_version: u16, + pub protocol: TradeProtocolCapabilityReport, + pub storage: TradeStorageCapabilityReport, + pub core_mvp: TradeCoreMvpCapabilityReport, + pub optional_integrations: TradeOptionalIntegrationCapabilityReport, +} + +#[cfg(feature = "runtime")] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +#[non_exhaustive] +pub struct TradeProtocolCapabilityReport { + pub protocol_profile_id: &'static str, + pub wire_profile_id: &'static str, + pub schema_version: u16, + pub mutation_contract_ids: Vec<&'static str>, + pub mutation_event_kinds: Vec<u32>, + pub reducer_contract_id: &'static str, + pub reducer_version: u16, +} + +#[cfg(feature = "runtime")] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +#[non_exhaustive] +pub struct TradeStorageCapabilityReport { + pub storage_profile_id: &'static str, + pub private_storage_profile_id: &'static str, + pub private_store_schema_version: i64, + pub max_private_artifact_bytes: usize, + pub private_artifact_kinds: Vec<TradePrivateArtifactKind>, +} + +#[cfg(feature = "runtime")] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +#[non_exhaustive] +pub struct TradeCoreMvpCapabilityReport { + pub commands: bool, + pub queries: bool, + pub local_event_store: bool, + pub semantic_outbox: bool, + pub protected_private_artifacts: bool, + pub backup_restore: bool, + pub local_signer: bool, +} + +#[cfg(feature = "runtime")] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +#[non_exhaustive] +pub struct TradeOptionalIntegrationCapabilityReport { + pub myc_nip46_signer: bool, + pub radrootsd_execution: bool, + pub rhi_attestation: bool, + pub tangle_transport: bool, + pub reticulum_transport: bool, +} + +#[cfg(feature = "runtime")] +fn trade_runtime_capabilities() -> TradeRuntimeCapabilityReport { + TradeRuntimeCapabilityReport { + api_version: TRADE_RUNTIME_CAPABILITY_API_VERSION, + protocol: TradeProtocolCapabilityReport { + protocol_profile_id: TRADE_RUNTIME_PROTOCOL_PROFILE_ID, + wire_profile_id: TRADE_RUNTIME_WIRE_PROFILE_ID, + schema_version: RADROOTS_TRADE_SCHEMA_VERSION, + mutation_contract_ids: RADROOTS_TRADE_MUTATION_CONTRACT_IDS.to_vec(), + mutation_event_kinds: TRADE_MUTATION_EVENT_KINDS.to_vec(), + reducer_contract_id: RADROOTS_TRADE_REDUCER_CONTRACT_ID, + reducer_version: RADROOTS_TRADE_REDUCER_VERSION, + }, + storage: TradeStorageCapabilityReport { + storage_profile_id: TRADE_RUNTIME_STORAGE_PROFILE_ID, + private_storage_profile_id: TRADE_RUNTIME_PRIVATE_STORAGE_PROFILE_ID, + private_store_schema_version: SDK_PRIVATE_STORE_SCHEMA_VERSION, + max_private_artifact_bytes: RADROOTS_TRADE_MAX_PRIVATE_ARTIFACT_BYTES, + private_artifact_kinds: vec![ + TradePrivateArtifactKind::BindingTerms, + TradePrivateArtifactKind::Message, + TradePrivateArtifactKind::ContactBundle, + TradePrivateArtifactKind::DeliveryInstruction, + ], + }, + core_mvp: TradeCoreMvpCapabilityReport { + commands: true, + queries: true, + local_event_store: true, + semantic_outbox: true, + protected_private_artifacts: true, + backup_restore: true, + local_signer: cfg!(feature = "local-signer"), + }, + optional_integrations: TradeOptionalIntegrationCapabilityReport { + myc_nip46_signer: cfg!(feature = "signer-adapters"), + radrootsd_execution: cfg!(feature = "radrootsd-execution"), + rhi_attestation: false, + tangle_transport: false, + reticulum_transport: false, + }, + } +} + +#[cfg(feature = "runtime")] #[derive(Clone, Debug, Serialize)] #[non_exhaustive] pub struct GetTradeRequest { diff --git a/crates/sdk/tests/unit/error_tests.rs b/crates/sdk/tests/unit/error_tests.rs @@ -1,11 +1,13 @@ use super::{ - RadrootsSdkError, RadrootsSdkGeoNamesErrorKind, RadrootsSdkTradeErrorKind, redacted_relay_url, + RadrootsSdkError, RadrootsSdkGeoNamesErrorKind, RadrootsSdkTradeErrorKind, + radroots_sdk_error_catalog, redacted_relay_url, }; use crate::privacy::{PrivacyPreflightStatus, ProductSensitivityField}; use crate::transport::ReticulumBehavior; use radroots_authority::RadrootsAuthorityError; use radroots_event::contract::RadrootsActorRole; use radroots_geocoder::{GeoNamesAssetFetcher, GeoNamesBlockingHttpFetcher, GeocoderError}; +use std::collections::BTreeSet; #[test] fn authority_error_conversion_redacts_pubkey_mismatches_and_falls_back() { @@ -399,6 +401,73 @@ fn sdk_error_contract_methods_cover_representative_classes_and_details() { } #[test] +fn sdk_error_catalog_exposes_stable_codes_and_metadata() { + let catalog = radroots_sdk_error_catalog(); + let codes = catalog + .iter() + .map(|entry| entry.code) + .collect::<BTreeSet<_>>(); + + assert_eq!(codes.len(), catalog.len()); + assert!(codes.contains("io")); + assert!(codes.contains("signer_auth_challenge_pending")); + assert!(codes.contains("product_sync_unsupported")); + assert!(codes.contains("reticulum_transport_deferred")); + assert!(codes.contains("unsupported_profile_schema")); + assert!(codes.contains("geonames_lookup")); + + for trade_kind in [ + RadrootsSdkTradeErrorKind::InvalidEnvelope, + RadrootsSdkTradeErrorKind::InvalidCommandBody, + RadrootsSdkTradeErrorKind::PrivateArtifactMissing, + RadrootsSdkTradeErrorKind::PrivateArtifactCommitmentMismatch, + RadrootsSdkTradeErrorKind::PrivateArtifactAcknowledgementMissing, + RadrootsSdkTradeErrorKind::TradeNotFound, + RadrootsSdkTradeErrorKind::QueryLimitInvalid, + RadrootsSdkTradeErrorKind::CursorInvalid, + ] { + assert!(codes.contains(trade_kind.code())); + } + + for entry in catalog { + assert!(!entry.code.is_empty()); + assert!(!entry.recovery_actions.is_empty()); + } + + let timeout = RadrootsSdkError::SignerRequestTimedOut { + mode: "myc_nip46".to_owned(), + }; + let timeout_entry = catalog + .iter() + .find(|entry| entry.code == timeout.code()) + .expect("timeout catalog entry"); + assert_eq!(timeout_entry.class, timeout.class()); + assert_eq!(timeout_entry.retryable, timeout.retryable()); + let timeout_recovery_actions = timeout.recovery_actions(); + assert_eq!( + timeout_entry.recovery_actions, + timeout_recovery_actions.as_slice() + ); + + let trade = RadrootsSdkError::Trade { + kind: RadrootsSdkTradeErrorKind::PrivateArtifactCommitmentMismatch, + operation: "trade.decide_candidate".to_owned(), + message: "private artifact commitment mismatch".to_owned(), + }; + let trade_entry = catalog + .iter() + .find(|entry| entry.code == trade.code()) + .expect("trade catalog entry"); + assert_eq!(trade_entry.class, trade.class()); + assert_eq!(trade_entry.retryable, trade.retryable()); + let trade_recovery_actions = trade.recovery_actions(); + assert_eq!( + trade_entry.recovery_actions, + trade_recovery_actions.as_slice() + ); +} + +#[test] fn geonames_error_conversion_maps_source_errors_to_sdk_kinds() { let path = std::path::PathBuf::from("geonames-test.db"); let download_error = GeoNamesBlockingHttpFetcher diff --git a/crates/sdk/tests/unit/signer_provider_tests.rs b/crates/sdk/tests/unit/signer_provider_tests.rs @@ -4,7 +4,7 @@ use nostr::{EventBuilder, JsonUtil, Kind, Tag}; use radroots_authority::RadrootsLocalEventSigner; use radroots_event::contract::RadrootsActorRole; use radroots_event::draft::RadrootsEventDraft; -use radroots_event::kinds::{KIND_COOP, KIND_FARM}; +use radroots_event::kinds::{KIND_COOP, KIND_FARM, KIND_LISTING, TRADE_MUTATION_EVENT_KINDS}; use radroots_nostr::prelude::{RadrootsNostrEvent, RadrootsNostrSecretKey}; use radroots_nostr_connect::prelude::{ RADROOTS_NOSTR_CONNECT_RPC_KIND, RadrootsNostrConnectClientTarget, RadrootsNostrConnectError, @@ -516,15 +516,21 @@ async fn nip46_transport_adapter_delegates_publish_and_response_poll() { fn myc_nip46_product_permissions_cover_sdk_write_event_kinds() { let permissions = radroots_sdk_myc_nip46_product_permissions(); let rendered = radroots_sdk_myc_nip46_product_permission_strings(); + let mut expected_kinds = vec![KIND_FARM, KIND_LISTING]; + expected_kinds.extend_from_slice(&TRADE_MUTATION_EVENT_KINDS); + assert_eq!(permissions.as_slice().len(), expected_kinds.len()); assert_eq!( - permissions.as_slice().len(), - RADROOTS_SDK_MYC_NIP46_PRODUCT_SIGN_EVENT_KINDS.len() + RADROOTS_SDK_MYC_NIP46_PRODUCT_SIGN_EVENT_KINDS.as_slice(), + expected_kinds.as_slice() ); assert_eq!(rendered.len(), permissions.as_slice().len()); for kind in RADROOTS_SDK_MYC_NIP46_PRODUCT_SIGN_EVENT_KINDS { assert!(rendered.contains(&format!("sign_event:{kind}"))); } + for old_trade_write_kind in [3422, 3423, 3432] { + assert!(!rendered.contains(&format!("sign_event:{old_trade_write_kind}"))); + } assert!(!rendered.contains(&"sign_event:1".to_owned())); } diff --git a/crates/sdk/tests/unit/trade_runtime_tests.rs b/crates/sdk/tests/unit/trade_runtime_tests.rs @@ -10,8 +10,10 @@ use radroots_event::{ RadrootsAddressableCoordinate, RadrootsDTag, RadrootsEventId, RadrootsInventoryBinId, RadrootsPublicKey, RadrootsTradeId, }, + kinds::TRADE_MUTATION_EVENT_KINDS, trade::{ - RADROOTS_TRADE_DECISION_CONTRACT_ID, RADROOTS_TRADE_PROPOSAL_CONTRACT_ID, + RADROOTS_TRADE_DECISION_CONTRACT_ID, RADROOTS_TRADE_MAX_PRIVATE_ARTIFACT_BYTES, + RADROOTS_TRADE_MUTATION_CONTRACT_IDS, RADROOTS_TRADE_PROPOSAL_CONTRACT_ID, RADROOTS_TRADE_SCHEMA_VERSION, RadrootsFulfillmentProfileV1, RadrootsSellerReservationAssertionV1, RadrootsSellerReservationLineV1, RadrootsTradeCancellationProfileV1, RadrootsTradeCandidateLineV1, @@ -21,7 +23,10 @@ use radroots_event::{ }, }; use radroots_nostr::prelude::{RadrootsNostrKeys, RadrootsNostrSecretKey}; -use radroots_trade::workflow::RadrootsTradePrivateTermsStateV1; +use radroots_trade::workflow::{ + RADROOTS_TRADE_REDUCER_CONTRACT_ID, RADROOTS_TRADE_REDUCER_VERSION, + RadrootsTradePrivateTermsStateV1, +}; const BUYER_SECRET_KEY_HEX: &str = "10c5304d6c9ae3a1a16f7860f1cc8f5e3a76225a2663b3a989a0d775919b7df5"; @@ -50,6 +55,67 @@ fn local_signer(secret_key_hex: &str) -> (String, RadrootsLocalEventSigner) { ) } +#[tokio::test] +async fn trade_capabilities_report_canonical_release_product_surface() { + let sdk = RadrootsClient::builder().build().await.expect("sdk"); + let capabilities = sdk.trades().capabilities(); + + assert_eq!( + capabilities.api_version, + TRADE_RUNTIME_CAPABILITY_API_VERSION + ); + assert_eq!( + capabilities.protocol.protocol_profile_id, + TRADE_RUNTIME_PROTOCOL_PROFILE_ID + ); + assert_eq!( + capabilities.protocol.wire_profile_id, + TRADE_RUNTIME_WIRE_PROFILE_ID + ); + assert_eq!( + capabilities.protocol.schema_version, + RADROOTS_TRADE_SCHEMA_VERSION + ); + assert_eq!( + capabilities.protocol.mutation_contract_ids, + RADROOTS_TRADE_MUTATION_CONTRACT_IDS.to_vec() + ); + assert_eq!( + capabilities.protocol.mutation_event_kinds, + TRADE_MUTATION_EVENT_KINDS.to_vec() + ); + assert!(!capabilities.protocol.mutation_event_kinds.contains(&3422)); + assert_eq!( + capabilities.protocol.reducer_contract_id, + RADROOTS_TRADE_REDUCER_CONTRACT_ID + ); + assert_eq!( + capabilities.protocol.reducer_version, + RADROOTS_TRADE_REDUCER_VERSION + ); + assert_eq!( + capabilities.storage.storage_profile_id, + TRADE_RUNTIME_STORAGE_PROFILE_ID + ); + assert_eq!( + capabilities.storage.private_storage_profile_id, + TRADE_RUNTIME_PRIVATE_STORAGE_PROFILE_ID + ); + assert_eq!( + capabilities.storage.max_private_artifact_bytes, + RADROOTS_TRADE_MAX_PRIVATE_ARTIFACT_BYTES + ); + assert!(capabilities.core_mvp.commands); + assert!(capabilities.core_mvp.queries); + assert!(capabilities.core_mvp.local_event_store); + assert!(capabilities.core_mvp.semantic_outbox); + assert!(capabilities.core_mvp.protected_private_artifacts); + assert!(capabilities.core_mvp.backup_restore); + assert!(!capabilities.optional_integrations.rhi_attestation); + assert!(!capabilities.optional_integrations.tangle_transport); + assert!(!capabilities.optional_integrations.reticulum_transport); +} + fn buyer_actor(buyer_pubkey: &str) -> RadrootsActorContext { RadrootsActorContext::test(buyer_pubkey, [RadrootsActorRole::Buyer]).expect("buyer") } diff --git a/crates/trade_bindings/src/dto.rs b/crates/trade_bindings/src/dto.rs @@ -189,9 +189,9 @@ pub struct RadrootsTradeListingProjection { pub delivery_method: Option<RadrootsListingDeliveryMethodImport>, pub location: Option<RadrootsListingPublicLocationImport>, pub images: Option<Vec<RadrootsListingImageImport>>, - pub order_count: u32, - pub open_order_count: u32, - pub terminal_order_count: u32, + pub trade_count: u32, + pub open_trade_count: u32, + pub terminal_trade_count: u32, } #[derive(dto_bindgen::Dto)] @@ -222,10 +222,10 @@ pub enum RadrootsTradeListingSortField { SellerPubkey, #[serde(rename = "inventory_available")] InventoryAvailable, - #[serde(rename = "open_order_count")] - OpenOrderCount, - #[serde(rename = "total_order_count")] - TotalOrderCount, + #[serde(rename = "open_trade_count")] + OpenTradeCount, + #[serde(rename = "total_trade_count")] + TotalTradeCount, } #[derive(dto_bindgen::Dto)] @@ -244,9 +244,9 @@ pub struct RadrootsTradeMarketplaceListingSummary { pub primary_bin_id: String, pub primary_bin_label: Option<String>, pub primary_bin_total: RadrootsTradeListingTotal, - pub order_count: u32, - pub open_order_count: u32, - pub terminal_order_count: u32, + pub trade_count: u32, + pub open_trade_count: u32, + pub terminal_trade_count: u32, } #[derive(dto_bindgen::Dto)] diff --git a/crates/trade_bindings/src/lib.rs b/crates/trade_bindings/src/lib.rs @@ -78,14 +78,14 @@ pub const TRADE_LARGE_INTEGER_POLICIES: &[TradeLargeIntegerPolicyEntry] = &[ "RadrootsTradeListingBackofficeView", "open_moderation_flag_count", ), - json_number_safe_count("RadrootsTradeListingProjection", "order_count"), - json_number_safe_count("RadrootsTradeListingProjection", "open_order_count"), - json_number_safe_count("RadrootsTradeListingProjection", "terminal_order_count"), - json_number_safe_count("RadrootsTradeMarketplaceListingSummary", "order_count"), - json_number_safe_count("RadrootsTradeMarketplaceListingSummary", "open_order_count"), + json_number_safe_count("RadrootsTradeListingProjection", "trade_count"), + json_number_safe_count("RadrootsTradeListingProjection", "open_trade_count"), + json_number_safe_count("RadrootsTradeListingProjection", "terminal_trade_count"), + json_number_safe_count("RadrootsTradeMarketplaceListingSummary", "trade_count"), + json_number_safe_count("RadrootsTradeMarketplaceListingSummary", "open_trade_count"), json_number_safe_count( "RadrootsTradeMarketplaceListingSummary", - "terminal_order_count", + "terminal_trade_count", ), ]; @@ -268,32 +268,32 @@ mod tests { ), ( "RadrootsTradeListingProjection", - "order_count", + "trade_count", super::TradeLargeIntegerPolicy::JsonNumberSafeCount ), ( "RadrootsTradeListingProjection", - "open_order_count", + "open_trade_count", super::TradeLargeIntegerPolicy::JsonNumberSafeCount ), ( "RadrootsTradeListingProjection", - "terminal_order_count", + "terminal_trade_count", super::TradeLargeIntegerPolicy::JsonNumberSafeCount ), ( "RadrootsTradeMarketplaceListingSummary", - "order_count", + "trade_count", super::TradeLargeIntegerPolicy::JsonNumberSafeCount ), ( "RadrootsTradeMarketplaceListingSummary", - "open_order_count", + "open_trade_count", super::TradeLargeIntegerPolicy::JsonNumberSafeCount ), ( "RadrootsTradeMarketplaceListingSummary", - "terminal_order_count", + "terminal_trade_count", super::TradeLargeIntegerPolicy::JsonNumberSafeCount ), ] diff --git a/tools/sdk_xtask_import/src/dto_roots.rs b/tools/sdk_xtask_import/src/dto_roots.rs @@ -149,6 +149,23 @@ const TRADE_EXTERNAL_OVERRIDES: &[DtoExternalOverride] = &[ const TRADE_REQUIRED_EXTERNAL_PACKAGE_IMPORTS: &[&str] = &[CORE_BINDINGS_PACKAGE_NAME, EVENT_BINDINGS_PACKAGE_NAME]; +const RETIRED_ORDER_EVENT_DTO_ROOTS: &[&str] = &[ + "RadrootsOrderCancellation", + "RadrootsOrderDecision", + "RadrootsOrderDecisionOutcome", + "RadrootsOrderEconomicActor", + "RadrootsOrderEconomicEffect", + "RadrootsOrderEconomicItem", + "RadrootsOrderEconomicLine", + "RadrootsOrderEconomicLineKind", + "RadrootsOrderEconomicTotals", + "RadrootsOrderEconomics", + "RadrootsOrderEventType", + "RadrootsOrderInventoryCommitment", + "RadrootsOrderItem", + "RadrootsOrderPricingBasis", + "RadrootsOrderRequest", +]; pub fn package_root_set(package_key: &str) -> Option<&'static DtoPackageRootSet> { DTO_PACKAGE_ROOTS @@ -206,7 +223,10 @@ fn core_roots() -> Vec<RootDescriptor> { } fn event_roots() -> Vec<RootDescriptor> { - radroots_event::dto::dto_roots().into_iter().collect() + radroots_event::dto::dto_roots() + .into_iter() + .filter(|root| !retired_order_event_dto_root(root)) + .collect() } fn event_index_roots() -> Vec<RootDescriptor> { @@ -217,6 +237,15 @@ fn trade_roots() -> Vec<RootDescriptor> { radroots_trade_bindings::dto_roots() } +fn retired_order_event_dto_root(root: &RootDescriptor) -> bool { + let type_name = root + .rust_type_name + .rsplit("::") + .next() + .unwrap_or(root.rust_type_name); + RETIRED_ORDER_EVENT_DTO_ROOTS.contains(&type_name) +} + fn core_import_options( registry: &Registry, mut options: DtoRegistryRenderOptions, @@ -617,21 +646,6 @@ mod tests { "RadrootsMessageFileDimensions", "RadrootsMessageRecipient", "RadrootsNip01EventWireDto", - "RadrootsOrderCancellation", - "RadrootsOrderDecision", - "RadrootsOrderDecisionOutcome", - "RadrootsOrderEconomicActor", - "RadrootsOrderEconomicEffect", - "RadrootsOrderEconomicItem", - "RadrootsOrderEconomicLine", - "RadrootsOrderEconomicLineKind", - "RadrootsOrderEconomicTotals", - "RadrootsOrderEconomics", - "RadrootsOrderEventType", - "RadrootsOrderInventoryCommitment", - "RadrootsOrderItem", - "RadrootsOrderPricingBasis", - "RadrootsOrderRequest", "RadrootsPlot", "RadrootsPlotLocation", "RadrootsPlotRef", @@ -885,6 +899,7 @@ mod tests { let actual = type_inventory(EVENT_BINDINGS_TYPES_TS); assert_eq!(actual, EVENT_TYPE_INVENTORY); + assert!(!EVENT_BINDINGS_TYPES_TS.contains("RadrootsOrder")); } #[test]