commit ebd6fc76629f8cb7688a04c8012bd1103008e94e
parent 87cf4ff726d7eee0f11a5eef5a8206f4960b6956
Author: triesap <tyson@radroots.org>
Date: Sat, 27 Jun 2026 21:45:13 +0000
trade: source order workflow projection bindings
- Remove the SDK-local trade order workflow projection descriptor.
- Generate the projection from the rr-rs source trade DTO root.
- Import event-owned order support types from generated event bindings.
- Drop stale discount fields and required event evidence from trade types.
Diffstat:
4 files changed, 77 insertions(+), 52 deletions(-)
diff --git a/crates/trade_bindings/src/dto.rs b/crates/trade_bindings/src/dto.rs
@@ -4,7 +4,8 @@ use dto_bindgen_core::{
VariantShape, WireFieldNames,
};
use radroots_trade::{
- listing::model::RadrootsTradeListingTotal, workflow::RadrootsTradeWorkflowState,
+ listing::model::RadrootsTradeListingTotal, order::RadrootsTradeOrderWorkflowProjection,
+ workflow::RadrootsTradeWorkflowState,
};
pub fn dto_roots() -> Vec<RootDescriptor> {
@@ -35,7 +36,6 @@ pub fn dto_roots() -> Vec<RootDescriptor> {
RootDescriptor::new::<RadrootsTradeOrderQuery>(),
RootDescriptor::new::<RadrootsTradeOrderSort>(),
RootDescriptor::new::<RadrootsTradeOrderSortField>(),
- RootDescriptor::new::<RadrootsTradeOrderWorkflowProjection>(),
RootDescriptor::new::<RadrootsTradeReviewPriority>(),
RootDescriptor::new::<RadrootsTradeReviewQueueEntry>(),
RootDescriptor::new::<RadrootsTradeReviewStatus>(),
@@ -58,7 +58,6 @@ macro_rules! imported_ts_type {
imported_ts_type!(RadrootsCoreDecimalImport, "RadrootsCoreDecimal");
imported_ts_type!(RadrootsCoreDiscountImport, "RadrootsCoreDiscount");
-imported_ts_type!(RadrootsCoreDiscountValueImport, "RadrootsCoreDiscountValue");
imported_ts_type!(RadrootsCoreMoneyImport, "RadrootsCoreMoney");
imported_ts_type!(RadrootsCoreQuantityImport, "RadrootsCoreQuantity");
imported_ts_type!(RadrootsCoreQuantityPriceImport, "RadrootsCoreQuantityPrice");
@@ -80,12 +79,9 @@ imported_ts_type!(
"RadrootsListingPublicLocation"
);
imported_ts_type!(RadrootsListingProductImport, "RadrootsListingProduct");
-imported_ts_type!(RadrootsNostrEventPtrImport, "RadrootsNostrEventPtr");
imported_ts_type!(RadrootsPlotRefImport, "RadrootsPlotRef");
imported_ts_type!(RadrootsResourceAreaRefImport, "RadrootsResourceAreaRef");
-imported_ts_type!(RadrootsOrderEconomicLineImport, "RadrootsOrderEconomicLine");
imported_ts_type!(RadrootsOrderEventTypeImport, "RadrootsOrderEventType");
-imported_ts_type!(RadrootsOrderItemImport, "RadrootsOrderItem");
#[derive(dto_bindgen::Dto)]
pub struct RadrootsTradeFacetCount {
@@ -275,7 +271,6 @@ pub struct RadrootsTradeMarketplaceOrderSummary {
pub last_message_type: RadrootsOrderEventTypeImport,
pub item_count: u32,
pub total_bin_count: u32,
- pub has_requested_discounts: bool,
pub last_reason: Option<String>,
}
@@ -372,29 +367,6 @@ pub enum RadrootsTradeOrderSortField {
}
#[derive(dto_bindgen::Dto)]
-pub struct RadrootsTradeOrderWorkflowProjection {
- pub order_id: String,
- pub listing_addr: String,
- pub buyer_pubkey: String,
- pub seller_pubkey: String,
- pub items: Vec<RadrootsOrderItemImport>,
- pub requested_discounts: Option<Vec<RadrootsOrderEconomicLineImport>>,
- pub status: RadrootsTradeWorkflowState,
- pub listing_snapshot: Option<RadrootsNostrEventPtrImport>,
- pub root_event_id: String,
- pub last_event_id: String,
- pub last_discount_request: Option<RadrootsCoreDiscountValueImport>,
- pub last_discount_offer: Option<RadrootsCoreDiscountValueImport>,
- pub accepted_discount: Option<RadrootsCoreDiscountValueImport>,
- pub last_reason: Option<String>,
- pub last_discount_decline_reason: Option<String>,
- pub revision_count: u32,
- pub cancellation_count: u32,
- pub last_message_type: RadrootsOrderEventTypeImport,
- pub last_actor_pubkey: String,
-}
-
-#[derive(dto_bindgen::Dto)]
pub enum RadrootsTradeReviewPriority {
#[serde(rename = "low")]
Low,
diff --git a/crates/trade_bindings/src/lib.rs b/crates/trade_bindings/src/lib.rs
@@ -7,6 +7,7 @@ pub use dto::dto_roots;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TradeTypeDisposition {
SourceTradeRoot,
+ SourceTradeSupport,
EventsBindingImport,
SdkLocalPackageShape,
}
@@ -38,7 +39,10 @@ pub const TRADE_TYPE_INVENTORY: &[TradeTypeInventoryEntry] = &[
event_import("RadrootsListingProduct"),
event_import("RadrootsListingPublicLocation"),
event_import("RadrootsListingStatus"),
+ event_import("RadrootsOrderEconomics"),
event_import("RadrootsOrderEventType"),
+ event_import("RadrootsOrderInventoryCommitment"),
+ source_support("RadrootsOrderIssue"),
local_shape("RadrootsTradeFacetCount"),
source_root("RadrootsTradeListing"),
local_shape("RadrootsTradeListingBackofficeOverlay"),
@@ -65,7 +69,7 @@ pub const TRADE_TYPE_INVENTORY: &[TradeTypeInventoryEntry] = &[
local_shape("RadrootsTradeOrderQuery"),
local_shape("RadrootsTradeOrderSort"),
local_shape("RadrootsTradeOrderSortField"),
- local_shape("RadrootsTradeOrderWorkflowProjection"),
+ source_root("RadrootsTradeOrderWorkflowProjection"),
local_shape("RadrootsTradeReviewPriority"),
local_shape("RadrootsTradeReviewQueueEntry"),
local_shape("RadrootsTradeReviewStatus"),
@@ -94,8 +98,6 @@ pub const TRADE_LARGE_INTEGER_POLICIES: &[TradeLargeIntegerPolicyEntry] = &[
"RadrootsTradeOrderBackofficeView",
"open_moderation_flag_count",
),
- json_number_safe_count("RadrootsTradeOrderWorkflowProjection", "revision_count"),
- json_number_safe_count("RadrootsTradeOrderWorkflowProjection", "cancellation_count"),
];
const fn source_root(export_name: &'static str) -> TradeTypeInventoryEntry {
@@ -105,6 +107,13 @@ const fn source_root(export_name: &'static str) -> TradeTypeInventoryEntry {
}
}
+const fn source_support(export_name: &'static str) -> TradeTypeInventoryEntry {
+ TradeTypeInventoryEntry {
+ export_name,
+ disposition: TradeTypeDisposition::SourceTradeSupport,
+ }
+}
+
const fn event_import(export_name: &'static str) -> TradeTypeInventoryEntry {
TradeTypeInventoryEntry {
export_name,
@@ -165,7 +174,10 @@ mod tests {
"RadrootsListingProduct",
"RadrootsListingPublicLocation",
"RadrootsListingStatus",
+ "RadrootsOrderEconomics",
"RadrootsOrderEventType",
+ "RadrootsOrderInventoryCommitment",
+ "RadrootsOrderIssue",
"RadrootsTradeFacetCount",
"RadrootsTradeListing",
"RadrootsTradeListingBackofficeOverlay",
@@ -213,7 +225,9 @@ mod tests {
"RadrootsListingProduct",
"RadrootsListingPublicLocation",
"RadrootsListingStatus",
+ "RadrootsOrderEconomics",
"RadrootsOrderEventType",
+ "RadrootsOrderInventoryCommitment",
] {
assert_eq!(
disposition(export_name),
@@ -236,12 +250,21 @@ mod tests {
"RadrootsTradeListing",
"RadrootsTradeListingSubtotal",
"RadrootsTradeListingTotal",
+ "RadrootsTradeOrderWorkflowProjection",
"RadrootsTradeWorkflowState"
]
);
}
#[test]
+ fn trade_source_support_types_are_marked_for_source_registry() {
+ assert_eq!(
+ disposition("RadrootsOrderIssue"),
+ TradeTypeDisposition::SourceTradeSupport
+ );
+ }
+
+ #[test]
fn trade_large_integer_policy_covers_current_count_fields() {
let actual = TRADE_LARGE_INTEGER_POLICIES
.iter()
@@ -306,16 +329,6 @@ mod tests {
"open_moderation_flag_count",
super::TradeLargeIntegerPolicy::JsonNumberSafeCount
),
- (
- "RadrootsTradeOrderWorkflowProjection",
- "revision_count",
- super::TradeLargeIntegerPolicy::JsonNumberSafeCount
- ),
- (
- "RadrootsTradeOrderWorkflowProjection",
- "cancellation_count",
- super::TradeLargeIntegerPolicy::JsonNumberSafeCount
- ),
]
);
}
diff --git a/packages/trade-bindings/src/generated/types.ts b/packages/trade-bindings/src/generated/types.ts
@@ -4,7 +4,6 @@ import type {
RadrootsCoreCurrency,
RadrootsCoreDecimal,
RadrootsCoreDiscount,
- RadrootsCoreDiscountValue,
RadrootsCoreMoney,
RadrootsCoreQuantity,
RadrootsCoreUnit,
@@ -18,14 +17,15 @@ import type {
RadrootsListingImage,
RadrootsListingProduct,
RadrootsListingPublicLocation,
- RadrootsNostrEventPtr,
- RadrootsOrderEconomicLine,
+ RadrootsOrderEconomics,
RadrootsOrderEventType,
- RadrootsOrderItem,
+ RadrootsOrderInventoryCommitment,
RadrootsPlotRef,
RadrootsResourceAreaRef,
} from "@radroots/events-bindings";
+export type RadrootsOrderIssue = "missing_request" | { multiple_requests: { event_ids: Array<string>, }, } | { request_payload_invalid: { event_id: string, }, } | { request_order_id_mismatch: { event_id: string, }, } | { request_author_mismatch: { event_id: string, }, } | { request_listing_address_invalid: { event_id: string, }, } | { request_seller_listing_mismatch: { event_id: string, }, } | { decision_payload_invalid: { event_id: string, }, } | { decision_order_id_mismatch: { event_id: string, }, } | { decision_author_mismatch: { event_id: string, }, } | { decision_counterparty_mismatch: { event_id: string, }, } | { decision_buyer_mismatch: { event_id: string, }, } | { decision_seller_mismatch: { event_id: string, }, } | { decision_listing_address_invalid: { event_id: string, }, } | { decision_listing_mismatch: { event_id: string, }, } | { decision_root_mismatch: { event_id: string, }, } | { decision_previous_mismatch: { event_id: string, }, } | { decision_missing_inventory_commitments: { event_id: string, }, } | { decision_inventory_commitment_mismatch: { event_id: string, }, } | { decision_missing_reason: { event_id: string, }, } | { conflicting_decisions: { event_ids: Array<string>, }, } | { revision_proposal_payload_invalid: { event_id: string, }, } | { revision_proposal_order_id_mismatch: { event_id: string, }, } | { revision_proposal_author_mismatch: { event_id: string, }, } | { revision_proposal_counterparty_mismatch: { event_id: string, }, } | { revision_proposal_buyer_mismatch: { event_id: string, }, } | { revision_proposal_seller_mismatch: { event_id: string, }, } | { revision_proposal_listing_address_invalid: { event_id: string, }, } | { revision_proposal_listing_mismatch: { event_id: string, }, } | { revision_proposal_root_mismatch: { event_id: string, }, } | { revision_proposal_previous_mismatch: { event_id: string, }, } | { revision_decision_without_proposal: { event_id: string, }, } | { revision_decision_payload_invalid: { event_id: string, }, } | { revision_decision_order_id_mismatch: { event_id: string, }, } | { revision_decision_author_mismatch: { event_id: string, }, } | { revision_decision_counterparty_mismatch: { event_id: string, }, } | { revision_decision_buyer_mismatch: { event_id: string, }, } | { revision_decision_seller_mismatch: { event_id: string, }, } | { revision_decision_listing_address_invalid: { event_id: string, }, } | { revision_decision_listing_mismatch: { event_id: string, }, } | { revision_decision_root_mismatch: { event_id: string, }, } | { revision_decision_previous_mismatch: { event_id: string, }, } | { revision_decision_revision_id_mismatch: { event_id: string, }, } | { cancellation_without_cancellable_order: { event_id: string, }, } | { cancellation_payload_invalid: { event_id: string, }, } | { cancellation_order_id_mismatch: { event_id: string, }, } | { cancellation_author_mismatch: { event_id: string, }, } | { cancellation_counterparty_mismatch: { event_id: string, }, } | { cancellation_buyer_mismatch: { event_id: string, }, } | { cancellation_seller_mismatch: { event_id: string, }, } | { cancellation_listing_address_invalid: { event_id: string, }, } | { cancellation_listing_mismatch: { event_id: string, }, } | { cancellation_root_mismatch: { event_id: string, }, } | { cancellation_previous_mismatch: { event_id: string, }, } | { forked_lifecycle: { event_ids: Array<string>, }, } | { validation_receipt_without_pending_agreement: { event_id: string, }, } | { validation_receipt_order_id_mismatch: { event_id: string, }, } | { validation_receipt_type_mismatch: { event_id: string, }, } | { validation_receipt_root_mismatch: { event_id: string, }, } | { validation_receipt_target_mismatch: { event_id: string, }, } | { validation_receipt_listing_mismatch: { event_id: string, }, } | { conflicting_validation_receipts: { event_ids: Array<string>, }, } | { deterministic_validation_failure: { event_id: string, reason: string, }, } | { stale_listing_event: { expected_event_id: string, current_event_id: string, }, };
+
export type RadrootsTradeFacetCount = { key: string, count: number, };
export type RadrootsTradeListing = { listing_id: string, listing_addr: string, seller_pubkey: string, title: string, description: string, product_type: string, primary_bin_id: string, bin_quantity: RadrootsCoreQuantity, unit: RadrootsCoreUnit, unit_price: RadrootsCoreMoney, inventory_available: RadrootsCoreDecimal, availability: RadrootsListingAvailability, location: RadrootsListingPublicLocation, delivery_method: RadrootsListingDeliveryMethod, listing: RadrootsListing, };
@@ -56,7 +56,7 @@ export type RadrootsTradeListingTotal = { price_amount: RadrootsCoreMoney, price
export type RadrootsTradeMarketplaceListingSummary = { listing_addr: string, seller_pubkey: string, farm_pubkey: string, farm_id: string, product_key: string, product_title: string, product_category: string, product_summary?: string | null, listing_status: RadrootsTradeListingMarketStatus, location_primary?: string | null, inventory_available?: RadrootsCoreDecimal | null, primary_bin_id: string, primary_bin_label?: string | null, primary_bin_total: RadrootsTradeListingTotal, order_count: number, open_order_count: number, terminal_order_count: number, };
-export type RadrootsTradeMarketplaceOrderSummary = { order_id: string, listing_addr: string, buyer_pubkey: string, seller_pubkey: string, status: RadrootsTradeWorkflowState, last_message_type: RadrootsOrderEventType, item_count: number, total_bin_count: number, has_requested_discounts: boolean, last_reason?: string | null, };
+export type RadrootsTradeMarketplaceOrderSummary = { order_id: string, listing_addr: string, buyer_pubkey: string, seller_pubkey: string, status: RadrootsTradeWorkflowState, last_message_type: RadrootsOrderEventType, item_count: number, total_bin_count: number, last_reason?: string | null, };
export type RadrootsTradeModerationFlag = { code: string, severity: RadrootsTradeModerationSeverity, status: RadrootsTradeModerationStatus, source?: string | null, reason?: string | null, };
@@ -78,7 +78,7 @@ export type RadrootsTradeOrderSort = { field: RadrootsTradeOrderSortField, direc
export type RadrootsTradeOrderSortField = "order_id" | "listing_addr" | "buyer_pubkey" | "seller_pubkey" | "status" | "last_message_type" | "total_bin_count";
-export type RadrootsTradeOrderWorkflowProjection = { order_id: string, listing_addr: string, buyer_pubkey: string, seller_pubkey: string, items: Array<RadrootsOrderItem>, requested_discounts?: Array<RadrootsOrderEconomicLine> | null, status: RadrootsTradeWorkflowState, listing_snapshot?: RadrootsNostrEventPtr | null, root_event_id: string, last_event_id: string, last_discount_request?: RadrootsCoreDiscountValue | null, last_discount_offer?: RadrootsCoreDiscountValue | null, accepted_discount?: RadrootsCoreDiscountValue | null, last_reason?: string | null, last_discount_decline_reason?: string | null, revision_count: number, cancellation_count: number, last_message_type: RadrootsOrderEventType, last_actor_pubkey: string, };
+export type RadrootsTradeOrderWorkflowProjection = { order_id: string, status: RadrootsTradeWorkflowState, request_event_id?: string | null, decision_event_id?: string | null, cancellation_event_id?: string | null, validation_receipt_event_id?: string | null, lifecycle_terminal: boolean, economics?: RadrootsOrderEconomics | null, agreement_event_id?: string | null, pending_revision_event_id?: string | null, pending_inventory_reservations: Array<RadrootsOrderInventoryCommitment>, committed_inventory_reservations: Array<RadrootsOrderInventoryCommitment>, listing_addr?: string | null, buyer_pubkey?: string | null, seller_pubkey?: string | null, last_event_id?: string | null, issues: Array<RadrootsOrderIssue>, };
export type RadrootsTradeReviewPriority = "low" | "normal" | "high" | "critical";
diff --git a/tools/xtask/src/dto_roots.rs b/tools/xtask/src/dto_roots.rs
@@ -157,9 +157,16 @@ const TRADE_EXTERNAL_OVERRIDES: &[DtoExternalOverride] = &[
events_override("RadrootsNostrEventPtr"),
events_override("RadrootsPlotRef"),
events_override("RadrootsResourceAreaRef"),
+ events_override("RadrootsOrderEconomicActor"),
+ events_override("RadrootsOrderEconomicEffect"),
+ events_override("RadrootsOrderEconomicItem"),
events_override("RadrootsOrderEconomicLine"),
+ events_override("RadrootsOrderEconomicLineKind"),
+ events_override("RadrootsOrderEconomics"),
events_override("RadrootsOrderEventType"),
+ events_override("RadrootsOrderInventoryCommitment"),
events_override("RadrootsOrderItem"),
+ events_override("RadrootsOrderPricingBasis"),
];
const TRADE_REQUIRED_EXTERNAL_PACKAGE_IMPORTS: &[&str] =
@@ -217,7 +224,7 @@ pub fn replica_db_schema_types_module() -> Result<DtoTypesModule, String> {
pub fn trade_types_module() -> Result<DtoTypesModule, String> {
let root_set = package_root_set("trade").ok_or_else(|| "missing trade DTO roots".to_owned())?;
let registry = root_set.registry();
- let options = trade_import_options(DtoRegistryRenderOptions::default())?;
+ let options = trade_import_options(®istry, DtoRegistryRenderOptions::default())?;
let rendered = render_registry_types(®istry, &options)?;
validate_external_override_usage(&rendered, TRADE_EXTERNAL_OVERRIDES)?;
Ok(rendered)
@@ -286,11 +293,19 @@ fn with_checked_external_type(
}
fn trade_import_options(
+ registry: &Registry,
mut options: DtoRegistryRenderOptions,
) -> Result<DtoRegistryRenderOptions, String> {
let package_exports = generated_external_package_exports()?;
for override_target in TRADE_EXTERNAL_OVERRIDES {
validate_external_override_target(*override_target, &package_exports)?;
+ if let Ok(type_id) = registry.type_id_by_export_name(override_target.target_type) {
+ options = options.with_external_type(
+ type_id,
+ override_target.import_name,
+ override_target.from,
+ );
+ }
options = options.with_external_override(
override_target.target_type,
override_target.import_name,
@@ -624,6 +639,7 @@ mod tests {
"RadrootsEventsIndexedIndexCheckpoint",
];
const TRADE_TYPE_INVENTORY: &[&str] = &[
+ "RadrootsOrderIssue",
"RadrootsTradeFacetCount",
"RadrootsTradeListing",
"RadrootsTradeListingBackofficeOverlay",
@@ -760,7 +776,9 @@ mod tests {
#[test]
fn trade_external_override_targets_resolve_to_generated_exports() {
- trade_import_options(DtoRegistryRenderOptions::default())
+ let registry = package_root_set("trade").expect("trade roots").registry();
+
+ trade_import_options(®istry, DtoRegistryRenderOptions::default())
.expect("trade external overrides validate");
}
@@ -918,10 +936,22 @@ mod tests {
.get("@radroots/events-bindings")
.is_some_and(|names| names.contains("RadrootsOrderEventType"))
);
+ assert!(
+ imports
+ .get("@radroots/events-bindings")
+ .is_some_and(|names| names.contains("RadrootsOrderEconomics"))
+ );
+ assert!(
+ imports
+ .get("@radroots/events-bindings")
+ .is_some_and(|names| names.contains("RadrootsOrderInventoryCommitment"))
+ );
for duplicate in [
"export type RadrootsListing = ",
"export type RadrootsFarmRef = ",
+ "export type RadrootsOrderEconomics = ",
+ "export type RadrootsOrderInventoryCommitment = ",
"export type RadrootsCommercialMessagePayload = ",
"export type RadrootsCommercialMessageType = ",
"export type RadrootsOrderStatus = ",
@@ -936,6 +966,7 @@ mod tests {
);
assert!(marketplace_order_summary.contains("status: RadrootsTradeWorkflowState"));
assert!(marketplace_order_summary.contains("last_message_type: RadrootsOrderEventType"));
+ assert!(!marketplace_order_summary.contains("has_requested_discounts"));
let order_query = type_declaration(TRADE_BINDINGS_TYPES_TS, "RadrootsTradeOrderQuery");
assert!(order_query.contains("status?: RadrootsTradeWorkflowState | null"));
@@ -945,8 +976,17 @@ mod tests {
"RadrootsTradeOrderWorkflowProjection",
);
assert!(workflow_projection.contains("status: RadrootsTradeWorkflowState"));
- assert!(workflow_projection.contains("last_message_type: RadrootsOrderEventType"));
+ assert!(workflow_projection.contains("request_event_id?: string | null"));
+ assert!(workflow_projection.contains("last_event_id?: string | null"));
+ assert!(workflow_projection.contains("listing_addr?: string | null"));
for stale_counter in [
+ "root_event_id",
+ "last_message_type",
+ "last_discount_request",
+ "last_discount_offer",
+ "accepted_discount",
+ "last_discount_decline_reason",
+ "has_requested_discounts",
"question_count",
"answer_count",
"discount_request_count",