commit 908de111a715b71161b5fb8d4a4c3d36be5b8b79
parent 5c695d9197f36945772e05c820085671b61a24a4
Author: triesap <tyson@radroots.org>
Date: Thu, 18 Jun 2026 23:59:01 -0700
app: route order lifecycle through sdk
- add app SDK runtime commands for revision, cancellation, fulfillment, and receipt writes
- feed request and lifecycle evidence into SDK order enqueue calls before publishing follow-on events
- record migration receipts for lifecycle writes and refresh projections through the SDK-backed path
- narrow sync metadata and source guards so lifecycle direct publish calls cannot re-enter production paths
Diffstat:
5 files changed, 1023 insertions(+), 271 deletions(-)
diff --git a/crates/desktop/src/runtime.rs b/crates/desktop/src/runtime.rs
@@ -9,11 +9,13 @@ use chrono::{DateTime, Duration, Utc};
use radroots_app_core::{
AppBuildIdentity, AppDesktopRuntimePaths, AppRuntimeCapture, AppRuntimeMode,
AppRuntimePathsError, AppRuntimeSnapshot, AppSdkConfig, AppSdkDiagnostics,
- AppSdkFarmPublishRequest, AppSdkLifecycleState, AppSdkOrderDecisionRequest,
- AppSdkOrderSubmitRequest, AppSdkProjectionLifecycleState, AppSdkRelayUrlPolicy, AppSdkRuntime,
- AppSdkRuntimeError, AppSdkRuntimeIssue, AppSdkRuntimeStatus, AppSdkStoragePaths,
- AppSdkWorkflowReceipt, AppSharedAccountsPaths, PackDayExportWriteError,
- prepare_pack_day_export_bundle_at_data_root,
+ AppSdkFarmPublishRequest, AppSdkLifecycleState, AppSdkOrderCancellationRequest,
+ AppSdkOrderDecisionRequest, AppSdkOrderFulfillmentUpdateRequest,
+ AppSdkOrderReceiptRecordRequest, AppSdkOrderRevisionDecisionRequest,
+ AppSdkOrderRevisionProposalRequest, AppSdkOrderSubmitRequest, AppSdkProjectionLifecycleState,
+ AppSdkRelayUrlPolicy, AppSdkRuntime, AppSdkRuntimeError, AppSdkRuntimeIssue,
+ AppSdkRuntimeStatus, AppSdkStoragePaths, AppSdkWorkflowReceipt, AppSharedAccountsPaths,
+ PackDayExportWriteError, prepare_pack_day_export_bundle_at_data_root,
shared_local_events_database_path_from_shared_accounts, write_prepared_pack_day_export_bundle,
};
use radroots_app_remote_signer::{
@@ -117,9 +119,11 @@ use radroots_sdk::protocol::order::{
RadrootsOrderRevisionProposal,
};
use radroots_sdk::{
- FARM_PUBLISH_OPERATION_KIND, ORDER_DECISION_OPERATION_KIND, ORDER_SUBMIT_OPERATION_KIND,
- RadrootsSdkClient, RadrootsSdkConfig, RelayConfig, SdkEnvironment, SdkPublishReceipt,
- SdkTransportMode, SdkTransportReceipt, SignerConfig,
+ FARM_PUBLISH_OPERATION_KIND, ORDER_CANCELLATION_OPERATION_KIND, ORDER_DECISION_OPERATION_KIND,
+ ORDER_FULFILLMENT_UPDATE_OPERATION_KIND, ORDER_RECEIPT_RECORD_OPERATION_KIND,
+ ORDER_REVISION_DECISION_OPERATION_KIND, ORDER_REVISION_PROPOSAL_OPERATION_KIND,
+ ORDER_SUBMIT_OPERATION_KIND, RadrootsSdkClient, RadrootsSdkConfig, RelayConfig, SdkEnvironment,
+ SdkPublishReceipt, SdkTransportMode, SdkTransportReceipt, SignerConfig,
};
use radroots_sql_core::SqliteExecutor;
use radroots_trade::listing::parse_public_listing_address;
@@ -258,6 +262,7 @@ struct ResolvedAppOrderFulfillmentEvidence {
#[derive(Clone, Debug, Eq, PartialEq)]
struct ResolvedAppOrderLifecycleEvidence {
+ evidence_events: Vec<SdkRadrootsNostrEvent>,
status: RadrootsOrderStatus,
payment_state: RadrootsOrderPaymentState,
agreement_event_id: Option<String>,
@@ -2954,15 +2959,14 @@ impl DesktopAppRuntimeState {
status: RadrootsOrderFulfillmentState,
) -> Result<bool, AppSqliteError> {
let payload = self.prepare_seller_order_fulfillment(order_id, status)?;
- let operation = PendingSyncOperation::from_publish_payload(
- AppPublishPayload::OrderFulfillment(payload),
- current_utc_timestamp(),
- )
- .map_err(|_| AppSqliteError::InvalidProjection {
- reason: "seller order fulfillment publish payload must serialize",
- })?;
- let _ = self.enqueue_selected_account_sync_operation_once(operation)?;
- self.attempt_sync(SyncTrigger::ManualRefresh)
+ let source_record_id = order_fulfillment_sdk_source_record_id(&payload);
+ self.enqueue_order_fulfillment_payload_via_sdk(
+ &payload,
+ AppSdkMigrationReceiptSourceKind::LocalOutbox,
+ source_record_id.as_str(),
+ )?;
+ let _ = self.refresh_selected_account_sync()?;
+ Ok(true)
}
fn prepare_seller_order_revision_proposal(
@@ -3105,15 +3109,14 @@ impl DesktopAppRuntimeState {
) -> Result<bool, AppSqliteError> {
let payload =
self.prepare_seller_order_revision_proposal(order_id, items, economics, reason)?;
- let operation = PendingSyncOperation::from_publish_payload(
- AppPublishPayload::OrderRevisionProposal(payload),
- current_utc_timestamp(),
- )
- .map_err(|_| AppSqliteError::InvalidProjection {
- reason: "seller order revision publish payload must serialize",
- })?;
- let _ = self.enqueue_selected_account_sync_operation_once(operation)?;
- self.attempt_sync(SyncTrigger::ManualRefresh)
+ let source_record_id = order_revision_proposal_sdk_source_record_id(&payload);
+ self.enqueue_order_revision_proposal_payload_via_sdk(
+ &payload,
+ AppSdkMigrationReceiptSourceKind::LocalOutbox,
+ source_record_id.as_str(),
+ )?;
+ let _ = self.refresh_selected_account_sync()?;
+ Ok(true)
}
fn prepare_buyer_order_revision_decision(
@@ -3246,15 +3249,14 @@ impl DesktopAppRuntimeState {
decision: RadrootsOrderRevisionOutcome,
) -> Result<bool, AppSqliteError> {
let payload = self.prepare_buyer_order_revision_decision(order_id, decision)?;
- let operation = PendingSyncOperation::from_publish_payload(
- AppPublishPayload::OrderRevisionDecision(payload),
- current_utc_timestamp(),
- )
- .map_err(|_| AppSqliteError::InvalidProjection {
- reason: "buyer order revision publish payload must serialize",
- })?;
- let _ = self.enqueue_selected_account_sync_operation_once(operation)?;
- self.attempt_sync(SyncTrigger::ManualRefresh)
+ let source_record_id = order_revision_decision_sdk_source_record_id(&payload);
+ self.enqueue_order_revision_decision_payload_via_sdk(
+ &payload,
+ AppSdkMigrationReceiptSourceKind::LocalOutbox,
+ source_record_id.as_str(),
+ )?;
+ let _ = self.refresh_selected_account_sync()?;
+ Ok(true)
}
fn prepare_buyer_order_cancellation(
@@ -3372,15 +3374,14 @@ impl DesktopAppRuntimeState {
order_id: OrderId,
) -> Result<bool, AppSqliteError> {
let payload = self.prepare_buyer_order_cancellation(order_id)?;
- let operation = PendingSyncOperation::from_publish_payload(
- AppPublishPayload::OrderCancellation(payload),
- current_utc_timestamp(),
- )
- .map_err(|_| AppSqliteError::InvalidProjection {
- reason: "buyer order cancellation publish payload must serialize",
- })?;
- let _ = self.enqueue_selected_account_sync_operation_once(operation)?;
- self.attempt_sync(SyncTrigger::ManualRefresh)
+ let source_record_id = order_cancellation_sdk_source_record_id(&payload);
+ self.enqueue_order_cancellation_payload_via_sdk(
+ &payload,
+ AppSdkMigrationReceiptSourceKind::LocalOutbox,
+ source_record_id.as_str(),
+ )?;
+ let _ = self.refresh_selected_account_sync()?;
+ Ok(true)
}
fn prepare_buyer_order_receipt(
@@ -3491,15 +3492,14 @@ impl DesktopAppRuntimeState {
outcome: AppOrderReceiptOutcome,
) -> Result<bool, AppSqliteError> {
let payload = self.prepare_buyer_order_receipt(order_id, outcome)?;
- let operation = PendingSyncOperation::from_publish_payload(
- AppPublishPayload::OrderReceipt(payload),
- current_utc_timestamp(),
- )
- .map_err(|_| AppSqliteError::InvalidProjection {
- reason: "buyer order receipt publish payload must serialize",
- })?;
- let _ = self.enqueue_selected_account_sync_operation_once(operation)?;
- self.attempt_sync(SyncTrigger::ManualRefresh)
+ let source_record_id = order_receipt_sdk_source_record_id(&payload);
+ self.enqueue_order_receipt_payload_via_sdk(
+ &payload,
+ AppSdkMigrationReceiptSourceKind::LocalOutbox,
+ source_record_id.as_str(),
+ )?;
+ let _ = self.refresh_selected_account_sync()?;
+ Ok(true)
}
fn start_order_recovery(
@@ -5017,37 +5017,6 @@ impl DesktopAppRuntimeState {
self.refresh_selected_account_sync()
}
- fn enqueue_selected_account_sync_operation_once(
- &mut self,
- operation: PendingSyncOperation,
- ) -> Result<bool, AppSqliteError> {
- let Some(account_id) = self
- .state_store
- .identity_projection()
- .selected_account
- .as_ref()
- .map(|account| account.account.account_id.clone())
- else {
- return Ok(false);
- };
- let already_enqueued = {
- let Some(sqlite_store) = self.sqlite_store.as_ref() else {
- return Ok(false);
- };
- let existing = sqlite_store.load_pending_sync_operations(account_id.as_str())?;
- existing.iter().any(|pending| {
- pending.operation.aggregate == operation.aggregate
- && pending.operation.operation == operation.operation
- && pending.operation.payload_json == operation.payload_json
- })
- };
- if already_enqueued {
- return self.refresh_selected_account_sync();
- }
-
- self.enqueue_selected_account_sync_operations(vec![operation])
- }
-
fn enqueue_selected_account_product_publish_operation(
&mut self,
product_id: ProductId,
@@ -5384,6 +5353,298 @@ impl DesktopAppRuntimeState {
}
}
+ fn enqueue_order_revision_proposal_payload_via_sdk(
+ &self,
+ payload: &AppOrderRevisionProposalPublishPayload,
+ source_kind: AppSdkMigrationReceiptSourceKind,
+ source_record_id: &str,
+ ) -> Result<(), AppSqliteError> {
+ let operation_kind = ORDER_REVISION_PROPOSAL_OPERATION_KIND;
+ let request_evidence = self.resolve_seller_order_request_evidence(payload.app_order_id)?;
+ let lifecycle = self.resolve_order_lifecycle_evidence(&request_evidence)?;
+ let actor_pubkey = self
+ .local_signing_identity_for_publish_payload(&AppPublishPayload::OrderRevisionProposal(
+ payload.clone(),
+ ))
+ .and_then(|identity| {
+ let actor_pubkey = identity.public_key_hex();
+ let target_relays = normalized_app_sync_relay_urls(&self.nostr_relay_urls)?;
+ let request = AppSdkOrderRevisionProposalRequest {
+ actor_account_id: payload.context.account_id.clone(),
+ actor_pubkey: actor_pubkey.clone(),
+ signer_keys: identity.into_keys(),
+ evidence_events: lifecycle.evidence_events,
+ root_event: order_lifecycle_sdk_event_ptr(
+ payload.request_event_id.as_str(),
+ target_relays.as_slice(),
+ "order revision proposal requires request event id",
+ )?,
+ previous_event: order_lifecycle_sdk_event_ptr(
+ payload.prev_event_id.as_str(),
+ target_relays.as_slice(),
+ "order revision proposal requires previous event id",
+ )?,
+ proposal: order_revision_proposal_publish_payload_to_sdk_revision(payload)?,
+ relay_url_policy: sdk_relay_url_policy_for_targets(target_relays.as_slice()),
+ target_relays,
+ idempotency_key: Some(sdk_idempotency_key(source_record_id)),
+ };
+ self.enqueue_app_sdk_order_revision_proposal(request)
+ .map(|receipt| (actor_pubkey, receipt))
+ .map_err(sync_transport_error_from_sdk_runtime_error)
+ });
+ match actor_pubkey {
+ Ok((actor_pubkey, receipt)) => self.record_app_sdk_migration_success(
+ source_kind,
+ source_record_id,
+ operation_kind,
+ actor_pubkey.as_str(),
+ &receipt,
+ ),
+ Err(error) => self.record_app_sdk_migration_failure(
+ source_kind,
+ source_record_id,
+ operation_kind,
+ None,
+ sync_transport_error_detail_json(&error),
+ ),
+ }
+ }
+
+ fn enqueue_order_revision_decision_payload_via_sdk(
+ &self,
+ payload: &AppOrderRevisionDecisionPublishPayload,
+ source_kind: AppSdkMigrationReceiptSourceKind,
+ source_record_id: &str,
+ ) -> Result<(), AppSqliteError> {
+ let operation_kind = ORDER_REVISION_DECISION_OPERATION_KIND;
+ let request_evidence = self.resolve_seller_order_request_evidence(payload.app_order_id)?;
+ let lifecycle = self.resolve_order_lifecycle_evidence(&request_evidence)?;
+ let actor_pubkey = self
+ .local_signing_identity_for_publish_payload(&AppPublishPayload::OrderRevisionDecision(
+ payload.clone(),
+ ))
+ .and_then(|identity| {
+ let actor_pubkey = identity.public_key_hex();
+ let target_relays = normalized_app_sync_relay_urls(&self.nostr_relay_urls)?;
+ let request = AppSdkOrderRevisionDecisionRequest {
+ actor_account_id: payload.context.account_id.clone(),
+ actor_pubkey: actor_pubkey.clone(),
+ signer_keys: identity.into_keys(),
+ evidence_events: lifecycle.evidence_events,
+ root_event: order_lifecycle_sdk_event_ptr(
+ payload.request_event_id.as_str(),
+ target_relays.as_slice(),
+ "order revision decision requires request event id",
+ )?,
+ previous_event: order_lifecycle_sdk_event_ptr(
+ payload.prev_event_id.as_str(),
+ target_relays.as_slice(),
+ "order revision decision requires previous event id",
+ )?,
+ decision: order_revision_decision_publish_payload_to_sdk_revision_decision(
+ payload,
+ )?,
+ relay_url_policy: sdk_relay_url_policy_for_targets(target_relays.as_slice()),
+ target_relays,
+ idempotency_key: Some(sdk_idempotency_key(source_record_id)),
+ };
+ self.enqueue_app_sdk_order_revision_decision(request)
+ .map(|receipt| (actor_pubkey, receipt))
+ .map_err(sync_transport_error_from_sdk_runtime_error)
+ });
+ match actor_pubkey {
+ Ok((actor_pubkey, receipt)) => self.record_app_sdk_migration_success(
+ source_kind,
+ source_record_id,
+ operation_kind,
+ actor_pubkey.as_str(),
+ &receipt,
+ ),
+ Err(error) => self.record_app_sdk_migration_failure(
+ source_kind,
+ source_record_id,
+ operation_kind,
+ None,
+ sync_transport_error_detail_json(&error),
+ ),
+ }
+ }
+
+ fn enqueue_order_cancellation_payload_via_sdk(
+ &self,
+ payload: &AppOrderCancellationPublishPayload,
+ source_kind: AppSdkMigrationReceiptSourceKind,
+ source_record_id: &str,
+ ) -> Result<(), AppSqliteError> {
+ let operation_kind = ORDER_CANCELLATION_OPERATION_KIND;
+ let request_evidence = self.resolve_seller_order_request_evidence(payload.app_order_id)?;
+ let lifecycle = self.resolve_order_lifecycle_evidence(&request_evidence)?;
+ let actor_pubkey = self
+ .local_signing_identity_for_publish_payload(&AppPublishPayload::OrderCancellation(
+ payload.clone(),
+ ))
+ .and_then(|identity| {
+ let actor_pubkey = identity.public_key_hex();
+ let target_relays = normalized_app_sync_relay_urls(&self.nostr_relay_urls)?;
+ let request = AppSdkOrderCancellationRequest {
+ actor_account_id: payload.context.account_id.clone(),
+ actor_pubkey: actor_pubkey.clone(),
+ signer_keys: identity.into_keys(),
+ evidence_events: lifecycle.evidence_events,
+ root_event: order_lifecycle_sdk_event_ptr(
+ payload.request_event_id.as_str(),
+ target_relays.as_slice(),
+ "order cancellation requires request event id",
+ )?,
+ previous_event: order_lifecycle_sdk_event_ptr(
+ payload.prev_event_id.as_str(),
+ target_relays.as_slice(),
+ "order cancellation requires previous event id",
+ )?,
+ cancellation: order_cancellation_publish_payload_to_sdk_cancellation(payload)?,
+ relay_url_policy: sdk_relay_url_policy_for_targets(target_relays.as_slice()),
+ target_relays,
+ idempotency_key: Some(sdk_idempotency_key(source_record_id)),
+ };
+ self.enqueue_app_sdk_order_cancellation(request)
+ .map(|receipt| (actor_pubkey, receipt))
+ .map_err(sync_transport_error_from_sdk_runtime_error)
+ });
+ match actor_pubkey {
+ Ok((actor_pubkey, receipt)) => self.record_app_sdk_migration_success(
+ source_kind,
+ source_record_id,
+ operation_kind,
+ actor_pubkey.as_str(),
+ &receipt,
+ ),
+ Err(error) => self.record_app_sdk_migration_failure(
+ source_kind,
+ source_record_id,
+ operation_kind,
+ None,
+ sync_transport_error_detail_json(&error),
+ ),
+ }
+ }
+
+ fn enqueue_order_fulfillment_payload_via_sdk(
+ &self,
+ payload: &AppOrderFulfillmentPublishPayload,
+ source_kind: AppSdkMigrationReceiptSourceKind,
+ source_record_id: &str,
+ ) -> Result<(), AppSqliteError> {
+ let operation_kind = ORDER_FULFILLMENT_UPDATE_OPERATION_KIND;
+ let request_evidence = self.resolve_seller_order_request_evidence(payload.app_order_id)?;
+ let lifecycle = self.resolve_order_lifecycle_evidence(&request_evidence)?;
+ let actor_pubkey = self
+ .local_signing_identity_for_publish_payload(&AppPublishPayload::OrderFulfillment(
+ payload.clone(),
+ ))
+ .and_then(|identity| {
+ let actor_pubkey = identity.public_key_hex();
+ let target_relays = normalized_app_sync_relay_urls(&self.nostr_relay_urls)?;
+ let request = AppSdkOrderFulfillmentUpdateRequest {
+ actor_account_id: payload.context.account_id.clone(),
+ actor_pubkey: actor_pubkey.clone(),
+ signer_keys: identity.into_keys(),
+ evidence_events: lifecycle.evidence_events,
+ root_event: order_lifecycle_sdk_event_ptr(
+ payload.request_event_id.as_str(),
+ target_relays.as_slice(),
+ "order fulfillment requires request event id",
+ )?,
+ previous_event: order_lifecycle_sdk_event_ptr(
+ payload.prev_event_id.as_str(),
+ target_relays.as_slice(),
+ "order fulfillment requires previous event id",
+ )?,
+ fulfillment: order_fulfillment_publish_payload_to_sdk_fulfillment(payload)?,
+ relay_url_policy: sdk_relay_url_policy_for_targets(target_relays.as_slice()),
+ target_relays,
+ idempotency_key: Some(sdk_idempotency_key(source_record_id)),
+ };
+ self.enqueue_app_sdk_order_fulfillment_update(request)
+ .map(|receipt| (actor_pubkey, receipt))
+ .map_err(sync_transport_error_from_sdk_runtime_error)
+ });
+ match actor_pubkey {
+ Ok((actor_pubkey, receipt)) => self.record_app_sdk_migration_success(
+ source_kind,
+ source_record_id,
+ operation_kind,
+ actor_pubkey.as_str(),
+ &receipt,
+ ),
+ Err(error) => self.record_app_sdk_migration_failure(
+ source_kind,
+ source_record_id,
+ operation_kind,
+ None,
+ sync_transport_error_detail_json(&error),
+ ),
+ }
+ }
+
+ fn enqueue_order_receipt_payload_via_sdk(
+ &self,
+ payload: &AppOrderReceiptPublishPayload,
+ source_kind: AppSdkMigrationReceiptSourceKind,
+ source_record_id: &str,
+ ) -> Result<(), AppSqliteError> {
+ let operation_kind = ORDER_RECEIPT_RECORD_OPERATION_KIND;
+ let request_evidence = self.resolve_seller_order_request_evidence(payload.app_order_id)?;
+ let lifecycle = self.resolve_order_lifecycle_evidence(&request_evidence)?;
+ let actor_pubkey = self
+ .local_signing_identity_for_publish_payload(&AppPublishPayload::OrderReceipt(
+ payload.clone(),
+ ))
+ .and_then(|identity| {
+ let actor_pubkey = identity.public_key_hex();
+ let target_relays = normalized_app_sync_relay_urls(&self.nostr_relay_urls)?;
+ let request = AppSdkOrderReceiptRecordRequest {
+ actor_account_id: payload.context.account_id.clone(),
+ actor_pubkey: actor_pubkey.clone(),
+ signer_keys: identity.into_keys(),
+ evidence_events: lifecycle.evidence_events,
+ root_event: order_lifecycle_sdk_event_ptr(
+ payload.request_event_id.as_str(),
+ target_relays.as_slice(),
+ "order receipt requires request event id",
+ )?,
+ previous_event: order_lifecycle_sdk_event_ptr(
+ payload.prev_event_id.as_str(),
+ target_relays.as_slice(),
+ "order receipt requires previous event id",
+ )?,
+ receipt: order_receipt_publish_payload_to_sdk_receipt(payload)?,
+ relay_url_policy: sdk_relay_url_policy_for_targets(target_relays.as_slice()),
+ target_relays,
+ idempotency_key: Some(sdk_idempotency_key(source_record_id)),
+ };
+ self.enqueue_app_sdk_order_receipt_record(request)
+ .map(|receipt| (actor_pubkey, receipt))
+ .map_err(sync_transport_error_from_sdk_runtime_error)
+ });
+ match actor_pubkey {
+ Ok((actor_pubkey, receipt)) => self.record_app_sdk_migration_success(
+ source_kind,
+ source_record_id,
+ operation_kind,
+ actor_pubkey.as_str(),
+ &receipt,
+ ),
+ Err(error) => self.record_app_sdk_migration_failure(
+ source_kind,
+ source_record_id,
+ operation_kind,
+ None,
+ sync_transport_error_detail_json(&error),
+ ),
+ }
+ }
+
fn local_signing_identity_for_publish_payload(
&self,
payload: &AppPublishPayload,
@@ -5415,6 +5676,41 @@ impl DesktopAppRuntimeState {
self.with_app_sdk_runtime(|runtime| runtime.enqueue_order_decision(request))
}
+ fn enqueue_app_sdk_order_revision_proposal(
+ &self,
+ request: AppSdkOrderRevisionProposalRequest,
+ ) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeError> {
+ self.with_app_sdk_runtime(|runtime| runtime.enqueue_order_revision_proposal(request))
+ }
+
+ fn enqueue_app_sdk_order_revision_decision(
+ &self,
+ request: AppSdkOrderRevisionDecisionRequest,
+ ) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeError> {
+ self.with_app_sdk_runtime(|runtime| runtime.enqueue_order_revision_decision(request))
+ }
+
+ fn enqueue_app_sdk_order_cancellation(
+ &self,
+ request: AppSdkOrderCancellationRequest,
+ ) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeError> {
+ self.with_app_sdk_runtime(|runtime| runtime.enqueue_order_cancellation(request))
+ }
+
+ fn enqueue_app_sdk_order_fulfillment_update(
+ &self,
+ request: AppSdkOrderFulfillmentUpdateRequest,
+ ) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeError> {
+ self.with_app_sdk_runtime(|runtime| runtime.enqueue_order_fulfillment_update(request))
+ }
+
+ fn enqueue_app_sdk_order_receipt_record(
+ &self,
+ request: AppSdkOrderReceiptRecordRequest,
+ ) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeError> {
+ self.with_app_sdk_runtime(|runtime| runtime.enqueue_order_receipt_record(request))
+ }
+
fn with_app_sdk_runtime<T>(
&self,
command: impl FnOnce(&AppSdkRuntime) -> Result<T, AppSdkRuntimeError>,
@@ -5915,6 +6211,7 @@ impl DesktopAppRuntimeState {
.then_with(|| left.id.cmp(&right.id))
});
+ let mut evidence_events = vec![request.request_event.clone()];
let mut buckets = AppActiveOrderEvidenceBuckets::default();
let request_event_id =
active_order_event_id(request.request_event_id.as_str(), "request_event_id")?;
@@ -5933,6 +6230,7 @@ impl DesktopAppRuntimeState {
{
continue;
}
+ evidence_events.push(event.clone());
let event_id = active_order_event_id(event.id.as_str(), "event_id")?;
let author_pubkey = active_order_pubkey(event.author.as_str(), "author_pubkey")?;
match event.kind {
@@ -6141,6 +6439,7 @@ impl DesktopAppRuntimeState {
.transpose()?;
Ok(ResolvedAppOrderLifecycleEvidence {
+ evidence_events,
status: projection.status,
payment_state: projection.payment.state,
agreement_event_id: projection
@@ -7687,6 +7986,40 @@ fn order_decision_sdk_source_record_id(payload: &AppOrderDecisionPublishPayload)
format!("app:order_decision:{}", payload.app_order_id)
}
+fn order_revision_proposal_sdk_source_record_id(
+ payload: &AppOrderRevisionProposalPublishPayload,
+) -> String {
+ format!(
+ "app:order_revision_proposal:{}:{}",
+ payload.app_order_id, payload.revision_id
+ )
+}
+
+fn order_revision_decision_sdk_source_record_id(
+ payload: &AppOrderRevisionDecisionPublishPayload,
+) -> String {
+ format!(
+ "app:order_revision_decision:{}:{}",
+ payload.app_order_id, payload.revision_id
+ )
+}
+
+fn order_cancellation_sdk_source_record_id(payload: &AppOrderCancellationPublishPayload) -> String {
+ format!("app:order_cancellation:{}", payload.app_order_id)
+}
+
+fn order_fulfillment_sdk_source_record_id(payload: &AppOrderFulfillmentPublishPayload) -> String {
+ format!(
+ "app:order_fulfillment:{}:{}",
+ payload.app_order_id,
+ order_fulfillment_status_storage_key(payload.status)
+ )
+}
+
+fn order_receipt_sdk_source_record_id(payload: &AppOrderReceiptPublishPayload) -> String {
+ format!("app:order_receipt:{}", payload.app_order_id)
+}
+
fn sdk_relay_url_policy_for_targets(target_relays: &[String]) -> AppSdkRelayUrlPolicy {
if target_relays
.iter()
@@ -7854,82 +8187,21 @@ async fn publish_app_payload(
AppPublishPayload::OrderDecision(_) => Err(AppSyncTransportError::failed(
"order decision publish uses AppSdkRuntime",
)),
- AppPublishPayload::OrderRevisionProposal(payload) => {
- let proposal = order_revision_proposal_publish_payload_to_sdk_revision(payload)?;
- let request_event_id = publish_event_id(payload.request_event_id.as_str())?;
- let prev_event_id = publish_event_id(payload.prev_event_id.as_str())?;
- client
- .order()
- .publish_order_revision_proposal_with_identity(
- identity,
- &request_event_id,
- &prev_event_id,
- &proposal,
- )
- .await
- .map_err(|error| AppSyncTransportError::failed(error.to_string()))
- }
- AppPublishPayload::OrderRevisionDecision(payload) => {
- let decision =
- order_revision_decision_publish_payload_to_sdk_revision_decision(payload)?;
- let request_event_id = publish_event_id(payload.request_event_id.as_str())?;
- let prev_event_id = publish_event_id(payload.prev_event_id.as_str())?;
- client
- .order()
- .publish_order_revision_decision_with_identity(
- identity,
- &request_event_id,
- &prev_event_id,
- &decision,
- )
- .await
- .map_err(|error| AppSyncTransportError::failed(error.to_string()))
- }
- AppPublishPayload::OrderCancellation(payload) => {
- let cancellation = order_cancellation_publish_payload_to_sdk_cancellation(payload)?;
- let request_event_id = publish_event_id(payload.request_event_id.as_str())?;
- let prev_event_id = publish_event_id(payload.prev_event_id.as_str())?;
- client
- .order()
- .publish_order_cancellation_with_identity(
- identity,
- &request_event_id,
- &prev_event_id,
- &cancellation,
- )
- .await
- .map_err(|error| AppSyncTransportError::failed(error.to_string()))
- }
- AppPublishPayload::OrderFulfillment(payload) => {
- let fulfillment = order_fulfillment_publish_payload_to_sdk_fulfillment(payload)?;
- let request_event_id = publish_event_id(payload.request_event_id.as_str())?;
- let prev_event_id = publish_event_id(payload.prev_event_id.as_str())?;
- client
- .order()
- .publish_fulfillment_update_with_identity(
- identity,
- &request_event_id,
- &prev_event_id,
- &fulfillment,
- )
- .await
- .map_err(|error| AppSyncTransportError::failed(error.to_string()))
- }
- AppPublishPayload::OrderReceipt(payload) => {
- let receipt = order_receipt_publish_payload_to_sdk_receipt(payload)?;
- let request_event_id = publish_event_id(payload.request_event_id.as_str())?;
- let prev_event_id = publish_event_id(payload.prev_event_id.as_str())?;
- client
- .order()
- .publish_buyer_receipt_with_identity(
- identity,
- &request_event_id,
- &prev_event_id,
- &receipt,
- )
- .await
- .map_err(|error| AppSyncTransportError::failed(error.to_string()))
- }
+ AppPublishPayload::OrderRevisionProposal(_) => Err(AppSyncTransportError::failed(
+ "order revision proposal publish uses AppSdkRuntime",
+ )),
+ AppPublishPayload::OrderRevisionDecision(_) => Err(AppSyncTransportError::failed(
+ "order revision decision publish uses AppSdkRuntime",
+ )),
+ AppPublishPayload::OrderCancellation(_) => Err(AppSyncTransportError::failed(
+ "order cancellation publish uses AppSdkRuntime",
+ )),
+ AppPublishPayload::OrderFulfillment(_) => Err(AppSyncTransportError::failed(
+ "order fulfillment publish uses AppSdkRuntime",
+ )),
+ AppPublishPayload::OrderReceipt(_) => Err(AppSyncTransportError::failed(
+ "order receipt publish uses AppSdkRuntime",
+ )),
}
}
@@ -8179,6 +8451,32 @@ fn order_decision_sdk_request_event_ptr(
})
}
+fn order_lifecycle_sdk_event_ptr(
+ event_id: &str,
+ target_relays: &[String],
+ missing_message: &'static str,
+) -> Result<RadrootsNostrEventPtr, AppSyncTransportError> {
+ let event_id = event_id.trim();
+ if event_id.is_empty() {
+ return Err(AppSyncTransportError::failed(missing_message));
+ }
+ Ok(RadrootsNostrEventPtr {
+ id: event_id.to_owned(),
+ relays: target_relays.first().cloned(),
+ })
+}
+
+fn order_fulfillment_status_storage_key(status: RadrootsOrderFulfillmentState) -> &'static str {
+ match status {
+ RadrootsOrderFulfillmentState::AcceptedNotFulfilled => "accepted_not_fulfilled",
+ RadrootsOrderFulfillmentState::Preparing => "preparing",
+ RadrootsOrderFulfillmentState::ReadyForPickup => "ready_for_pickup",
+ RadrootsOrderFulfillmentState::OutForDelivery => "out_for_delivery",
+ RadrootsOrderFulfillmentState::Delivered => "delivered",
+ RadrootsOrderFulfillmentState::SellerCancelled => "seller_cancelled",
+ }
+}
+
#[cfg(test)]
fn selected_listing_relay(
listing_relays: &[String],
diff --git a/crates/desktop/src/source_guards.rs b/crates/desktop/src/source_guards.rs
@@ -1311,43 +1311,43 @@ const LEGACY_SDK_BOUNDARY_ALLOWLIST: &[LegacySdkBoundaryAllowlistEntry] = &[
path: "crates/desktop/src/runtime.rs",
pattern: "SdkDirectRelayAppSyncTransport",
owner: "rpv1-app-sdk-refactor.07",
- reason: "desktop runtime still owns deferred direct relay publish transport for unmigrated publish workflows",
- removal_condition: "remove when farm, listing, order, fulfillment, and receipt publish workflows enqueue through AppSdkRuntime",
+ reason: "desktop runtime still owns deferred direct relay publish transport for listing publish",
+ removal_condition: "remove when listing publish workflow enqueues through AppSdkRuntime",
},
LegacySdkBoundaryAllowlistEntry {
path: "crates/desktop/src/runtime.rs",
pattern: "RadrootsSdkClient",
owner: "rpv1-app-sdk-refactor.07",
- reason: "desktop runtime still constructs the legacy direct publish client for unmigrated publish workflows",
+ reason: "desktop runtime still constructs the legacy direct publish client for listing publish",
removal_condition: "remove when direct publish workflows no longer construct SDK clients outside AppSdkRuntime",
},
LegacySdkBoundaryAllowlistEntry {
path: "crates/desktop/src/runtime.rs",
pattern: "RadrootsSdkConfig",
owner: "rpv1-app-sdk-refactor.07",
- reason: "desktop runtime still configures the legacy direct publish client for unmigrated publish workflows",
+ reason: "desktop runtime still configures the legacy direct publish client for listing publish",
removal_condition: "remove when direct publish workflows no longer configure SDK clients outside AppSdkRuntime",
},
LegacySdkBoundaryAllowlistEntry {
path: "crates/desktop/src/runtime.rs",
pattern: "SdkTransportMode::RelayDirect",
owner: "rpv1-app-sdk-refactor.07",
- reason: "desktop runtime still uses relay direct publish transport for deferred workflow migration",
- removal_condition: "remove when all publish workflows route through SDK canonical outbox and sync APIs",
+ reason: "desktop runtime still uses relay direct publish transport for listing publish",
+ removal_condition: "remove when listing publish workflow routes through SDK canonical outbox and sync APIs",
},
LegacySdkBoundaryAllowlistEntry {
path: "crates/desktop/src/runtime.rs",
pattern: "SignerConfig::LocalIdentity",
owner: "rpv1-app-sdk-refactor.07",
- reason: "desktop runtime still configures direct local signing for deferred workflow migration",
+ reason: "desktop runtime still configures direct local signing for listing publish",
removal_condition: "remove when publish signing is mediated by AppSdkRuntime and SDK signer adapters",
},
LegacySdkBoundaryAllowlistEntry {
path: "crates/desktop/src/runtime.rs",
pattern: "PendingSyncOperation::from_publish_payload",
owner: "rpv1-app-sdk-refactor.07",
- reason: "desktop runtime still creates legacy local outbox publish work for unmigrated listing and order lifecycle workflows",
- removal_condition: "remove when listing and remaining order lifecycle publish workflows write SDK canonical outbox requests instead of app local_outbox operations",
+ reason: "desktop runtime still creates legacy local outbox publish work for listing publish",
+ removal_condition: "remove when listing publish writes SDK canonical outbox requests instead of app local_outbox operations",
},
LegacySdkBoundaryAllowlistEntry {
path: "crates/desktop/src/runtime.rs",
@@ -1357,41 +1357,6 @@ const LEGACY_SDK_BOUNDARY_ALLOWLIST: &[LegacySdkBoundaryAllowlistEntry] = &[
removal_condition: "remove when listing publish workflow enqueues through AppSdkRuntime",
},
LegacySdkBoundaryAllowlistEntry {
- path: "crates/desktop/src/runtime.rs",
- pattern: "publish_order_revision_proposal_with_identity",
- owner: "rpv1-app-sdk-refactor.07",
- reason: "desktop runtime still calls legacy direct SDK order revision proposal publish APIs",
- removal_condition: "remove when seller order revision proposal workflow enqueues through AppSdkRuntime",
- },
- LegacySdkBoundaryAllowlistEntry {
- path: "crates/desktop/src/runtime.rs",
- pattern: "publish_order_revision_decision_with_identity",
- owner: "rpv1-app-sdk-refactor.07",
- reason: "desktop runtime still calls legacy direct SDK order revision decision publish APIs",
- removal_condition: "remove when buyer order revision decision workflow enqueues through AppSdkRuntime",
- },
- LegacySdkBoundaryAllowlistEntry {
- path: "crates/desktop/src/runtime.rs",
- pattern: "publish_order_cancellation_with_identity",
- owner: "rpv1-app-sdk-refactor.07",
- reason: "desktop runtime still calls legacy direct SDK order cancellation publish APIs",
- removal_condition: "remove when buyer order cancellation workflow enqueues through AppSdkRuntime",
- },
- LegacySdkBoundaryAllowlistEntry {
- path: "crates/desktop/src/runtime.rs",
- pattern: "publish_fulfillment_update_with_identity",
- owner: "rpv1-app-sdk-refactor.07",
- reason: "desktop runtime still calls legacy direct SDK fulfillment publish APIs",
- removal_condition: "remove when seller fulfillment workflow enqueues through AppSdkRuntime",
- },
- LegacySdkBoundaryAllowlistEntry {
- path: "crates/desktop/src/runtime.rs",
- pattern: "publish_buyer_receipt_with_identity",
- owner: "rpv1-app-sdk-refactor.07",
- reason: "desktop runtime still calls legacy direct SDK receipt publish APIs",
- removal_condition: "remove when buyer receipt workflow enqueues through AppSdkRuntime",
- },
- LegacySdkBoundaryAllowlistEntry {
path: "crates/desktop/src/accounts.rs",
pattern: "RadrootsIdentity::from_secret_key_str",
owner: "rpv1-app-sdk-hardening.04",
@@ -1423,8 +1388,8 @@ const LEGACY_SDK_BOUNDARY_ALLOWLIST: &[LegacySdkBoundaryAllowlistEntry] = &[
path: "crates/sync/src/publish.rs",
pattern: "SdkTransportMode::RelayDirect",
owner: "rpv1-app-sdk-refactor.07",
- reason: "sync payload metadata still marks legacy app local outbox publish work as relay direct",
- removal_condition: "remove when app sync publish payloads are replaced by SDK canonical outbox requests",
+ reason: "sync payload metadata still marks legacy listing local outbox publish work as relay direct",
+ removal_condition: "remove when listing publish payload metadata is replaced by SDK canonical outbox requests",
},
LegacySdkBoundaryAllowlistEntry {
path: "crates/sync/src/publish.rs",
@@ -1434,41 +1399,6 @@ const LEGACY_SDK_BOUNDARY_ALLOWLIST: &[LegacySdkBoundaryAllowlistEntry] = &[
removal_condition: "remove when listing publish payload metadata is replaced by SDK canonical outbox requests",
},
LegacySdkBoundaryAllowlistEntry {
- path: "crates/sync/src/publish.rs",
- pattern: "publish_order_revision_proposal_with_identity",
- owner: "rpv1-app-sdk-refactor.07",
- reason: "sync payload metadata still names legacy order revision proposal SDK publish operations",
- removal_condition: "remove when order revision proposal payload metadata is replaced by SDK canonical outbox requests",
- },
- LegacySdkBoundaryAllowlistEntry {
- path: "crates/sync/src/publish.rs",
- pattern: "publish_order_revision_decision_with_identity",
- owner: "rpv1-app-sdk-refactor.07",
- reason: "sync payload metadata still names legacy order revision decision SDK publish operations",
- removal_condition: "remove when order revision decision payload metadata is replaced by SDK canonical outbox requests",
- },
- LegacySdkBoundaryAllowlistEntry {
- path: "crates/sync/src/publish.rs",
- pattern: "publish_order_cancellation_with_identity",
- owner: "rpv1-app-sdk-refactor.07",
- reason: "sync payload metadata still names legacy order cancellation SDK publish operations",
- removal_condition: "remove when order cancellation payload metadata is replaced by SDK canonical outbox requests",
- },
- LegacySdkBoundaryAllowlistEntry {
- path: "crates/sync/src/publish.rs",
- pattern: "publish_fulfillment_update_with_identity",
- owner: "rpv1-app-sdk-refactor.07",
- reason: "sync payload metadata still names legacy fulfillment SDK publish operations",
- removal_condition: "remove when fulfillment payload metadata is replaced by SDK canonical outbox requests",
- },
- LegacySdkBoundaryAllowlistEntry {
- path: "crates/sync/src/publish.rs",
- pattern: "publish_buyer_receipt_with_identity",
- owner: "rpv1-app-sdk-refactor.07",
- reason: "sync payload metadata still names legacy receipt SDK publish operations",
- removal_condition: "remove when receipt payload metadata is replaced by SDK canonical outbox requests",
- },
- LegacySdkBoundaryAllowlistEntry {
path: "crates/store/src/lib.rs",
pattern: ".enqueue_pending_operation(",
owner: "rpv1-app-sdk-refactor.07",
diff --git a/crates/runtime/src/lib.rs b/crates/runtime/src/lib.rs
@@ -38,13 +38,15 @@ pub use runtime::{
pub use sdk::{
APP_SDK_DEFAULT_COMMAND_QUEUE_CAPACITY, APP_SDK_STORAGE_DIR_NAME, AppSdkConfig,
AppSdkDiagnostics, AppSdkEventStoreDiagnostics, AppSdkFarmPublishRequest,
- AppSdkIntegrityDiagnostics, AppSdkLifecycleState, AppSdkOrderDecisionRequest,
- AppSdkOrderSubmitRequest, AppSdkOutboxDiagnostics, AppSdkProjectionLifecycleState,
- AppSdkProjectionLifecycleStatus, AppSdkRelayUrlPolicy, AppSdkRestorePreflightReceipt,
- AppSdkRestorePreflightRequest, AppSdkRuntime, AppSdkRuntimeError, AppSdkRuntimeIssue,
- AppSdkRuntimeStatus, AppSdkSqliteStoreDiagnostics, AppSdkStorageDiagnostics,
- AppSdkStoragePaths, AppSdkSyncDiagnostics, AppSdkSyncEventStoreDiagnostics,
- AppSdkSyncOutboxDiagnostics, AppSdkSyncRelayTargetDiagnostics, AppSdkWorkflowReceipt,
- app_sdk_storage_root_from_data_root,
+ AppSdkIntegrityDiagnostics, AppSdkLifecycleState, AppSdkOrderCancellationRequest,
+ AppSdkOrderDecisionRequest, AppSdkOrderFulfillmentUpdateRequest,
+ AppSdkOrderReceiptRecordRequest, AppSdkOrderRevisionDecisionRequest,
+ AppSdkOrderRevisionProposalRequest, AppSdkOrderSubmitRequest, AppSdkOutboxDiagnostics,
+ AppSdkProjectionLifecycleState, AppSdkProjectionLifecycleStatus, AppSdkRelayUrlPolicy,
+ AppSdkRestorePreflightReceipt, AppSdkRestorePreflightRequest, AppSdkRuntime,
+ AppSdkRuntimeError, AppSdkRuntimeIssue, AppSdkRuntimeStatus, AppSdkSqliteStoreDiagnostics,
+ AppSdkStorageDiagnostics, AppSdkStoragePaths, AppSdkSyncDiagnostics,
+ AppSdkSyncEventStoreDiagnostics, AppSdkSyncOutboxDiagnostics, AppSdkSyncRelayTargetDiagnostics,
+ AppSdkWorkflowReceipt, app_sdk_storage_root_from_data_root,
};
pub use startup::{AppStartupEvent, AppStartupEventMetadata, launch_startup_event};
diff --git a/crates/runtime/src/sdk.rs b/crates/runtime/src/sdk.rs
@@ -15,17 +15,27 @@ use radroots_events::{
RadrootsNostrEvent, RadrootsNostrEventPtr,
contract::RadrootsActorRole,
farm::RadrootsFarm,
- order::{RadrootsOrderDecision, RadrootsOrderRequest},
+ order::{
+ RadrootsOrderCancellation, RadrootsOrderDecision, RadrootsOrderFulfillmentUpdate,
+ RadrootsOrderReceipt, RadrootsOrderRequest, RadrootsOrderRevisionDecision,
+ RadrootsOrderRevisionProposal,
+ },
};
use radroots_nostr::prelude::RadrootsNostrKeys;
use radroots_sdk::{
FARM_PUBLISH_OPERATION_KIND, FarmEnqueuePublishRequest, FarmEnqueueReceipt, IntegrityReceipt,
- IntegrityRequest, ORDER_DECISION_OPERATION_KIND, ORDER_SUBMIT_OPERATION_KIND,
- OrderDecisionEnqueueRequest, OrderDecisionReceipt, OrderRequestEvidenceIngestRequest,
- OrderSubmitEnqueueRequest, OrderSubmitReceipt, RadrootsSdk, RadrootsSdkError,
- RadrootsSdkStoragePaths, RestoreReceipt, RestoreRequest, SdkBackupVerification,
- SdkRelayUrlPolicy as SdkRuntimeRelayUrlPolicy, StorageStatusReceipt, StorageStatusRequest,
- SyncStatusReceipt, SyncStatusRequest,
+ IntegrityRequest, ORDER_CANCELLATION_OPERATION_KIND, ORDER_DECISION_OPERATION_KIND,
+ ORDER_FULFILLMENT_UPDATE_OPERATION_KIND, ORDER_RECEIPT_RECORD_OPERATION_KIND,
+ ORDER_REVISION_DECISION_OPERATION_KIND, ORDER_REVISION_PROPOSAL_OPERATION_KIND,
+ ORDER_SUBMIT_OPERATION_KIND, OrderCancellationEnqueueRequest, OrderCancellationReceipt,
+ OrderDecisionEnqueueRequest, OrderDecisionReceipt, OrderEvidenceIngestRequest,
+ OrderFulfillmentUpdateEnqueueRequest, OrderFulfillmentUpdateReceipt,
+ OrderReceiptRecordEnqueueRequest, OrderReceiptRecordReceipt, OrderRequestEvidenceIngestRequest,
+ OrderRevisionDecisionEnqueueRequest, OrderRevisionDecisionReceipt,
+ OrderRevisionProposalEnqueueRequest, OrderRevisionProposalReceipt, OrderSubmitEnqueueRequest,
+ OrderSubmitReceipt, RadrootsSdk, RadrootsSdkError, RadrootsSdkStoragePaths, RestoreReceipt,
+ RestoreRequest, SdkBackupVerification, SdkRelayUrlPolicy as SdkRuntimeRelayUrlPolicy,
+ StorageStatusReceipt, StorageStatusRequest, SyncStatusReceipt, SyncStatusRequest,
};
use radroots_sdk::{SdkMutationState, SdkRelayTargetPolicy};
use serde::Serialize;
@@ -227,6 +237,71 @@ pub struct AppSdkOrderDecisionRequest {
pub idempotency_key: Option<String>,
}
+pub struct AppSdkOrderRevisionProposalRequest {
+ pub actor_account_id: String,
+ pub actor_pubkey: String,
+ pub signer_keys: RadrootsNostrKeys,
+ pub evidence_events: Vec<RadrootsNostrEvent>,
+ pub root_event: RadrootsNostrEventPtr,
+ pub previous_event: RadrootsNostrEventPtr,
+ pub proposal: RadrootsOrderRevisionProposal,
+ pub target_relays: Vec<String>,
+ pub relay_url_policy: AppSdkRelayUrlPolicy,
+ pub idempotency_key: Option<String>,
+}
+
+pub struct AppSdkOrderRevisionDecisionRequest {
+ pub actor_account_id: String,
+ pub actor_pubkey: String,
+ pub signer_keys: RadrootsNostrKeys,
+ pub evidence_events: Vec<RadrootsNostrEvent>,
+ pub root_event: RadrootsNostrEventPtr,
+ pub previous_event: RadrootsNostrEventPtr,
+ pub decision: RadrootsOrderRevisionDecision,
+ pub target_relays: Vec<String>,
+ pub relay_url_policy: AppSdkRelayUrlPolicy,
+ pub idempotency_key: Option<String>,
+}
+
+pub struct AppSdkOrderCancellationRequest {
+ pub actor_account_id: String,
+ pub actor_pubkey: String,
+ pub signer_keys: RadrootsNostrKeys,
+ pub evidence_events: Vec<RadrootsNostrEvent>,
+ pub root_event: RadrootsNostrEventPtr,
+ pub previous_event: RadrootsNostrEventPtr,
+ pub cancellation: RadrootsOrderCancellation,
+ pub target_relays: Vec<String>,
+ pub relay_url_policy: AppSdkRelayUrlPolicy,
+ pub idempotency_key: Option<String>,
+}
+
+pub struct AppSdkOrderFulfillmentUpdateRequest {
+ pub actor_account_id: String,
+ pub actor_pubkey: String,
+ pub signer_keys: RadrootsNostrKeys,
+ pub evidence_events: Vec<RadrootsNostrEvent>,
+ pub root_event: RadrootsNostrEventPtr,
+ pub previous_event: RadrootsNostrEventPtr,
+ pub fulfillment: RadrootsOrderFulfillmentUpdate,
+ pub target_relays: Vec<String>,
+ pub relay_url_policy: AppSdkRelayUrlPolicy,
+ pub idempotency_key: Option<String>,
+}
+
+pub struct AppSdkOrderReceiptRecordRequest {
+ pub actor_account_id: String,
+ pub actor_pubkey: String,
+ pub signer_keys: RadrootsNostrKeys,
+ pub evidence_events: Vec<RadrootsNostrEvent>,
+ pub root_event: RadrootsNostrEventPtr,
+ pub previous_event: RadrootsNostrEventPtr,
+ pub receipt: RadrootsOrderReceipt,
+ pub target_relays: Vec<String>,
+ pub relay_url_policy: AppSdkRelayUrlPolicy,
+ pub idempotency_key: Option<String>,
+}
+
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct AppSdkWorkflowReceipt {
pub operation_kind: String,
@@ -331,6 +406,26 @@ enum AppSdkWorkerCommand {
AppSdkOrderDecisionRequest,
mpsc::Sender<Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue>>,
),
+ EnqueueOrderRevisionProposal(
+ AppSdkOrderRevisionProposalRequest,
+ mpsc::Sender<Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue>>,
+ ),
+ EnqueueOrderRevisionDecision(
+ AppSdkOrderRevisionDecisionRequest,
+ mpsc::Sender<Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue>>,
+ ),
+ EnqueueOrderCancellation(
+ AppSdkOrderCancellationRequest,
+ mpsc::Sender<Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue>>,
+ ),
+ EnqueueOrderFulfillmentUpdate(
+ AppSdkOrderFulfillmentUpdateRequest,
+ mpsc::Sender<Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue>>,
+ ),
+ EnqueueOrderReceiptRecord(
+ AppSdkOrderReceiptRecordRequest,
+ mpsc::Sender<Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue>>,
+ ),
BeginProjectionRebuild(
mpsc::Sender<Result<AppSdkProjectionLifecycleStatus, AppSdkRuntimeIssue>>,
),
@@ -350,6 +445,19 @@ impl fmt::Debug for AppSdkWorkerCommand {
Self::EnqueueFarmPublish(_, _) => formatter.write_str("EnqueueFarmPublish"),
Self::EnqueueOrderSubmit(_, _) => formatter.write_str("EnqueueOrderSubmit"),
Self::EnqueueOrderDecision(_, _) => formatter.write_str("EnqueueOrderDecision"),
+ Self::EnqueueOrderRevisionProposal(_, _) => {
+ formatter.write_str("EnqueueOrderRevisionProposal")
+ }
+ Self::EnqueueOrderRevisionDecision(_, _) => {
+ formatter.write_str("EnqueueOrderRevisionDecision")
+ }
+ Self::EnqueueOrderCancellation(_, _) => formatter.write_str("EnqueueOrderCancellation"),
+ Self::EnqueueOrderFulfillmentUpdate(_, _) => {
+ formatter.write_str("EnqueueOrderFulfillmentUpdate")
+ }
+ Self::EnqueueOrderReceiptRecord(_, _) => {
+ formatter.write_str("EnqueueOrderReceiptRecord")
+ }
Self::BeginProjectionRebuild(_) => formatter.write_str("BeginProjectionRebuild"),
Self::CompleteProjectionRebuild(_) => formatter.write_str("CompleteProjectionRebuild"),
}
@@ -498,6 +606,51 @@ impl AppSdkRuntime {
})
}
+ pub fn enqueue_order_revision_proposal(
+ &self,
+ request: AppSdkOrderRevisionProposalRequest,
+ ) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeError> {
+ self.run_command(|response_sender| {
+ AppSdkWorkerCommand::EnqueueOrderRevisionProposal(request, response_sender)
+ })
+ }
+
+ pub fn enqueue_order_revision_decision(
+ &self,
+ request: AppSdkOrderRevisionDecisionRequest,
+ ) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeError> {
+ self.run_command(|response_sender| {
+ AppSdkWorkerCommand::EnqueueOrderRevisionDecision(request, response_sender)
+ })
+ }
+
+ pub fn enqueue_order_cancellation(
+ &self,
+ request: AppSdkOrderCancellationRequest,
+ ) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeError> {
+ self.run_command(|response_sender| {
+ AppSdkWorkerCommand::EnqueueOrderCancellation(request, response_sender)
+ })
+ }
+
+ pub fn enqueue_order_fulfillment_update(
+ &self,
+ request: AppSdkOrderFulfillmentUpdateRequest,
+ ) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeError> {
+ self.run_command(|response_sender| {
+ AppSdkWorkerCommand::EnqueueOrderFulfillmentUpdate(request, response_sender)
+ })
+ }
+
+ pub fn enqueue_order_receipt_record(
+ &self,
+ request: AppSdkOrderReceiptRecordRequest,
+ ) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeError> {
+ self.run_command(|response_sender| {
+ AppSdkWorkerCommand::EnqueueOrderReceiptRecord(request, response_sender)
+ })
+ }
+
pub fn begin_projection_rebuild(
&self,
) -> Result<AppSdkProjectionLifecycleStatus, AppSdkRuntimeError> {
@@ -996,6 +1149,67 @@ fn run_app_sdk_worker(
};
send_worker_result(&shared, response_sender, result);
}
+ AppSdkWorkerCommand::EnqueueOrderRevisionProposal(request, response_sender) => {
+ let result = if let Some(issue) = lifecycle_busy_issue(&shared) {
+ Err(issue)
+ } else {
+ match sdk.as_ref() {
+ Some(sdk) => {
+ enqueue_order_revision_proposal_with_sdk(&runtime, sdk, request)
+ }
+ None => Err(runtime_unavailable_issue(&shared)),
+ }
+ };
+ send_worker_result(&shared, response_sender, result);
+ }
+ AppSdkWorkerCommand::EnqueueOrderRevisionDecision(request, response_sender) => {
+ let result = if let Some(issue) = lifecycle_busy_issue(&shared) {
+ Err(issue)
+ } else {
+ match sdk.as_ref() {
+ Some(sdk) => {
+ enqueue_order_revision_decision_with_sdk(&runtime, sdk, request)
+ }
+ None => Err(runtime_unavailable_issue(&shared)),
+ }
+ };
+ send_worker_result(&shared, response_sender, result);
+ }
+ AppSdkWorkerCommand::EnqueueOrderCancellation(request, response_sender) => {
+ let result = if let Some(issue) = lifecycle_busy_issue(&shared) {
+ Err(issue)
+ } else {
+ match sdk.as_ref() {
+ Some(sdk) => enqueue_order_cancellation_with_sdk(&runtime, sdk, request),
+ None => Err(runtime_unavailable_issue(&shared)),
+ }
+ };
+ send_worker_result(&shared, response_sender, result);
+ }
+ AppSdkWorkerCommand::EnqueueOrderFulfillmentUpdate(request, response_sender) => {
+ let result = if let Some(issue) = lifecycle_busy_issue(&shared) {
+ Err(issue)
+ } else {
+ match sdk.as_ref() {
+ Some(sdk) => {
+ enqueue_order_fulfillment_update_with_sdk(&runtime, sdk, request)
+ }
+ None => Err(runtime_unavailable_issue(&shared)),
+ }
+ };
+ send_worker_result(&shared, response_sender, result);
+ }
+ AppSdkWorkerCommand::EnqueueOrderReceiptRecord(request, response_sender) => {
+ let result = if let Some(issue) = lifecycle_busy_issue(&shared) {
+ Err(issue)
+ } else {
+ match sdk.as_ref() {
+ Some(sdk) => enqueue_order_receipt_record_with_sdk(&runtime, sdk, request),
+ None => Err(runtime_unavailable_issue(&shared)),
+ }
+ };
+ send_worker_result(&shared, response_sender, result);
+ }
AppSdkWorkerCommand::BeginProjectionRebuild(response_sender) => {
let result = match sdk.as_ref() {
Some(_) => Ok(begin_projection_rebuild(&shared)),
@@ -1084,6 +1298,41 @@ fn run_degraded_worker(
Err(runtime_unavailable_issue(&shared)),
);
}
+ AppSdkWorkerCommand::EnqueueOrderRevisionProposal(_, response_sender) => {
+ send_worker_result(
+ &shared,
+ response_sender,
+ Err(runtime_unavailable_issue(&shared)),
+ );
+ }
+ AppSdkWorkerCommand::EnqueueOrderRevisionDecision(_, response_sender) => {
+ send_worker_result(
+ &shared,
+ response_sender,
+ Err(runtime_unavailable_issue(&shared)),
+ );
+ }
+ AppSdkWorkerCommand::EnqueueOrderCancellation(_, response_sender) => {
+ send_worker_result(
+ &shared,
+ response_sender,
+ Err(runtime_unavailable_issue(&shared)),
+ );
+ }
+ AppSdkWorkerCommand::EnqueueOrderFulfillmentUpdate(_, response_sender) => {
+ send_worker_result(
+ &shared,
+ response_sender,
+ Err(runtime_unavailable_issue(&shared)),
+ );
+ }
+ AppSdkWorkerCommand::EnqueueOrderReceiptRecord(_, response_sender) => {
+ send_worker_result(
+ &shared,
+ response_sender,
+ Err(runtime_unavailable_issue(&shared)),
+ );
+ }
AppSdkWorkerCommand::BeginProjectionRebuild(response_sender) => {
send_worker_result(
&shared,
@@ -1260,6 +1509,192 @@ fn enqueue_order_decision_with_sdk(
))
}
+fn enqueue_order_revision_proposal_with_sdk(
+ runtime: &tokio::runtime::Runtime,
+ sdk: &RadrootsSdk,
+ request: AppSdkOrderRevisionProposalRequest,
+) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue> {
+ let actor = sdk_actor_context(
+ request.actor_pubkey.as_str(),
+ request.actor_account_id.as_str(),
+ RadrootsActorRole::Seller,
+ )?;
+ let signer = sdk_local_signer(request.signer_keys)?;
+ let target_relays = sdk_relay_targets(request.target_relays, request.relay_url_policy)?;
+ ingest_order_evidence_with_sdk(runtime, sdk, request.evidence_events)?;
+ let mut enqueue = OrderRevisionProposalEnqueueRequest::new(
+ actor,
+ request.root_event,
+ request.previous_event,
+ request.proposal,
+ target_relays,
+ );
+ if let Some(idempotency_key) = request.idempotency_key.as_deref() {
+ enqueue = enqueue
+ .try_with_idempotency_key(idempotency_key)
+ .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?;
+ }
+ let receipt = runtime
+ .block_on(sdk.orders().enqueue_revision_proposal(enqueue, &signer))
+ .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?;
+ Ok(app_sdk_order_revision_proposal_receipt(
+ receipt,
+ request.actor_pubkey,
+ ))
+}
+
+fn enqueue_order_revision_decision_with_sdk(
+ runtime: &tokio::runtime::Runtime,
+ sdk: &RadrootsSdk,
+ request: AppSdkOrderRevisionDecisionRequest,
+) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue> {
+ let actor = sdk_actor_context(
+ request.actor_pubkey.as_str(),
+ request.actor_account_id.as_str(),
+ RadrootsActorRole::Buyer,
+ )?;
+ let signer = sdk_local_signer(request.signer_keys)?;
+ let target_relays = sdk_relay_targets(request.target_relays, request.relay_url_policy)?;
+ ingest_order_evidence_with_sdk(runtime, sdk, request.evidence_events)?;
+ let mut enqueue = OrderRevisionDecisionEnqueueRequest::new(
+ actor,
+ request.root_event,
+ request.previous_event,
+ request.decision,
+ target_relays,
+ );
+ if let Some(idempotency_key) = request.idempotency_key.as_deref() {
+ enqueue = enqueue
+ .try_with_idempotency_key(idempotency_key)
+ .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?;
+ }
+ let receipt = runtime
+ .block_on(sdk.orders().enqueue_revision_decision(enqueue, &signer))
+ .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?;
+ Ok(app_sdk_order_revision_decision_receipt(
+ receipt,
+ request.actor_pubkey,
+ ))
+}
+
+fn enqueue_order_cancellation_with_sdk(
+ runtime: &tokio::runtime::Runtime,
+ sdk: &RadrootsSdk,
+ request: AppSdkOrderCancellationRequest,
+) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue> {
+ let actor = sdk_actor_context(
+ request.actor_pubkey.as_str(),
+ request.actor_account_id.as_str(),
+ RadrootsActorRole::Buyer,
+ )?;
+ let signer = sdk_local_signer(request.signer_keys)?;
+ let target_relays = sdk_relay_targets(request.target_relays, request.relay_url_policy)?;
+ ingest_order_evidence_with_sdk(runtime, sdk, request.evidence_events)?;
+ let mut enqueue = OrderCancellationEnqueueRequest::new(
+ actor,
+ request.root_event,
+ request.previous_event,
+ request.cancellation,
+ target_relays,
+ );
+ if let Some(idempotency_key) = request.idempotency_key.as_deref() {
+ enqueue = enqueue
+ .try_with_idempotency_key(idempotency_key)
+ .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?;
+ }
+ let receipt = runtime
+ .block_on(sdk.orders().enqueue_cancellation(enqueue, &signer))
+ .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?;
+ Ok(app_sdk_order_cancellation_receipt(
+ receipt,
+ request.actor_pubkey,
+ ))
+}
+
+fn enqueue_order_fulfillment_update_with_sdk(
+ runtime: &tokio::runtime::Runtime,
+ sdk: &RadrootsSdk,
+ request: AppSdkOrderFulfillmentUpdateRequest,
+) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue> {
+ let actor = sdk_actor_context(
+ request.actor_pubkey.as_str(),
+ request.actor_account_id.as_str(),
+ RadrootsActorRole::Seller,
+ )?;
+ let signer = sdk_local_signer(request.signer_keys)?;
+ let target_relays = sdk_relay_targets(request.target_relays, request.relay_url_policy)?;
+ ingest_order_evidence_with_sdk(runtime, sdk, request.evidence_events)?;
+ let mut enqueue = OrderFulfillmentUpdateEnqueueRequest::new(
+ actor,
+ request.root_event,
+ request.previous_event,
+ request.fulfillment,
+ target_relays,
+ );
+ if let Some(idempotency_key) = request.idempotency_key.as_deref() {
+ enqueue = enqueue
+ .try_with_idempotency_key(idempotency_key)
+ .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?;
+ }
+ let receipt = runtime
+ .block_on(sdk.orders().enqueue_fulfillment_update(enqueue, &signer))
+ .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?;
+ Ok(app_sdk_order_fulfillment_update_receipt(
+ receipt,
+ request.actor_pubkey,
+ ))
+}
+
+fn enqueue_order_receipt_record_with_sdk(
+ runtime: &tokio::runtime::Runtime,
+ sdk: &RadrootsSdk,
+ request: AppSdkOrderReceiptRecordRequest,
+) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue> {
+ let actor = sdk_actor_context(
+ request.actor_pubkey.as_str(),
+ request.actor_account_id.as_str(),
+ RadrootsActorRole::Buyer,
+ )?;
+ let signer = sdk_local_signer(request.signer_keys)?;
+ let target_relays = sdk_relay_targets(request.target_relays, request.relay_url_policy)?;
+ ingest_order_evidence_with_sdk(runtime, sdk, request.evidence_events)?;
+ let mut enqueue = OrderReceiptRecordEnqueueRequest::new(
+ actor,
+ request.root_event,
+ request.previous_event,
+ request.receipt,
+ target_relays,
+ );
+ if let Some(idempotency_key) = request.idempotency_key.as_deref() {
+ enqueue = enqueue
+ .try_with_idempotency_key(idempotency_key)
+ .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?;
+ }
+ let receipt = runtime
+ .block_on(sdk.orders().enqueue_receipt_record(enqueue, &signer))
+ .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?;
+ Ok(app_sdk_order_receipt_record_receipt(
+ receipt,
+ request.actor_pubkey,
+ ))
+}
+
+fn ingest_order_evidence_with_sdk(
+ runtime: &tokio::runtime::Runtime,
+ sdk: &RadrootsSdk,
+ evidence_events: Vec<RadrootsNostrEvent>,
+) -> Result<(), AppSdkRuntimeIssue> {
+ for event in evidence_events {
+ runtime
+ .block_on(
+ sdk.orders()
+ .ingest_evidence(OrderEvidenceIngestRequest::new(event)),
+ )
+ .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?;
+ }
+ Ok(())
+}
+
fn sdk_actor_context(
actor_pubkey: &str,
actor_account_id: &str,
@@ -1334,6 +1769,86 @@ fn app_sdk_order_decision_receipt(
}
}
+fn app_sdk_order_revision_proposal_receipt(
+ receipt: OrderRevisionProposalReceipt,
+ actor_pubkey: String,
+) -> AppSdkWorkflowReceipt {
+ AppSdkWorkflowReceipt {
+ operation_kind: ORDER_REVISION_PROPOSAL_OPERATION_KIND.to_owned(),
+ expected_event_id: receipt.expected_event_id.as_str().to_owned(),
+ signed_event_id: receipt.signed_event_id.as_str().to_owned(),
+ outbox_operation_id: receipt.outbox_operation_id,
+ outbox_event_id: receipt.outbox_event_id,
+ state: sdk_mutation_state_key(receipt.state).to_owned(),
+ idempotency_digest_prefix: receipt.idempotency_digest_prefix,
+ actor_pubkey,
+ }
+}
+
+fn app_sdk_order_revision_decision_receipt(
+ receipt: OrderRevisionDecisionReceipt,
+ actor_pubkey: String,
+) -> AppSdkWorkflowReceipt {
+ AppSdkWorkflowReceipt {
+ operation_kind: ORDER_REVISION_DECISION_OPERATION_KIND.to_owned(),
+ expected_event_id: receipt.expected_event_id.as_str().to_owned(),
+ signed_event_id: receipt.signed_event_id.as_str().to_owned(),
+ outbox_operation_id: receipt.outbox_operation_id,
+ outbox_event_id: receipt.outbox_event_id,
+ state: sdk_mutation_state_key(receipt.state).to_owned(),
+ idempotency_digest_prefix: receipt.idempotency_digest_prefix,
+ actor_pubkey,
+ }
+}
+
+fn app_sdk_order_cancellation_receipt(
+ receipt: OrderCancellationReceipt,
+ actor_pubkey: String,
+) -> AppSdkWorkflowReceipt {
+ AppSdkWorkflowReceipt {
+ operation_kind: ORDER_CANCELLATION_OPERATION_KIND.to_owned(),
+ expected_event_id: receipt.expected_event_id.as_str().to_owned(),
+ signed_event_id: receipt.signed_event_id.as_str().to_owned(),
+ outbox_operation_id: receipt.outbox_operation_id,
+ outbox_event_id: receipt.outbox_event_id,
+ state: sdk_mutation_state_key(receipt.state).to_owned(),
+ idempotency_digest_prefix: receipt.idempotency_digest_prefix,
+ actor_pubkey,
+ }
+}
+
+fn app_sdk_order_fulfillment_update_receipt(
+ receipt: OrderFulfillmentUpdateReceipt,
+ actor_pubkey: String,
+) -> AppSdkWorkflowReceipt {
+ AppSdkWorkflowReceipt {
+ operation_kind: ORDER_FULFILLMENT_UPDATE_OPERATION_KIND.to_owned(),
+ expected_event_id: receipt.expected_event_id.as_str().to_owned(),
+ signed_event_id: receipt.signed_event_id.as_str().to_owned(),
+ outbox_operation_id: receipt.outbox_operation_id,
+ outbox_event_id: receipt.outbox_event_id,
+ state: sdk_mutation_state_key(receipt.state).to_owned(),
+ idempotency_digest_prefix: receipt.idempotency_digest_prefix,
+ actor_pubkey,
+ }
+}
+
+fn app_sdk_order_receipt_record_receipt(
+ receipt: OrderReceiptRecordReceipt,
+ actor_pubkey: String,
+) -> AppSdkWorkflowReceipt {
+ AppSdkWorkflowReceipt {
+ operation_kind: ORDER_RECEIPT_RECORD_OPERATION_KIND.to_owned(),
+ expected_event_id: receipt.expected_event_id.as_str().to_owned(),
+ signed_event_id: receipt.signed_event_id.as_str().to_owned(),
+ outbox_operation_id: receipt.outbox_operation_id,
+ outbox_event_id: receipt.outbox_event_id,
+ state: sdk_mutation_state_key(receipt.state).to_owned(),
+ idempotency_digest_prefix: receipt.idempotency_digest_prefix,
+ actor_pubkey,
+ }
+}
+
fn sdk_mutation_state_key(state: SdkMutationState) -> &'static str {
match state {
SdkMutationState::StoredAndQueued => "enqueued",
diff --git a/crates/sync/src/publish.rs b/crates/sync/src/publish.rs
@@ -7,7 +7,10 @@ use radroots_sdk::protocol::order::{
RadrootsOrderRevisionOutcome,
};
use radroots_sdk::{
- FARM_PUBLISH_OPERATION_KIND, ORDER_DECISION_OPERATION_KIND, ORDER_SUBMIT_OPERATION_KIND,
+ FARM_PUBLISH_OPERATION_KIND, ORDER_CANCELLATION_OPERATION_KIND, ORDER_DECISION_OPERATION_KIND,
+ ORDER_FULFILLMENT_UPDATE_OPERATION_KIND, ORDER_RECEIPT_RECORD_OPERATION_KIND,
+ ORDER_REVISION_DECISION_OPERATION_KIND, ORDER_REVISION_PROPOSAL_OPERATION_KIND,
+ ORDER_SUBMIT_OPERATION_KIND,
};
use serde::{Deserialize, Serialize};
use thiserror::Error;
@@ -49,11 +52,11 @@ impl AppPublishWorkKind {
Self::Listing => "listing.publish_draft_with_identity",
Self::OrderRequest => ORDER_SUBMIT_OPERATION_KIND,
Self::OrderDecision => ORDER_DECISION_OPERATION_KIND,
- Self::OrderRevisionProposal => "trade.publish_order_revision_proposal_with_identity",
- Self::OrderRevisionDecision => "trade.publish_order_revision_decision_with_identity",
- Self::OrderCancellation => "trade.publish_order_cancellation_with_identity",
- Self::OrderFulfillment => "trade.publish_fulfillment_update_with_identity",
- Self::OrderReceipt => "trade.publish_buyer_receipt_with_identity",
+ Self::OrderRevisionProposal => ORDER_REVISION_PROPOSAL_OPERATION_KIND,
+ Self::OrderRevisionDecision => ORDER_REVISION_DECISION_OPERATION_KIND,
+ Self::OrderCancellation => ORDER_CANCELLATION_OPERATION_KIND,
+ Self::OrderFulfillment => ORDER_FULFILLMENT_UPDATE_OPERATION_KIND,
+ Self::OrderReceipt => ORDER_RECEIPT_RECORD_OPERATION_KIND,
}
}
}
@@ -320,13 +323,15 @@ impl AppPublishPayload {
pub const fn legacy_sdk_transport_mode(&self) -> Option<SdkTransportMode> {
match self {
- Self::FarmProfile(_) | Self::OrderRequest(_) | Self::OrderDecision(_) => None,
- Self::Listing(_)
+ Self::Listing(_) => Some(SdkTransportMode::RelayDirect),
+ Self::FarmProfile(_)
+ | Self::OrderRequest(_)
+ | Self::OrderDecision(_)
| Self::OrderRevisionProposal(_)
| Self::OrderRevisionDecision(_)
| Self::OrderCancellation(_)
| Self::OrderFulfillment(_)
- | Self::OrderReceipt(_) => Some(SdkTransportMode::RelayDirect),
+ | Self::OrderReceipt(_) => None,
}
}
@@ -801,7 +806,9 @@ mod tests {
AppOrderRequestPublishPayload, AppOrderRevisionDecisionPublishPayload,
AppOrderRevisionProposalPublishPayload, AppPublishContext, AppPublishPayload,
AppPublishValidationFailure, AppPublishWorkKind, FARM_PUBLISH_OPERATION_KIND,
- ORDER_DECISION_OPERATION_KIND,
+ ORDER_CANCELLATION_OPERATION_KIND, ORDER_DECISION_OPERATION_KIND,
+ ORDER_FULFILLMENT_UPDATE_OPERATION_KIND, ORDER_RECEIPT_RECORD_OPERATION_KIND,
+ ORDER_REVISION_DECISION_OPERATION_KIND, ORDER_REVISION_PROPOSAL_OPERATION_KIND,
};
use crate::{
PendingSyncOperation, PendingSyncOperationState, SyncAggregateRef, SyncOperationKind,
@@ -1067,15 +1074,15 @@ mod tests {
assert_eq!(
cancellation.work_kind().sdk_operation(),
- "trade.publish_order_cancellation_with_identity"
+ ORDER_CANCELLATION_OPERATION_KIND
);
assert_eq!(
fulfillment.work_kind().sdk_operation(),
- "trade.publish_fulfillment_update_with_identity"
+ ORDER_FULFILLMENT_UPDATE_OPERATION_KIND
);
assert_eq!(
receipt.work_kind().sdk_operation(),
- "trade.publish_buyer_receipt_with_identity"
+ ORDER_RECEIPT_RECORD_OPERATION_KIND
);
assert_eq!(fulfillment.validation_failures(), Vec::new());
@@ -1224,12 +1231,12 @@ mod tests {
assert_eq!(
valid_proposal.work_kind().sdk_operation(),
- "trade.publish_order_revision_proposal_with_identity"
+ ORDER_REVISION_PROPOSAL_OPERATION_KIND
);
assert_eq!(valid_proposal.validation_failures(), Vec::new());
assert_eq!(
invalid_decision.work_kind().sdk_operation(),
- "trade.publish_order_revision_decision_with_identity"
+ ORDER_REVISION_DECISION_OPERATION_KIND
);
let proposal_reason_codes: Vec<&str> = invalid_proposal