commit 33ed23a220643548f8816b8098ebe8f8cf7133e6 parent 9b99c76042412f066c96e70e3a0744ad3eb53f1d Author: triesap <tyson@radroots.org> Date: Sat, 11 Jul 2026 23:25:13 +0000 crate-surface: use runtime store namespace - update Studio dependencies to runtime_store and singular event crates - rename shared runtime-store imports, provenance, and localized keys - align SDK adapter with current transport profile APIs - pass reducer-visible evidence into SDK revision decisions Diffstat:
31 files changed, 1031 insertions(+), 888 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock @@ -5091,7 +5091,7 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" name = "radroots_authority" version = "0.1.0-alpha.2" dependencies = [ - "radroots_events", + "radroots_event", "radroots_nostr", ] @@ -5105,37 +5105,38 @@ dependencies = [ ] [[package]] -name = "radroots_event_store" +name = "radroots_event" version = "0.1.0-alpha.2" dependencies = [ - "radroots_events", - "radroots_nostr", + "hex", + "radroots_core", "serde", "serde_json", - "sqlx", - "thiserror 1.0.69", + "sha2", ] [[package]] -name = "radroots_events" +name = "radroots_event_codec" version = "0.1.0-alpha.2" dependencies = [ - "hex", + "nostr", "radroots_core", + "radroots_event", "serde", "serde_json", - "sha2", ] [[package]] -name = "radroots_events_codec" +name = "radroots_event_store" version = "0.1.0-alpha.2" dependencies = [ - "nostr", - "radroots_core", - "radroots_events", + "radroots_event", + "radroots_nostr", + "radroots_transport", "serde", "serde_json", + "sqlx", + "thiserror 1.0.69", ] [[package]] @@ -5158,7 +5159,7 @@ name = "radroots_identity" version = "0.1.0-alpha.2" dependencies = [ "nostr", - "radroots_events", + "radroots_event", "radroots_protected_store", "radroots_runtime", "radroots_runtime_paths", @@ -5170,16 +5171,6 @@ dependencies = [ ] [[package]] -name = "radroots_local_events" -version = "0.1.0-alpha.2" -dependencies = [ - "radroots_sql_core", - "serde", - "serde_json", - "thiserror 1.0.69", -] - -[[package]] name = "radroots_log" version = "0.1.0-alpha.2" dependencies = [ @@ -5196,8 +5187,8 @@ version = "0.1.0-alpha.2" dependencies = [ "nostr", "nostr-sdk", - "radroots_events", - "radroots_events_codec", + "radroots_event", + "radroots_event_codec", "radroots_identity", "serde", "serde_json", @@ -5253,8 +5244,9 @@ name = "radroots_outbox" version = "0.1.0-alpha.2" dependencies = [ "hex", + "radroots_event", "radroots_event_store", - "radroots_events", + "radroots_transport", "serde", "serde_json", "sha2", @@ -5275,23 +5267,6 @@ dependencies = [ ] [[package]] -name = "radroots_relay_transport" -version = "0.1.0-alpha.2" -dependencies = [ - "futures", - "nostr", - "radroots_event_store", - "radroots_events", - "radroots_nostr", - "radroots_outbox", - "serde", - "serde_json", - "thiserror 1.0.69", - "tokio", - "url", -] - -[[package]] name = "radroots_runtime" version = "0.1.0-alpha.2" dependencies = [ @@ -5322,24 +5297,36 @@ dependencies = [ ] [[package]] +name = "radroots_runtime_store" +version = "0.1.0-alpha.2" +dependencies = [ + "radroots_sql_core", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] name = "radroots_sdk" version = "0.1.0" dependencies = [ "hex", "nostr", "radroots_authority", + "radroots_event", + "radroots_event_codec", "radroots_event_store", - "radroots_events", - "radroots_events_codec", "radroots_geocoder", "radroots_identity", "radroots_nostr", "radroots_nostr_connect", "radroots_nostr_signer", "radroots_outbox", - "radroots_relay_transport", "radroots_runtime_paths", "radroots_trade", + "radroots_transport", + "radroots_transport_nostr", + "radroots_transport_reticulum", "serde", "serde_json", "sha2", @@ -5373,13 +5360,13 @@ dependencies = [ "gpui-component", "gpui-component-assets", "radroots_core", - "radroots_events", - "radroots_events_codec", + "radroots_event", + "radroots_event_codec", "radroots_identity", - "radroots_local_events", "radroots_nostr", "radroots_nostr_accounts", "radroots_protected_store", + "radroots_runtime_store", "radroots_sdk", "radroots_secret_vault", "radroots_sql_core", @@ -5408,10 +5395,10 @@ dependencies = [ "chrono", "radroots_authority", "radroots_core", - "radroots_events", - "radroots_local_events", + "radroots_event", "radroots_nostr", "radroots_runtime_paths", + "radroots_runtime_store", "radroots_sdk", "radroots_studio_app_view", "radroots_trade", @@ -5451,9 +5438,9 @@ name = "radroots_studio_app_sqlite" version = "0.1.0" dependencies = [ "radroots_core", - "radroots_events", - "radroots_events_codec", - "radroots_local_events", + "radroots_event", + "radroots_event_codec", + "radroots_runtime_store", "radroots_sql_core", "radroots_studio_app_sync", "radroots_studio_app_view", @@ -5480,7 +5467,7 @@ dependencies = [ name = "radroots_studio_app_sync" version = "0.1.0" dependencies = [ - "radroots_events", + "radroots_event", "radroots_sdk", "radroots_studio_app_view", "serde", @@ -5511,7 +5498,7 @@ name = "radroots_studio_app_view" version = "0.1.0" dependencies = [ "radroots_core", - "radroots_events", + "radroots_event", "radroots_studio_app_types", "radroots_trade", "serde", @@ -5527,9 +5514,9 @@ dependencies = [ "hex", "radroots_authority", "radroots_core", + "radroots_event", + "radroots_event_codec", "radroots_event_store", - "radroots_events", - "radroots_events_codec", "serde", "serde_json", "sha2", @@ -5538,6 +5525,39 @@ dependencies = [ ] [[package]] +name = "radroots_transport" +version = "0.1.0-alpha.2" +dependencies = [ + "serde", + "sha2", +] + +[[package]] +name = "radroots_transport_nostr" +version = "0.1.0-alpha.2" +dependencies = [ + "futures", + "nostr", + "radroots_event", + "radroots_event_store", + "radroots_nostr", + "radroots_outbox", + "radroots_transport", + "serde", + "serde_json", + "thiserror 1.0.69", + "tokio", + "url", +] + +[[package]] +name = "radroots_transport_reticulum" +version = "0.1.0-alpha.2" +dependencies = [ + "radroots_transport", +] + +[[package]] name = "rand" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml @@ -33,10 +33,10 @@ gpui-component-assets = "0.5.1" mf2_i18n = { path = "../../../vendor/triesap/mf2_i18n/crates/mf2_i18n" } radroots_core = { path = "../lib/crates/core", default-features = false, features = ["std"] } radroots_authority = { path = "../lib/crates/authority" } -radroots_events = { path = "../lib/crates/events", default-features = false, features = ["serde", "std"] } -radroots_events_codec = { path = "../lib/crates/events_codec", features = ["serde_json"] } +radroots_event = { path = "../lib/crates/event", default-features = false, features = ["serde", "std"] } +radroots_event_codec = { path = "../lib/crates/event_codec", features = ["serde_json"] } radroots_identity = { path = "../lib/crates/identity" } -radroots_local_events = { path = "../lib/crates/local_events", features = ["native"] } +radroots_runtime_store = { path = "../lib/crates/runtime_store", features = ["native"] } radroots_nostr = { path = "../lib/crates/nostr", features = ["client"] } radroots_nostr_accounts = { path = "../lib/crates/nostr_accounts" } radroots_nostr_connect = { path = "../lib/crates/nostr_connect" } diff --git a/crates/desktop/Cargo.toml b/crates/desktop/Cargo.toml @@ -15,7 +15,7 @@ gpui.workspace = true gpui-component.workspace = true gpui-component-assets.workspace = true radroots_core.workspace = true -radroots_events_codec.workspace = true +radroots_event_codec.workspace = true radroots_identity.workspace = true radroots_nostr.workspace = true radroots_nostr_accounts.workspace = true @@ -30,8 +30,8 @@ radroots_studio_app_sqlite.workspace = true radroots_studio_app_state.workspace = true radroots_studio_app_sync.workspace = true radroots_studio_app_ui.workspace = true -radroots_events.workspace = true -radroots_local_events.workspace = true +radroots_event.workspace = true +radroots_runtime_store.workspace = true radroots_sql_core.workspace = true radroots_trade.workspace = true serde_json.workspace = true diff --git a/crates/desktop/src/runtime.rs b/crates/desktop/src/runtime.rs @@ -10,8 +10,8 @@ use radroots_core::{ RadrootsCoreCurrency, RadrootsCoreDecimal, RadrootsCoreMoney, RadrootsCoreQuantity, RadrootsCoreQuantityPrice, RadrootsCoreUnit, }; -use radroots_events::{ - RadrootsNostrEvent as SdkRadrootsNostrEvent, RadrootsNostrEventPtr, +use radroots_event::{ + RadrootsEventEnvelope, RadrootsEventPtr, farm::{RadrootsFarm, RadrootsFarmPublicLocation, RadrootsFarmRef}, ids::{ RadrootsDTag, RadrootsEventId, RadrootsInventoryBinId, RadrootsListingAddress, @@ -33,29 +33,30 @@ use radroots_events::{ RadrootsOrderRevisionDecision, RadrootsOrderRevisionOutcome, RadrootsOrderRevisionProposal, }, }; -use radroots_events_codec::order::{ +use radroots_event_codec::order::{ order_cancellation_from_event, order_decision_from_event, order_event_context_from_tags, order_request_from_event, order_revision_decision_from_event, order_revision_proposal_from_event, }; use radroots_identity::{RadrootsIdentity, RadrootsIdentityId}; -use radroots_local_events::{ - BUYER_ORDER_REQUEST_ACTOR_SOURCE_RESOLVED_ACCOUNT, - BUYER_ORDER_REQUEST_ACTOR_SOURCE_UNRESOLVED_APP, BUYER_ORDER_REQUEST_DOCUMENT_KIND, - BUYER_ORDER_REQUEST_LOCAL_WORK_RECORD_KIND, LocalEventRecord, LocalEventRecordInput, - LocalEventRecordUpdate, LocalEventsStore, LocalRecordFamily, LocalRecordStatus, - PublishOutboxStatus, RelayDeliveryEvidence, RelayDeliveryFailure, SourceRuntime, - buyer_order_request_local_work_record_id, validate_buyer_order_request_local_work_payload, -}; use radroots_nostr::prelude::{ RadrootsNostrClient, RadrootsNostrEvent, RadrootsNostrFilter, RadrootsNostrOutput, RadrootsNostrTimestamp, radroots_nostr_kind, radroots_nostr_parse_pubkey, }; use radroots_nostr_accounts::prelude::RadrootsNostrAccountsManager; +use radroots_runtime_store::{ + BUYER_ORDER_REQUEST_ACTOR_SOURCE_RESOLVED_ACCOUNT, + BUYER_ORDER_REQUEST_ACTOR_SOURCE_UNRESOLVED_APP, BUYER_ORDER_REQUEST_DOCUMENT_KIND, + BUYER_ORDER_REQUEST_LOCAL_WORK_RECORD_KIND, PublishOutboxStatus, RelayDeliveryEvidence, + RelayDeliveryFailure, RuntimeStore, RuntimeStoreRecord, RuntimeStoreRecordFamily, + RuntimeStoreRecordInput, RuntimeStoreRecordStatus, RuntimeStoreRecordUpdate, SourceRuntime, + buyer_order_request_local_work_record_id, validate_buyer_order_request_local_work_payload, +}; use radroots_sdk::{ - FARM_PUBLISH_OPERATION_KIND, LISTING_PUBLISH_OPERATION_KIND, TRADE_CANCELLATION_OPERATION_KIND, - TRADE_DECISION_OPERATION_KIND, TRADE_REVISION_DECISION_OPERATION_KIND, - TRADE_REVISION_PROPOSAL_OPERATION_KIND, TRADE_SUBMIT_OPERATION_KIND, + FARM_PUBLISH_OPERATION_KIND, LISTING_PUBLISH_OPERATION_KIND, NostrRelayUrlPolicy, + TRADE_CANCELLATION_OPERATION_KIND, TRADE_DECISION_OPERATION_KIND, + TRADE_REVISION_DECISION_OPERATION_KIND, TRADE_REVISION_PROPOSAL_OPERATION_KIND, + TRADE_SUBMIT_OPERATION_KIND, TargetSet, }; use radroots_sql_core::SqliteExecutor; use radroots_studio_app_core::{ @@ -68,7 +69,7 @@ use radroots_studio_app_core::{ AppSdkTradeDecisionRequest, AppSdkTradeProposeRequest, AppSdkTradeRevisionDecisionRequest, AppSdkTradeRevisionProposalRequest, 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, + shared_runtime_store_database_path_from_shared_accounts, write_prepared_pack_day_export_bundle, }; use radroots_studio_app_remote_signer::{ RadrootsAppRemoteSignerApprovedSession, RadrootsAppRemoteSignerPendingSession, @@ -76,7 +77,7 @@ use radroots_studio_app_remote_signer::{ use radroots_studio_app_sqlite::{ APP_ACTIVITY_CONTEXT_LIMIT, AppLocalInteropImportReport, AppSdkWorkflowReceiptInput, AppSdkWorkflowReceiptSourceKind, AppSdkWorkflowReceiptState, AppSqliteError, AppSqliteStore, - BuyerOrderLocalEventExport, BuyerOrderLocalEventLine, BuyerRepeatDemandApplyOutcome, + BuyerOrderRuntimeStoreExport, BuyerOrderRuntimeStoreLine, BuyerRepeatDemandApplyOutcome, DatabaseTarget, SelectedBuyerOrderScope, SellerOrderDecisionExport, StoredPendingSyncOperation, StoredRelayIngestCursor, StoredSyncConflict, derive_farm_rules_readiness, projected_order_id_from_trade_request, @@ -223,7 +224,7 @@ pub enum AppSellerOrderDecisionCommand { #[derive(Clone, Debug, Eq, PartialEq)] struct ResolvedAppSellerOrderRequest { - request_event: SdkRadrootsNostrEvent, + request_event: RadrootsEventEnvelope, request_event_id: String, request_author_pubkey: String, listing_event_id: Option<String>, @@ -238,6 +239,7 @@ struct ResolvedAppOrderDecisionEvidence { #[derive(Clone, Debug, Eq, PartialEq)] struct ResolvedAppOrderRevisionProposalEvidence { + event: RadrootsEventEnvelope, event_id: String, payload: RadrootsOrderRevisionProposal, } @@ -1094,12 +1096,12 @@ impl DesktopAppRuntime { .attempt_sync(SyncTrigger::ManualRefresh) } - pub fn refresh_shared_local_events( + pub fn refresh_shared_runtime_store( &self, ) -> Result<AppLocalInteropImportReport, AppSqliteError> { let mut state = self.lock_state_mut(); - let report = state.import_shared_local_events()?; - let _ = state.refresh_selected_account_context_after_local_events()?; + let report = state.import_shared_runtime_store()?; + let _ = state.refresh_selected_account_context_after_runtime_store()?; Ok(report) } @@ -1347,7 +1349,7 @@ impl DesktopAppSdkReadyDiagnosticsSummary { integrity_outbox_ok: diagnostics.integrity.outbox_ok, sync_source: diagnostics.sync.source.clone(), sync_observed_at_ms: diagnostics.sync.observed_at_ms, - sync_relay_target_count: diagnostics.sync.relay_targets.configured_count, + sync_relay_target_count: diagnostics.sync.transport_targets.configured_count, } } @@ -1587,9 +1589,9 @@ impl DesktopAppRuntimeState { } let database_path = paths.app.data.join(APP_DATABASE_FILE_NAME); let sqlite_store = AppSqliteStore::open(DatabaseTarget::Path(database_path.clone()))?; - let shared_local_events_database_path = paths.shared_local_events_database_path()?; + let shared_runtime_store_database_path = paths.shared_runtime_store_database_path()?; let _ = sqlite_store - .import_shared_local_events_from_path(shared_local_events_database_path.as_path())?; + .import_shared_runtime_store_from_path(shared_runtime_store_database_path.as_path())?; let database_schema_version = sqlite_store.schema_version()?; let mut state_store = AppStateStore::load(AppStatePersistenceRepository::file_backed( paths.app.data.join(APP_STATE_FILE_NAME), @@ -1854,9 +1856,9 @@ impl DesktopAppRuntimeState { } fn refresh_personal_browse_navigation(&mut self) -> Result<bool, AppSqliteError> { - let report = self.import_shared_local_events()?; + let report = self.import_shared_runtime_store()?; let local_changed = report.imported_records > 0 || report.skipped_records > 0; - let context_changed = self.refresh_selected_account_context_after_local_events()?; + let context_changed = self.refresh_selected_account_context_after_runtime_store()?; Ok(local_changed || context_changed) } @@ -2554,7 +2556,7 @@ impl DesktopAppRuntimeState { order_id: OrderId, command: AppSellerOrderDecisionCommand, ) -> Result<AppOrderDecisionPublishPayload, AppSqliteError> { - let _ = self.import_shared_local_events()?; + let _ = self.import_shared_runtime_store()?; let relay_urls = normalized_app_sync_relay_urls(&self.nostr_relay_urls).map_err(|_| { AppSqliteError::InvalidProjection { reason: "seller order decision requires valid configured relays", @@ -2587,7 +2589,7 @@ impl DesktopAppRuntimeState { }); }; let account_id = selected_account.account.account_id.clone(); - let seller_pubkey = self.local_events_owner_pubkey(selected_account).ok_or( + let seller_pubkey = self.runtime_store_owner_pubkey(selected_account).ok_or( AppSqliteError::InvalidProjection { reason: "seller order decision requires a selected seller public key", }, @@ -2684,7 +2686,7 @@ impl DesktopAppRuntimeState { || report.local_import.imported_records > 0 || report.local_import.skipped_records > 0 { - let _ = self.refresh_selected_account_context_after_local_events()?; + let _ = self.refresh_selected_account_context_after_runtime_store()?; } Ok(()) } @@ -2721,7 +2723,7 @@ impl DesktopAppRuntimeState { reason: &str, confirm_public_note: bool, ) -> Result<AppOrderRevisionProposalPublishPayload, AppSqliteError> { - let _ = self.import_shared_local_events()?; + let _ = self.import_shared_runtime_store()?; let relay_urls = normalized_app_sync_relay_urls(&self.nostr_relay_urls).map_err(|_| { AppSqliteError::InvalidProjection { reason: "seller order revision requires valid configured relays", @@ -2754,7 +2756,7 @@ impl DesktopAppRuntimeState { }); }; let account_id = selected_account.account.account_id.clone(); - let seller_pubkey = self.local_events_owner_pubkey(selected_account).ok_or( + let seller_pubkey = self.runtime_store_owner_pubkey(selected_account).ok_or( AppSqliteError::InvalidProjection { reason: "seller order revision requires a selected seller public key", }, @@ -2861,7 +2863,7 @@ impl DesktopAppRuntimeState { decision: RadrootsOrderRevisionOutcome, confirm_public_note: bool, ) -> Result<AppOrderRevisionDecisionPublishPayload, AppSqliteError> { - let _ = self.import_shared_local_events()?; + let _ = self.import_shared_runtime_store()?; let relay_urls = normalized_app_sync_relay_urls(&self.nostr_relay_urls).map_err(|_| { AppSqliteError::InvalidProjection { reason: "buyer order revision requires valid configured relays", @@ -2884,7 +2886,7 @@ impl DesktopAppRuntimeState { reason: "buyer order revision requires a selected buyer account", }); }; - let buyer_pubkey = self.local_events_owner_pubkey(selected_account).ok_or( + let buyer_pubkey = self.runtime_store_owner_pubkey(selected_account).ok_or( AppSqliteError::InvalidProjection { reason: "buyer order revision requires a selected buyer public key", }, @@ -3007,7 +3009,7 @@ impl DesktopAppRuntimeState { order_id: OrderId, confirm_public_note: bool, ) -> Result<AppOrderCancellationPublishPayload, AppSqliteError> { - let _ = self.import_shared_local_events()?; + let _ = self.import_shared_runtime_store()?; let relay_urls = normalized_app_sync_relay_urls(&self.nostr_relay_urls).map_err(|_| { AppSqliteError::InvalidProjection { reason: "buyer order cancellation requires valid configured relays", @@ -3030,7 +3032,7 @@ impl DesktopAppRuntimeState { reason: "buyer order cancellation requires a selected buyer account", }); }; - let buyer_pubkey = self.local_events_owner_pubkey(selected_account).ok_or( + let buyer_pubkey = self.runtime_store_owner_pubkey(selected_account).ok_or( AppSqliteError::InvalidProjection { reason: "buyer order cancellation requires a selected buyer public key", }, @@ -3734,7 +3736,7 @@ impl DesktopAppRuntimeState { projection: AppIdentityProjection, ) -> Result<bool, DesktopAppRuntimeCommandError> { let projection = self.decorate_identity_projection(projection)?; - let _ = self.import_shared_local_events()?; + let _ = self.import_shared_runtime_store()?; let continuity_state = self.continuity_state(); let selected_account_context = load_selected_account_context(self.sqlite_store()?, &projection, &continuity_state)?; @@ -3756,7 +3758,7 @@ impl DesktopAppRuntimeState { fn refresh_selected_account_context( &self, ) -> Result<DesktopSelectedAccountContext, DesktopAppRuntimeFarmSetupError> { - let _ = self.import_shared_local_events()?; + let _ = self.import_shared_runtime_store()?; let continuity_state = self.continuity_state(); Ok(load_selected_account_context( self.sqlite_store_for_farm_setup()?, @@ -4099,7 +4101,7 @@ impl DesktopAppRuntimeState { &result, )?; if relay_context_changed { - changed |= self.refresh_selected_account_context_after_local_events()?; + changed |= self.refresh_selected_account_context_after_runtime_store()?; } } Err(error) => { @@ -4114,7 +4116,7 @@ impl DesktopAppRuntimeState { self.ingest_configured_relay_events_for_sync(None, &started_at)?; if relay_context_changed { changed |= self.refresh_selected_account_sync()?; - changed |= self.refresh_selected_account_context_after_local_events()?; + changed |= self.refresh_selected_account_context_after_runtime_store()?; } } } @@ -4353,7 +4355,7 @@ impl DesktopAppRuntimeState { let receipt_import_changed = if result.published_receipts.is_empty() { false } else { - let report = self.import_shared_local_events()?; + let report = self.import_shared_runtime_store()?; report.imported_records > 0 || report.skipped_records > 0 }; { @@ -4466,7 +4468,7 @@ impl DesktopAppRuntimeState { fn enqueue_selected_account_order_sync_operation( &mut self, buyer_context: &BuyerContext, - order: &BuyerOrderLocalEventExport, + order: &BuyerOrderRuntimeStoreExport, local_work: Option<&AppOrderLocalWorkPublishSource>, ) -> Result<bool, AppSqliteError> { let Some(payload) = self.order_request_publish_payload(buyer_context, order, local_work)? @@ -4481,7 +4483,7 @@ impl DesktopAppRuntimeState { .unwrap_or_else(|| format!("app:order_request:{}", payload.order_id)); self.enqueue_order_request_payload_via_sdk( &payload, - AppSdkWorkflowReceiptSourceKind::SharedLocalEvent, + AppSdkWorkflowReceiptSourceKind::SharedRuntimeStore, source_record_id.as_str(), )?; self.refresh_selected_account_sync() @@ -4618,7 +4620,7 @@ impl DesktopAppRuntimeState { let Some(farm_id) = self.selected_farm_id() else { return Ok(None); }; - let Some(farm_pubkey) = self.local_events_owner_pubkey(selected_account) else { + let Some(farm_pubkey) = self.runtime_store_owner_pubkey(selected_account) else { return Ok(None); }; let farm_setup = self.state_store.farm_setup_projection(); @@ -4666,7 +4668,7 @@ impl DesktopAppRuntimeState { fn order_request_publish_payload( &self, buyer_context: &BuyerContext, - order: &BuyerOrderLocalEventExport, + order: &BuyerOrderRuntimeStoreExport, local_work: Option<&AppOrderLocalWorkPublishSource>, ) -> Result<Option<AppOrderRequestPublishPayload>, AppSqliteError> { let Some(local_work) = local_work else { @@ -4675,7 +4677,7 @@ impl DesktopAppRuntimeState { let Some(buyer_account) = self.selected_buyer_account(buyer_context) else { return Ok(None); }; - let buyer_pubkey = self.local_events_owner_pubkey(buyer_account); + let buyer_pubkey = self.runtime_store_owner_pubkey(buyer_account); let export = AppBuyerOrderRequestExport::from_order(order, buyer_pubkey.as_deref())?; if !export.is_supported() { return Ok(None); @@ -4990,6 +4992,9 @@ impl DesktopAppRuntimeState { locator: trade_locator_from_revision_decision_payload(payload)?, revision_id: publish_revision_id(payload.revision_id.as_str())?, decision: payload.decision.clone(), + evidence: self + .order_revision_decision_sdk_evidence(payload) + .map_err(|error| AppSyncTransportError::failed(error.to_string()))?, confirm_public_note: payload.confirm_public_note, idempotency_key: Some(sdk_idempotency_key(source_record_id)), }; @@ -5059,6 +5064,25 @@ impl DesktopAppRuntimeState { } } + fn order_revision_decision_sdk_evidence( + &self, + payload: &AppOrderRevisionDecisionPublishPayload, + ) -> Result<Vec<RadrootsEventEnvelope>, AppSqliteError> { + let request = self.resolve_seller_order_request_evidence(payload.app_order_id)?; + let lifecycle = self.resolve_order_lifecycle_evidence(&request)?; + let Some(proposal) = active_order_pending_revision_proposal(&lifecycle) else { + return Err(AppSqliteError::InvalidProjection { + reason: "buyer order revision requires a pending seller proposal", + }); + }; + if proposal.payload.revision_id.to_string() != payload.revision_id { + return Err(AppSqliteError::InvalidProjection { + reason: "buyer order revision evidence does not match requested revision", + }); + } + Ok(vec![request.request_event, proposal.event.clone()]) + } + fn local_signing_identity_for_publish_payload( &self, payload: &AppPublishPayload, @@ -5345,7 +5369,7 @@ impl DesktopAppRuntimeState { &self, query: &BuyerSearchScreenQueryState, ) -> Result<radroots_studio_app_view::BuyerListingsProjection, AppSqliteError> { - let _ = self.import_shared_local_events()?; + let _ = self.import_shared_runtime_store()?; let Some(sqlite_store) = self.sqlite_store.as_ref() else { return Ok(Default::default()); }; @@ -5470,7 +5494,7 @@ impl DesktopAppRuntimeState { &self, query: &ProductsScreenQueryState, ) -> Result<ProductsListProjection, AppSqliteError> { - let _ = self.import_shared_local_events()?; + let _ = self.import_shared_runtime_store()?; let Some(sqlite_store) = self.sqlite_store.as_ref() else { return Ok(ProductsListProjection::default()); }; @@ -5481,7 +5505,7 @@ impl DesktopAppRuntimeState { sqlite_store.load_products(farm_id, &query.search_query, query.filter, query.sort) } - fn import_shared_local_events(&self) -> Result<AppLocalInteropImportReport, AppSqliteError> { + fn import_shared_runtime_store(&self) -> Result<AppLocalInteropImportReport, AppSqliteError> { let Some(sqlite_store) = self.sqlite_store.as_ref() else { return Ok(AppLocalInteropImportReport::default()); }; @@ -5489,11 +5513,11 @@ impl DesktopAppRuntimeState { return Ok(AppLocalInteropImportReport::default()); }; let Some(database_path) = - shared_local_events_database_path_from_shared_accounts(shared_accounts_paths) + shared_runtime_store_database_path_from_shared_accounts(shared_accounts_paths) else { return Ok(AppLocalInteropImportReport::default()); }; - sqlite_store.import_shared_local_events_from_path(database_path.as_path()) + sqlite_store.import_shared_runtime_store_from_path(database_path.as_path()) } fn resolve_seller_order_request_evidence( @@ -5529,7 +5553,7 @@ impl DesktopAppRuntimeState { order_id: &OrderId, matched_requests: &mut BTreeMap<String, ResolvedAppSellerOrderRequest>, ) -> Result<(), AppSqliteError> { - let store = self.open_shared_local_events_store()?; + let store = self.open_shared_runtime_store_store()?; let Some(store) = store else { return Ok(()); }; @@ -5543,13 +5567,13 @@ impl DesktopAppRuntimeState { before_seq, APP_SELLER_ORDER_DECISION_EVIDENCE_PAGE_SIZE, ) - .map_err(|source| AppSqliteError::LocalEvents { + .map_err(|source| AppSqliteError::RuntimeStore { operation: "load shared order request evidence", source, })?, None => store .list_records_changed_latest(APP_SELLER_ORDER_DECISION_EVIDENCE_PAGE_SIZE) - .map_err(|source| AppSqliteError::LocalEvents { + .map_err(|source| AppSqliteError::RuntimeStore { operation: "load shared order request evidence", source, })?, @@ -5562,7 +5586,7 @@ impl DesktopAppRuntimeState { before = records.last().map(|record| (record.change_seq, record.seq)); for record in records { - if record.family != LocalRecordFamily::SignedEvent + if record.family != RuntimeStoreRecordFamily::SignedEvent || record.event_kind != Some(i64::from(RadrootsOrderEventType::OrderRequested.kind())) || !signed_order_request_evidence_record_is_usable(&record) @@ -5630,6 +5654,7 @@ impl DesktopAppRuntimeState { }); let mut buckets = AppActiveOrderEvidenceBuckets::default(); + let mut signed_events_by_id = BTreeMap::new(); let request_event_id = active_order_event_id(request.request_event_id.as_str(), "request_event_id")?; let request_author_pubkey = active_order_pubkey( @@ -5649,6 +5674,7 @@ impl DesktopAppRuntimeState { } 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")?; + signed_events_by_id.insert(event_id.to_string(), event.clone()); match event.kind { KIND_ORDER_DECISION => { let envelope = order_decision_from_event(&event).map_err(|_| { @@ -5774,11 +5800,20 @@ impl DesktopAppRuntimeState { revision_proposals: buckets .revision_proposals .into_iter() - .map(|proposal| ResolvedAppOrderRevisionProposalEvidence { - event_id: proposal.event_id.to_string(), - payload: proposal.payload, + .map(|proposal| { + let event = signed_events_by_id + .get(proposal.event_id.as_str()) + .cloned() + .ok_or(AppSqliteError::InvalidProjection { + reason: "order lifecycle evidence is invalid", + })?; + Ok(ResolvedAppOrderRevisionProposalEvidence { + event, + event_id: proposal.event_id.to_string(), + payload: proposal.payload, + }) }) - .collect(), + .collect::<Result<Vec<_>, AppSqliteError>>()?, revision_decisions: buckets .revision_decisions .into_iter() @@ -5795,7 +5830,7 @@ impl DesktopAppRuntimeState { fn collect_order_lifecycle_signed_events( &self, - ) -> Result<Vec<SdkRadrootsNostrEvent>, AppSqliteError> { + ) -> Result<Vec<RadrootsEventEnvelope>, AppSqliteError> { let mut events = Vec::new(); let mut seen_event_ids = BTreeSet::new(); let kinds = [ @@ -5817,7 +5852,7 @@ impl DesktopAppRuntimeState { } } - let Some(store) = self.open_shared_local_events_store()? else { + let Some(store) = self.open_shared_runtime_store_store()? else { return Ok(events); }; let mut before = None; @@ -5829,13 +5864,13 @@ impl DesktopAppRuntimeState { before_seq, APP_SELLER_ORDER_DECISION_EVIDENCE_PAGE_SIZE, ) - .map_err(|source| AppSqliteError::LocalEvents { + .map_err(|source| AppSqliteError::RuntimeStore { operation: "load shared order lifecycle evidence", source, })?, None => store .list_records_changed_latest(APP_SELLER_ORDER_DECISION_EVIDENCE_PAGE_SIZE) - .map_err(|source| AppSqliteError::LocalEvents { + .map_err(|source| AppSqliteError::RuntimeStore { operation: "load shared order lifecycle evidence", source, })?, @@ -5851,7 +5886,7 @@ impl DesktopAppRuntimeState { let Some(kind) = record.event_kind else { continue; }; - if record.family != LocalRecordFamily::SignedEvent + if record.family != RuntimeStoreRecordFamily::SignedEvent || !kinds.contains(&u32::try_from(kind).unwrap_or_default()) || !signed_order_request_evidence_record_is_usable(&record) { @@ -5873,14 +5908,14 @@ impl DesktopAppRuntimeState { Ok(events) } - fn open_shared_local_events_store( + fn open_shared_runtime_store_store( &self, - ) -> Result<Option<LocalEventsStore<SqliteExecutor>>, AppSqliteError> { + ) -> Result<Option<RuntimeStore<SqliteExecutor>>, AppSqliteError> { let Some(shared_accounts_paths) = self.shared_accounts_paths.as_ref() else { return Ok(None); }; let Some(database_path) = - shared_local_events_database_path_from_shared_accounts(shared_accounts_paths) + shared_runtime_store_database_path_from_shared_accounts(shared_accounts_paths) else { return Ok(None); }; @@ -5891,16 +5926,16 @@ impl DesktopAppRuntimeState { })?; } let executor = SqliteExecutor::open(database_path.as_path()).map_err(|source| { - AppSqliteError::LocalEventsSql { - operation: "open shared local events database", + AppSqliteError::RuntimeStoreSql { + operation: "open shared runtime store database", source, } })?; - let store = LocalEventsStore::new(executor); + let store = RuntimeStore::new(executor); store .migrate_up() - .map_err(|source| AppSqliteError::LocalEventsSql { - operation: "migrate shared local events database", + .map_err(|source| AppSqliteError::RuntimeStoreSql { + operation: "migrate shared runtime store database", source, })?; @@ -5918,7 +5953,7 @@ impl DesktopAppRuntimeState { }; let timestamp = current_runtime_time_ms()?; let farm_d_tag = d_tag_from_uuid(saved_farm.farm_id.as_uuid()); - let owner_pubkey = self.local_events_owner_pubkey(account); + let owner_pubkey = self.runtime_store_owner_pubkey(account); let exportability = local_work_exportability(owner_pubkey.as_deref()); let delivery_method = projection .draft @@ -5957,10 +5992,10 @@ impl DesktopAppRuntimeState { }, }); let record_id = format!("app:local_work:farm:{farm_d_tag}:{}", Uuid::now_v7()); - let input = LocalEventRecordInput { + let input = RuntimeStoreRecordInput { record_id: record_id.clone(), - family: LocalRecordFamily::LocalWork, - status: LocalRecordStatus::LocalSaved, + family: RuntimeStoreRecordFamily::LocalWork, + status: RuntimeStoreRecordStatus::LocalSaved, source_runtime: SourceRuntime::App, created_at_ms: timestamp, inserted_at_ms: timestamp, @@ -6009,7 +6044,7 @@ impl DesktopAppRuntimeState { let farm_d_tag = d_tag_from_uuid(farm_id.as_uuid()); let listing_d_tag = d_tag_from_uuid(product_id.as_uuid()); let primary_bin_id = listing_primary_bin_id(listing_d_tag.as_str()); - let owner_pubkey = self.local_events_owner_pubkey(account); + let owner_pubkey = self.runtime_store_owner_pubkey(account); let listing_addr = owner_pubkey .as_ref() .map(|pubkey| format!("{KIND_LISTING}:{pubkey}:{listing_d_tag}")); @@ -6080,10 +6115,10 @@ impl DesktopAppRuntimeState { }, }); let record_id = format!("app:local_work:listing:{listing_d_tag}:{}", Uuid::now_v7()); - let input = LocalEventRecordInput { + let input = RuntimeStoreRecordInput { record_id: record_id.clone(), - family: LocalRecordFamily::LocalWork, - status: LocalRecordStatus::LocalSaved, + family: RuntimeStoreRecordFamily::LocalWork, + status: RuntimeStoreRecordStatus::LocalSaved, source_runtime: SourceRuntime::App, created_at_ms: timestamp, inserted_at_ms: timestamp, @@ -6113,7 +6148,7 @@ impl DesktopAppRuntimeState { &self, sqlite_store: &AppSqliteStore, buyer_context: &BuyerContext, - order: &BuyerOrderLocalEventExport, + order: &BuyerOrderRuntimeStoreExport, ) -> Result<Option<AppOrderLocalWorkPublishSource>, AppSqliteError> { let Some(shared_accounts_paths) = self.shared_accounts_paths.as_ref() else { return Ok(None); @@ -6122,14 +6157,14 @@ impl DesktopAppRuntimeState { let record_id = buyer_order_request_local_work_record_id( order.order_id.to_string().as_str(), ) - .map_err(|source| AppSqliteError::LocalEvents { + .map_err(|source| AppSqliteError::RuntimeStore { operation: "build app buyer order request record id", source, })?; let buyer_account = self.selected_buyer_account(buyer_context); let owner_account_id = buyer_account.map(|account| account.account.account_id.clone()); let buyer_pubkey = - buyer_account.and_then(|account| self.local_events_owner_pubkey(account)); + buyer_account.and_then(|account| self.runtime_store_owner_pubkey(account)); let export = AppBuyerOrderRequestExport::from_order(order, buyer_pubkey.as_deref())?; let payload = buyer_order_request_local_work_payload( order, @@ -6142,7 +6177,7 @@ impl DesktopAppRuntimeState { return Ok(Some(AppOrderLocalWorkPublishSource { record_id, payload })); } validate_buyer_order_request_local_work_payload(&payload).map_err(|source| { - AppSqliteError::LocalEvents { + AppSqliteError::RuntimeStore { operation: "validate app buyer order request local work payload", source, } @@ -6157,10 +6192,10 @@ impl DesktopAppRuntimeState { record_id.as_str(), payload_json.as_str(), )?; - let input = LocalEventRecordInput { + let input = RuntimeStoreRecordInput { record_id: record_id.clone(), - family: LocalRecordFamily::LocalWork, - status: LocalRecordStatus::LocalSaved, + family: RuntimeStoreRecordFamily::LocalWork, + status: RuntimeStoreRecordStatus::LocalSaved, source_runtime: SourceRuntime::App, created_at_ms: timestamp, inserted_at_ms: timestamp, @@ -6198,10 +6233,10 @@ impl DesktopAppRuntimeState { fn append_app_local_work_record( &self, shared_accounts_paths: &AppSharedAccountsPaths, - input: &LocalEventRecordInput, + input: &RuntimeStoreRecordInput, ) -> Result<(), AppSqliteError> { let Some(database_path) = - shared_local_events_database_path_from_shared_accounts(shared_accounts_paths) + shared_runtime_store_database_path_from_shared_accounts(shared_accounts_paths) else { return Ok(()); }; @@ -6212,21 +6247,21 @@ impl DesktopAppRuntimeState { })?; } let executor = SqliteExecutor::open(database_path.as_path()).map_err(|source| { - AppSqliteError::LocalEventsSql { - operation: "open shared local events database", + AppSqliteError::RuntimeStoreSql { + operation: "open shared runtime store database", source, } })?; - let store = LocalEventsStore::new(executor); + let store = RuntimeStore::new(executor); store .migrate_up() - .map_err(|source| AppSqliteError::LocalEventsSql { - operation: "migrate shared local events database", + .map_err(|source| AppSqliteError::RuntimeStoreSql { + operation: "migrate shared runtime store database", source, })?; store .append_record(input) - .map_err(|source| AppSqliteError::LocalEvents { + .map_err(|source| AppSqliteError::RuntimeStore { operation: "append app local work record", source, })?; @@ -6244,7 +6279,7 @@ impl DesktopAppRuntimeState { return Ok(()); }; let Some(database_path) = - shared_local_events_database_path_from_shared_accounts(shared_accounts_paths) + shared_runtime_store_database_path_from_shared_accounts(shared_accounts_paths) else { return Ok(()); }; @@ -6255,16 +6290,16 @@ impl DesktopAppRuntimeState { })?; } let executor = SqliteExecutor::open(database_path.as_path()).map_err(|source| { - AppSqliteError::LocalEventsSql { - operation: "open shared local events database", + AppSqliteError::RuntimeStoreSql { + operation: "open shared runtime store database", source, } })?; - let store = LocalEventsStore::new(executor); + let store = RuntimeStore::new(executor); store .migrate_up() - .map_err(|source| AppSqliteError::LocalEventsSql { - operation: "migrate shared local events database", + .map_err(|source| AppSqliteError::RuntimeStoreSql { + operation: "migrate shared runtime store database", source, })?; let timestamp = current_runtime_time_ms()?; @@ -6275,7 +6310,7 @@ impl DesktopAppRuntimeState { .as_deref() .map(|source_record_id| { store.get_record(source_record_id).map_err(|source| { - AppSqliteError::LocalEvents { + AppSqliteError::RuntimeStore { operation: "load app publish source record", source, } @@ -6301,10 +6336,10 @@ impl DesktopAppRuntimeState { .and_then(|record| record.listing_addr.clone()) .or_else(|| receipt.listing_addr.clone()) .or_else(|| signed_event_listing_addr(receipt)); - let event_record = LocalEventRecordInput { + let event_record = RuntimeStoreRecordInput { record_id: format!("app:signed_event:{}", receipt.event_id), - family: LocalRecordFamily::SignedEvent, - status: LocalRecordStatus::Published, + family: RuntimeStoreRecordFamily::SignedEvent, + status: RuntimeStoreRecordStatus::Published, source_runtime: SourceRuntime::App, created_at_ms: i64::from(receipt.event_created_at) * 1_000, inserted_at_ms: timestamp, @@ -6327,7 +6362,7 @@ impl DesktopAppRuntimeState { }; store .append_record(&event_record) - .map_err(|source| AppSqliteError::LocalEvents { + .map_err(|source| AppSqliteError::RuntimeStore { operation: "append app published event record", source, })?; @@ -6336,19 +6371,19 @@ impl DesktopAppRuntimeState { let Some(source_record) = source_record.as_ref() else { continue; }; - if source_record.family == LocalRecordFamily::LocalWork { + if source_record.family == RuntimeStoreRecordFamily::LocalWork { continue; } store - .update_outbox(&LocalEventRecordUpdate { + .update_outbox(&RuntimeStoreRecordUpdate { record_id: source_record_id.to_owned(), - status: LocalRecordStatus::Published, + status: RuntimeStoreRecordStatus::Published, outbox_status: PublishOutboxStatus::Acknowledged, relay_set_fingerprint: Some(receipt.relay_set_fingerprint.clone()), relay_delivery_json: Some(receipt.relay_delivery_json.clone()), updated_at_ms: timestamp, }) - .map_err(|source| AppSqliteError::LocalEvents { + .map_err(|source| AppSqliteError::RuntimeStore { operation: "update app publish source evidence", source, })?; @@ -6358,7 +6393,7 @@ impl DesktopAppRuntimeState { Ok(()) } - fn local_events_owner_pubkey( + fn runtime_store_owner_pubkey( &self, account: &radroots_studio_app_view::SelectedAccountProjection, ) -> Option<String> { @@ -6390,7 +6425,7 @@ impl DesktopAppRuntimeState { .filter(|account| account.account.account_id == *account_id) } - fn refresh_selected_account_context_after_local_events( + fn refresh_selected_account_context_after_runtime_store( &mut self, ) -> Result<bool, AppSqliteError> { let Some(sqlite_store) = self.sqlite_store.as_ref() else { @@ -6405,9 +6440,9 @@ impl DesktopAppRuntimeState { } fn sync_on_foreground_resume(&mut self) -> Result<bool, AppSqliteError> { - let report = self.import_shared_local_events()?; + let report = self.import_shared_runtime_store()?; let local_changed = report.imported_records > 0 || report.skipped_records > 0; - let context_changed = self.refresh_selected_account_context_after_local_events()?; + let context_changed = self.refresh_selected_account_context_after_runtime_store()?; let coordination_changed = self.retry_pending_personal_order_coordination()?; let sync_changed = self.attempt_sync(SyncTrigger::ForegroundResume)?; @@ -6815,7 +6850,7 @@ fn current_runtime_time_seconds() -> Result<i64, AppSqliteError> { fn normalized_app_sync_relay_urls( relay_urls: &[String], ) -> Result<Vec<String>, AppSyncTransportError> { - let normalized = radroots_local_events::normalize_relay_urls(relay_urls).map_err(|error| { + let normalized = normalized_app_nostr_relay_urls(relay_urls).map_err(|error| { AppSyncTransportError::failed(format!("invalid direct relay app sync relay url: {error}")) })?; if normalized.is_empty() { @@ -6827,11 +6862,29 @@ fn normalized_app_sync_relay_urls( } fn normalized_app_relay_ingest_urls(relay_urls: &[String]) -> Result<Vec<String>, AppSqliteError> { - let normalized = radroots_local_events::normalize_relay_urls(relay_urls).map_err(|_| { - AppSqliteError::InvalidProjection { - reason: "app relay ingest requires valid relay urls", + normalized_app_nostr_relay_urls(relay_urls).map_err(|_| AppSqliteError::InvalidProjection { + reason: "app relay ingest requires valid relay urls", + }) +} + +fn normalized_app_nostr_relay_urls( + relay_urls: &[String], +) -> Result<Vec<String>, radroots_sdk::RadrootsSdkError> { + if relay_urls.is_empty() { + return Ok(Vec::new()); + } + let mut normalized = Vec::new(); + for relay_url in relay_urls { + let relay_url = + TargetSet::nostr_relays([relay_url.as_str()], NostrRelayUrlPolicy::Localhost)? + .nostr_relay_urls() + .into_iter() + .next() + .expect("single relay target set must contain one relay"); + if !normalized.iter().any(|existing| existing == &relay_url) { + normalized.push(relay_url); } - })?; + } Ok(normalized) } @@ -7092,7 +7145,7 @@ fn append_unique_relays(target: &mut Vec<String>, relays: Vec<String>) { fn direct_relay_event_records( receipt: &AppDirectRelayFetchReceipt, inserted_at_ms: i64, -) -> Result<Vec<LocalEventRecord>, AppDirectRelayIngestError> { +) -> Result<Vec<RuntimeStoreRecord>, AppDirectRelayIngestError> { let mut records = Vec::with_capacity(receipt.events.len()); for (index, event) in receipt.events.iter().enumerate() { @@ -7128,12 +7181,12 @@ fn direct_relay_event_records( reason: "app relay ingest sequence must fit i64", } })?); - records.push(LocalEventRecord { + records.push(RuntimeStoreRecord { seq: local_seq, change_seq: local_seq, record_id: format!("app:relay_event:{event_id}"), - family: LocalRecordFamily::SignedEvent, - status: LocalRecordStatus::Published, + family: RuntimeStoreRecordFamily::SignedEvent, + status: RuntimeStoreRecordStatus::Published, source_runtime: direct_relay_event_source_runtime(kind, listing_d_tag.as_deref()), created_at_ms, inserted_at_ms, @@ -7357,7 +7410,7 @@ fn farm_publish_source_record( source_local_event_id .map(|record_id| { ( - AppSdkWorkflowReceiptSourceKind::SharedLocalEvent, + AppSdkWorkflowReceiptSourceKind::SharedRuntimeStore, record_id.to_owned(), ) }) @@ -7377,7 +7430,7 @@ fn listing_publish_source_record( source_local_event_id .map(|record_id| { ( - AppSdkWorkflowReceiptSourceKind::SharedLocalEvent, + AppSdkWorkflowReceiptSourceKind::SharedRuntimeStore, record_id.to_owned(), ) }) @@ -7729,7 +7782,7 @@ fn parse_app_listing_delivery_method( fn order_request_sdk_listing_event_ptr( payload: &AppOrderRequestPublishPayload, -) -> Result<RadrootsNostrEventPtr, AppSyncTransportError> { +) -> Result<RadrootsEventPtr, AppSyncTransportError> { let listing_event_id = payload .listing_event_id .as_deref() @@ -7742,7 +7795,7 @@ fn order_request_sdk_listing_event_ptr( .into_iter() .next(); - Ok(RadrootsNostrEventPtr { + Ok(RadrootsEventPtr { id: listing_event_id, relays: listing_relay, }) @@ -7965,7 +8018,7 @@ struct AppOrderLocalWorkPublishSource { impl AppBuyerOrderRequestExport { fn from_order( - order: &BuyerOrderLocalEventExport, + order: &BuyerOrderRuntimeStoreExport, buyer_pubkey: Option<&str>, ) -> Result<Self, AppSqliteError> { let mut support_issues = Vec::new(); @@ -8052,7 +8105,7 @@ impl AppBuyerOrderRequestExport { } fn buyer_order_request_local_work_payload( - order: &BuyerOrderLocalEventExport, + order: &BuyerOrderRuntimeStoreExport, buyer_context: &BuyerContext, record_id: &str, export: &AppBuyerOrderRequestExport, @@ -8129,7 +8182,7 @@ fn buyer_order_request_local_work_payload( } fn order_economics_json( - order: &BuyerOrderLocalEventExport, + order: &BuyerOrderRuntimeStoreExport, support_issues: &mut Vec<&'static str>, ) -> Result<Option<serde_json::Value>, AppSqliteError> { let mut economics_items = Vec::with_capacity(order.lines.len()); @@ -8227,7 +8280,7 @@ fn order_economics_json( } fn order_currency_and_total( - order: &BuyerOrderLocalEventExport, + order: &BuyerOrderRuntimeStoreExport, ) -> Result<Option<(String, u32)>, AppSqliteError> { let mut currency = None::<String>; let mut total_minor_units = 0_u32; @@ -8265,8 +8318,8 @@ fn order_currency_and_total( } fn shared_optional_line_value( - lines: &[BuyerOrderLocalEventLine], - value: impl Fn(&BuyerOrderLocalEventLine) -> Option<&str>, + lines: &[BuyerOrderRuntimeStoreLine], + value: impl Fn(&BuyerOrderRuntimeStoreLine) -> Option<&str>, ) -> Option<String> { let mut resolved = None::<String>; for line in lines { @@ -8284,7 +8337,7 @@ fn shared_optional_line_value( resolved } -fn shared_listing_relays(lines: &[BuyerOrderLocalEventLine]) -> Vec<String> { +fn shared_listing_relays(lines: &[BuyerOrderRuntimeStoreLine]) -> Vec<String> { let mut seen = BTreeSet::new(); let mut relays = Vec::new(); for line in lines { @@ -9367,8 +9420,8 @@ fn current_utc_timestamp() -> String { } fn signed_event_from_local_record( - record: &LocalEventRecord, -) -> Result<Option<SdkRadrootsNostrEvent>, AppSqliteError> { + record: &RuntimeStoreRecord, +) -> Result<Option<RadrootsEventEnvelope>, AppSqliteError> { let Some(id) = record.event_id.as_deref().map(str::trim) else { return Ok(None); }; @@ -9392,7 +9445,7 @@ fn signed_event_from_local_record( reason: "signed local event kind must fit u32", })?; - Ok(Some(SdkRadrootsNostrEvent { + Ok(Some(RadrootsEventEnvelope { id: id.to_owned(), author: author.to_owned(), created_at, @@ -9437,7 +9490,7 @@ fn event_tags_from_value( .collect() } -fn trade_chain_tag_value(event: &SdkRadrootsNostrEvent, key: &str) -> Option<String> { +fn trade_chain_tag_value(event: &RadrootsEventEnvelope, key: &str) -> Option<String> { event.tags.iter().find_map(|tag| { if tag.first().map(String::as_str) == Some(key) { tag.get(1) @@ -9472,7 +9525,7 @@ fn active_order_pubkey( } fn active_order_event_record_context( - event: &SdkRadrootsNostrEvent, + event: &RadrootsEventEnvelope, message_type: RadrootsOrderEventType, ) -> Result<(RadrootsPublicKey, RadrootsEventId, RadrootsEventId), AppSqliteError> { let context = order_event_context_from_tags(message_type, &event.tags).map_err(|_| { @@ -9527,7 +9580,7 @@ fn active_order_pending_revision_proposal( fn insert_seller_order_request_evidence( order_id: &OrderId, - event: &SdkRadrootsNostrEvent, + event: &RadrootsEventEnvelope, payload: RadrootsOrderRequest, matched_requests: &mut BTreeMap<String, ResolvedAppSellerOrderRequest>, ) { @@ -9752,8 +9805,8 @@ fn farm_sync_payload( .to_string() } -fn signed_order_request_evidence_record_is_usable(record: &LocalEventRecord) -> bool { - if record.status != LocalRecordStatus::Published +fn signed_order_request_evidence_record_is_usable(record: &RuntimeStoreRecord) -> bool { + if record.status != RuntimeStoreRecordStatus::Published || matches!( record.outbox_status, PublishOutboxStatus::Pending | PublishOutboxStatus::Failed @@ -9787,18 +9840,18 @@ mod tests { use radroots_core::{ RadrootsCoreCurrency, RadrootsCoreDecimal, RadrootsCoreMoney, RadrootsCoreUnit, }; - use radroots_events::ids::{ + use radroots_event::ids::{ RadrootsEventId, RadrootsInventoryBinId, RadrootsListingAddress, RadrootsOrderId, RadrootsOrderQuoteId, RadrootsOrderRevisionId, RadrootsPublicKey, }; - use radroots_events::order::{ + use radroots_event::order::{ RadrootsOrderCancellation, RadrootsOrderDecision, RadrootsOrderDecisionOutcome, RadrootsOrderEconomicItem, RadrootsOrderEconomics, RadrootsOrderInventoryCommitment, RadrootsOrderItem, RadrootsOrderPricingBasis, RadrootsOrderRequest, RadrootsOrderRevisionOutcome, RadrootsOrderRevisionProposal, }; - use radroots_events::{RadrootsNostrEvent as SdkRadrootsNostrEvent, RadrootsNostrEventPtr}; - use radroots_events_codec::{ + use radroots_event::{RadrootsEventEnvelope, RadrootsEventPtr}; + use radroots_event_codec::{ order::{ order_cancellation_event_build, order_decision_event_build, order_request_event_build, order_revision_proposal_event_build, @@ -9806,11 +9859,6 @@ mod tests { wire::WireEventParts, }; use radroots_identity::{RadrootsIdentity, RadrootsIdentityId}; - use radroots_local_events::{ - BUYER_ORDER_REQUEST_LOCAL_WORK_RECORD_KIND, LocalEventRecord, LocalEventRecordInput, - LocalEventsStore, LocalRecordFamily, LocalRecordStatus, PublishOutboxStatus, - RelayDeliveryEvidence, SourceRuntime, - }; use radroots_nostr::prelude::{ RadrootsNostrClient, RadrootsNostrEvent, RadrootsNostrKeys, RadrootsNostrSecretKey, RadrootsNostrTimestamp, radroots_event_from_nostr, radroots_nostr_build_event, @@ -9820,6 +9868,11 @@ mod tests { RadrootsNostrMemoryAccountStore, RadrootsNostrSecretVaultMemory, RadrootsSecretVault, account_secret_slot, }; + use radroots_runtime_store::{ + BUYER_ORDER_REQUEST_LOCAL_WORK_RECORD_KIND, PublishOutboxStatus, RelayDeliveryEvidence, + RuntimeStore, RuntimeStoreRecord, RuntimeStoreRecordFamily, RuntimeStoreRecordInput, + RuntimeStoreRecordStatus, SourceRuntime, + }; use radroots_sdk::{ LISTING_PUBLISH_OPERATION_KIND, TRADE_CANCELLATION_OPERATION_KIND, TRADE_DECISION_OPERATION_KIND, TRADE_REVISION_DECISION_OPERATION_KIND, @@ -10166,7 +10219,7 @@ mod tests { }); } - fn seed_relay_with_sdk_event(relay: &ThreadedAckRelay, event: &SdkRadrootsNostrEvent) { + fn seed_relay_with_sdk_event(relay: &ThreadedAckRelay, event: &RadrootsEventEnvelope) { relay.seed_event(json!({ "id": event.id, "pubkey": event.author, @@ -10196,7 +10249,7 @@ mod tests { paths: &AppDesktopRuntimePaths, event_id: &str, ) { - let event = shared_local_event_records(paths) + let event = shared_runtime_store_records(paths) .into_iter() .find(|record| record.event_id.as_deref() == Some(event_id)) .and_then(|record| { @@ -10262,7 +10315,7 @@ mod tests { secret_key_hex: &str, created_at: u32, parts: WireEventParts, - ) -> SdkRadrootsNostrEvent { + ) -> RadrootsEventEnvelope { let secret_key = RadrootsNostrSecretKey::from_hex(secret_key_hex).expect("secret key"); let keys = RadrootsNostrKeys::new(secret_key); let event = radroots_nostr_build_event(parts.kind, parts.content, parts.tags) @@ -10277,7 +10330,7 @@ mod tests { pubkey: &str, created_at: u32, parts: WireEventParts, - ) -> Option<SdkRadrootsNostrEvent> { + ) -> Option<RadrootsEventEnvelope> { match pubkey { SDK_TEST_BUYER_PUBLIC_KEY_HEX => Some(signed_test_event( SDK_TEST_BUYER_SECRET_KEY_HEX, @@ -10299,9 +10352,9 @@ mod tests { event_pubkey: &str, created_at: u32, parts: WireEventParts, - ) -> SdkRadrootsNostrEvent { + ) -> RadrootsEventEnvelope { signed_test_event_for_pubkey(event_pubkey, created_at, parts.clone()).unwrap_or_else(|| { - SdkRadrootsNostrEvent { + RadrootsEventEnvelope { id: event_id, author: event_pubkey.to_owned(), created_at, @@ -10890,7 +10943,7 @@ mod tests { let listing = super::listing_publish_payload_to_sdk_listing(&listing_payload, Some(&public_location)) .expect("listing payload should convert to SDK listing"); - let parts = radroots_events_codec::listing::encode::to_wire_parts(&listing) + let parts = radroots_event_codec::listing::encode::to_wire_parts(&listing) .expect("listing draft should build"); let event = radroots_nostr_build_event(parts.kind, parts.content, parts.tags) .expect("listing event builder should build") @@ -11838,7 +11891,7 @@ mod tests { .collect::<Vec<_>>(); assert!(product_pending_operations.is_empty()); - let records = shared_local_event_records(&paths); + let records = shared_runtime_store_records(&paths); let listing_record = records .iter() .find(|record| { @@ -11873,7 +11926,7 @@ mod tests { .expect("sqlite store") .sdk_workflow_receipt_repository() .load_receipt( - AppSdkWorkflowReceiptSourceKind::SharedLocalEvent, + AppSdkWorkflowReceiptSourceKind::SharedRuntimeStore, listing_record.record_id.as_str(), ) .expect("listing SDK workflow receipt should load") @@ -11990,7 +12043,7 @@ mod tests { Some(draft.clone()) ); - let records = shared_local_event_records(&paths); + let records = shared_runtime_store_records(&paths); let listing_record = records .iter() .find(|record| { @@ -12008,7 +12061,7 @@ mod tests { .expect("sqlite store") .sdk_workflow_receipt_repository() .load_receipt( - AppSdkWorkflowReceiptSourceKind::SharedLocalEvent, + AppSdkWorkflowReceiptSourceKind::SharedRuntimeStore, listing_record.record_id.as_str(), ) .expect("failed listing SDK workflow receipt should load") @@ -12030,7 +12083,7 @@ mod tests { .save_product_editor_draft(draft.clone()) .expect("retry should enqueue listing publish through SDK runtime") ); - let retry_records = shared_local_event_records(&paths); + let retry_records = shared_runtime_store_records(&paths); let enqueued_listing_receipts = { let state = runtime.lock_state(); let repository = state @@ -12050,7 +12103,7 @@ mod tests { .filter_map(|record| { repository .load_receipt( - AppSdkWorkflowReceiptSourceKind::SharedLocalEvent, + AppSdkWorkflowReceiptSourceKind::SharedRuntimeStore, record.record_id.as_str(), ) .expect("retry listing SDK workflow receipt should load") @@ -12327,7 +12380,7 @@ mod tests { .collect::<Vec<_>>(); assert!(product_pending_operations.is_empty()); - let records = shared_local_event_records(&paths); + let records = shared_runtime_store_records(&paths); let listing_record = records .iter() .find(|record| { @@ -12516,9 +12569,9 @@ mod tests { SyncCheckpointState::Current ); assert_eq!( - shared_local_event_records(&paths) + shared_runtime_store_records(&paths) .into_iter() - .filter(|record| record.family == LocalRecordFamily::SignedEvent) + .filter(|record| record.family == RuntimeStoreRecordFamily::SignedEvent) .count(), 1 ); @@ -12648,8 +12701,8 @@ mod tests { } #[test] - fn runtime_shared_local_events_refresh_reports_and_reloads_products() { - let (runtime, paths) = bootstrapped_runtime("shared_local_events_refresh"); + fn runtime_shared_runtime_store_refresh_reports_and_reloads_products() { + let (runtime, paths) = bootstrapped_runtime("shared_runtime_store_refresh"); assert!( runtime .generate_local_account(Some("Farmer".to_owned())) @@ -12667,8 +12720,8 @@ mod tests { append_cli_local_listing_records(&paths, account_id.as_str()); let report = runtime - .refresh_shared_local_events() - .expect("shared local events should refresh"); + .refresh_shared_runtime_store() + .expect("shared runtime store should refresh"); let summary = runtime.summary(); assert_eq!(report.scanned_records, 2); @@ -12711,8 +12764,8 @@ mod tests { } #[test] - fn runtime_buyer_search_imports_shared_local_events_before_read() { - let (runtime, paths) = bootstrapped_runtime("buyer_search_shared_local_events_refresh"); + fn runtime_buyer_search_imports_shared_runtime_store_before_read() { + let (runtime, paths) = bootstrapped_runtime("buyer_search_shared_runtime_store_refresh"); assert!( runtime .generate_local_account(Some("Buyer".to_owned())) @@ -12751,9 +12804,9 @@ mod tests { } #[test] - fn runtime_buyer_search_repeated_query_refreshes_shared_local_events() { + fn runtime_buyer_search_repeated_query_refreshes_shared_runtime_store() { let (runtime, paths) = - bootstrapped_runtime("buyer_search_same_query_shared_local_events_refresh"); + bootstrapped_runtime("buyer_search_same_query_shared_runtime_store_refresh"); assert!( runtime .generate_local_account(Some("Buyer".to_owned())) @@ -12816,8 +12869,8 @@ mod tests { } #[test] - fn runtime_shared_local_events_refresh_reloads_buyer_browse_idempotently() { - let (runtime, paths) = bootstrapped_runtime("buyer_browse_shared_local_events_refresh"); + fn runtime_shared_runtime_store_refresh_reloads_buyer_browse_idempotently() { + let (runtime, paths) = bootstrapped_runtime("buyer_browse_shared_runtime_store_refresh"); assert!( runtime .generate_local_account(Some("Buyer".to_owned())) @@ -12826,8 +12879,8 @@ mod tests { append_cli_signed_buyer_listing_record(&paths); let report = runtime - .refresh_shared_local_events() - .expect("shared local events should refresh"); + .refresh_shared_runtime_store() + .expect("shared runtime store should refresh"); let summary = runtime.summary(); assert_eq!(report.scanned_records, 1); assert_eq!(report.imported_records, 1); @@ -12839,8 +12892,8 @@ mod tests { ); let second_report = runtime - .refresh_shared_local_events() - .expect("second shared local events refresh should succeed"); + .refresh_shared_runtime_store() + .expect("second shared runtime store refresh should succeed"); assert_eq!(second_report.scanned_records, 0); assert_eq!(second_report.imported_records, 0); assert_eq!(second_report.skipped_records, 0); @@ -12859,7 +12912,7 @@ mod tests { } #[test] - fn runtime_buyer_browse_selection_refreshes_shared_local_events() { + fn runtime_buyer_browse_selection_refreshes_shared_runtime_store() { let (runtime, paths) = bootstrapped_runtime("buyer_browse_selection_shared_events_refresh"); assert!( runtime @@ -12933,7 +12986,7 @@ mod tests { } #[test] - fn runtime_buyer_browse_selection_surfaces_shared_local_events_import_errors() { + fn runtime_buyer_browse_selection_surfaces_shared_runtime_store_import_errors() { let (runtime, paths) = bootstrapped_runtime("buyer_browse_selection_import_error"); assert!( runtime @@ -12941,16 +12994,16 @@ mod tests { .expect("account should generate") ); let database_path = paths - .shared_local_events_database_path() - .expect("shared local events path"); + .shared_runtime_store_database_path() + .expect("shared runtime store path"); if let Some(parent) = database_path.parent() { - fs::create_dir_all(parent).expect("shared local events parent directory"); + fs::create_dir_all(parent).expect("shared runtime store parent directory"); } if database_path.is_file() { - fs::remove_file(&database_path).expect("shared local events file should be removable"); + fs::remove_file(&database_path).expect("shared runtime store file should be removable"); } else if database_path.is_dir() { fs::remove_dir_all(&database_path) - .expect("shared local events directory should be removable"); + .expect("shared runtime store directory should be removable"); } fs::create_dir(&database_path).expect("directory should block sqlite open"); @@ -12958,8 +13011,8 @@ mod tests { .select_personal_section(PersonalSection::Browse) .expect_err("buyer Browse selection should surface import errors"); match error { - AppSqliteError::LocalEventsSql { operation, .. } => { - assert_eq!(operation, "open shared local events database"); + AppSqliteError::RuntimeStoreSql { operation, .. } => { + assert_eq!(operation, "open shared runtime store database"); } unexpected => panic!("unexpected Browse selection error: {unexpected:?}"), } @@ -12968,13 +13021,13 @@ mod tests { } #[test] - fn runtime_buyer_detail_open_imports_shared_local_events_before_lookup() { - assert_detail_open_imports_shared_local_events_before_lookup( - "buyer_browse_detail_shared_local_events_refresh", + fn runtime_buyer_detail_open_imports_shared_runtime_store_before_lookup() { + assert_detail_open_imports_shared_runtime_store_before_lookup( + "buyer_browse_detail_shared_runtime_store_refresh", PersonalSection::Browse, ); - assert_detail_open_imports_shared_local_events_before_lookup( - "buyer_search_detail_shared_local_events_refresh", + assert_detail_open_imports_shared_runtime_store_before_lookup( + "buyer_search_detail_shared_runtime_store_refresh", PersonalSection::Search, ); } @@ -13028,7 +13081,7 @@ mod tests { .expect("product draft should save") ); - let records = shared_local_event_records(&paths); + let records = shared_runtime_store_records(&paths); let app_records = records .iter() .filter(|record| record.source_runtime == SourceRuntime::App) @@ -13045,8 +13098,8 @@ mod tests { == Some("farm_config_v1") }) .expect("farm local work record"); - assert_eq!(farm_record.family, LocalRecordFamily::LocalWork); - assert_eq!(farm_record.status, LocalRecordStatus::LocalSaved); + assert_eq!(farm_record.family, RuntimeStoreRecordFamily::LocalWork); + assert_eq!(farm_record.status, RuntimeStoreRecordStatus::LocalSaved); assert_eq!(farm_record.outbox_status, PublishOutboxStatus::None); assert_eq!( farm_record.owner_account_id.as_deref(), @@ -13088,8 +13141,8 @@ mod tests { == Some("listing_draft_v1") }) .expect("listing local work record"); - assert_eq!(listing_record.family, LocalRecordFamily::LocalWork); - assert_eq!(listing_record.status, LocalRecordStatus::LocalSaved); + assert_eq!(listing_record.family, RuntimeStoreRecordFamily::LocalWork); + assert_eq!(listing_record.status, RuntimeStoreRecordStatus::LocalSaved); assert_eq!(listing_record.outbox_status, PublishOutboxStatus::None); assert_eq!( listing_record.owner_account_id.as_deref(), @@ -13182,7 +13235,7 @@ mod tests { .record_published_sync_receipts(&[receipt]) .expect("published receipt should record"); - let records = shared_local_event_records(&paths); + let records = shared_runtime_store_records(&paths); let signed_record = records .iter() .find(|record| record.record_id == "app:signed_event:event-app-owner") @@ -13199,12 +13252,12 @@ mod tests { fn runtime_published_receipts_reject_conflicting_source_owner() { let (runtime, paths) = bootstrapped_runtime("published_receipt_owner_conflict"); let database_path = paths - .shared_local_events_database_path() - .expect("shared local events path"); + .shared_runtime_store_database_path() + .expect("shared runtime store path"); let executor = - SqliteExecutor::open(database_path.as_path()).expect("open shared local events db"); - let store = LocalEventsStore::new(executor); - store.migrate_up().expect("migrate shared local events"); + SqliteExecutor::open(database_path.as_path()).expect("open shared runtime store db"); + let store = RuntimeStore::new(executor); + store.migrate_up().expect("migrate shared runtime store"); store .append_record(&local_work_record( "app:local_work:conflict-source", @@ -13232,7 +13285,7 @@ mod tests { } )); assert!( - shared_local_event_records(&paths) + shared_runtime_store_records(&paths) .iter() .all(|record| record.record_id != "app:signed_event:event-app-owner-conflict") ); @@ -13289,7 +13342,7 @@ mod tests { .expect("unresolved listing local work should append"); } - let records = shared_local_event_records(&paths); + let records = shared_runtime_store_records(&paths); let app_records = records .iter() .filter(|record| record.source_runtime == SourceRuntime::App) @@ -13672,7 +13725,7 @@ mod tests { .expect("sdk diagnostics should be present"); assert_eq!(diagnostics.runtime.state, AppSdkLifecycleState::Ready); assert_eq!(diagnostics.storage.storage_kind, "directory"); - assert_eq!(diagnostics.sync.relay_targets.configured_count, 1); + assert_eq!(diagnostics.sync.transport_targets.configured_count, 1); assert!( runtime .shutdown_sdk_runtime() @@ -13746,7 +13799,7 @@ mod tests { assert!( issue .recovery_actions - .contains(&"configure_relay_targets".to_owned()) + .contains(&"configure_transport_targets".to_owned()) ); } unexpected => panic!("unexpected diagnostics state: {unexpected:?}"), @@ -15448,7 +15501,7 @@ mod tests { } #[test] - fn runtime_finds_seller_order_request_evidence_past_first_local_events_page() { + fn runtime_finds_seller_order_request_evidence_past_first_runtime_store_page() { let relay = ThreadedAckRelay::spawn(); let (runtime, paths, order_id, _product_id, _seller_pubkey, _buyer_pubkey) = seller_order_decision_runtime("seller_order_old_request_evidence", 6, 2); @@ -15601,8 +15654,8 @@ mod tests { assert_eq!(persisted_order_status(&runtime, order_id), "needs_action"); assert_eq!(relay.event_count(), 1); - assert!(!shared_local_event_records(&paths).iter().any(|record| { - record.family == LocalRecordFamily::SignedEvent + assert!(!shared_runtime_store_records(&paths).iter().any(|record| { + record.family == RuntimeStoreRecordFamily::SignedEvent && record.event_kind == Some(3423) && record.event_pubkey.as_deref() == Some(seller_pubkey.as_str()) })); @@ -15632,8 +15685,8 @@ mod tests { assert_eq!(persisted_order_status(&runtime, order_id), "needs_action"); assert_eq!(relay.event_count(), 1); - assert!(!shared_local_event_records(&paths).iter().any(|record| { - record.family == LocalRecordFamily::SignedEvent + assert!(!shared_runtime_store_records(&paths).iter().any(|record| { + record.family == RuntimeStoreRecordFamily::SignedEvent && record.event_kind == Some(3423) && record.event_pubkey.as_deref() == Some(seller_pubkey.as_str()) })); @@ -15692,7 +15745,7 @@ mod tests { } #[test] - fn runtime_places_supported_buyer_order_into_shared_local_events() { + fn runtime_places_supported_buyer_order_into_shared_runtime_store() { let (runtime, paths) = bootstrapped_runtime("buyer_order_local_event"); assert!( runtime @@ -15815,7 +15868,7 @@ mod tests { assert_eq!(coordination_after.attempt_count, 1); } - let records = shared_local_event_records(&paths); + let records = shared_runtime_store_records(&paths); let order_records = records .iter() .filter(|record| { @@ -15829,8 +15882,8 @@ mod tests { .collect::<Vec<_>>(); assert_eq!(order_records.len(), 1); let order_record = order_records[0]; - assert_eq!(order_record.family, LocalRecordFamily::LocalWork); - assert_eq!(order_record.status, LocalRecordStatus::LocalSaved); + assert_eq!(order_record.family, RuntimeStoreRecordFamily::LocalWork); + assert_eq!(order_record.status, RuntimeStoreRecordStatus::LocalSaved); assert_eq!(order_record.outbox_status, PublishOutboxStatus::None); assert_eq!( order_record.record_id, @@ -15920,7 +15973,7 @@ mod tests { ) .expect("buyer order status should mutate before retry refresh"); } - unblock_shared_local_events_database(&paths); + unblock_shared_runtime_store_database(&paths); assert!( runtime .retry_pending_personal_order_coordination() @@ -16013,7 +16066,7 @@ mod tests { fn runtime_buyer_order_shared_append_failure_is_recoverable_after_restart() { let (runtime, paths, buyer_account_id, order_id) = blocked_buyer_order_runtime("buyer_order_append_failure_restart"); - unblock_shared_local_events_database(&paths); + unblock_shared_runtime_store_database(&paths); drop(runtime); let restarted_runtime = restart_runtime(paths.clone()); @@ -16083,7 +16136,7 @@ mod tests { { let (runtime, paths, buyer_account_id, order_id) = blocked_buyer_order_runtime("buyer_order_append_failure_foreground_resume"); - unblock_shared_local_events_database(&paths); + unblock_shared_runtime_store_database(&paths); assert!( runtime .sync_on_foreground_resume() @@ -16230,8 +16283,8 @@ mod tests { let fixture = linked_buyer_lifecycle_runtime("linked_buyer_order_open"); let report = fixture .runtime - .refresh_shared_local_events() - .expect("linked buyer local events should import"); + .refresh_shared_runtime_store() + .expect("linked buyer runtime store should import"); assert!(report.imported_records > 0); assert!( @@ -16283,8 +16336,8 @@ mod tests { ); fixture .runtime - .refresh_shared_local_events() - .expect("linked buyer local events should import"); + .refresh_shared_runtime_store() + .expect("linked buyer runtime store should import"); assert!( fixture .runtime @@ -16335,7 +16388,7 @@ mod tests { install_direct_relay_sync_transport(&fixture.runtime, &relay); fixture .runtime - .refresh_shared_local_events() + .refresh_shared_runtime_store() .expect("linked buyer revision proposal should import"); assert!( fixture @@ -16368,8 +16421,8 @@ mod tests { install_direct_relay_sync_transport(&fixture.runtime, &relay); fixture .runtime - .refresh_shared_local_events() - .expect("linked buyer local events should import"); + .refresh_shared_runtime_store() + .expect("linked buyer runtime store should import"); assert!( fixture .runtime @@ -16401,8 +16454,8 @@ mod tests { install_direct_relay_sync_transport(&fixture.runtime, &relay); fixture .runtime - .refresh_shared_local_events() - .expect("linked buyer local events should import"); + .refresh_shared_runtime_store() + .expect("linked buyer runtime store should import"); assert!( fixture .runtime @@ -16464,8 +16517,8 @@ mod tests { ); fixture .runtime - .refresh_shared_local_events() - .expect("linked buyer local events should import"); + .refresh_shared_runtime_store() + .expect("linked buyer runtime store should import"); assert!( fixture .runtime @@ -19567,15 +19620,15 @@ mod tests { fn append_cli_local_listing_records(paths: &AppDesktopRuntimePaths, account_id: &str) { let database_path = paths - .shared_local_events_database_path() - .expect("shared local events path"); + .shared_runtime_store_database_path() + .expect("shared runtime store path"); if let Some(parent) = database_path.parent() { - fs::create_dir_all(parent).expect("shared local events directory should create"); + fs::create_dir_all(parent).expect("shared runtime store directory should create"); } let executor = - SqliteExecutor::open(database_path.as_path()).expect("open shared local events db"); - let store = LocalEventsStore::new(executor); - store.migrate_up().expect("migrate shared local events"); + SqliteExecutor::open(database_path.as_path()).expect("open shared runtime store db"); + let store = RuntimeStore::new(executor); + store.migrate_up().expect("migrate shared runtime store"); let farm_key = "AAAAAAAAAAAAAAAAAAAAAA"; let listing_key = "BBBBBBBBBBBBBBBBBBBBBB"; store @@ -19684,15 +19737,15 @@ mod tests { bin_id: &str, ) { let database_path = paths - .shared_local_events_database_path() - .expect("shared local events path"); + .shared_runtime_store_database_path() + .expect("shared runtime store path"); if let Some(parent) = database_path.parent() { - fs::create_dir_all(parent).expect("shared local events directory should create"); + fs::create_dir_all(parent).expect("shared runtime store directory should create"); } let executor = - SqliteExecutor::open(database_path.as_path()).expect("open shared local events db"); - let store = LocalEventsStore::new(executor); - store.migrate_up().expect("migrate shared local events"); + SqliteExecutor::open(database_path.as_path()).expect("open shared runtime store db"); + let store = RuntimeStore::new(executor); + store.migrate_up().expect("migrate shared runtime store"); let farm_key = "CCCCCCCCCCCCCCCCCCCCCC"; let owner_pubkey = BUYER_VISIBLE_SELLER_PUBKEY; let record_id = format!("cli:signed_event:{record_suffix}"); @@ -19724,10 +19777,10 @@ mod tests { }); let event_id = signed_event_id(record_id.as_str()); store - .append_record(&LocalEventRecordInput { + .append_record(&RuntimeStoreRecordInput { record_id: record_id.to_owned(), - family: LocalRecordFamily::SignedEvent, - status: LocalRecordStatus::Published, + family: RuntimeStoreRecordFamily::SignedEvent, + status: RuntimeStoreRecordStatus::Published, source_runtime: SourceRuntime::Cli, created_at_ms, inserted_at_ms: created_at_ms + 1, @@ -20109,15 +20162,15 @@ mod tests { stock_count: u32, ) { let database_path = paths - .shared_local_events_database_path() - .expect("shared local events path"); + .shared_runtime_store_database_path() + .expect("shared runtime store path"); if let Some(parent) = database_path.parent() { - fs::create_dir_all(parent).expect("shared local events directory should create"); + fs::create_dir_all(parent).expect("shared runtime store directory should create"); } let executor = - SqliteExecutor::open(database_path.as_path()).expect("open shared local events db"); - let store = LocalEventsStore::new(executor); - store.migrate_up().expect("migrate shared local events"); + SqliteExecutor::open(database_path.as_path()).expect("open shared runtime store db"); + let store = RuntimeStore::new(executor); + store.migrate_up().expect("migrate shared runtime store"); let listing_addr = format!("30402:{seller_pubkey}:{listing_key}"); let listing_event_id = test_event_id_seed(listing_event_id); let content = json!({ @@ -20147,10 +20200,10 @@ mod tests { } }); store - .append_record(&LocalEventRecordInput { + .append_record(&RuntimeStoreRecordInput { record_id: "app:signed_event:listing:seller-order-decision".to_owned(), - family: LocalRecordFamily::SignedEvent, - status: LocalRecordStatus::Published, + family: RuntimeStoreRecordFamily::SignedEvent, + status: RuntimeStoreRecordStatus::Published, source_runtime: SourceRuntime::App, created_at_ms: 1_774_000_000_000, inserted_at_ms: 1_774_000_000_001, @@ -20215,15 +20268,15 @@ mod tests { order_quantity: u32, ) -> String { let database_path = paths - .shared_local_events_database_path() - .expect("shared local events path"); + .shared_runtime_store_database_path() + .expect("shared runtime store path"); if let Some(parent) = database_path.parent() { - fs::create_dir_all(parent).expect("shared local events directory should create"); + fs::create_dir_all(parent).expect("shared runtime store directory should create"); } let executor = - SqliteExecutor::open(database_path.as_path()).expect("open shared local events db"); - let store = LocalEventsStore::new(executor); - store.migrate_up().expect("migrate shared local events"); + SqliteExecutor::open(database_path.as_path()).expect("open shared runtime store db"); + let store = RuntimeStore::new(executor); + store.migrate_up().expect("migrate shared runtime store"); let order = RadrootsOrderRequest { order_id: test_order_id(trade_order_id), listing_addr: test_listing_addr(listing_addr), @@ -20236,7 +20289,7 @@ mod tests { economics: signed_order_request_economics(trade_order_id, order_quantity), }; let parts = order_request_event_build( - &RadrootsNostrEventPtr { + &RadrootsEventPtr { id: test_event_id_seed(listing_event_id), relays: Some("wss://relay.example".to_owned()), }, @@ -20263,10 +20316,10 @@ mod tests { .to_json_value() .expect("acknowledged relay delivery json"); store - .append_record(&LocalEventRecordInput { + .append_record(&RuntimeStoreRecordInput { record_id, - family: LocalRecordFamily::SignedEvent, - status: LocalRecordStatus::Published, + family: RuntimeStoreRecordFamily::SignedEvent, + status: RuntimeStoreRecordStatus::Published, source_runtime: SourceRuntime::Test, created_at_ms: 1_774_000_010_000, inserted_at_ms: 1_774_000_010_001, @@ -20309,15 +20362,15 @@ mod tests { ) -> String { assert_eq!(buyer_pubkey, SDK_TEST_BUYER_PUBLIC_KEY_HEX); let database_path = paths - .shared_local_events_database_path() - .expect("shared local events path"); + .shared_runtime_store_database_path() + .expect("shared runtime store path"); if let Some(parent) = database_path.parent() { - fs::create_dir_all(parent).expect("shared local events directory should create"); + fs::create_dir_all(parent).expect("shared runtime store directory should create"); } let executor = - SqliteExecutor::open(database_path.as_path()).expect("open shared local events db"); - let store = LocalEventsStore::new(executor); - store.migrate_up().expect("migrate shared local events"); + SqliteExecutor::open(database_path.as_path()).expect("open shared runtime store db"); + let store = RuntimeStore::new(executor); + store.migrate_up().expect("migrate shared runtime store"); let order = RadrootsOrderRequest { order_id: test_order_id(trade_order_id), listing_addr: test_listing_addr(listing_addr), @@ -20330,7 +20383,7 @@ mod tests { economics: signed_order_request_economics(trade_order_id, order_quantity), }; let parts = order_request_event_build( - &RadrootsNostrEventPtr { + &RadrootsEventPtr { id: test_event_id_seed(listing_event_id), relays: Some("wss://relay.example".to_owned()), }, @@ -20358,10 +20411,10 @@ mod tests { .to_json_value() .expect("acknowledged relay delivery json"); store - .append_record(&LocalEventRecordInput { + .append_record(&RuntimeStoreRecordInput { record_id, - family: LocalRecordFamily::SignedEvent, - status: LocalRecordStatus::Published, + family: RuntimeStoreRecordFamily::SignedEvent, + status: RuntimeStoreRecordStatus::Published, source_runtime: SourceRuntime::Test, created_at_ms: 1_774_000_010_000, inserted_at_ms: 1_774_000_010_001, @@ -20587,15 +20640,15 @@ mod tests { parts: WireEventParts, ) -> String { let database_path = paths - .shared_local_events_database_path() - .expect("shared local events path"); + .shared_runtime_store_database_path() + .expect("shared runtime store path"); if let Some(parent) = database_path.parent() { - fs::create_dir_all(parent).expect("shared local events directory should create"); + fs::create_dir_all(parent).expect("shared runtime store directory should create"); } let executor = - SqliteExecutor::open(database_path.as_path()).expect("open shared local events db"); - let store = LocalEventsStore::new(executor); - store.migrate_up().expect("migrate shared local events"); + SqliteExecutor::open(database_path.as_path()).expect("open shared runtime store db"); + let store = RuntimeStore::new(executor); + store.migrate_up().expect("migrate shared runtime store"); let created_at = test_event_created_at(record_id, 1_774_000_020); let event = test_event_from_parts( record_id, @@ -20615,10 +20668,10 @@ mod tests { .to_json_value() .expect("acknowledged relay delivery json"); store - .append_record(&LocalEventRecordInput { + .append_record(&RuntimeStoreRecordInput { record_id: record_id.to_owned(), - family: LocalRecordFamily::SignedEvent, - status: LocalRecordStatus::Published, + family: RuntimeStoreRecordFamily::SignedEvent, + status: RuntimeStoreRecordStatus::Published, source_runtime: SourceRuntime::Test, created_at_ms: i64::from(created_at) * 1000, inserted_at_ms: i64::from(created_at) * 1000 + 1, @@ -20652,13 +20705,13 @@ mod tests { fn mark_shared_seller_order_request_evidence_pending(paths: &AppDesktopRuntimePaths) { let database_path = paths - .shared_local_events_database_path() - .expect("shared local events path"); + .shared_runtime_store_database_path() + .expect("shared runtime store path"); let executor = - SqliteExecutor::open(database_path.as_path()).expect("open shared local events db"); + SqliteExecutor::open(database_path.as_path()).expect("open shared runtime store db"); executor .exec( - "UPDATE local_event_record + "UPDATE runtime_store_record SET status = 'pending_publish', outbox_status = 'pending', relay_set_fingerprint = NULL, @@ -20671,22 +20724,22 @@ mod tests { fn append_unrelated_signed_event_records(paths: &AppDesktopRuntimePaths, count: usize) { let database_path = paths - .shared_local_events_database_path() - .expect("shared local events path"); + .shared_runtime_store_database_path() + .expect("shared runtime store path"); let executor = - SqliteExecutor::open(database_path.as_path()).expect("open shared local events db"); - let store = LocalEventsStore::new(executor); - store.migrate_up().expect("migrate shared local events"); + SqliteExecutor::open(database_path.as_path()).expect("open shared runtime store db"); + let store = RuntimeStore::new(executor); + store.migrate_up().expect("migrate shared runtime store"); let pubkey = "2222222222222222222222222222222222222222222222222222222222222222"; for index in 0..count { let record_id = format!("app:signed_event:unrelated:{index}"); let event_id = signed_event_id(record_id.as_str()); store - .append_record(&LocalEventRecordInput { + .append_record(&RuntimeStoreRecordInput { record_id, - family: LocalRecordFamily::SignedEvent, - status: LocalRecordStatus::Published, + family: RuntimeStoreRecordFamily::SignedEvent, + status: RuntimeStoreRecordStatus::Published, source_runtime: SourceRuntime::Test, created_at_ms: 1_774_000_100_000 + i64::try_from(index).unwrap_or_default(), inserted_at_ms: 1_774_000_100_001 + i64::try_from(index).unwrap_or_default(), @@ -20737,7 +20790,7 @@ mod tests { )) } - fn assert_detail_open_imports_shared_local_events_before_lookup( + fn assert_detail_open_imports_shared_runtime_store_before_lookup( label: &str, section: PersonalSection, ) { @@ -20780,7 +20833,7 @@ mod tests { PersonalSection::Search => summary.personal_projection.search.detail, _ => None, } - .expect("buyer detail should open from imported shared local events"); + .expect("buyer detail should open from imported shared runtime store"); assert_eq!(detail.listing.product_id, product_id); assert_eq!(detail.listing.title, "Buyer Visible Eggs"); @@ -20794,11 +20847,11 @@ mod tests { farm_key: &str, listing_addr: Option<String>, payload: serde_json::Value, - ) -> LocalEventRecordInput { - LocalEventRecordInput { + ) -> RuntimeStoreRecordInput { + RuntimeStoreRecordInput { record_id: record_id.to_owned(), - family: LocalRecordFamily::LocalWork, - status: LocalRecordStatus::LocalSaved, + family: RuntimeStoreRecordFamily::LocalWork, + status: RuntimeStoreRecordStatus::LocalSaved, source_runtime: SourceRuntime::Cli, created_at_ms: 1000, inserted_at_ms: 1001, @@ -20853,13 +20906,13 @@ mod tests { } } - fn shared_local_event_records(paths: &AppDesktopRuntimePaths) -> Vec<LocalEventRecord> { + fn shared_runtime_store_records(paths: &AppDesktopRuntimePaths) -> Vec<RuntimeStoreRecord> { let database_path = paths - .shared_local_events_database_path() - .expect("shared local events path"); + .shared_runtime_store_database_path() + .expect("shared runtime store path"); let executor = - SqliteExecutor::open(database_path.as_path()).expect("open shared local events db"); - let store = LocalEventsStore::new(executor); + SqliteExecutor::open(database_path.as_path()).expect("open shared runtime store db"); + let store = RuntimeStore::new(executor); store .list_records_after_seq(0, 100) .expect("shared local records should list") @@ -20870,7 +20923,7 @@ mod tests { trade_order_id: &str, ) -> String { let record_id = format!("app:signed_event:order-request:{trade_order_id}"); - shared_local_event_records(paths) + shared_runtime_store_records(paths) .into_iter() .find(|record| record.record_id == record_id) .and_then(|record| record.event_id) @@ -20881,11 +20934,11 @@ mod tests { paths: &AppDesktopRuntimePaths, kind: i64, pubkey: &str, - ) -> Vec<SdkRadrootsNostrEvent> { - shared_local_event_records(paths) + ) -> Vec<RadrootsEventEnvelope> { + shared_runtime_store_records(paths) .into_iter() .filter(|record| { - record.family == LocalRecordFamily::SignedEvent + record.family == RuntimeStoreRecordFamily::SignedEvent && record.event_kind == Some(kind) && record.event_pubkey.as_deref() == Some(pubkey) }) @@ -20971,7 +21024,7 @@ mod tests { .expect("sqlite store") .sdk_workflow_receipt_repository() .load_receipt( - AppSdkWorkflowReceiptSourceKind::SharedLocalEvent, + AppSdkWorkflowReceiptSourceKind::SharedRuntimeStore, source_record_id.as_str(), ) .expect("SDK workflow receipt should load") @@ -21082,7 +21135,7 @@ mod tests { } fn buyer_order_local_work_record_ids(paths: &AppDesktopRuntimePaths) -> Vec<String> { - shared_local_event_records(paths) + shared_runtime_store_records(paths) .into_iter() .filter(|record| { record.source_runtime == SourceRuntime::App @@ -21156,13 +21209,13 @@ mod tests { }) .expect("buyer order review draft should save") ); - block_shared_local_events_database(&paths); + block_shared_runtime_store_database(&paths); let error = runtime .place_personal_order() - .expect_err("blocked local events should fail order completion"); + .expect_err("blocked runtime store should fail order completion"); - assert!(matches!(error, AppSqliteError::LocalEventsSql { .. })); + assert!(matches!(error, AppSqliteError::RuntimeStoreSql { .. })); let summary = runtime.summary(); assert_eq!( summary.shell_projection.selected_section, @@ -21219,26 +21272,26 @@ mod tests { (runtime, paths, buyer_account_id, visible_order_id) } - fn block_shared_local_events_database(paths: &AppDesktopRuntimePaths) { + fn block_shared_runtime_store_database(paths: &AppDesktopRuntimePaths) { let database_path = paths - .shared_local_events_database_path() - .expect("shared local events path"); + .shared_runtime_store_database_path() + .expect("shared runtime store path"); if let Some(parent) = database_path.parent() { - fs::create_dir_all(parent).expect("shared local events directory should create"); + fs::create_dir_all(parent).expect("shared runtime store directory should create"); } if database_path.is_file() { - fs::remove_file(&database_path).expect("shared local events file should remove"); + fs::remove_file(&database_path).expect("shared runtime store file should remove"); } else if database_path.is_dir() { fs::remove_dir_all(&database_path) - .expect("shared local events directory should remove"); + .expect("shared runtime store directory should remove"); } fs::create_dir(&database_path).expect("blocking directory should create"); } - fn unblock_shared_local_events_database(paths: &AppDesktopRuntimePaths) { + fn unblock_shared_runtime_store_database(paths: &AppDesktopRuntimePaths) { let database_path = paths - .shared_local_events_database_path() - .expect("shared local events path"); + .shared_runtime_store_database_path() + .expect("shared runtime store path"); if database_path.is_dir() { fs::remove_dir_all(&database_path).expect("blocking directory should remove"); } diff --git a/crates/desktop/src/source_guards.rs b/crates/desktop/src/source_guards.rs @@ -110,7 +110,7 @@ const ALLOWED_WINDOW_LITERALS: &[&str] = &[ "CARGO_PKG_VERSION", "clock", "configuration", - "configure_relay_targets", + "configure_transport_targets", "customer_labels.txt", "desktop runtime paths should resolve", "desktop runtime roots require HOME for macos", @@ -734,7 +734,7 @@ const REQUIRED_WINDOW_COPY_KEYS: &[&str] = &[ "AppTextKey::TradeWorkflowProvenanceApp", "AppTextKey::TradeWorkflowProvenanceCli", "AppTextKey::TradeWorkflowProvenanceRelay", - "AppTextKey::TradeWorkflowProvenanceLocalEvents", + "AppTextKey::TradeWorkflowProvenanceRuntimeStore", "AppTextKey::TradeWorkflowProvenanceUnknown", "AppTextKey::OrdersRemindersTitle", "AppTextKey::OrdersReminderLogTitle", @@ -1035,7 +1035,7 @@ const FORBIDDEN_HARDCODED_WORKFLOW_UI_LITERALS: &[&str] = &[ "App", "CLI", "Relay", - "Local events", + "Runtime store", "Unknown", ]; @@ -1359,6 +1359,13 @@ const SDK_BOUNDARY_EXCEPTIONS: &[SdkBoundaryExceptionEntry] = &[ reason: "store facade accepts app local_outbox publish operations for deferred workflows", removal_condition: "remove when app local_outbox enqueue is replaced by SDK canonical outbox enqueue APIs", }, + SdkBoundaryExceptionEntry { + path: "crates/runtime/src/sdk.rs", + pattern: "TradeEvidenceIngestRequest", + owner: "rpv1-csv1.03", + reason: "revision-decision mutations pass reducer-visible runtime-store signed evidence into the SDK explicit evidence mode", + removal_condition: "remove when revision-decision SDK mutations can consume shared runtime-store evidence without app-core evidence bridging", + }, ]; #[test] @@ -1657,7 +1664,7 @@ fn app_sdk_trade_mutation_requests_stay_locator_and_resync_owned() { "trade revision decision", "fn trade_revision_decide_with_sdk(", "fn trade_cancel_with_sdk(", - 1usize, + 0usize, ), ( "trade cancellation", @@ -1679,6 +1686,19 @@ fn app_sdk_trade_mutation_requests_stay_locator_and_resync_owned() { "{label} must not use local-only evidence for app mutation authority" ); } + let revision_decision = source_segment( + source.as_str(), + "fn trade_revision_decide_with_sdk(", + "fn trade_cancel_with_sdk(", + ); + assert!( + revision_decision.contains("TradeEvidenceMode::require_explicit_evidence("), + "trade revision decision must pass reducer-visible runtime-store evidence into SDK explicit evidence mode" + ); + assert!( + revision_decision.contains("TradeEvidenceIngestRequest::new"), + "trade revision decision explicit evidence must be converted through SDK evidence ingest requests" + ); } #[test] @@ -1842,16 +1862,21 @@ fn strict_sdk_boundary_scanner_rejects_unexcepted_new_production_paths() { "crates/runtime/src/sdk.rs", "fn mutate() { sdk.trades().ingest_evidence(TradeEvidenceIngestRequest::new(event)); }", ); - assert_eq!(evidence_findings.len(), 2); + assert_eq!(evidence_findings.len(), 1); assert!( evidence_findings .iter() - .any(|finding| finding.pattern == "TradeEvidenceIngestRequest") + .any(|finding| finding.pattern == ".ingest_evidence(") + ); + let unexcepted_evidence_type_findings = unexcepted_sdk_boundary_patterns( + "crates/desktop/src/runtime.rs", + "fn mutate() { let _ = TradeEvidenceIngestRequest::new(event); }", ); + assert_eq!(unexcepted_evidence_type_findings.len(), 1); assert!( - evidence_findings + unexcepted_evidence_type_findings .iter() - .any(|finding| finding.pattern == ".ingest_evidence(") + .any(|finding| finding.pattern == "TradeEvidenceIngestRequest") ); let adapter_hook_findings = unexcepted_sdk_boundary_patterns( "crates/runtime/src/sdk.rs", diff --git a/crates/desktop/src/window.rs b/crates/desktop/src/window.rs @@ -8692,7 +8692,7 @@ fn sdk_recovery_actions_text(actions: &[String]) -> String { fn sdk_recovery_action_key(action: &str) -> AppTextKey { match action { - "configure_relay_targets" => AppTextKey::ValueSdkRecoveryConfigureRelayTargets, + "configure_transport_targets" => AppTextKey::ValueSdkRecoveryConfigureRelayTargets, "retry_startup" => AppTextKey::ValueSdkRecoveryRetryStartup, "wait_for_sdk_lifecycle" => AppTextKey::ValueSdkRecoveryWaitForLifecycle, "retry_status_refresh" => AppTextKey::ValueSdkRecoveryRetryStatusRefresh, @@ -11704,7 +11704,7 @@ fn trade_workflow_source_key(source: TradeWorkflowSource) -> AppTextKey { TradeWorkflowSource::App => AppTextKey::TradeWorkflowProvenanceApp, TradeWorkflowSource::Cli => AppTextKey::TradeWorkflowProvenanceCli, TradeWorkflowSource::Relay => AppTextKey::TradeWorkflowProvenanceRelay, - TradeWorkflowSource::LocalEvents => AppTextKey::TradeWorkflowProvenanceLocalEvents, + TradeWorkflowSource::RuntimeStore => AppTextKey::TradeWorkflowProvenanceRuntimeStore, TradeWorkflowSource::Unknown => AppTextKey::TradeWorkflowProvenanceUnknown, } } @@ -12597,7 +12597,9 @@ fn startup_home_body(runtime: &DesktopAppRuntimeSummary) -> impl IntoElement { div().w_full().text_center().child(home_body_text(body)) } -async fn connect_configured_relays(relay_urls: Vec<String>) -> Result<RadrootsNostrClient, String> { +async fn connect_configured_targets( + relay_urls: Vec<String>, +) -> Result<RadrootsNostrClient, String> { let client = RadrootsNostrClient::new_signerless(); for relay_url in relay_urls { client @@ -12614,7 +12616,7 @@ struct StartupAppInitResult { } async fn run_startup_app_init(relay_urls: Vec<String>) -> Result<StartupAppInitResult, String> { - let relay_client = connect_configured_relays(relay_urls).await?; + let relay_client = connect_configured_targets(relay_urls).await?; Ok(StartupAppInitResult { relay_client }) } @@ -16146,7 +16148,7 @@ fn home_empty_state_card(title_key: AppTextKey, body_key: AppTextKey) -> impl In fn buyer_order_place_failure_notice(error: &AppSqliteError) -> BuyerWorkspaceNotice { match error { - AppSqliteError::LocalEventsSql { .. } | AppSqliteError::LocalEvents { .. } => { + AppSqliteError::RuntimeStoreSql { .. } | AppSqliteError::RuntimeStore { .. } => { BuyerWorkspaceNotice::OrderCoordinationFailed } _ => BuyerWorkspaceNotice::OrderPlaceFailed, @@ -16429,8 +16431,8 @@ mod tests { (HomeView::new(runtime), paths, home_dir) } - fn block_shared_local_events_database(paths: &AppDesktopRuntimePaths) { - let database_path = paths.shared_local_events_database_path().unwrap(); + fn block_shared_runtime_store_database(paths: &AppDesktopRuntimePaths) { + let database_path = paths.shared_runtime_store_database_path().unwrap(); if let Some(parent) = database_path.parent() { fs::create_dir_all(parent).unwrap(); } @@ -16587,7 +16589,7 @@ mod tests { #[test] fn buyer_browse_refresh_failure_uses_typed_visible_notice() { let (mut view, paths, home_dir) = test_home_view("buyer_notice"); - block_shared_local_events_database(&paths); + block_shared_runtime_store_database(&paths); assert!(view.select_personal_section_update(PersonalSection::Browse)); assert_eq!( @@ -16601,7 +16603,7 @@ mod tests { #[test] fn buyer_search_refresh_failure_uses_typed_visible_notice() { let (mut view, paths, home_dir) = test_home_view("buyer_notice"); - block_shared_local_events_database(&paths); + block_shared_runtime_store_database(&paths); assert!(view.set_personal_search_query_update("eggs")); assert_eq!( @@ -16615,7 +16617,7 @@ mod tests { #[test] fn buyer_detail_open_failure_uses_typed_visible_notice() { let (mut view, paths, home_dir) = test_home_view("buyer_notice"); - block_shared_local_events_database(&paths); + block_shared_runtime_store_database(&paths); assert!( view.open_personal_product_detail_update(PersonalSection::Browse, ProductId::new()) @@ -16870,8 +16872,8 @@ mod tests { AppTextKey::TradeWorkflowProvenanceRelay, ), ( - TradeWorkflowSource::LocalEvents, - AppTextKey::TradeWorkflowProvenanceLocalEvents, + TradeWorkflowSource::RuntimeStore, + AppTextKey::TradeWorkflowProvenanceRuntimeStore, ), ( TradeWorkflowSource::Unknown, @@ -18708,7 +18710,7 @@ mod tests { code: "invalid_relay_url".to_owned(), class: "configuration".to_owned(), retryable: false, - recovery_actions: vec!["configure_relay_targets".to_owned()], + recovery_actions: vec!["configure_transport_targets".to_owned()], }; let mut sdk_status = fixture_sdk_status(AppSdkLifecycleState::Degraded); sdk_status.last_issue = Some(issue.clone()); diff --git a/crates/i18n/src/keys.rs b/crates/i18n/src/keys.rs @@ -450,7 +450,7 @@ define_app_text_keys! { TradeWorkflowProvenanceApp => "trade.workflow.provenance.app", TradeWorkflowProvenanceCli => "trade.workflow.provenance.cli", TradeWorkflowProvenanceRelay => "trade.workflow.provenance.relay", - TradeWorkflowProvenanceLocalEvents => "trade.workflow.provenance.local_events", + TradeWorkflowProvenanceRuntimeStore => "trade.workflow.provenance.runtime_store", TradeWorkflowProvenanceUnknown => "trade.workflow.provenance.unknown", OrdersRemindersTitle => "orders.reminders.title", OrdersReminderLogTitle => "orders.reminder_log.title", diff --git a/crates/i18n/src/lib.rs b/crates/i18n/src/lib.rs @@ -668,8 +668,8 @@ mod tests { ); assert_eq!(app_text(AppTextKey::TradeWorkflowProvenanceCli), "CLI"); assert_eq!( - app_text(AppTextKey::TradeWorkflowProvenanceLocalEvents), - "Local events" + app_text(AppTextKey::TradeWorkflowProvenanceRuntimeStore), + "Runtime store" ); } diff --git a/crates/runtime/Cargo.toml b/crates/runtime/Cargo.toml @@ -11,9 +11,9 @@ publish = false [dependencies] chrono.workspace = true radroots_authority.workspace = true -radroots_events.workspace = true +radroots_event.workspace = true radroots_studio_app_view.workspace = true -radroots_local_events.workspace = true +radroots_runtime_store.workspace = true radroots_nostr.workspace = true radroots_runtime_paths.workspace = true radroots_sdk.workspace = true diff --git a/crates/runtime/src/lib.rs b/crates/runtime/src/lib.rs @@ -24,9 +24,10 @@ pub use paths::{ AppSharedAccountsPaths, AppSharedIdentityPaths, SHARED_ACCOUNTS_NAMESPACE, SHARED_ACCOUNTS_NAMESPACE_KIND, SHARED_ACCOUNTS_NAMESPACE_VALUE, SHARED_ACCOUNTS_STORE_FILE_NAME, SHARED_IDENTITIES_NAMESPACE, SHARED_IDENTITIES_NAMESPACE_KIND, - SHARED_IDENTITIES_NAMESPACE_VALUE, SHARED_IDENTITY_FILE_NAME, SHARED_LOCAL_EVENTS_DB_FILE_NAME, - SHARED_LOCAL_EVENTS_NAMESPACE, SHARED_LOCAL_EVENTS_NAMESPACE_KIND, - SHARED_LOCAL_EVENTS_NAMESPACE_VALUE, shared_local_events_database_path_from_shared_accounts, + SHARED_IDENTITIES_NAMESPACE_VALUE, SHARED_IDENTITY_FILE_NAME, + SHARED_RUNTIME_STORE_DB_FILE_NAME, SHARED_RUNTIME_STORE_NAMESPACE, + SHARED_RUNTIME_STORE_NAMESPACE_KIND, SHARED_RUNTIME_STORE_NAMESPACE_VALUE, + shared_runtime_store_database_path_from_shared_accounts, }; pub use runtime::{ APP_HOST_PLATFORM, APP_ID, APP_LOCAL_LOG_ROOT_ENV, APP_NAME, APP_NOSTR_RELAY_URLS_ENV, @@ -44,9 +45,9 @@ pub use sdk::{ AppSdkRestorePreflightReceipt, AppSdkRestorePreflightRequest, AppSdkRuntime, AppSdkRuntimeError, AppSdkRuntimeIssue, AppSdkRuntimeStatus, AppSdkSqliteStoreDiagnostics, AppSdkStorageDiagnostics, AppSdkStoragePaths, AppSdkSyncDiagnostics, - AppSdkSyncEventStoreDiagnostics, AppSdkSyncOutboxDiagnostics, AppSdkSyncRelayTargetDiagnostics, - AppSdkTradeCancellationRequest, AppSdkTradeDecision, AppSdkTradeDecisionRequest, - AppSdkTradeProposeRequest, AppSdkTradeRevisionDecisionRequest, + AppSdkSyncEventStoreDiagnostics, AppSdkSyncOutboxDiagnostics, + AppSdkSyncTransportTargetDiagnostics, AppSdkTradeCancellationRequest, AppSdkTradeDecision, + AppSdkTradeDecisionRequest, AppSdkTradeProposeRequest, AppSdkTradeRevisionDecisionRequest, AppSdkTradeRevisionProposalRequest, AppSdkWorkflowReceipt, app_sdk_storage_root_from_data_root, }; pub use startup::{AppStartupEvent, AppStartupEventMetadata, launch_startup_event}; diff --git a/crates/runtime/src/paths.rs b/crates/runtime/src/paths.rs @@ -7,14 +7,14 @@ use std::{ }; pub use radroots_runtime_paths::{ - DEFAULT_SHARED_LOCAL_EVENTS_DB_FILE_NAME as SHARED_LOCAL_EVENTS_DB_FILE_NAME, - DEFAULT_SHARED_LOCAL_EVENTS_NAMESPACE as SHARED_LOCAL_EVENTS_NAMESPACE, - DEFAULT_SHARED_LOCAL_EVENTS_NAMESPACE_KIND as SHARED_LOCAL_EVENTS_NAMESPACE_KIND, - DEFAULT_SHARED_LOCAL_EVENTS_NAMESPACE_VALUE as SHARED_LOCAL_EVENTS_NAMESPACE_VALUE, + DEFAULT_SHARED_RUNTIME_STORE_DB_FILE_NAME as SHARED_RUNTIME_STORE_DB_FILE_NAME, + DEFAULT_SHARED_RUNTIME_STORE_NAMESPACE as SHARED_RUNTIME_STORE_NAMESPACE, + DEFAULT_SHARED_RUNTIME_STORE_NAMESPACE_KIND as SHARED_RUNTIME_STORE_NAMESPACE_KIND, + DEFAULT_SHARED_RUNTIME_STORE_NAMESPACE_VALUE as SHARED_RUNTIME_STORE_NAMESPACE_VALUE, }; use radroots_runtime_paths::{ - default_shared_local_events_database_path_from_data_root, - default_shared_local_events_database_path_from_shared_accounts_data_root, + default_shared_runtime_store_database_path_from_data_root, + default_shared_runtime_store_database_path_from_shared_accounts_data_root, }; pub const APP_RUNTIME_NAMESPACE_KIND: &str = "apps"; @@ -121,8 +121,8 @@ pub struct AppDesktopRuntimePaths { } impl AppSharedAccountsPaths { - pub fn shared_local_events_database_path(&self) -> Option<PathBuf> { - shared_local_events_database_path_from_shared_accounts(self) + pub fn shared_runtime_store_database_path(&self) -> Option<PathBuf> { + shared_runtime_store_database_path_from_shared_accounts(self) } } @@ -200,26 +200,26 @@ impl AppDesktopRuntimePaths { }) } - pub fn shared_local_events_database_path(&self) -> Result<PathBuf, AppRuntimePathsError> { + pub fn shared_runtime_store_database_path(&self) -> Result<PathBuf, AppRuntimePathsError> { let data_root = self .app .data .parent() .and_then(|apps_root| apps_root.parent()) - .ok_or(AppRuntimePathsError::SharedLocalEventsPath)?; + .ok_or(AppRuntimePathsError::SharedRuntimeStorePath)?; - Ok(shared_local_events_database_path_from_data_root(data_root)) + Ok(shared_runtime_store_database_path_from_data_root(data_root)) } } -pub fn shared_local_events_database_path_from_shared_accounts( +pub fn shared_runtime_store_database_path_from_shared_accounts( paths: &AppSharedAccountsPaths, ) -> Option<PathBuf> { - default_shared_local_events_database_path_from_shared_accounts_data_root(&paths.data_root).ok() + default_shared_runtime_store_database_path_from_shared_accounts_data_root(&paths.data_root).ok() } -fn shared_local_events_database_path_from_data_root(data_root: &Path) -> PathBuf { - default_shared_local_events_database_path_from_data_root(data_root) +fn shared_runtime_store_database_path_from_data_root(data_root: &Path) -> PathBuf { + default_shared_runtime_store_database_path_from_data_root(data_root) } fn resolve_desktop_base_roots( @@ -306,7 +306,7 @@ pub enum AppRuntimePathsError { EmptyRepoLocalRoot, UnsupportedPathProfile { value: String }, UnsupportedPlatform { platform: AppRuntimePlatform }, - SharedLocalEventsPath, + SharedRuntimeStorePath, } impl fmt::Display for AppRuntimePathsError { @@ -338,7 +338,7 @@ impl fmt::Display for AppRuntimePathsError { "desktop runtime roots are unsupported on {}", platform.label() ), - Self::SharedLocalEventsPath => formatter + Self::SharedRuntimeStorePath => formatter .write_str("desktop app data root must be nested under the Radroots data root"), } } @@ -355,7 +355,7 @@ mod tests { AppDesktopRuntimePaths, AppRuntimeHostEnvironment, AppRuntimePathsError, AppRuntimePlatform, AppRuntimeRoots, SHARED_ACCOUNTS_NAMESPACE, SHARED_ACCOUNTS_STORE_FILE_NAME, SHARED_IDENTITIES_NAMESPACE, SHARED_IDENTITY_FILE_NAME, - SHARED_LOCAL_EVENTS_DB_FILE_NAME, SHARED_LOCAL_EVENTS_NAMESPACE, + SHARED_RUNTIME_STORE_DB_FILE_NAME, SHARED_RUNTIME_STORE_NAMESPACE, }; #[test] @@ -399,11 +399,11 @@ mod tests { ); assert_eq!( paths - .shared_local_events_database_path() - .expect("shared local events path"), + .shared_runtime_store_database_path() + .expect("shared runtime store path"), PathBuf::from("/Users/treesap/.radroots/data") - .join(SHARED_LOCAL_EVENTS_NAMESPACE) - .join(SHARED_LOCAL_EVENTS_DB_FILE_NAME) + .join(SHARED_RUNTIME_STORE_NAMESPACE) + .join(SHARED_RUNTIME_STORE_DB_FILE_NAME) ); } @@ -488,11 +488,11 @@ mod tests { assert_eq!( paths .shared_accounts - .shared_local_events_database_path() - .expect("shared local events path"), + .shared_runtime_store_database_path() + .expect("shared runtime store path"), PathBuf::from("/repo/infra/local/runtime/radroots/data") - .join(SHARED_LOCAL_EVENTS_NAMESPACE) - .join(SHARED_LOCAL_EVENTS_DB_FILE_NAME) + .join(SHARED_RUNTIME_STORE_NAMESPACE) + .join(SHARED_RUNTIME_STORE_DB_FILE_NAME) ); } diff --git a/crates/runtime/src/runtime.rs b/crates/runtime/src/runtime.rs @@ -3,7 +3,7 @@ use std::{ time::{SystemTime, UNIX_EPOCH}, }; -use radroots_local_events::normalize_relay_url; +use radroots_sdk::{NostrRelayUrlPolicy, TargetSet}; use serde::Serialize; use thiserror::Error; @@ -254,10 +254,18 @@ fn normalize_app_relay_url( field: &'static str, relay: &str, ) -> Result<String, AppRuntimeConfigError> { - normalize_relay_url(relay).map_err(|_| AppRuntimeConfigError::InvalidRelayUrl { - field, - value: relay.to_owned(), - }) + TargetSet::nostr_relays([relay], NostrRelayUrlPolicy::Localhost) + .map(|targets| { + targets + .nostr_relay_urls() + .into_iter() + .next() + .expect("single relay target set must contain one relay") + }) + .map_err(|_| AppRuntimeConfigError::InvalidRelayUrl { + field, + value: relay.to_owned(), + }) } fn require_path_value( @@ -553,10 +561,7 @@ mod tests { ) .expect("ipv6 relay url should resolve"); - assert_eq!( - config.nostr_relay_urls, - vec!["wss://[2001:db8::1]:443/relay"] - ); + assert_eq!(config.nostr_relay_urls, vec!["wss://[2001:db8::1]/relay"]); } #[test] diff --git a/crates/runtime/src/sdk.rs b/crates/runtime/src/sdk.rs @@ -11,8 +11,8 @@ use std::{ }; use radroots_authority::{RadrootsActorContext, RadrootsLocalEventSigner}; -use radroots_events::{ - RadrootsNostrEventPtr, +use radroots_event::{ + RadrootsEventEnvelope, RadrootsEventPtr, contract::RadrootsActorRole, farm::RadrootsFarm, ids::{ @@ -27,24 +27,24 @@ use radroots_events::{ }, }; use radroots_nostr::prelude::RadrootsNostrKeys; +use radroots_sdk::SdkMutationState; use radroots_sdk::{ - AckPolicy, FARM_PUBLISH_OPERATION_KIND, FarmEnqueuePublishRequest, FarmEnqueueReceipt, - IntegrityReceipt, IntegrityRequest, LISTING_PUBLISH_OPERATION_KIND, - ListingEnqueuePublishRequest, ListingEnqueueReceipt, PrivacyPreflightConfirmation, + FARM_PUBLISH_OPERATION_KIND, FarmEnqueuePublishRequest, FarmEnqueueReceipt, IntegrityReceipt, + IntegrityRequest, LISTING_PUBLISH_OPERATION_KIND, ListingEnqueuePublishRequest, + ListingEnqueueReceipt, NostrProfile, NostrRelayUrlPolicy, PrivacyPreflightConfirmation, ProductSensitivityField, PublishMode, RadrootsClient, RadrootsSdkError, - RadrootsSdkLocalKeySigner, RadrootsSdkSignerProvider, RadrootsSdkStoragePaths, - RelayResolutionPolicy, RestoreReceipt, RestoreRequest, SdkBackupVerification, - SdkPublicLocality, SdkRelayUrlPolicy as SdkRuntimeRelayUrlPolicy, StorageStatusReceipt, - StorageStatusRequest, SyncStatusReceipt, SyncStatusRequest, TRADE_CANCELLATION_OPERATION_KIND, - TRADE_DECISION_OPERATION_KIND, TRADE_REVISION_DECISION_OPERATION_KIND, - TRADE_REVISION_PROPOSAL_OPERATION_KIND, TRADE_SUBMIT_OPERATION_KIND, TradeAcceptRequest, - TradeCancelRequest, TradeCancellationPlan, TradeCancellationReceipt, TradeDecisionPlan, - TradeDecisionReceipt, TradeDeclineRequest, TradeEvidenceMode, TradeMutationOutcome, + RadrootsSdkLocalKeySigner, RadrootsSdkSignerProvider, RadrootsSdkStoragePaths, RestoreReceipt, + RestoreRequest, SatisfactionPolicy, SdkBackupVerification, SdkPublicLocality, + StorageStatusReceipt, StorageStatusRequest, SyncStatusReceipt, SyncStatusRequest, + TRADE_CANCELLATION_OPERATION_KIND, TRADE_DECISION_OPERATION_KIND, + TRADE_REVISION_DECISION_OPERATION_KIND, TRADE_REVISION_PROPOSAL_OPERATION_KIND, + TRADE_SUBMIT_OPERATION_KIND, TargetPolicy, TradeAcceptRequest, TradeCancelRequest, + TradeCancellationPlan, TradeCancellationReceipt, TradeDecisionPlan, TradeDecisionReceipt, + TradeDeclineRequest, TradeEvidenceIngestRequest, TradeEvidenceMode, TradeMutationOutcome, TradeProposeRequest, TradeRevisionDecisionPlan, TradeRevisionDecisionReceipt, TradeRevisionDecisionRequest, TradeRevisionProposalPlan, TradeRevisionProposalReceipt, - TradeRevisionProposalRequest, TradeSubmitPlan, TradeSubmitReceipt, + TradeRevisionProposalRequest, TradeSubmitPlan, TradeSubmitReceipt, TransportProfile, }; -use radroots_sdk::{SdkMutationState, SdkRelayTargetPolicy}; use radroots_trade::identity::RadrootsTradeLocator; use serde::Serialize; use serde_json::{Value, json}; @@ -141,7 +141,7 @@ pub struct AppSdkEventStoreDiagnostics { pub store: AppSdkSqliteStoreDiagnostics, pub total_events: i64, pub projection_eligible_events: i64, - pub relay_observations: i64, + pub transport_observations: i64, pub last_event_seq: Option<i64>, pub last_event_updated_at_ms: Option<i64>, } @@ -175,14 +175,14 @@ pub struct AppSdkSyncDiagnostics { pub observed_at_ms: i64, pub event_store: AppSdkSyncEventStoreDiagnostics, pub outbox: AppSdkSyncOutboxDiagnostics, - pub relay_targets: AppSdkSyncRelayTargetDiagnostics, + pub transport_targets: AppSdkSyncTransportTargetDiagnostics, } #[derive(Clone, Debug, PartialEq)] pub struct AppSdkSyncEventStoreDiagnostics { pub total_events: i64, pub projection_eligible_events: i64, - pub relay_observations: i64, + pub transport_observations: i64, pub last_event_seq: Option<i64>, pub last_event_updated_at_ms: Option<i64>, } @@ -201,9 +201,9 @@ pub struct AppSdkSyncOutboxDiagnostics { } #[derive(Clone, Debug, PartialEq)] -pub struct AppSdkSyncRelayTargetDiagnostics { +pub struct AppSdkSyncTransportTargetDiagnostics { pub configured_count: usize, - pub configured_relays: Vec<String>, + pub configured_targets: Vec<String>, } #[derive(Clone, Debug, PartialEq)] @@ -251,7 +251,7 @@ pub struct AppSdkTradeProposeRequest { pub actor_account_id: String, pub actor_pubkey: String, pub signer_keys: RadrootsNostrKeys, - pub listing_event: RadrootsNostrEventPtr, + pub listing_event: RadrootsEventPtr, pub order_id: RadrootsOrderId, pub listing_addr: RadrootsListingAddress, pub seller_pubkey: RadrootsPublicKey, @@ -301,6 +301,7 @@ pub struct AppSdkTradeRevisionDecisionRequest { pub locator: RadrootsTradeLocator, pub revision_id: RadrootsOrderRevisionId, pub decision: RadrootsOrderRevisionOutcome, + pub evidence: Vec<RadrootsEventEnvelope>, pub confirm_public_note: bool, pub idempotency_key: Option<String>, } @@ -759,7 +760,7 @@ impl Drop for AppSdkRuntime { } } -impl From<AppSdkRelayUrlPolicy> for SdkRuntimeRelayUrlPolicy { +impl From<AppSdkRelayUrlPolicy> for NostrRelayUrlPolicy { fn from(policy: AppSdkRelayUrlPolicy) -> Self { match policy { AppSdkRelayUrlPolicy::Public => Self::Public, @@ -876,7 +877,7 @@ impl From<StorageStatusReceipt> for AppSdkStorageDiagnostics { store: receipt.event_store.store.into(), total_events: receipt.event_store.total_events, projection_eligible_events: receipt.event_store.projection_eligible_events, - relay_observations: receipt.event_store.relay_observations, + transport_observations: receipt.event_store.transport_observations, last_event_seq: receipt.event_store.last_event_seq, last_event_updated_at_ms: receipt.event_store.last_event_updated_at_ms, }, @@ -929,7 +930,7 @@ impl From<SyncStatusReceipt> for AppSdkSyncDiagnostics { event_store: AppSdkSyncEventStoreDiagnostics { total_events: receipt.event_store.total_events, projection_eligible_events: receipt.event_store.projection_eligible_events, - relay_observations: receipt.event_store.relay_observations, + transport_observations: receipt.event_store.transport_observations, last_event_seq: receipt.event_store.last_event_seq, last_event_updated_at_ms: receipt.event_store.last_event_updated_at_ms, }, @@ -944,9 +945,14 @@ impl From<SyncStatusReceipt> for AppSdkSyncDiagnostics { last_attempt_at_ms: receipt.outbox.last_attempt_at_ms, last_error: receipt.outbox.last_error, }, - relay_targets: AppSdkSyncRelayTargetDiagnostics { - configured_count: receipt.relay_targets.configured_count, - configured_relays: receipt.relay_targets.configured_relays, + transport_targets: AppSdkSyncTransportTargetDiagnostics { + configured_count: receipt.transport_profile.configured_transport_target_count, + configured_targets: receipt + .transport_profile + .configured_transport_targets + .into_iter() + .map(|target| target.endpoint_uri) + .collect(), }, } } @@ -1369,13 +1375,11 @@ fn run_degraded_worker( } async fn build_sdk_runtime(config: &AppSdkConfig) -> Result<RadrootsClient, RadrootsSdkError> { - let mut builder = RadrootsClient::builder() + RadrootsClient::builder() .directory_storage(config.storage_root.clone()) - .relay_url_policy(config.relay_url_policy.into()); - for relay_url in &config.relay_urls { - builder = builder.relay_url(relay_url.clone()); - } - builder.build().await + .transport_profile(app_transport_profile(config)?) + .build() + .await } async fn build_sdk_runtime_with_signer( @@ -1384,29 +1388,37 @@ async fn build_sdk_runtime_with_signer( ) -> Result<RadrootsClient, AppSdkRuntimeIssue> { let signer = RadrootsSdkLocalKeySigner::new(keys) .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?; - let mut builder = RadrootsClient::builder() + let transport_profile = app_transport_profile(config) + .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?; + RadrootsClient::builder() .directory_storage(config.storage_root.clone()) - .relay_url_policy(config.relay_url_policy.into()) - .signer_provider(RadrootsSdkSignerProvider::LocalKey(signer)); - for relay_url in &config.relay_urls { - builder = builder.relay_url(relay_url.clone()); - } - builder + .transport_profile(transport_profile) + .signer_provider(RadrootsSdkSignerProvider::LocalKey(signer)) .build() .await .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error)) } +fn app_transport_profile(config: &AppSdkConfig) -> Result<TransportProfile, RadrootsSdkError> { + if config.relay_urls.is_empty() { + return Ok(TransportProfile::local_only()); + } + Ok(TransportProfile::nostr(NostrProfile::new( + config.relay_urls.iter().map(String::as_str), + config.relay_url_policy.into(), + )?)) +} + fn app_trade_publish_mode() -> PublishMode { PublishMode::EnqueueOnly } -fn app_trade_ack_policy() -> AckPolicy { - AckPolicy::NoWait +fn app_trade_satisfaction_policy() -> SatisfactionPolicy { + SatisfactionPolicy::NoWait } -fn app_trade_relay_resolution_policy() -> RelayResolutionPolicy { - RelayResolutionPolicy::configured_relays() +fn app_trade_target_policy() -> TargetPolicy { + TargetPolicy::default_profile() } fn app_trade_privacy_confirmation(confirm_public_note: bool) -> PrivacyPreflightConfirmation { @@ -1502,7 +1514,7 @@ fn enqueue_farm_publish_with_sdk( RadrootsActorRole::Farmer, )?; let signer = sdk_local_signer(request.signer_keys)?; - let target_relays = sdk_relay_targets(request.target_relays, request.relay_url_policy)?; + let target_relays = sdk_transport_targets(request.target_relays, request.relay_url_policy)?; let mut enqueue = FarmEnqueuePublishRequest::new(actor, request.farm, target_relays); if let Some(idempotency_key) = request.idempotency_key.as_deref() { enqueue = enqueue @@ -1529,7 +1541,7 @@ fn enqueue_listing_publish_with_sdk( RadrootsActorRole::Seller, )?; let signer = sdk_local_signer(request.signer_keys)?; - let target_relays = sdk_relay_targets(request.target_relays, request.relay_url_policy)?; + let target_relays = sdk_transport_targets(request.target_relays, request.relay_url_policy)?; let mut enqueue = ListingEnqueuePublishRequest::new(actor, request.listing, target_relays); if let Some(idempotency_key) = request.idempotency_key.as_deref() { enqueue = enqueue @@ -1564,9 +1576,9 @@ fn trade_propose_with_sdk( request.seller_pubkey, request.items, request.economics, - app_trade_relay_resolution_policy(), + app_trade_target_policy(), app_trade_publish_mode(), - app_trade_ack_policy(), + app_trade_satisfaction_policy(), ) .with_optional_public_note(request.public_note) .with_privacy_confirmation(app_trade_privacy_confirmation(request.confirm_public_note)); @@ -1593,7 +1605,7 @@ fn trade_decision_with_sdk( )?; let sdk = runtime.block_on(build_sdk_runtime_with_signer(config, request.signer_keys))?; let publish_mode = app_trade_publish_mode(); - let ack_policy = app_trade_ack_policy(); + let satisfaction_policy = app_trade_satisfaction_policy(); let outcome = match request.decision { AppSdkTradeDecision::Accept { inventory_commitments, @@ -1602,9 +1614,9 @@ fn trade_decision_with_sdk( actor, request.locator, inventory_commitments, - app_trade_relay_resolution_policy(), + app_trade_target_policy(), publish_mode, - ack_policy, + satisfaction_policy, TradeEvidenceMode::ResyncBeforeMutation, ) .with_privacy_confirmation(app_trade_privacy_confirmation(false)); @@ -1622,9 +1634,9 @@ fn trade_decision_with_sdk( actor, request.locator, reason, - app_trade_relay_resolution_policy(), + app_trade_target_policy(), publish_mode, - ack_policy, + satisfaction_policy, TradeEvidenceMode::ResyncBeforeMutation, ) .with_privacy_confirmation(app_trade_privacy_confirmation(request.confirm_public_note)); @@ -1659,9 +1671,9 @@ fn trade_revision_propose_with_sdk( request.items, request.economics, request.reason, - app_trade_relay_resolution_policy(), + app_trade_target_policy(), app_trade_publish_mode(), - app_trade_ack_policy(), + app_trade_satisfaction_policy(), TradeEvidenceMode::ResyncBeforeMutation, ) .with_privacy_confirmation(app_trade_privacy_confirmation(request.confirm_public_note)); @@ -1692,10 +1704,15 @@ fn trade_revision_decide_with_sdk( request.locator, request.revision_id, request.decision.clone(), - app_trade_relay_resolution_policy(), + app_trade_target_policy(), app_trade_publish_mode(), - app_trade_ack_policy(), - TradeEvidenceMode::ResyncBeforeMutation, + app_trade_satisfaction_policy(), + TradeEvidenceMode::require_explicit_evidence( + request + .evidence + .into_iter() + .map(TradeEvidenceIngestRequest::new), + ), ) .with_privacy_confirmation(app_trade_privacy_confirmation(request.confirm_public_note)); if let Some(idempotency_key) = request.idempotency_key.as_deref() { @@ -1729,9 +1746,9 @@ fn trade_cancel_with_sdk( actor, request.locator, request.reason, - app_trade_relay_resolution_policy(), + app_trade_target_policy(), app_trade_publish_mode(), - app_trade_ack_policy(), + app_trade_satisfaction_policy(), TradeEvidenceMode::ResyncBeforeMutation, ) .with_privacy_confirmation(app_trade_privacy_confirmation(request.confirm_public_note)); @@ -1764,11 +1781,11 @@ fn sdk_local_signer( }) } -fn sdk_relay_targets( +fn sdk_transport_targets( relays: Vec<String>, policy: AppSdkRelayUrlPolicy, -) -> Result<SdkRelayTargetPolicy, AppSdkRuntimeIssue> { - SdkRelayTargetPolicy::try_explicit(relays, policy.into()) +) -> Result<TargetPolicy, AppSdkRuntimeIssue> { + TargetPolicy::try_nostr_relays(relays, policy.into()) .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error)) } @@ -2060,7 +2077,7 @@ mod tests { RadrootsCoreCurrency, RadrootsCoreDecimal, RadrootsCoreMoney, RadrootsCoreQuantity, RadrootsCoreQuantityPrice, RadrootsCoreUnit, }; - use radroots_events::{ + use radroots_event::{ farm::RadrootsFarmRef, ids::{RadrootsDTag, RadrootsInventoryBinId}, listing::{ @@ -2071,8 +2088,8 @@ mod tests { }; use radroots_nostr::prelude::{RadrootsNostrKeys, RadrootsNostrSecretKey}; use radroots_sdk::{ - BackupRequest, LISTING_PUBLISH_OPERATION_KIND, RadrootsClient, - SdkRelayUrlPolicy as SdkRuntimeRelayUrlPolicy, + BackupRequest, LISTING_PUBLISH_OPERATION_KIND, NostrProfile, NostrRelayUrlPolicy, + RadrootsClient, TransportProfile, }; use crate::{ @@ -2169,11 +2186,11 @@ mod tests { assert!(integrity.outbox_ok); let sync = runtime.sync_status().expect("sync diagnostics should load"); assert_eq!(sync.source, "sdk_canonical_stores"); - assert_eq!(sync.relay_targets.configured_count, 1); + assert_eq!(sync.transport_targets.configured_count, 1); let diagnostics = runtime.diagnostics().expect("diagnostics should load"); assert_eq!(diagnostics.runtime.state, AppSdkLifecycleState::Ready); assert_eq!(diagnostics.storage.storage_kind, "directory"); - assert_eq!(diagnostics.sync.relay_targets.configured_count, 1); + assert_eq!(diagnostics.sync.transport_targets.configured_count, 1); runtime.shutdown().expect("sdk runtime should shut down"); assert_eq!(runtime.status().state, AppSdkLifecycleState::Stopped); let _ = fs::remove_dir_all(storage_root); @@ -2247,7 +2264,7 @@ mod tests { assert!( issue .recovery_actions - .contains(&"configure_relay_targets".to_owned()) + .contains(&"configure_transport_targets".to_owned()) ); assert_eq!(issue.detail_json["code"], "invalid_relay_url"); let error = runtime @@ -2334,8 +2351,10 @@ mod tests { .block_on( RadrootsClient::builder() .directory_storage(backup_source_root.clone()) - .relay_url_policy(SdkRuntimeRelayUrlPolicy::Localhost) - .relay_url("ws://127.0.0.1:8080") + .transport_profile(TransportProfile::nostr( + NostrProfile::new(["ws://127.0.0.1:8080"], NostrRelayUrlPolicy::Localhost) + .expect("backup source relay profile"), + )) .build(), ) .expect("source sdk should build"); diff --git a/crates/store/Cargo.toml b/crates/store/Cargo.toml @@ -10,9 +10,9 @@ publish = false [dependencies] radroots_core.workspace = true -radroots_events.workspace = true -radroots_events_codec.workspace = true -radroots_local_events.workspace = true +radroots_event.workspace = true +radroots_event_codec.workspace = true +radroots_runtime_store.workspace = true radroots_studio_app_view.workspace = true radroots_studio_app_sync.workspace = true radroots_sql_core.workspace = true diff --git a/crates/store/migrations/0023_order_workflow_display_projection.sql b/crates/store/migrations/0023_order_workflow_display_projection.sql @@ -10,7 +10,7 @@ ALTER TABLE orders ALTER TABLE orders ADD COLUMN workflow_provenance_source TEXT NOT NULL DEFAULT 'unknown' CHECK ( - workflow_provenance_source IN ('app', 'cli', 'relay', 'local_events', 'unknown') + workflow_provenance_source IN ('app', 'cli', 'relay', 'runtime_store', 'unknown') ); ALTER TABLE orders diff --git a/crates/store/migrations/0025_order_workflow_agreement_projection.sql b/crates/store/migrations/0025_order_workflow_agreement_projection.sql @@ -33,7 +33,7 @@ CREATE TABLE orders ( workflow_inventory IN ('available', 'reserved', 'sold_out', 'needs_review') ), workflow_provenance_source TEXT NOT NULL DEFAULT 'unknown' CHECK ( - workflow_provenance_source IN ('app', 'cli', 'relay', 'local_events', 'unknown') + workflow_provenance_source IN ('app', 'cli', 'relay', 'runtime_store', 'unknown') ), workflow_provenance_last_event_id TEXT ); diff --git a/crates/store/migrations/0028_sdk_workflow_receipts.sql b/crates/store/migrations/0028_sdk_workflow_receipts.sql @@ -1,7 +1,7 @@ CREATE TABLE app_sdk_workflow_receipts ( id TEXT PRIMARY KEY NOT NULL, source_kind TEXT NOT NULL CHECK ( - source_kind IN ('local_outbox', 'shared_local_event') + source_kind IN ('local_outbox', 'shared_runtime_store') ), source_record_id TEXT NOT NULL, sdk_operation_kind TEXT NOT NULL, diff --git a/crates/store/migrations/0029_order_workflow_validation_receipt_agreement.sql b/crates/store/migrations/0029_order_workflow_validation_receipt_agreement.sql @@ -36,7 +36,7 @@ CREATE TABLE orders ( workflow_inventory IN ('available', 'reserved', 'sold_out', 'needs_review') ), workflow_provenance_source TEXT NOT NULL DEFAULT 'unknown' CHECK ( - workflow_provenance_source IN ('app', 'cli', 'relay', 'local_events', 'unknown') + workflow_provenance_source IN ('app', 'cli', 'relay', 'runtime_store', 'unknown') ), workflow_provenance_last_event_id TEXT ); diff --git a/crates/store/src/error.rs b/crates/store/src/error.rs @@ -1,6 +1,6 @@ use std::{io, path::PathBuf}; -use radroots_local_events::LocalEventsError; +use radroots_runtime_store::RuntimeStoreError; use radroots_sql_core::SqlError; use thiserror::Error; @@ -93,16 +93,16 @@ pub enum AppSqliteError { DecodeEnum { field: &'static str, value: String }, #[error("invalid farm-rules projection: {reason}")] InvalidProjection { reason: &'static str }, - #[error("failed to access shared local events store during {operation}")] - LocalEventsSql { + #[error("failed to access shared runtime store store during {operation}")] + RuntimeStoreSql { operation: &'static str, #[source] source: SqlError, }, #[error("failed to import shared local event records during {operation}")] - LocalEvents { + RuntimeStore { operation: &'static str, #[source] - source: LocalEventsError, + source: RuntimeStoreError, }, } diff --git a/crates/store/src/interop.rs b/crates/store/src/interop.rs @@ -1,7 +1,7 @@ use std::{fs, path::Path}; -use radroots_events::{ - RadrootsNostrEvent, +use radroots_event::{ + RadrootsEventEnvelope, ids::{RadrootsEventId, RadrootsOrderId, RadrootsPublicKey}, kinds::{ KIND_FARM as RADROOTS_KIND_FARM, KIND_LISTING as RADROOTS_KIND_LISTING, @@ -18,14 +18,14 @@ use radroots_events::{ RadrootsOrderRevisionOutcome, }, }; -use radroots_events_codec::order::{ +use radroots_event_codec::order::{ order_cancellation_from_event, order_decision_from_event, order_event_context_from_tags, order_request_from_event, order_revision_decision_from_event, order_revision_proposal_from_event, }; -use radroots_local_events::{ - LocalEventRecord, LocalEventsStore, LocalRecordFamily, LocalRecordStatus, PublishOutboxStatus, - RelayDeliveryEvidence, RelayDeliveryState, SourceRuntime, +use radroots_runtime_store::{ + PublishOutboxStatus, RelayDeliveryEvidence, RelayDeliveryState, RuntimeStore, + RuntimeStoreRecord, RuntimeStoreRecordFamily, RuntimeStoreRecordStatus, SourceRuntime, }; use radroots_sql_core::{SqlExecutor, SqliteExecutor}; use radroots_studio_app_view::{ @@ -50,7 +50,7 @@ use uuid::Uuid; use crate::repo::farm_setup::AppFarmSetupRepository; use crate::{AppSqliteError, AppSqliteStore}; -const LOCAL_EVENTS_BATCH_LIMIT: u32 = 500; +const RUNTIME_STORE_BATCH_LIMIT: u32 = 500; const APP_LOCAL_INTEROP_CURSOR_ID: &str = "radroots_studio_app_sqlite_projection_v1"; const KIND_FARM: i64 = RADROOTS_KIND_FARM as i64; const KIND_LISTING: i64 = RADROOTS_KIND_LISTING as i64; @@ -117,16 +117,16 @@ impl<'a> AppLocalInteropRepository<'a> { })?; } let executor = SqliteExecutor::open(shared_database_path).map_err(|source| { - AppSqliteError::LocalEventsSql { - operation: "open shared local events database", + AppSqliteError::RuntimeStoreSql { + operation: "open shared runtime store database", source, } })?; - let store = LocalEventsStore::new(executor); + let store = RuntimeStore::new(executor); store .migrate_up() - .map_err(|source| AppSqliteError::LocalEventsSql { - operation: "migrate shared local events database", + .map_err(|source| AppSqliteError::RuntimeStoreSql { + operation: "migrate shared runtime store database", source, })?; self.import_from_store(&store) @@ -134,7 +134,7 @@ impl<'a> AppLocalInteropRepository<'a> { pub fn import_from_store<E>( &self, - store: &LocalEventsStore<E>, + store: &RuntimeStore<E>, ) -> Result<AppLocalInteropImportReport, AppSqliteError> where E: SqlExecutor, @@ -143,8 +143,8 @@ impl<'a> AppLocalInteropRepository<'a> { let mut after_change_seq = self.last_imported_change_seq()?; loop { let records = store - .list_records_changed_after(after_change_seq, LOCAL_EVENTS_BATCH_LIMIT) - .map_err(|source| AppSqliteError::LocalEvents { + .list_records_changed_after(after_change_seq, RUNTIME_STORE_BATCH_LIMIT) + .map_err(|source| AppSqliteError::RuntimeStore { operation: "list changed shared local event records", source, })?; @@ -158,7 +158,7 @@ impl<'a> AppLocalInteropRepository<'a> { ImportOutcome::Skipped => report.skipped_records += 1, } } - if batch_len < LOCAL_EVENTS_BATCH_LIMIT as usize { + if batch_len < RUNTIME_STORE_BATCH_LIMIT as usize { break; } } @@ -170,7 +170,7 @@ impl<'a> AppLocalInteropRepository<'a> { pub fn import_records( &self, - records: &[LocalEventRecord], + records: &[RuntimeStoreRecord], ) -> Result<AppLocalInteropImportReport, AppSqliteError> { let mut report = AppLocalInteropImportReport::default(); for record in records { @@ -247,7 +247,7 @@ impl<'a> AppLocalInteropRepository<'a> { pub fn load_signed_events_by_kind( &self, event_kind: i64, - ) -> Result<Vec<RadrootsNostrEvent>, AppSqliteError> { + ) -> Result<Vec<RadrootsEventEnvelope>, AppSqliteError> { let mut statement = self .connection .prepare( @@ -310,7 +310,7 @@ impl<'a> AppLocalInteropRepository<'a> { fn load_signed_event_by_event_id( &self, event_id: &str, - ) -> Result<Option<RadrootsNostrEvent>, AppSqliteError> { + ) -> Result<Option<RadrootsEventEnvelope>, AppSqliteError> { let mut statement = self .connection .prepare( @@ -411,7 +411,7 @@ impl<'a> AppLocalInteropRepository<'a> { Ok(()) } - fn import_record(&self, record: &LocalEventRecord) -> Result<ImportOutcome, AppSqliteError> { + fn import_record(&self, record: &RuntimeStoreRecord) -> Result<ImportOutcome, AppSqliteError> { self.begin_import_record_savepoint()?; match self.import_record_inner(record) { Ok(outcome) => { @@ -428,7 +428,7 @@ impl<'a> AppLocalInteropRepository<'a> { fn import_record_inner( &self, - record: &LocalEventRecord, + record: &RuntimeStoreRecord, ) -> Result<ImportOutcome, AppSqliteError> { let superseded_listing_ids = match self.duplicate_signed_event_action(record)? { DuplicateSignedEventAction::Import => Vec::new(), @@ -440,8 +440,8 @@ impl<'a> AppLocalInteropRepository<'a> { DuplicateSignedEventAction::Skip => return Ok(ImportOutcome::Skipped), }; let projection = match record.family { - LocalRecordFamily::LocalWork => self.import_local_work(record)?, - LocalRecordFamily::SignedEvent => self.import_signed_event(record)?, + RuntimeStoreRecordFamily::LocalWork => self.import_local_work(record)?, + RuntimeStoreRecordFamily::SignedEvent => self.import_signed_event(record)?, }; match projection { Some(projection) => { @@ -494,9 +494,9 @@ impl<'a> AppLocalInteropRepository<'a> { fn duplicate_signed_event_action( &self, - record: &LocalEventRecord, + record: &RuntimeStoreRecord, ) -> Result<DuplicateSignedEventAction, AppSqliteError> { - if record.family != LocalRecordFamily::SignedEvent { + if record.family != RuntimeStoreRecordFamily::SignedEvent { return Ok(DuplicateSignedEventAction::Import); } let Some(event_id) = record @@ -737,7 +737,7 @@ impl<'a> AppLocalInteropRepository<'a> { fn import_local_work( &self, - record: &LocalEventRecord, + record: &RuntimeStoreRecord, ) -> Result<Option<ProjectionRecord>, AppSqliteError> { let Some(payload) = record.local_work_json.as_ref() else { return Ok(None); @@ -751,7 +751,7 @@ impl<'a> AppLocalInteropRepository<'a> { fn import_signed_event( &self, - record: &LocalEventRecord, + record: &RuntimeStoreRecord, ) -> Result<Option<ProjectionRecord>, AppSqliteError> { match record.event_kind { Some(KIND_FARM) => self.import_signed_farm(record), @@ -767,7 +767,7 @@ impl<'a> AppLocalInteropRepository<'a> { fn import_farm_config( &self, - record: &LocalEventRecord, + record: &RuntimeStoreRecord, payload: &Value, ) -> Result<Option<ProjectionRecord>, AppSqliteError> { let Some(document) = payload.get("document") else { @@ -826,7 +826,7 @@ impl<'a> AppLocalInteropRepository<'a> { fn import_listing_draft( &self, - record: &LocalEventRecord, + record: &RuntimeStoreRecord, payload: &Value, ) -> Result<Option<ProjectionRecord>, AppSqliteError> { let Some(document) = payload.get("document") else { @@ -898,7 +898,7 @@ impl<'a> AppLocalInteropRepository<'a> { fn import_signed_farm( &self, - record: &LocalEventRecord, + record: &RuntimeStoreRecord, ) -> Result<Option<ProjectionRecord>, AppSqliteError> { let Some(content) = record.event_content.as_deref() else { return Ok(None); @@ -941,7 +941,7 @@ impl<'a> AppLocalInteropRepository<'a> { fn import_signed_listing( &self, - record: &LocalEventRecord, + record: &RuntimeStoreRecord, ) -> Result<Option<ProjectionRecord>, AppSqliteError> { let content = record .event_content @@ -1110,7 +1110,7 @@ impl<'a> AppLocalInteropRepository<'a> { fn import_signed_active_order( &self, - record: &LocalEventRecord, + record: &RuntimeStoreRecord, ) -> Result<Option<ProjectionRecord>, AppSqliteError> { if !signed_event_record_is_usable(record) { return Ok(Some(signed_event_projection(record))); @@ -1127,7 +1127,7 @@ impl<'a> AppLocalInteropRepository<'a> { fn import_signed_validation_receipt( &self, - record: &LocalEventRecord, + record: &RuntimeStoreRecord, ) -> Result<Option<ProjectionRecord>, AppSqliteError> { if !signed_event_record_is_usable(record) { return Ok(Some(signed_event_projection(record))); @@ -1147,7 +1147,7 @@ impl<'a> AppLocalInteropRepository<'a> { fn project_active_order( &self, - record: &LocalEventRecord, + record: &RuntimeStoreRecord, current_evidence: ActiveOrderEvidence, ) -> Result<(), AppSqliteError> { if let ActiveOrderEvidence::Request(request) = ¤t_evidence { @@ -1223,7 +1223,7 @@ impl<'a> AppLocalInteropRepository<'a> { fn upsert_order_request( &self, - record: &LocalEventRecord, + record: &RuntimeStoreRecord, payload: &RadrootsOrderRequest, root_event_id: &str, ) -> Result<OrderId, AppSqliteError> { @@ -1294,7 +1294,7 @@ impl<'a> AppLocalInteropRepository<'a> { order_id, projection, revision, - TradeProvenanceProjection::from_primary_source(TradeWorkflowSource::LocalEvents), + TradeProvenanceProjection::from_primary_source(TradeWorkflowSource::RuntimeStore), ); let Some(status) = order_status_from_active_order_projection(projection) else { return Ok(()); @@ -1335,7 +1335,7 @@ impl<'a> AppLocalInteropRepository<'a> { fn upsert_validation_receipt_projection( &self, - event: &RadrootsNostrEvent, + event: &RadrootsEventEnvelope, receipt: &RadrootsTradeValidationReceipt, tags: &RadrootsValidationReceiptTags, ) -> Result<(), AppSqliteError> { @@ -1545,7 +1545,7 @@ impl<'a> AppLocalInteropRepository<'a> { status, agreement, inventory, - TradeWorkflowSource::LocalEvents.storage_key(), + TradeWorkflowSource::RuntimeStore.storage_key(), target_event_id, ], ) @@ -1579,7 +1579,7 @@ impl<'a> AppLocalInteropRepository<'a> { order_id: OrderId, payload: &RadrootsOrderRequest, existing_listing: Option<&ExistingListingProjection>, - record: &LocalEventRecord, + record: &RuntimeStoreRecord, ) -> Result<(), AppSqliteError> { self.connection .execute( @@ -1841,7 +1841,7 @@ impl<'a> AppLocalInteropRepository<'a> { fn mark_farm_buyer_visible( &self, farm_id: FarmId, - record: &LocalEventRecord, + record: &RuntimeStoreRecord, method: FarmOrderMethod, ) -> Result<(), AppSqliteError> { self.connection @@ -2221,7 +2221,7 @@ impl<'a> AppLocalInteropRepository<'a> { fn existing_app_origin_listing_projection( &self, - record: &LocalEventRecord, + record: &RuntimeStoreRecord, farm_key: &str, listing_key: &str, listing_pubkey: Option<&str>, @@ -2330,7 +2330,7 @@ impl<'a> AppLocalInteropRepository<'a> { fn signed_listing_is_current( &self, - record: &LocalEventRecord, + record: &RuntimeStoreRecord, listing_key: &str, ) -> Result<bool, AppSqliteError> { if !signed_listing_has_public_evidence(record) { @@ -2456,7 +2456,7 @@ impl<'a> AppLocalInteropRepository<'a> { fn record_import( &self, - record: &LocalEventRecord, + record: &RuntimeStoreRecord, projected_kind: &str, projected_id: Option<String>, ) -> Result<(), AppSqliteError> { @@ -2569,7 +2569,7 @@ impl AppSqliteStore { AppLocalInteropRepository::new(&self.connection) } - pub fn import_shared_local_events_from_path( + pub fn import_shared_runtime_store_from_path( &self, shared_database_path: &Path, ) -> Result<AppLocalInteropImportReport, AppSqliteError> { @@ -2577,9 +2577,9 @@ impl AppSqliteStore { .import_from_path(shared_database_path) } - pub fn import_shared_local_events_from_store<E>( + pub fn import_shared_runtime_store_from_store<E>( &self, - store: &LocalEventsStore<E>, + store: &RuntimeStore<E>, ) -> Result<AppLocalInteropImportReport, AppSqliteError> where E: SqlExecutor, @@ -2589,7 +2589,7 @@ impl AppSqliteStore { pub fn import_local_event_records( &self, - records: &[LocalEventRecord], + records: &[RuntimeStoreRecord], ) -> Result<AppLocalInteropImportReport, AppSqliteError> { self.local_interop_repository().import_records(records) } @@ -2603,7 +2603,7 @@ impl AppSqliteStore { pub fn load_local_interop_signed_events_by_kind( &self, event_kind: i64, - ) -> Result<Vec<RadrootsNostrEvent>, AppSqliteError> { + ) -> Result<Vec<RadrootsEventEnvelope>, AppSqliteError> { self.local_interop_repository() .load_signed_events_by_kind(event_kind) } @@ -2725,7 +2725,7 @@ enum ListingCurrentnessIdentity { } impl ListingCurrentnessIdentity { - fn from_record(record: &LocalEventRecord, listing_key: &str) -> Option<Self> { + fn from_record(record: &RuntimeStoreRecord, listing_key: &str) -> Option<Self> { if let Some(listing_addr) = record .listing_addr .as_deref() @@ -2939,7 +2939,7 @@ fn signed_event_evidence_precedence( outbox_status: &str, ) -> u8 { let mut precedence = 0; - if local_status == LocalRecordStatus::Published.as_str() { + if local_status == RuntimeStoreRecordStatus::Published.as_str() { precedence += 1; } if outbox_status == PublishOutboxStatus::Acknowledged.as_str() { @@ -3032,15 +3032,15 @@ fn active_order_event_kind(kind: i64) -> bool { ACTIVE_ORDER_EVENT_KINDS.contains(&kind) } -fn active_event_id(event: &RadrootsNostrEvent) -> Option<RadrootsEventId> { +fn active_event_id(event: &RadrootsEventEnvelope) -> Option<RadrootsEventId> { event.id.parse().ok() } -fn active_author_pubkey(event: &RadrootsNostrEvent) -> Option<RadrootsPublicKey> { +fn active_author_pubkey(event: &RadrootsEventEnvelope) -> Option<RadrootsPublicKey> { event.author.parse().ok() } -fn active_order_evidence_from_event(event: &RadrootsNostrEvent) -> Option<ActiveOrderEvidence> { +fn active_order_evidence_from_event(event: &RadrootsEventEnvelope) -> Option<ActiveOrderEvidence> { match i64::from(event.kind) { KIND_ORDER_REQUEST => { let envelope = order_request_from_event(event).ok()?; @@ -3113,7 +3113,7 @@ fn dedupe_active_order_evidence(evidence: &mut Vec<ActiveOrderEvidence>) { evidence.dedup_by(|left, right| left.event_id() == right.event_id()); } -fn signed_event_projection(record: &LocalEventRecord) -> ProjectionRecord { +fn signed_event_projection(record: &RuntimeStoreRecord) -> ProjectionRecord { ProjectionRecord { kind: "signed_event", projected_id: record.event_id.clone(), @@ -3121,8 +3121,8 @@ fn signed_event_projection(record: &LocalEventRecord) -> ProjectionRecord { } fn signed_event_from_record( - record: &LocalEventRecord, -) -> Result<Option<RadrootsNostrEvent>, AppSqliteError> { + record: &RuntimeStoreRecord, +) -> Result<Option<RadrootsEventEnvelope>, AppSqliteError> { let Some(id) = record .event_id .as_deref() @@ -3159,7 +3159,7 @@ fn signed_event_from_record( let Some(tags) = record.event_tags_json.as_ref().and_then(tags_from_json) else { return Ok(None); }; - Ok(Some(RadrootsNostrEvent { + Ok(Some(RadrootsEventEnvelope { id: id.to_owned(), author: author.to_owned(), created_at, @@ -3170,8 +3170,8 @@ fn signed_event_from_record( })) } -fn signed_event_record_is_usable(record: &LocalEventRecord) -> bool { - if record.status != LocalRecordStatus::Published +fn signed_event_record_is_usable(record: &RuntimeStoreRecord) -> bool { + if record.status != RuntimeStoreRecordStatus::Published || matches!( record.outbox_status, PublishOutboxStatus::Pending | PublishOutboxStatus::Failed @@ -3194,7 +3194,7 @@ fn signed_event_record_is_usable(record: &LocalEventRecord) -> bool { fn signed_event_local_interop_evidence_is_usable( evidence: &StoredLocalInteropSignedEventEvidence, ) -> bool { - if evidence.local_status != LocalRecordStatus::Published.as_str() + if evidence.local_status != RuntimeStoreRecordStatus::Published.as_str() || matches!(evidence.outbox_status.as_str(), "pending" | "failed") { return false; @@ -3216,7 +3216,7 @@ fn signed_event_local_interop_evidence_is_usable( fn signed_event_from_local_interop_evidence( evidence: &StoredLocalInteropSignedEventEvidence, -) -> Result<Option<RadrootsNostrEvent>, AppSqliteError> { +) -> Result<Option<RadrootsEventEnvelope>, AppSqliteError> { let Some(id) = evidence .event_id .as_deref() @@ -3262,7 +3262,7 @@ fn signed_event_from_local_interop_evidence( let Some(tags) = tags_from_json(&tags_value) else { return Ok(None); }; - Ok(Some(RadrootsNostrEvent { + Ok(Some(RadrootsEventEnvelope { id: id.to_owned(), author: author.to_owned(), created_at, @@ -3385,7 +3385,7 @@ fn active_order_agreement_source( fn order_line_product_id( payload: &RadrootsOrderRequest, existing_listing: Option<&ExistingListingProjection>, - item: &radroots_events::order::RadrootsOrderItem, + item: &radroots_event::order::RadrootsOrderItem, ) -> ProductId { order_agreement_line_product_id( payload.listing_addr.as_str(), @@ -3453,7 +3453,7 @@ fn order_customer_display_name(buyer_pubkey: &str) -> String { } } -fn order_buyer_context_key(record: &LocalEventRecord, buyer_pubkey: &str) -> String { +fn order_buyer_context_key(record: &RuntimeStoreRecord, buyer_pubkey: &str) -> String { if record.source_runtime == SourceRuntime::App && record .event_pubkey @@ -3480,7 +3480,7 @@ fn format_quantity_display(quantity: u32, unit_label: &str) -> String { } } -fn listing_event_id_from_order_record(record: &LocalEventRecord) -> Option<String> { +fn listing_event_id_from_order_record(record: &RuntimeStoreRecord) -> Option<String> { record .event_tags_json .as_ref() @@ -3513,7 +3513,7 @@ fn string_at(value: &Value, path: &[&str]) -> Option<String> { } } -fn listing_id(record: &LocalEventRecord) -> Option<String> { +fn listing_id(record: &RuntimeStoreRecord) -> Option<String> { record .listing_addr .as_deref() @@ -3566,7 +3566,7 @@ fn parse_u64_quantity(value: &str) -> Option<u64> { } fn signed_listing_product_status( - record: &LocalEventRecord, + record: &RuntimeStoreRecord, content: Option<&Value>, tags: Option<&Value>, ) -> Option<ProductStatus> { @@ -3582,8 +3582,8 @@ fn signed_listing_product_status( } } -fn signed_listing_has_public_evidence(record: &LocalEventRecord) -> bool { - if record.status != LocalRecordStatus::Published { +fn signed_listing_has_public_evidence(record: &RuntimeStoreRecord) -> bool { + if record.status != RuntimeStoreRecordStatus::Published { return false; } if record.outbox_status == PublishOutboxStatus::Acknowledged { @@ -3601,7 +3601,7 @@ fn signed_event_import_has_public_evidence( outbox_status: &str, relay_delivery_json: Option<&str>, ) -> bool { - if local_status != LocalRecordStatus::Published.as_str() { + if local_status != RuntimeStoreRecordStatus::Published.as_str() { return false; } if outbox_status == PublishOutboxStatus::Acknowledged.as_str() { @@ -3859,8 +3859,8 @@ mod tests { use radroots_core::{ RadrootsCoreCurrency, RadrootsCoreDecimal, RadrootsCoreMoney, RadrootsCoreUnit, }; - use radroots_events::{ - RadrootsNostrEvent, RadrootsNostrEventPtr, + use radroots_event::{ + RadrootsEventEnvelope, RadrootsEventPtr, ids::{ RadrootsEventId, RadrootsInventoryBinId, RadrootsListingAddress, RadrootsOrderId, RadrootsOrderQuoteId, RadrootsOrderRevisionId, RadrootsPublicKey, @@ -3873,16 +3873,16 @@ mod tests { RadrootsOrderRevisionProposal, }, }; - use radroots_events_codec::{ + use radroots_event_codec::{ order::{ order_cancellation_event_build, order_decision_event_build, order_request_event_build, order_revision_decision_event_build, order_revision_proposal_event_build, }, wire::WireEventParts, }; - use radroots_local_events::{ - LocalEventRecordInput, LocalEventRecordUpdate, LocalEventsStore, LocalRecordFamily, - LocalRecordStatus, PublishOutboxStatus, RelayDeliveryEvidence, SourceRuntime, + use radroots_runtime_store::{ + PublishOutboxStatus, RelayDeliveryEvidence, RuntimeStore, RuntimeStoreRecordFamily, + RuntimeStoreRecordInput, RuntimeStoreRecordStatus, RuntimeStoreRecordUpdate, SourceRuntime, }; use radroots_sql_core::SqliteExecutor; use radroots_studio_app_view::{ @@ -3909,10 +3909,10 @@ mod tests { }; use crate::{AppSqliteStore, BuyerRepeatDemandApplyOutcome, DatabaseTarget}; - fn local_events_store() -> LocalEventsStore<SqliteExecutor> { - let executor = SqliteExecutor::open_memory().expect("open local events memory db"); - let store = LocalEventsStore::new(executor); - store.migrate_up().expect("migrate local events store"); + fn runtime_store_store() -> RuntimeStore<SqliteExecutor> { + let executor = SqliteExecutor::open_memory().expect("open runtime store memory db"); + let store = RuntimeStore::new(executor); + store.migrate_up().expect("migrate runtime store store"); store } @@ -3920,11 +3920,11 @@ mod tests { record_id: &str, farm_key: &str, payload: serde_json::Value, - ) -> LocalEventRecordInput { - LocalEventRecordInput { + ) -> RuntimeStoreRecordInput { + RuntimeStoreRecordInput { record_id: record_id.to_owned(), - family: LocalRecordFamily::LocalWork, - status: LocalRecordStatus::LocalSaved, + family: RuntimeStoreRecordFamily::LocalWork, + status: RuntimeStoreRecordStatus::LocalSaved, source_runtime: SourceRuntime::Cli, created_at_ms: 1000, inserted_at_ms: 1001, @@ -3955,11 +3955,11 @@ mod tests { farm_key: &str, readiness: &str, display_name: &str, - ) -> LocalEventRecordInput { - LocalEventRecordInput { + ) -> RuntimeStoreRecordInput { + RuntimeStoreRecordInput { record_id: record_id.to_owned(), - family: LocalRecordFamily::SignedEvent, - status: LocalRecordStatus::Published, + family: RuntimeStoreRecordFamily::SignedEvent, + status: RuntimeStoreRecordStatus::Published, source_runtime, created_at_ms: 1100, inserted_at_ms: 1101, @@ -4006,13 +4006,13 @@ mod tests { farm_key: &str, listing_key: &str, status_tag: &str, - ) -> LocalEventRecordInput { + ) -> RuntimeStoreRecordInput { signed_listing_record_with_publish_state( record_id, farm_key, listing_key, status_tag, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, ) } @@ -4022,9 +4022,9 @@ mod tests { farm_key: &str, listing_key: &str, status_tag: &str, - record_status: LocalRecordStatus, + record_status: RuntimeStoreRecordStatus, outbox_status: PublishOutboxStatus, - ) -> LocalEventRecordInput { + ) -> RuntimeStoreRecordInput { let relay_delivery_json = match outbox_status { PublishOutboxStatus::Acknowledged => Some(json!({ "state": "acknowledged", @@ -4032,13 +4032,16 @@ mod tests { })), PublishOutboxStatus::Failed => Some(json!({ "state": "failed", - "failed_relays": ["ws://127.0.0.1:1234/"] + "failed_relays": [{ + "relay_url": "ws://127.0.0.1:1234/", + "error": "relay rejected event" + }] })), PublishOutboxStatus::Pending | PublishOutboxStatus::None => None, }; - LocalEventRecordInput { + RuntimeStoreRecordInput { record_id: record_id.to_owned(), - family: LocalRecordFamily::SignedEvent, + family: RuntimeStoreRecordFamily::SignedEvent, status: record_status, source_runtime: SourceRuntime::Cli, created_at_ms: 1100, @@ -4089,9 +4092,9 @@ mod tests { location_primary: &str, availability_start: u64, availability_end: u64, - record_status: LocalRecordStatus, + record_status: RuntimeStoreRecordStatus, outbox_status: PublishOutboxStatus, - ) -> LocalEventRecordInput { + ) -> RuntimeStoreRecordInput { let relay_delivery_json = match outbox_status { PublishOutboxStatus::Acknowledged => Some(json!({ "state": "acknowledged", @@ -4099,7 +4102,10 @@ mod tests { })), PublishOutboxStatus::Failed => Some(json!({ "state": "failed", - "failed_relays": ["ws://127.0.0.1:1234/"] + "failed_relays": [{ + "relay_url": "ws://127.0.0.1:1234/", + "error": "relay rejected event" + }] })), PublishOutboxStatus::Pending | PublishOutboxStatus::None => None, }; @@ -4130,9 +4136,9 @@ mod tests { }, }); - LocalEventRecordInput { + RuntimeStoreRecordInput { record_id: record_id.to_owned(), - family: LocalRecordFamily::SignedEvent, + family: RuntimeStoreRecordFamily::SignedEvent, status: record_status, source_runtime: SourceRuntime::Cli, created_at_ms: 1100, @@ -4179,7 +4185,7 @@ mod tests { } fn set_listing_event_version( - record: &mut LocalEventRecordInput, + record: &mut RuntimeStoreRecordInput, event_id: &str, created_at: i64, title: &str, @@ -4303,7 +4309,7 @@ mod tests { record_id: &str, farm_key: &str, payload: serde_json::Value, - ) -> LocalEventRecordInput { + ) -> RuntimeStoreRecordInput { let mut record = local_work_record(record_id, farm_key, payload); record.source_runtime = SourceRuntime::App; record.owner_pubkey = Some("app-seller-pubkey".to_owned()); @@ -4399,8 +4405,8 @@ mod tests { raw.parse().expect("valid listing address") } - fn listing_event_ptr(event_id: &str) -> RadrootsNostrEventPtr { - RadrootsNostrEventPtr { + fn listing_event_ptr(event_id: &str) -> RadrootsEventPtr { + RadrootsEventPtr { id: test_event_id_seed(event_id), relays: Some("ws://127.0.0.1:1234/".to_owned()), } @@ -4554,7 +4560,7 @@ mod tests { struct ValidationReceiptOrderFixture { app_store: AppSqliteStore, - events: LocalEventsStore<SqliteExecutor>, + events: RuntimeStore<SqliteExecutor>, buyer_context: BuyerContext, seller_farm_id: FarmId, order_id: OrderId, @@ -4570,7 +4576,7 @@ mod tests { fn validation_receipt_order_fixture(label: &str) -> ValidationReceiptOrderFixture { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "DDDDDDDDDDDDDDDDDDDDDD"; let listing_key = "AAAAAAAAAAAAAAAAAAAAAw"; let seller_pubkey = test_pubkey(format!("{label}-seller").as_str()); @@ -4593,12 +4599,12 @@ mod tests { "North barn pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, )) .expect("append signed listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import signed listing"); let request_payload = order_request_payload( @@ -4626,7 +4632,7 @@ mod tests { )) .expect("append validation order request"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import validation order request"); let decision_payload = accepted_order_decision_payload( @@ -4657,7 +4663,7 @@ mod tests { )) .expect("append validation order decision"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import validation order decision"); ValidationReceiptOrderFixture { @@ -4680,12 +4686,16 @@ mod tests { } } - fn event_from_parts(event_id: &str, author: &str, parts: WireEventParts) -> RadrootsNostrEvent { + fn event_from_parts( + event_id: &str, + author: &str, + parts: WireEventParts, + ) -> RadrootsEventEnvelope { let event_id = event_id .parse::<RadrootsEventId>() .map(|event_id| event_id.to_string()) .unwrap_or_else(|_| test_event_id_seed(event_id)); - RadrootsNostrEvent { + RadrootsEventEnvelope { sig: format!("sig-{event_id}"), id: event_id, author: author.to_owned(), @@ -4701,7 +4711,7 @@ mod tests { author: &str, parts: WireEventParts, created_at: u32, - ) -> RadrootsNostrEvent { + ) -> RadrootsEventEnvelope { let mut event = event_from_parts(event_id, author, parts); event.created_at = created_at; event @@ -4765,7 +4775,7 @@ mod tests { target_event_id: &str, result: RadrootsValidationReceiptResult, created_at: u32, - ) -> RadrootsNostrEvent { + ) -> RadrootsEventEnvelope { let receipt = validation_receipt_payload(listing_event_id, root_event_id, target_event_id, result); let parts = @@ -4775,11 +4785,11 @@ mod tests { fn signed_order_event_record( record_id: &str, - event: &RadrootsNostrEvent, + event: &RadrootsEventEnvelope, listing_addr: &str, source_runtime: SourceRuntime, owner_account_id: Option<&str>, - ) -> LocalEventRecordInput { + ) -> RuntimeStoreRecordInput { let relay_delivery_json = RelayDeliveryEvidence::acknowledged( ["ws://127.0.0.1:1234"], ["ws://127.0.0.1:1234"], @@ -4789,10 +4799,10 @@ mod tests { .expect("acknowledged relay evidence") .to_json_value() .expect("acknowledged relay evidence json"); - LocalEventRecordInput { + RuntimeStoreRecordInput { record_id: record_id.to_owned(), - family: LocalRecordFamily::SignedEvent, - status: LocalRecordStatus::Published, + family: RuntimeStoreRecordFamily::SignedEvent, + status: RuntimeStoreRecordStatus::Published, source_runtime, created_at_ms: i64::from(event.created_at) * 1_000, inserted_at_ms: i64::from(event.created_at) * 1_000 + 1, @@ -4827,7 +4837,7 @@ mod tests { fn imports_signed_order_request_into_seller_order_projection() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "AAAAAAAAAAAAAAAAAAAAAA"; let listing_key = "AAAAAAAAAAAAAAAAAAAAAg"; let seller_pubkey = test_pubkey("seller-pubkey"); @@ -4849,12 +4859,12 @@ mod tests { "North barn pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, )) .expect("append signed listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import signed listing"); let payload = order_request_payload( order_id_raw, @@ -4876,7 +4886,7 @@ mod tests { .expect("append order request"); let report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import signed order request"); let farm_id = deterministic_farm_id(Some(seller_pubkey), farm_key); let order_id = projected_order_id(order_id_raw, buyer_pubkey, event.id.as_str()); @@ -4934,7 +4944,7 @@ mod tests { fn local_interop_order_request_evidence_requires_usable_delivery_state() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let buyer_pubkey = test_pubkey("buyer-pubkey"); let buyer_pubkey = buyer_pubkey.as_str(); let seller_pubkey = test_pubkey("seller-pubkey"); @@ -4990,7 +5000,7 @@ mod tests { SourceRuntime::Cli, None, ); - pending_record.status = LocalRecordStatus::PendingPublish; + pending_record.status = RuntimeStoreRecordStatus::PendingPublish; pending_record.outbox_status = PublishOutboxStatus::Pending; pending_record.relay_delivery_json = Some( RelayDeliveryEvidence::pending([relay_url]) @@ -5037,23 +5047,28 @@ mod tests { .append_record(&local_only_record) .expect("append local-only order request evidence"); - let malformed_delivery_event = build_event( - "order-request-evidence-malformed-delivery", - "malformed-delivery", + let invalid_delivery_event = build_event( + "order-request-evidence-invalid-delivery", + "invalid-delivery", ); - let mut malformed_delivery_record = signed_order_event_record( + let mut invalid_delivery_record = signed_order_event_record( "cli:signed_event:order-request:evidence-malformed-delivery", - &malformed_delivery_event, + &invalid_delivery_event, listing_addr.as_str(), SourceRuntime::Cli, None, ); - malformed_delivery_record.relay_delivery_json = Some(json!({ + invalid_delivery_record.relay_delivery_json = Some(json!({ "state": "acknowledged" })); - events - .append_record(&malformed_delivery_record) - .expect("append malformed delivery order request evidence"); + let invalid_delivery_error = events + .append_record(&invalid_delivery_record) + .expect_err("reject invalid delivery order request evidence"); + assert!( + invalid_delivery_error + .to_string() + .contains("acknowledged relay delivery evidence requires acknowledged_relays") + ); let malformed_event = build_event("order-request-evidence-malformed-event", "malformed-event"); @@ -5070,7 +5085,7 @@ mod tests { .expect("append malformed order request evidence"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import signed evidence records"); let signed_evidence = app_store .load_local_interop_signed_events_by_kind(KIND_ORDER_REQUEST) @@ -5083,7 +5098,7 @@ mod tests { fn app_origin_signed_order_request_and_decision_project_to_buyer_orders() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "CCCCCCCCCCCCCCCCCCCCCC"; let listing_key = "AAAAAAAAAAAAAAAAAAAAAg"; let seller_pubkey = test_pubkey("seller-pubkey"); @@ -5105,12 +5120,12 @@ mod tests { "North barn pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, )) .expect("append signed listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import signed listing"); let request_payload = order_request_payload( order_id_raw, @@ -5136,7 +5151,7 @@ mod tests { .expect("append app order request"); let request_report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import app order request"); let buyer_context = BuyerContext::account("acct_buyer"); let order_id = projected_order_id(order_id_raw, buyer_pubkey, request_event.id.as_str()); @@ -5175,7 +5190,7 @@ mod tests { .expect("append order decision"); let decision_report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import order decision"); let buyer_orders = app_store .load_buyer_orders(&buyer_context) @@ -5214,7 +5229,7 @@ mod tests { ); assert_eq!( buyer_orders.rows[0].workflow.provenance.primary_source, - TradeWorkflowSource::LocalEvents + TradeWorkflowSource::RuntimeStore ); assert_eq!( buyer_orders.rows[0] @@ -5234,7 +5249,7 @@ mod tests { fn duplicate_app_order_request_roots_project_to_distinct_buyer_orders() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "CCCCCCCCCCCCCCCCCCCCCC"; let listing_key = "AAAAAAAAAAAAAAAAAAAAAy"; let seller_pubkey = test_pubkey("duplicate-root-seller-pubkey"); @@ -5256,12 +5271,12 @@ mod tests { "North barn pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, )) .expect("append duplicate-root listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import duplicate-root listing"); let request_payload = order_request_payload( @@ -5311,7 +5326,7 @@ mod tests { .expect("append duplicate-root request"); } app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import duplicate-root requests"); let first_order_id = @@ -5338,7 +5353,7 @@ mod tests { fn app_origin_signed_order_request_and_decline_project_to_buyer_orders() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "CCCCCCCCCCCCCCCCCCCCCC"; let listing_key = "AAAAAAAAAAAAAAAAAAAAAg"; let seller_pubkey = test_pubkey("seller-pubkey"); @@ -5360,12 +5375,12 @@ mod tests { "North barn pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, )) .expect("append signed listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import signed listing"); let request_payload = order_request_payload( order_id_raw, @@ -5394,7 +5409,7 @@ mod tests { .expect("append app order request"); let request_report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import app order request"); let buyer_context = BuyerContext::account("acct_buyer"); let order_id = projected_order_id(order_id_raw, buyer_pubkey, request_event.id.as_str()); @@ -5435,7 +5450,7 @@ mod tests { .expect("append declined order decision"); let decision_report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import declined order decision"); let buyer_orders = app_store .load_buyer_orders(&buyer_context) @@ -5469,7 +5484,7 @@ mod tests { fn active_order_decision_projects_agreement_state_through_cli_reducer() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "DDDDDDDDDDDDDDDDDDDDDD"; let listing_key = "AAAAAAAAAAAAAAAAAAAAAw"; let seller_pubkey = test_pubkey("seller-pubkey"); @@ -5491,12 +5506,12 @@ mod tests { "North barn pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, )) .expect("append signed listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import signed listing"); let request_payload = order_request_payload( @@ -5525,7 +5540,7 @@ mod tests { )) .expect("append lifecycle order request"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import lifecycle order request"); let seller_farm_id = deterministic_farm_id(Some(seller_pubkey), farm_key); @@ -5556,7 +5571,7 @@ mod tests { )) .expect("append lifecycle order decision"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import lifecycle order decision"); let seller_orders = app_store .load_orders_list( @@ -5604,7 +5619,7 @@ mod tests { .expect("append valid validation receipt"); fixture .app_store - .import_shared_local_events_from_store(&fixture.events) + .import_shared_runtime_store_from_store(&fixture.events) .expect("import valid validation receipt"); let buyer_detail = fixture @@ -5699,7 +5714,7 @@ mod tests { .expect("append duplicate validation receipt"); fixture .app_store - .import_shared_local_events_from_store(&fixture.events) + .import_shared_runtime_store_from_store(&fixture.events) .expect("import validation receipts"); let buyer_detail = fixture @@ -5795,7 +5810,7 @@ mod tests { fn validation_receipt_import_before_order_request_attaches_when_request_arrives() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "DDDDDDDDDDDDDDDDDDDDDD"; let listing_key = "AAAAAAAAAAAAAAAAAAAAAw"; let seller_pubkey = test_pubkey("validation-out-of-order-seller"); @@ -5820,12 +5835,12 @@ mod tests { "North barn pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, )) .expect("append out-of-order listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import out-of-order listing"); let receipt_event = validation_receipt_event( @@ -5848,7 +5863,7 @@ mod tests { )) .expect("append receipt before request"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import receipt before request"); let pending_count: i64 = app_store @@ -5888,7 +5903,7 @@ mod tests { )) .expect("append request after receipt"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import request after receipt"); let order_id = projected_order_id(order_id_raw, buyer_pubkey, request_event.id.as_str()); @@ -5987,7 +6002,7 @@ mod tests { } fixture .app_store - .import_shared_local_events_from_store(&fixture.events) + .import_shared_runtime_store_from_store(&fixture.events) .expect("import invalid validation receipt candidates"); let buyer_detail = fixture @@ -6016,7 +6031,7 @@ mod tests { fn active_order_revision_projects_through_cli_reducer_state() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "EEEEEEEEEEEEEEEEEEEEEE"; let listing_key = "AAAAAAAAAAAAAAAAAAAAAw"; let seller_pubkey = test_pubkey("seller-pubkey"); @@ -6038,12 +6053,12 @@ mod tests { "North barn pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, )) .expect("append revision listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import revision listing"); let request_payload = order_request_payload( @@ -6069,7 +6084,7 @@ mod tests { )) .expect("append revision order request"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import revision order request"); let proposal_payload = revision_proposal_payload( @@ -6102,7 +6117,7 @@ mod tests { )) .expect("append revision proposal"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import revision proposal"); let seller_farm_id = deterministic_farm_id(Some(seller_pubkey), farm_key); @@ -6163,7 +6178,7 @@ mod tests { )) .expect("append revision decision"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import revision decision"); let seller_orders = app_store .load_orders_list( @@ -6204,7 +6219,7 @@ mod tests { fn active_order_pre_agreement_cancellation_projects_through_cli_reducer_state() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "EEEEEEEEEEEEEEEEEEEEEE"; let listing_key = "AAAAAAAAAAAAAAAAAAAAAx"; let seller_pubkey = test_pubkey("seller-pubkey"); @@ -6226,12 +6241,12 @@ mod tests { "North barn pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, )) .expect("append cancellation listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import cancellation listing"); let request_payload = order_request_payload( @@ -6257,7 +6272,7 @@ mod tests { )) .expect("append cancellation order request"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import cancellation order request"); let cancel_payload = order_cancel_payload( @@ -6283,7 +6298,7 @@ mod tests { )) .expect("append cancellation"); let cancel_report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import cancellation"); let seller_farm_id = deterministic_farm_id(Some(seller_pubkey), farm_key); @@ -6322,7 +6337,7 @@ mod tests { let run_case = |accepted_first: bool| { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "FFFFFFFFFFFFFFFFFFFFFF"; let listing_key = "AAAAAAAAAAAAAAAAAAAAAw"; let seller_pubkey = test_pubkey("seller-pubkey"); @@ -6348,7 +6363,7 @@ mod tests { "North barn pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, )) .expect("append conflict listing"); @@ -6426,7 +6441,7 @@ mod tests { } app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import conflicting decisions"); let order_id = projected_order_id(order_id_raw, buyer_pubkey, request_event.id.as_str()); @@ -6448,12 +6463,12 @@ mod tests { fn malformed_order_event_remains_signed_event_evidence_without_projection() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); events - .append_record(&LocalEventRecordInput { + .append_record(&RuntimeStoreRecordInput { record_id: "cli:signed_event:order-request:malformed".to_owned(), - family: LocalRecordFamily::SignedEvent, - status: LocalRecordStatus::Published, + family: RuntimeStoreRecordFamily::SignedEvent, + status: RuntimeStoreRecordStatus::Published, source_runtime: SourceRuntime::Cli, created_at_ms: 1100, inserted_at_ms: 1101, @@ -6485,7 +6500,7 @@ mod tests { .expect("append malformed order event"); let report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import malformed order event"); let imported = app_store .load_local_interop_records() @@ -6510,7 +6525,7 @@ mod tests { fn imports_cli_local_work_into_app_farm_and_product_projection() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "AAAAAAAAAAAAAAAAAAAAAA"; let listing_key = "BBBBBBBBBBBBBBBBBBBBBB"; events @@ -6581,11 +6596,11 @@ mod tests { .expect("append listing local work"); let report = app_store - .import_shared_local_events_from_store(&events) - .expect("import shared local events"); + .import_shared_runtime_store_from_store(&events) + .expect("import shared runtime store"); let second_report = app_store - .import_shared_local_events_from_store(&events) - .expect("import shared local events again"); + .import_shared_runtime_store_from_store(&events) + .expect("import shared runtime store again"); assert_eq!(report.scanned_records, 2); assert_eq!(report.imported_records, 2); @@ -6643,7 +6658,7 @@ mod tests { #[test] fn fresh_app_store_replays_existing_shared_records_after_another_app_imported_them() { - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "AAAAAAAAAAAAAAAAAAAAAA"; events .append_record(&local_work_record( @@ -6674,16 +6689,16 @@ mod tests { let first_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open first app sqlite store"); let first_report = first_store - .import_shared_local_events_from_store(&events) - .expect("first app imports shared local events"); + .import_shared_runtime_store_from_store(&events) + .expect("first app imports shared runtime store"); let second_same_store_report = first_store - .import_shared_local_events_from_store(&events) - .expect("first app imports unchanged shared local events"); + .import_shared_runtime_store_from_store(&events) + .expect("first app imports unchanged shared runtime store"); let second_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open second app sqlite store"); let fresh_store_report = second_store - .import_shared_local_events_from_store(&events) - .expect("fresh app imports shared local events"); + .import_shared_runtime_store_from_store(&events) + .expect("fresh app imports shared runtime store"); assert_eq!(first_report.scanned_records, 1); assert_eq!(first_report.imported_records, 1); @@ -6703,7 +6718,7 @@ mod tests { fn imports_signed_listing_tags_into_existing_local_product_projection() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "AAAAAAAAAAAAAAAAAAAAAA"; let listing_key = "BBBBBBBBBBBBBBBBBBBBBB"; events @@ -6766,13 +6781,13 @@ mod tests { .append_record(&listing) .expect("append listing local work"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import local work records"); events - .append_record(&LocalEventRecordInput { + .append_record(&RuntimeStoreRecordInput { record_id: "cli:signed_event:listing:event-1".to_owned(), - family: LocalRecordFamily::SignedEvent, - status: LocalRecordStatus::Published, + family: RuntimeStoreRecordFamily::SignedEvent, + status: RuntimeStoreRecordStatus::Published, source_runtime: SourceRuntime::Cli, created_at_ms: 1100, inserted_at_ms: 1101, @@ -6814,7 +6829,7 @@ mod tests { .expect("append signed listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import signed listing"); let imported = app_store .load_local_interop_records() @@ -6851,7 +6866,7 @@ mod tests { fn cli_origin_signed_window_listing_projects_into_buyer_browse_and_search() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "AAAAAAAAAAAAAAAAAAAAAA"; let listing_key = "BBBBBBBBBBBBBBBBBBBBBB"; events @@ -6867,13 +6882,13 @@ mod tests { "North barn pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, )) .expect("append signed listing"); let report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import signed listing"); let browse = app_store .load_buyer_listings("", &BTreeSet::new()) @@ -6906,7 +6921,7 @@ mod tests { fn app_origin_signed_window_listing_converges_into_buyer_visibility() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_uuid = Uuid::from_u128(0x55555555555545558555555555555555); let product_uuid = Uuid::from_u128(0x66666666666646668666666666666666); let farm_key = app_d_tag_from_uuid(farm_uuid); @@ -6973,7 +6988,7 @@ mod tests { .append_record(&app_listing_record) .expect("append app listing local work"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import app local records"); events .append_record(&signed_market_listing_record( @@ -6988,13 +7003,13 @@ mod tests { "App farmstand pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, )) .expect("append signed app-origin listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import signed app-origin listing"); let buyer_listings = app_store .load_buyer_listings("app eggs", &BTreeSet::new()) @@ -7010,7 +7025,7 @@ mod tests { fn network_app_origin_listing_cannot_claim_app_product_without_app_owned_evidence() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_uuid = Uuid::from_u128(0x77777777777747778777777777777777); let product_uuid = Uuid::from_u128(0x88888888888848888888888888888888); let farm_key = app_d_tag_from_uuid(farm_uuid); @@ -7029,7 +7044,7 @@ mod tests { "App farmstand pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, ); network_listing.source_runtime = SourceRuntime::Network; @@ -7039,7 +7054,7 @@ mod tests { .expect("append network app-origin listing"); let report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import network app-origin listing"); let imported = app_store .load_local_interop_records() @@ -7105,7 +7120,7 @@ mod tests { fn network_app_origin_listing_reuses_app_product_with_matching_app_owned_evidence() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_uuid = Uuid::from_u128(0x79797979797949799797979797979797); let product_uuid = Uuid::from_u128(0x89898989898949898989898989898989); let farm_key = app_d_tag_from_uuid(farm_uuid); @@ -7169,7 +7184,7 @@ mod tests { .append_record(&app_listing_record) .expect("append app listing local work"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import app local work"); let mut network_listing = signed_market_listing_record( "network-app-origin-matching-evidence", @@ -7183,7 +7198,7 @@ mod tests { "App farmstand pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, ); network_listing.source_runtime = SourceRuntime::Network; @@ -7193,7 +7208,7 @@ mod tests { .expect("append network app-origin listing"); let report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import network app-origin listing"); let product_count: i64 = app_store .connection() @@ -7235,7 +7250,7 @@ mod tests { fn network_app_origin_listing_requires_matching_event_pubkey_for_app_product_reuse() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_uuid = Uuid::from_u128(0x7a7a7a7a7a7a4a7a9a7a7a7a7a7a7a7a); let product_uuid = Uuid::from_u128(0x8a8a8a8a8a8a4a8aaa8a8a8a8a8a8a8a); let farm_key = app_d_tag_from_uuid(farm_uuid); @@ -7299,7 +7314,7 @@ mod tests { .append_record(&app_listing_record) .expect("append app listing local work"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import app local work"); let mut network_listing = signed_market_listing_record( "network-app-origin-foreign-event-pubkey", @@ -7313,7 +7328,7 @@ mod tests { "App farmstand pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, ); network_listing.source_runtime = SourceRuntime::Network; @@ -7324,7 +7339,7 @@ mod tests { .expect("append foreign network app-origin listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import network app-origin listing"); let product_count: i64 = app_store .connection() @@ -7359,7 +7374,7 @@ mod tests { fn app_signed_duplicate_replaces_network_listing_product_projection() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_uuid = Uuid::from_u128(0x99999999999949999999999999999999); let product_uuid = Uuid::from_u128(0xaaaaaaaaaaaa4aaaaaaaaaaaaaaaaaaa); let farm_key = app_d_tag_from_uuid(farm_uuid); @@ -7378,7 +7393,7 @@ mod tests { "App farmstand pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, ); network_listing.source_runtime = SourceRuntime::Network; @@ -7390,7 +7405,7 @@ mod tests { .expect("append network app-origin listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import network app-origin listing"); let network_product_id = deterministic_product_id(Some(seller_pubkey), listing_key.as_str()); @@ -7484,7 +7499,7 @@ mod tests { "App farmstand pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, ); app_listing.source_runtime = SourceRuntime::App; @@ -7495,7 +7510,7 @@ mod tests { .expect("append app signed duplicate listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import app signed duplicate listing"); let imported = app_store .load_local_interop_records() @@ -7565,7 +7580,7 @@ mod tests { fn failed_duplicate_listing_replacement_rolls_back_prior_visible_state() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_uuid = Uuid::from_u128(0x9b9b9b9b9b9b4b9bbb9b9b9b9b9b9b9b); let product_uuid = Uuid::from_u128(0xabababababab4abababababababababa); let farm_key = app_d_tag_from_uuid(farm_uuid); @@ -7584,7 +7599,7 @@ mod tests { "App farmstand pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, ); network_listing.source_runtime = SourceRuntime::Network; @@ -7595,7 +7610,7 @@ mod tests { .append_record(&network_listing) .expect("append network app-origin listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import network app-origin listing"); let network_product_id = @@ -7653,7 +7668,7 @@ mod tests { "App farmstand pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, ); app_listing.source_runtime = SourceRuntime::App; @@ -7664,7 +7679,7 @@ mod tests { .expect("append app signed duplicate listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect_err("duplicate replacement should roll back on cart migration failure"); let imported = app_store .load_local_interop_records() @@ -7729,7 +7744,7 @@ mod tests { "Pending barn pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::PendingPublish, + RuntimeStoreRecordStatus::PendingPublish, PublishOutboxStatus::Pending, ), signed_market_listing_record( @@ -7744,7 +7759,7 @@ mod tests { "South barn pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, ), signed_market_listing_record( @@ -7759,7 +7774,7 @@ mod tests { "East barn pickup", 946_684_800, 946_771_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, ), signed_market_listing_record( @@ -7774,7 +7789,7 @@ mod tests { "Unknown exchange point", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, ), signed_listing_record( @@ -7786,11 +7801,11 @@ mod tests { ] { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); events.append_record(&record).expect("append record"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import hidden listing record"); assert!(buyer_listing_titles(&app_store).is_empty()); @@ -7798,7 +7813,7 @@ mod tests { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "KKKKKKKKKKKKKKKKKKKKKK"; let listing_key = "LLLLLLLLLLLLLLLLLLLLLL"; events @@ -7828,13 +7843,13 @@ mod tests { )) .expect("append local-only listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import local-only listing"); assert!(buyer_listing_titles(&app_store).is_empty()); let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); events .append_record(&signed_market_listing_record( "current-active-window", @@ -7848,12 +7863,12 @@ mod tests { "West barn pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, )) .expect("append active listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import active listing"); assert_eq!(buyer_listing_titles(&app_store), vec!["Current Eggs"]); events @@ -7869,12 +7884,12 @@ mod tests { "West barn pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, )) .expect("append archived listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import archived listing"); assert!(buyer_listing_titles(&app_store).is_empty()); } @@ -7883,7 +7898,7 @@ mod tests { fn older_signed_listing_import_does_not_roll_back_current_product_state() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "CURRENTFARMAAAAAAAAAA"; let listing_key = "CURRENTLISTINGBBBBBB"; let mut newer = signed_market_listing_record( @@ -7898,7 +7913,7 @@ mod tests { "North barn pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, ); set_listing_event_version( @@ -7910,7 +7925,7 @@ mod tests { ); events.append_record(&newer).expect("append newer listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import newer listing"); let mut older = signed_market_listing_record( @@ -7925,7 +7940,7 @@ mod tests { "North barn pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, ); set_listing_event_version( @@ -7938,7 +7953,7 @@ mod tests { events.append_record(&older).expect("append older listing"); let report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import older listing"); let product: (String, Option<i64>) = app_store .connection() @@ -7966,7 +7981,7 @@ mod tests { fn equal_timestamp_signed_listing_currentness_uses_event_id_tie_breaker() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "TIEFARMAAAAAAAAAAAAAA"; let listing_key = "TIELISTINGBBBBBBBBBB"; let mut winning = signed_market_listing_record( @@ -7981,7 +7996,7 @@ mod tests { "North barn pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, ); set_listing_event_version( @@ -7995,7 +8010,7 @@ mod tests { .append_record(&winning) .expect("append winning listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import winning listing"); let mut losing = signed_market_listing_record( @@ -8010,7 +8025,7 @@ mod tests { "North barn pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, ); set_listing_event_version(&mut losing, "event-a-losing", 3_000, "Tie Loser Eggs", "1"); @@ -8019,7 +8034,7 @@ mod tests { .expect("append losing listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import losing listing"); let product: (String, Option<i64>) = app_store .connection() @@ -8036,14 +8051,14 @@ mod tests { fn signed_farm_import_prefers_event_identity_over_local_owner_metadata() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let signed_farm_key = "SIGNEDFARMAAAAAAAAAAAA"; let expected_farm_id = deterministic_farm_id(Some("event-pubkey"), signed_farm_key); events - .append_record(&LocalEventRecordInput { + .append_record(&RuntimeStoreRecordInput { record_id: "cli:signed_event:farm:event-identity".to_owned(), - family: LocalRecordFamily::SignedEvent, - status: LocalRecordStatus::Published, + family: RuntimeStoreRecordFamily::SignedEvent, + status: RuntimeStoreRecordStatus::Published, source_runtime: SourceRuntime::Cli, created_at_ms: 1100, inserted_at_ms: 1101, @@ -8080,7 +8095,7 @@ mod tests { .expect("append signed farm"); let report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import signed farm"); let imported = app_store .load_local_interop_records() @@ -8106,7 +8121,7 @@ mod tests { fn cli_signed_listing_import_uses_cli_identity_for_app_shaped_keys() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let signed_farm_key = app_d_tag_from_uuid(Uuid::from_u128(0x77777777777747778777777777777777)); let signed_listing_key = @@ -8116,10 +8131,10 @@ mod tests { let expected_product_id = deterministic_product_id(Some("listing-event-pubkey"), signed_listing_key.as_str()); events - .append_record(&LocalEventRecordInput { + .append_record(&RuntimeStoreRecordInput { record_id: "cli:signed_event:listing:event-identity".to_owned(), - family: LocalRecordFamily::SignedEvent, - status: LocalRecordStatus::Published, + family: RuntimeStoreRecordFamily::SignedEvent, + status: RuntimeStoreRecordStatus::Published, source_runtime: SourceRuntime::Cli, created_at_ms: 1100, inserted_at_ms: 1101, @@ -8167,7 +8182,7 @@ mod tests { .expect("append signed listing"); let report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import signed listing"); let imported = app_store .load_local_interop_records() @@ -8193,7 +8208,7 @@ mod tests { fn direct_record_import_dedupes_signed_events_by_event_id() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "SIGNEDFARMAAAAAAAAAAAA"; let listing_key = "SIGNEDLISTINGBBBBBBBB"; let first = events @@ -8233,7 +8248,7 @@ mod tests { fn app_order_request_receipt_replaces_prior_relay_duplicate() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let seller_pubkey = test_pubkey("seller-pubkey"); let seller_pubkey = seller_pubkey.as_str(); let buyer_pubkey = test_pubkey("buyer-pubkey"); @@ -8307,7 +8322,7 @@ mod tests { fn relay_order_decision_duplicate_does_not_downgrade_app_receipt() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let seller_pubkey = test_pubkey("seller-pubkey"); let seller_pubkey = seller_pubkey.as_str(); let buyer_pubkey = test_pubkey("buyer-pubkey"); @@ -8400,8 +8415,8 @@ mod tests { fn local_work_farm_import_preserves_duplicate_relay_signed_ready_farm() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let relay_events = local_events_store(); - let shared_events = local_events_store(); + let relay_events = runtime_store_store(); + let shared_events = runtime_store_store(); let farm_uuid = Uuid::from_u128(0x55555555555545558555555555555555); let farm_key = app_d_tag_from_uuid(farm_uuid); let signed_event_id = "event-app-relay-ready-farm"; @@ -8455,7 +8470,7 @@ mod tests { .expect("append duplicate signed farm"); let shared_report = app_store - .import_shared_local_events_from_store(&shared_events) + .import_shared_runtime_store_from_store(&shared_events) .expect("import shared local work after relay"); let stored_farm: (String, String, String) = app_store .connection() @@ -8476,7 +8491,7 @@ mod tests { fn signed_farm_without_readiness_preserves_listing_visible_farm() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "SIGNEDFARMAAAAAAAAAAAA"; let listing_key = "SIGNEDLISTINGBBBBBBBB"; let expected_farm_id = deterministic_farm_id(Some("seller-pubkey"), farm_key); @@ -8493,15 +8508,15 @@ mod tests { "West barn pickup", 4_102_444_800, 4_102_531_200, - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::Acknowledged, )) .expect("append visible listing"); events - .append_record(&LocalEventRecordInput { + .append_record(&RuntimeStoreRecordInput { record_id: "cli:signed_event:farm:no-readiness".to_owned(), - family: LocalRecordFamily::SignedEvent, - status: LocalRecordStatus::Published, + family: RuntimeStoreRecordFamily::SignedEvent, + status: RuntimeStoreRecordStatus::Published, source_runtime: SourceRuntime::Cli, created_at_ms: 1200, inserted_at_ms: 1201, @@ -8538,7 +8553,7 @@ mod tests { .expect("append farm without readiness"); let report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import listing and farm"); let stored_farm: (String, String, String) = app_store .connection() @@ -8564,7 +8579,7 @@ mod tests { ] { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "AAAAAAAAAAAAAAAAAAAAAA"; let listing_key = "BBBBBBBBBBBBBBBBBBBBBB"; events @@ -8577,7 +8592,7 @@ mod tests { .expect("append signed listing"); let report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import signed listing"); let product_status: String = app_store .connection() @@ -8594,7 +8609,7 @@ mod tests { fn maps_observed_signed_listing_as_published_without_outbox_acknowledgement() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "AAAAAAAAAAAAAAAAAAAAAA"; let listing_key = "BBBBBBBBBBBBBBBBBBBBBB"; let mut record = signed_listing_record_with_publish_state( @@ -8602,7 +8617,7 @@ mod tests { farm_key, listing_key, "active", - LocalRecordStatus::Published, + RuntimeStoreRecordStatus::Published, PublishOutboxStatus::None, ); record.relay_delivery_json = Some(json!({ @@ -8618,7 +8633,7 @@ mod tests { .expect("append observed signed listing"); let report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import observed signed listing"); let product_status: String = app_store .connection() @@ -8634,7 +8649,7 @@ mod tests { fn unknown_acknowledged_signed_listing_status_is_not_published() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "AAAAAAAAAAAAAAAAAAAAAA"; let listing_key = "BBBBBBBBBBBBBBBBBBBBBB"; events @@ -8647,7 +8662,7 @@ mod tests { .expect("append signed listing"); let report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import signed listing"); let imported = app_store .load_local_interop_records() @@ -8667,14 +8682,17 @@ mod tests { fn pending_or_failed_signed_listing_records_do_not_downgrade_published_product() { for (record_status, outbox_status) in [ ( - LocalRecordStatus::PendingPublish, + RuntimeStoreRecordStatus::PendingPublish, PublishOutboxStatus::Pending, ), - (LocalRecordStatus::Failed, PublishOutboxStatus::Failed), + ( + RuntimeStoreRecordStatus::Failed, + PublishOutboxStatus::Failed, + ), ] { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "AAAAAAAAAAAAAAAAAAAAAA"; let listing_key = "BBBBBBBBBBBBBBBBBBBBBB"; events @@ -8686,7 +8704,7 @@ mod tests { )) .expect("append confirmed signed listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import confirmed signed listing"); events .append_record(&signed_listing_record_with_publish_state( @@ -8700,7 +8718,7 @@ mod tests { .expect("append unconfirmed signed listing"); app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import unconfirmed signed listing"); let product_status: String = app_store .connection() @@ -8722,7 +8740,7 @@ mod tests { fn observes_outbox_updates_after_first_import_without_replaying_unchanged_rows() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_key = "AAAAAAAAAAAAAAAAAAAAAA"; let listing_key = "BBBBBBBBBBBBBBBBBBBBBB"; events @@ -8731,15 +8749,15 @@ mod tests { farm_key, listing_key, "active", - LocalRecordStatus::PendingPublish, + RuntimeStoreRecordStatus::PendingPublish, PublishOutboxStatus::Pending, )) .expect("append pending signed listing"); let first_report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import pending listing"); let unchanged_report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import unchanged listing"); assert_eq!(first_report.scanned_records, 1); @@ -8747,9 +8765,9 @@ mod tests { assert_eq!(unchanged_report.scanned_records, 0); events - .update_outbox(&LocalEventRecordUpdate { + .update_outbox(&RuntimeStoreRecordUpdate { record_id: "pending-listing".to_owned(), - status: LocalRecordStatus::Published, + status: RuntimeStoreRecordStatus::Published, outbox_status: PublishOutboxStatus::Acknowledged, relay_set_fingerprint: Some("relay-set".to_owned()), relay_delivery_json: Some(json!({ @@ -8760,7 +8778,7 @@ mod tests { }) .expect("update listing outbox"); let changed_report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import updated listing"); let product_status: String = app_store .connection() @@ -8780,7 +8798,7 @@ mod tests { #[test] fn app_authored_shared_records_replay_into_fresh_store_without_origin_duplicates() { - let events = local_events_store(); + let events = runtime_store_store(); let farm_uuid = Uuid::from_u128(0x11111111111111111111111111111111); let product_uuid = Uuid::from_u128(0x22222222222222222222222222222222); let farm_key = app_d_tag_from_uuid(farm_uuid); @@ -8856,11 +8874,11 @@ mod tests { AppSqliteStore::open(DatabaseTarget::InMemory).expect("open origin app sqlite store"); seed_app_projection(&origin_store, farm_uuid, product_uuid); let origin_report = origin_store - .import_shared_local_events_from_store(&events) - .expect("import shared local events into origin store"); + .import_shared_runtime_store_from_store(&events) + .expect("import shared runtime store into origin store"); let origin_second_report = origin_store - .import_shared_local_events_from_store(&events) - .expect("import unchanged shared local events into origin store"); + .import_shared_runtime_store_from_store(&events) + .expect("import unchanged shared runtime store into origin store"); let origin_product_count: i64 = origin_store .connection() .query_row("SELECT COUNT(*) FROM products", [], |row| row.get(0)) @@ -8901,8 +8919,8 @@ mod tests { let fresh_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open fresh app sqlite store"); let fresh_report = fresh_store - .import_shared_local_events_from_store(&events) - .expect("import shared local events into fresh store"); + .import_shared_runtime_store_from_store(&events) + .expect("import shared runtime store into fresh store"); let fresh_product_count: i64 = fresh_store .connection() .query_row("SELECT COUNT(*) FROM products", [], |row| row.get(0)) @@ -8932,7 +8950,7 @@ mod tests { fn app_authored_records_with_non_uuid_tags_do_not_rebind_to_cli_identity() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let app_record = app_local_work_record( "app:local_work:farm:invalid-tag", "not-a-uuid-d-tag", @@ -8958,8 +8976,8 @@ mod tests { .expect("append app local work"); let report = app_store - .import_shared_local_events_from_store(&events) - .expect("import shared local events"); + .import_shared_runtime_store_from_store(&events) + .expect("import shared runtime store"); let imported = app_store .load_local_interop_records() .expect("load imported records"); @@ -8981,7 +8999,7 @@ mod tests { fn signed_app_origin_listing_updates_existing_app_projection() { let app_store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store"); - let events = local_events_store(); + let events = runtime_store_store(); let farm_uuid = Uuid::from_u128(0x33333333333343338333333333333333); let product_uuid = Uuid::from_u128(0x44444444444444448444444444444444); let farm_key = app_d_tag_from_uuid(farm_uuid); @@ -9046,13 +9064,13 @@ mod tests { .expect("append app listing local work"); let local_report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import app local work"); events - .append_record(&LocalEventRecordInput { + .append_record(&RuntimeStoreRecordInput { record_id: "cli:signed_event:listing:app-origin".to_owned(), - family: LocalRecordFamily::SignedEvent, - status: LocalRecordStatus::Published, + family: RuntimeStoreRecordFamily::SignedEvent, + status: RuntimeStoreRecordStatus::Published, source_runtime: SourceRuntime::Cli, created_at_ms: 1100, inserted_at_ms: 1101, @@ -9092,7 +9110,7 @@ mod tests { }) .expect("append signed app-origin listing"); let signed_report = app_store - .import_shared_local_events_from_store(&events) + .import_shared_runtime_store_from_store(&events) .expect("import signed app-origin listing"); let imported = app_store .load_local_interop_records() diff --git a/crates/store/src/lib.rs b/crates/store/src/lib.rs @@ -36,8 +36,8 @@ pub use repo::{ APP_ACTIVITY_CONTEXT_LIMIT, APP_ACTIVITY_RETENTION_LIMIT, AppActivationRepository, AppActivityRepository, AppBuyerRepository, AppFarmRulesRepository, AppFarmSetupRepository, AppOrdersRepository, AppProductsRepository, AppRemindersRepository, AppTodayAgendaRepository, - BuyerOrderCoordinationRecord, BuyerOrderCoordinationState, BuyerOrderLocalEventExport, - BuyerOrderLocalEventLine, BuyerRepeatDemandApplyOutcome, SelectedBuyerOrderScope, + BuyerOrderCoordinationRecord, BuyerOrderCoordinationState, BuyerOrderRuntimeStoreExport, + BuyerOrderRuntimeStoreLine, BuyerRepeatDemandApplyOutcome, SelectedBuyerOrderScope, SellerOrderDecisionExport, SellerOrderDecisionLineExport, TODAY_AGENDA_LIST_LIMIT, TODAY_AGENDA_LOW_STOCK_THRESHOLD, derive_farm_rules_readiness, }; @@ -438,7 +438,7 @@ impl AppSqliteStore { &self, context: &BuyerContext, order_id: OrderId, - ) -> Result<Option<BuyerOrderLocalEventExport>, AppSqliteError> { + ) -> Result<Option<BuyerOrderRuntimeStoreExport>, AppSqliteError> { self.buyer_repository() .load_buyer_order_local_event_export(context, order_id) } diff --git a/crates/store/src/repo/buyer.rs b/crates/store/src/repo/buyer.rs @@ -80,7 +80,7 @@ fn normalized_nostr_pubkey(pubkey: &str) -> Option<String> { } #[derive(Clone, Debug, Eq, PartialEq)] -pub struct BuyerOrderLocalEventExport { +pub struct BuyerOrderRuntimeStoreExport { pub order_id: OrderId, pub farm_id: FarmId, pub farm_display_name: String, @@ -97,11 +97,11 @@ pub struct BuyerOrderLocalEventExport { pub fulfillment_window_label: Option<String>, pub fulfillment_starts_at: Option<String>, pub fulfillment_ends_at: Option<String>, - pub lines: Vec<BuyerOrderLocalEventLine>, + pub lines: Vec<BuyerOrderRuntimeStoreLine>, } #[derive(Clone, Debug, Eq, PartialEq)] -pub struct BuyerOrderLocalEventLine { +pub struct BuyerOrderRuntimeStoreLine { pub product_id: ProductId, pub title: String, pub quantity: u32, @@ -1061,7 +1061,7 @@ impl<'a> AppBuyerRepository<'a> { &self, context: &BuyerContext, order_id: OrderId, - ) -> Result<Option<BuyerOrderLocalEventExport>, AppSqliteError> { + ) -> Result<Option<BuyerOrderRuntimeStoreExport>, AppSqliteError> { let context_key = context.storage_key(); let Some(record) = self .connection @@ -1140,7 +1140,7 @@ impl<'a> AppBuyerRepository<'a> { let farm_id = parse_typed_id("orders.farm_id", farm_id)?; let lines = self.load_buyer_order_local_event_lines(order_id)?; - Ok(Some(BuyerOrderLocalEventExport { + Ok(Some(BuyerOrderRuntimeStoreExport { order_id, farm_id, farm_display_name, @@ -1906,7 +1906,7 @@ impl<'a> AppBuyerRepository<'a> { fn load_buyer_order_local_event_lines( &self, order_id: OrderId, - ) -> Result<Vec<BuyerOrderLocalEventLine>, AppSqliteError> { + ) -> Result<Vec<BuyerOrderRuntimeStoreLine>, AppSqliteError> { let order_id_string = order_id.to_string(); let mut statement = self .connection @@ -1987,7 +1987,7 @@ impl<'a> AppBuyerRepository<'a> { }); } - lines.push(BuyerOrderLocalEventLine { + lines.push(BuyerOrderRuntimeStoreLine { product_id, title, quantity, @@ -3913,7 +3913,7 @@ mod tests { order_id, "committed", "reserved", - "local_events", + "runtime_store", Some("agreement-event-1"), ); @@ -3931,7 +3931,7 @@ mod tests { assert_eq!(row.workflow.inventory, TradeInventoryStatus::Reserved); assert_eq!( row.workflow.provenance.primary_source, - TradeWorkflowSource::LocalEvents + TradeWorkflowSource::RuntimeStore ); assert_eq!( row.workflow.provenance.last_event_id.as_deref(), @@ -3967,7 +3967,7 @@ mod tests { order_id, "committed", "reserved", - "local_events", + "runtime_store", Some("buyer-workflow-event"), ); @@ -3984,7 +3984,7 @@ mod tests { order_id, "committed", "reserved", - "local_events", + "runtime_store", Some("buyer-workflow-event"), ); corrupt_order_workflow_display_projection(connection, order_id, column, "future_state"); diff --git a/crates/store/src/repo/mod.rs b/crates/store/src/repo/mod.rs @@ -20,7 +20,7 @@ pub use activity::{ }; pub use buyer::{ AppBuyerRepository, BuyerOrderCoordinationRecord, BuyerOrderCoordinationState, - BuyerOrderLocalEventExport, BuyerOrderLocalEventLine, BuyerRepeatDemandApplyOutcome, + BuyerOrderRuntimeStoreExport, BuyerOrderRuntimeStoreLine, BuyerRepeatDemandApplyOutcome, SelectedBuyerOrderScope, }; pub use farm_rules::{AppFarmRulesRepository, derive_farm_rules_readiness}; diff --git a/crates/store/src/repo/orders.rs b/crates/store/src/repo/orders.rs @@ -1608,7 +1608,7 @@ mod tests { order_id, "committed", "reserved", - "local_events", + "runtime_store", Some("seller-workflow-event"), ); @@ -1632,7 +1632,7 @@ mod tests { assert_eq!(workflow.inventory, TradeInventoryStatus::Reserved); assert_eq!( workflow.provenance.primary_source, - TradeWorkflowSource::LocalEvents + TradeWorkflowSource::RuntimeStore ); assert_eq!( workflow.provenance.last_event_id.as_deref(), @@ -1674,7 +1674,7 @@ mod tests { order_id, "committed", "reserved", - "local_events", + "runtime_store", Some("seller-workflow-event"), ); @@ -1691,7 +1691,7 @@ mod tests { order_id, "committed", "reserved", - "local_events", + "runtime_store", Some("seller-workflow-event"), ); corrupt_order_workflow_display_projection(connection, order_id, column, "future_state"); diff --git a/crates/store/src/repo/workflow.rs b/crates/store/src/repo/workflow.rs @@ -70,7 +70,7 @@ fn parse_trade_workflow_source( "app" => Ok(TradeWorkflowSource::App), "cli" => Ok(TradeWorkflowSource::Cli), "relay" => Ok(TradeWorkflowSource::Relay), - "local_events" => Ok(TradeWorkflowSource::LocalEvents), + "runtime_store" => Ok(TradeWorkflowSource::RuntimeStore), "unknown" => Ok(TradeWorkflowSource::Unknown), _ => Err(AppSqliteError::DecodeEnum { field, value }), } diff --git a/crates/store/src/sdk_workflow_receipts.rs b/crates/store/src/sdk_workflow_receipts.rs @@ -7,21 +7,21 @@ use crate::AppSqliteError; #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum AppSdkWorkflowReceiptSourceKind { LocalOutbox, - SharedLocalEvent, + SharedRuntimeStore, } impl AppSdkWorkflowReceiptSourceKind { pub const fn storage_key(self) -> &'static str { match self { Self::LocalOutbox => "local_outbox", - Self::SharedLocalEvent => "shared_local_event", + Self::SharedRuntimeStore => "shared_runtime_store", } } pub fn parse(value: &str) -> Result<Self, AppSqliteError> { match value { "local_outbox" => Ok(Self::LocalOutbox), - "shared_local_event" => Ok(Self::SharedLocalEvent), + "shared_runtime_store" => Ok(Self::SharedRuntimeStore), _ => Err(AppSqliteError::DecodeEnum { field: "app_sdk_workflow_receipts.source_kind", value: value.to_owned(), diff --git a/crates/sync/Cargo.toml b/crates/sync/Cargo.toml @@ -9,7 +9,7 @@ license.workspace = true publish = false [dependencies] -radroots_events.workspace = true +radroots_event.workspace = true radroots_studio_app_view.workspace = true radroots_sdk.workspace = true serde.workspace = true diff --git a/crates/sync/src/publish.rs b/crates/sync/src/publish.rs @@ -1,4 +1,4 @@ -use radroots_events::order::{ +use radroots_event::order::{ RadrootsOrderEconomics, RadrootsOrderItem, RadrootsOrderRevisionOutcome, }; use radroots_sdk::{ @@ -673,7 +673,7 @@ mod tests { use crate::{ PendingSyncOperation, PendingSyncOperationState, SyncAggregateRef, SyncOperationKind, }; - use radroots_events::order::{ + use radroots_event::order::{ RadrootsOrderEconomics, RadrootsOrderItem, RadrootsOrderRevisionOutcome, }; use radroots_studio_app_view::{FarmId, FarmReadiness, OrderId, ProductId, ProductStatus}; diff --git a/crates/view/Cargo.toml b/crates/view/Cargo.toml @@ -10,7 +10,7 @@ publish = false [dependencies] radroots_core.workspace = true -radroots_events.workspace = true +radroots_event.workspace = true radroots_studio_app_types.workspace = true radroots_trade.workspace = true serde.workspace = true diff --git a/crates/view/src/lib.rs b/crates/view/src/lib.rs @@ -3,7 +3,7 @@ pub use radroots_studio_app_types::*; use radroots_core::RadrootsCoreMoney; -use radroots_events::order::RadrootsOrderEconomics; +use radroots_event::order::RadrootsOrderEconomics; use radroots_trade::validation_receipt::{ RadrootsValidationReceiptProofSystem, RadrootsValidationReceiptResult, RadrootsValidationReceiptType, @@ -1241,7 +1241,7 @@ pub enum TradeWorkflowSource { App, Cli, Relay, - LocalEvents, + RuntimeStore, #[default] Unknown, } @@ -1252,7 +1252,7 @@ impl TradeWorkflowSource { Self::App => "app", Self::Cli => "cli", Self::Relay => "relay", - Self::LocalEvents => "local_events", + Self::RuntimeStore => "runtime_store", Self::Unknown => "unknown", } } @@ -1262,7 +1262,7 @@ impl TradeWorkflowSource { Self::App => "messages.trade.workflow.provenance.app", Self::Cli => "messages.trade.workflow.provenance.cli", Self::Relay => "messages.trade.workflow.provenance.relay", - Self::LocalEvents => "messages.trade.workflow.provenance.local_events", + Self::RuntimeStore => "messages.trade.workflow.provenance.runtime_store", Self::Unknown => "messages.trade.workflow.provenance.unknown", } } @@ -2126,11 +2126,11 @@ mod tests { use radroots_core::{ RadrootsCoreCurrency, RadrootsCoreDecimal, RadrootsCoreMoney, RadrootsCoreUnit, }; - use radroots_events::ids::{ + use radroots_event::ids::{ RadrootsEventId, RadrootsInventoryBinId, RadrootsListingAddress, RadrootsOrderId, RadrootsOrderQuoteId, RadrootsPublicKey, }; - use radroots_events::order::{ + use radroots_event::order::{ RadrootsOrderEconomicItem, RadrootsOrderEconomics, RadrootsOrderPricingBasis, }; use radroots_trade::validation_receipt::{ @@ -2940,7 +2940,7 @@ mod tests { order_id, &active_order, TradeRevisionStatus::Updated, - TradeProvenanceProjection::from_primary_source(TradeWorkflowSource::LocalEvents), + TradeProvenanceProjection::from_primary_source(TradeWorkflowSource::RuntimeStore), ); assert_eq!(projection.order_id, order_id); assert_eq!(projection.agreement, TradeAgreementStatus::Committed); @@ -2950,7 +2950,7 @@ mod tests { assert_eq!(projection.economics.currency_code.as_deref(), Some("USD")); assert_eq!( projection.provenance, - TradeProvenanceProjection::from_primary_source(TradeWorkflowSource::LocalEvents) + TradeProvenanceProjection::from_primary_source(TradeWorkflowSource::RuntimeStore) .with_last_event_id(Some( "3333333333333333333333333333333333333333333333333333333333333333".to_owned() )) @@ -2966,7 +2966,7 @@ mod tests { order_id, &pending_rhi_order, TradeRevisionStatus::None, - TradeProvenanceProjection::from_primary_source(TradeWorkflowSource::LocalEvents), + TradeProvenanceProjection::from_primary_source(TradeWorkflowSource::RuntimeStore), ); assert_eq!( pending_rhi_projection.agreement, @@ -2986,7 +2986,7 @@ mod tests { order_id, &requested_order, TradeRevisionStatus::None, - TradeProvenanceProjection::from_primary_source(TradeWorkflowSource::LocalEvents), + TradeProvenanceProjection::from_primary_source(TradeWorkflowSource::RuntimeStore), ); assert_eq!( requested_projection.agreement, @@ -3075,8 +3075,8 @@ mod tests { ); assert_eq!(TradeInventoryStatus::Reserved.storage_key(), "reserved"); assert_eq!( - TradeWorkflowSource::LocalEvents.storage_key(), - "local_events" + TradeWorkflowSource::RuntimeStore.storage_key(), + "runtime_store" ); assert_eq!( diff --git a/i18n/locales/en/messages.json b/i18n/locales/en/messages.json @@ -430,7 +430,7 @@ "trade.workflow.provenance.app": "App", "trade.workflow.provenance.cli": "CLI", "trade.workflow.provenance.relay": "Relay", - "trade.workflow.provenance.local_events": "Local events", + "trade.workflow.provenance.runtime_store": "Runtime store", "trade.workflow.provenance.unknown": "Unknown", "orders.reminders.title": "Reminders", "orders.reminder_log.title": "Reminder activity",