v0.3.8-pre.007

This commit is contained in:
2026-09-03 17:54:50 +02:00
parent 8130e01b70
commit d5b4aef194
16 changed files with 1139 additions and 55 deletions

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-store-desk/src/app_state.rs
// version: 2
// version: 3
//! Shared backend state owned by the Store Desk Tauri application.
@@ -105,7 +105,7 @@ impl crate::AppState {
application_version: env!("CARGO_PKG_VERSION").to_owned(),
config_document_count: document_count,
fallback_logging_active: runtime.fallback_active,
shell_phase: "pre.006-store-overview".to_owned(),
shell_phase: "pre.007-raw-transactions".to_owned(),
startup_diagnostic: runtime.startup_diagnostic.clone(),
});
}
@@ -115,6 +115,19 @@ impl crate::AppState {
return self.store_startup.status().await;
}
/// Executes one bounded RAW transaction inspection query through the retained Store facade.
pub(crate) async fn query_transactions(
&self,
request: crate::StoreTransactionQueryRequestDto,
) -> ksp_core_lib::Result<crate::StoreTransactionQueryResponseDto> {
return self.store_startup.query_transactions(request).await;
}
/// Loads one explicit RAW transaction detail through the retained Store facade.
pub(crate) async fn transaction_detail(&self, request: crate::StoreTransactionDetailRequestDto) -> ksp_core_lib::Result<crate::StoreTransactionDetailDto> {
return self.store_startup.transaction_detail(request).await;
}
/// Returns the resolved splash timings captured during application bootstrap.
#[must_use]
pub(crate) const fn splash_settings(&self) -> crate::SplashSettings {

View File

@@ -0,0 +1,99 @@
// file: crates/ksp-app-store-desk/src/dto_transaction.rs
// version: 1
//! Application-owned DTOs for RAW transaction inspection and detail commands.
use ts_rs::TS; // rust-rules: trait-import
/// Bounded Store-owned query request projected from one DataTables page request.
#[derive(Debug, serde::Deserialize, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_store_desk/dto_transaction/StoreTransactionQueryRequestDto.ts")]
pub(crate) struct StoreTransactionQueryRequestDto {
/// Stable Store sort direction code (`ascending` or `descending`).
pub(crate) direction: String,
/// Absolute zero-based inspection offset encoded as exact decimal text.
pub(crate) offset: String,
/// Whitelisted page size (`25`, `50`, or `100`).
pub(crate) limit: u32,
/// Optional inclusive maximum slot encoded as decimal text.
pub(crate) slot_max: std::option::Option<String>,
/// Optional inclusive minimum slot encoded as decimal text.
pub(crate) slot_min: std::option::Option<String>,
}
/// Payload-free RAW transaction row returned to the server-side DataTables adapter.
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_store_desk/dto_transaction/StoreTransactionRowDto.ts")]
pub(crate) struct StoreTransactionRowDto {
/// Optional canonical block timestamp encoded as exact Unix-millisecond decimal text.
pub(crate) block_time_unix_millis_decimal: std::option::Option<String>,
/// Canonical transaction content hash encoded as lower-case hexadecimal text.
pub(crate) content_hash: String,
/// KSP-owned RAW format identifier.
pub(crate) format_id: String,
/// KSP-owned RAW format version, safely representable in JavaScript.
pub(crate) format_version: u32,
/// Logical payload size encoded as exact decimal text while payload remains retained.
pub(crate) payload_size_decimal: std::option::Option<String>,
/// Stable logical retention-state code.
pub(crate) retention_state: String,
/// Canonical 64-byte transaction signature encoded as lower-case hexadecimal text.
pub(crate) signature: String,
/// Solana slot encoded as exact decimal text.
pub(crate) slot_decimal: String,
}
/// Server-side transaction table result using exact decimal counts.
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_store_desk/dto_transaction/StoreTransactionQueryResponseDto.ts")]
pub(crate) struct StoreTransactionQueryResponseDto {
/// Exact count after optional Store filters.
pub(crate) records_filtered_decimal: String,
/// Exact count in the mandatory Store network scope before optional filters.
pub(crate) records_total_decimal: String,
/// Payload-free inspection rows for the requested random-access page.
pub(crate) rows: std::vec::Vec<crate::StoreTransactionRowDto>,
}
/// App-owned identity request for one explicit RAW transaction detail load.
#[derive(Debug, serde::Deserialize, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_store_desk/dto_transaction/StoreTransactionDetailRequestDto.ts")]
pub(crate) struct StoreTransactionDetailRequestDto {
/// Canonical 64-byte transaction signature encoded as lower-case hexadecimal text.
pub(crate) signature: String,
}
/// Bounded detail projection for one RAW transaction.
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_store_desk/dto_transaction/StoreTransactionDetailDto.ts")]
pub(crate) struct StoreTransactionDetailDto {
/// Optional canonical block timestamp encoded as exact Unix-millisecond decimal text.
pub(crate) block_time_unix_millis_decimal: std::option::Option<String>,
/// Canonical content hash encoded as lower-case hexadecimal text.
pub(crate) content_hash: String,
/// KSP-owned RAW format identifier.
pub(crate) format_id: String,
/// KSP-owned RAW format version.
pub(crate) format_version: u32,
/// Bounded lower-case hexadecimal preview of the canonical RAW payload, when retained.
pub(crate) payload_preview_hex: std::option::Option<String>,
/// Whether the canonical payload is larger than the returned preview.
pub(crate) payload_preview_truncated: bool,
/// Exact canonical payload size while retained.
pub(crate) payload_size_decimal: std::option::Option<String>,
/// Stable logical retention-state code.
pub(crate) retention_state: String,
/// Canonical transaction signature encoded as lower-case hexadecimal text.
pub(crate) signature: String,
/// Solana slot encoded as exact decimal text.
pub(crate) slot_decimal: String,
}
#[cfg(test)]
#[path = "../unit_tests/dto_transaction.rs"]
mod tests;

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-store-desk/src/errors.rs
// version: 2
// version: 3
//! Application-local error codes for Store Desk desktop runtime surfaces.
@@ -19,8 +19,14 @@ pub(crate) const ERROR_CODE_LOGGING_BOOTSTRAP_FAILED: ksp_core_lib::ErrorCode =
pub(crate) const ERROR_CODE_SPLASH_ORIGIN_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("store_desk", "splash_origin_invalid");
/// A KSP desk splash environment duration is malformed or exceeds its safety bound.
pub(crate) const ERROR_CODE_SPLASH_SETTING_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("store_desk", "splash_setting_invalid");
/// Store Desk received an invalid transaction inspection/detail request.
pub(crate) const ERROR_CODE_STORE_QUERY_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("store_desk", "store_query_invalid");
/// Store Desk cannot serve a Store command because the runtime is unavailable or already closed.
pub(crate) const ERROR_CODE_STORE_RUNTIME_UNAVAILABLE: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("store_desk", "store_runtime_unavailable");
/// Store Desk cannot complete the bounded Store shutdown lifecycle.
pub(crate) const ERROR_CODE_STORE_SHUTDOWN_FAILED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("store_desk", "store_shutdown_failed");
/// Store Desk could not resolve the requested transaction identity to a coherent Store entity.
pub(crate) const ERROR_CODE_STORE_TRANSACTION_NOT_FOUND: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("store_desk", "store_transaction_not_found");
/// Tauri runtime assembly or execution failed.
pub(crate) const ERROR_CODE_TAURI_RUNTIME_FAILED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("store_desk", "tauri_runtime_failed");
/// A required Tauri window is missing from the configured application runtime.

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-store-desk/src/lib.rs
// version: 3
// version: 4
//! Tauri desktop scaffold for backend-neutral KSP Store inspection.
@@ -11,6 +11,7 @@ mod app_state;
mod bootstrap;
mod constants;
mod dto_common;
mod dto_transaction;
mod errors;
mod frontend_logging;
mod logging_runtime;
@@ -65,6 +66,16 @@ pub(crate) use self::dto_common::CommandErrorDto;
pub(crate) use self::dto_common::ShellStatusDto;
/// Backend-neutral Store runtime and health projection exposed to Overview.
pub(crate) use self::dto_common::StoreRuntimeStatusDto;
/// Bounded detail projection for one RAW transaction.
pub(crate) use self::dto_transaction::StoreTransactionDetailDto;
/// App-owned identity request for one explicit RAW transaction detail load.
pub(crate) use self::dto_transaction::StoreTransactionDetailRequestDto;
/// Bounded Store-owned query request projected from one DataTables page request.
pub(crate) use self::dto_transaction::StoreTransactionQueryRequestDto;
/// Server-side transaction table result using exact decimal counts.
pub(crate) use self::dto_transaction::StoreTransactionQueryResponseDto;
/// Payload-free RAW transaction row returned to the server-side DataTables adapter.
pub(crate) use self::dto_transaction::StoreTransactionRowDto;
/// Shared Store Desk runtime state is internally inconsistent.
pub(crate) use self::errors::ERROR_CODE_APP_STATE_INVALID;
/// Shared Store Desk runtime state cannot be locked safely.
@@ -81,8 +92,14 @@ pub(crate) use self::errors::ERROR_CODE_LOGGING_BOOTSTRAP_FAILED;
pub(crate) use self::errors::ERROR_CODE_SPLASH_ORIGIN_INVALID;
/// A KSP desk splash environment duration is malformed or exceeds its safety bound.
pub(crate) use self::errors::ERROR_CODE_SPLASH_SETTING_INVALID;
/// Store Desk received an invalid transaction inspection/detail request.
pub(crate) use self::errors::ERROR_CODE_STORE_QUERY_INVALID;
/// Store Desk cannot serve a Store command because the runtime is unavailable or already closed.
pub(crate) use self::errors::ERROR_CODE_STORE_RUNTIME_UNAVAILABLE;
/// Store Desk cannot complete the bounded Store shutdown lifecycle.
pub(crate) use self::errors::ERROR_CODE_STORE_SHUTDOWN_FAILED;
/// Store Desk could not resolve the requested transaction identity to a coherent Store entity.
pub(crate) use self::errors::ERROR_CODE_STORE_TRANSACTION_NOT_FOUND;
/// Tauri runtime assembly or execution failed.
pub(crate) use self::errors::ERROR_CODE_TAURI_RUNTIME_FAILED;
/// A required Tauri window is missing from the configured application runtime.

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-store-desk/src/store_runtime.rs
// version: 2
// version: 3
//! Composite-selected Store readiness, status and bounded shutdown lifecycle owned by Store Desk.
@@ -35,6 +35,27 @@ impl crate::StoreStartup {
};
}
/// Executes one bounded server-side RAW transaction inspection query.
pub(crate) async fn query_transactions(
&self,
request: crate::StoreTransactionQueryRequestDto,
) -> ksp_core_lib::Result<crate::StoreTransactionQueryResponseDto> {
let runtime = self.runtime.as_ref();
return match runtime {
std::option::Option::Some(value) => value.query_transactions(request).await,
std::option::Option::None => std::result::Result::Err(store_runtime_unavailable()),
};
}
/// Loads one explicit bounded RAW transaction detail projection.
pub(crate) async fn transaction_detail(&self, request: crate::StoreTransactionDetailRequestDto) -> ksp_core_lib::Result<crate::StoreTransactionDetailDto> {
let runtime = self.runtime.as_ref();
return match runtime {
std::option::Option::Some(value) => value.transaction_detail(request).await,
std::option::Option::None => std::result::Result::Err(store_runtime_unavailable()),
};
}
/// Closes the retained Store runtime if startup reached the physical Store-open phase.
pub(crate) async fn close(&self) -> ksp_core_lib::Result<()> {
let runtime = self.runtime.as_ref();
@@ -95,6 +116,68 @@ impl crate::StoreRuntime {
};
}
/// Executes one validated random-access transaction inspection query while retaining the Store read guard.
pub(crate) async fn query_transactions(
&self,
request: crate::StoreTransactionQueryRequestDto,
) -> ksp_core_lib::Result<crate::StoreTransactionQueryResponseDto> {
let locked = self.store.read().await;
let store = locked.as_ref();
let store = match store {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::result::Result::Err(store_runtime_unavailable()),
};
let query = transaction_query_from_request(store, &request);
let query = match query {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let page = ksp_store_lib::RawTransactionInspectionRead::inspect_raw_transactions(store, &query).await;
let page = match page {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let records_total_decimal = page.total_items().to_string();
let records_filtered_decimal = page.filtered_items().to_string();
let items = page.into_items();
let mut rows = std::vec::Vec::with_capacity(items.len());
for item in items {
rows.push(transaction_row_dto(&item));
}
return std::result::Result::Ok(crate::StoreTransactionQueryResponseDto { records_filtered_decimal, records_total_decimal, rows });
}
/// Loads one transaction detail by application-owned row identity without exposing Store network selection to the frontend.
pub(crate) async fn transaction_detail(&self, request: crate::StoreTransactionDetailRequestDto) -> ksp_core_lib::Result<crate::StoreTransactionDetailDto> {
let locked = self.store.read().await;
let store = locked.as_ref();
let store = match store {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::result::Result::Err(store_runtime_unavailable()),
};
let reference = transaction_reference_from_request(store, request.signature.as_str());
let reference = match reference {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let retention = ksp_store_lib::RawTransactionRetentionRead::get_raw_transaction_retention_state(store, &reference).await;
let retention = match retention {
std::result::Result::Ok(std::option::Option::Some(value)) => value,
std::result::Result::Ok(std::option::Option::None) => return std::result::Result::Err(store_transaction_not_found()),
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
return match retention {
ksp_store_lib::RawRetentionState::Full | ksp_store_lib::RawRetentionState::Archived => {
transaction_detail_with_payload(store, &reference, retention).await
},
ksp_store_lib::RawRetentionState::Purged => transaction_detail_from_tombstone(store, &reference).await,
_ => std::result::Result::Err(ksp_core_lib::Error::new(
crate::ERROR_CODE_APP_STATE_INVALID,
"Store Desk cannot project an unsupported transaction retention state",
)),
};
}
/// Explicitly closes the Store exactly once through its backend-neutral facade after all read guards have drained.
pub(crate) async fn close(&self) -> ksp_core_lib::Result<()> {
let mut locked = self.store.write().await;
@@ -127,6 +210,206 @@ impl crate::StoreRuntime {
}
}
const TRANSACTION_DETAIL_PREVIEW_BYTES: usize = 512;
fn transaction_query_from_request(
store: &ksp_store_lib::Store,
request: &crate::StoreTransactionQueryRequestDto,
) -> ksp_core_lib::Result<ksp_store_lib::RawTransactionInspectionQuery> {
let limit = match request.limit {
25 | 50 | 100 => ksp_store_lib::RawPageLimit::new(u64::from(request.limit)),
_ => return std::result::Result::Err(store_query_invalid()),
};
let limit = match limit {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return std::result::Result::Err(store_query_invalid()),
};
let offset = request.offset.parse::<u64>();
let offset = match offset {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return std::result::Result::Err(store_query_invalid()),
};
let slot_min = parse_optional_decimal_u64(request.slot_min.as_deref());
let slot_min = match slot_min {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let slot_max = parse_optional_decimal_u64(request.slot_max.as_deref());
let slot_max = match slot_max {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let slots = ksp_store_lib::RawSlotRange::new(slot_min, slot_max);
let slots = match slots {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return std::result::Result::Err(store_query_invalid()),
};
let direction = match request.direction.as_str() {
"ascending" => ksp_store_lib::RawSortDirection::Ascending,
"descending" => ksp_store_lib::RawSortDirection::Descending,
_ => return std::result::Result::Err(store_query_invalid()),
};
let network = store.runtime_snapshot().network().clone();
let page = ksp_store_lib::RawInspectionPageRequest::new(offset, limit);
return std::result::Result::Ok(ksp_store_lib::RawTransactionInspectionQuery::new(network, slots, direction, page));
}
fn transaction_reference_from_request(store: &ksp_store_lib::Store, signature_text: &str) -> ksp_core_lib::Result<ksp_store_lib::RawTransactionReference> {
let signature = decode_hex_64(signature_text);
let signature = match signature {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let network = store.runtime_snapshot().network().clone();
return std::result::Result::Ok(ksp_store_lib::RawTransactionReference::new(network, ksp_store_lib::RawTransactionSignature::new(signature)));
}
async fn transaction_detail_with_payload(
store: &ksp_store_lib::Store,
reference: &ksp_store_lib::RawTransactionReference,
retention: ksp_store_lib::RawRetentionState,
) -> ksp_core_lib::Result<crate::StoreTransactionDetailDto> {
let transaction = ksp_store_lib::RawTransactionRead::get_raw_transaction(store, reference).await;
let transaction = match transaction {
std::result::Result::Ok(std::option::Option::Some(value)) => value,
std::result::Result::Ok(std::option::Option::None) => {
return std::result::Result::Err(ksp_core_lib::Error::new(
crate::ERROR_CODE_APP_STATE_INVALID,
"Store Desk transaction retention state and payload availability disagree",
));
},
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let payload = transaction.payload();
let payload_bytes = payload.bytes();
let preview_len = std::cmp::min(payload_bytes.len(), TRANSACTION_DETAIL_PREVIEW_BYTES);
let preview = encode_hex(&payload_bytes[..preview_len]);
return std::result::Result::Ok(crate::StoreTransactionDetailDto {
block_time_unix_millis_decimal: transaction.block_time().map(|value| return value.unix_millis().to_string()),
content_hash: encode_hex(payload.content_hash().as_bytes()),
format_id: payload.format_id().as_str().to_owned(),
format_version: payload.format_version(),
payload_preview_hex: std::option::Option::Some(preview),
payload_preview_truncated: payload_bytes.len() > preview_len,
payload_size_decimal: std::option::Option::Some(payload.byte_len().to_string()),
retention_state: retention_state_code(retention).to_owned(),
signature: encode_hex(reference.signature().as_bytes()),
slot_decimal: transaction.slot().to_string(),
});
}
async fn transaction_detail_from_tombstone(
store: &ksp_store_lib::Store,
reference: &ksp_store_lib::RawTransactionReference,
) -> ksp_core_lib::Result<crate::StoreTransactionDetailDto> {
let tombstone = ksp_store_lib::RawTransactionRetentionRead::get_raw_transaction_tombstone(store, reference).await;
let tombstone = match tombstone {
std::result::Result::Ok(std::option::Option::Some(value)) => value,
std::result::Result::Ok(std::option::Option::None) => {
return std::result::Result::Err(ksp_core_lib::Error::new(
crate::ERROR_CODE_APP_STATE_INVALID,
"Store Desk purged transaction is missing its durable tombstone",
));
},
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
return std::result::Result::Ok(crate::StoreTransactionDetailDto {
block_time_unix_millis_decimal: std::option::Option::None,
content_hash: encode_hex(tombstone.content_hash().as_bytes()),
format_id: tombstone.format_id().as_str().to_owned(),
format_version: tombstone.format_version(),
payload_preview_hex: std::option::Option::None,
payload_preview_truncated: false,
payload_size_decimal: std::option::Option::None,
retention_state: retention_state_code(ksp_store_lib::RawRetentionState::Purged).to_owned(),
signature: encode_hex(reference.signature().as_bytes()),
slot_decimal: tombstone.slot().to_string(),
});
}
fn transaction_row_dto(summary: &ksp_store_lib::RawTransactionSummary) -> crate::StoreTransactionRowDto {
return crate::StoreTransactionRowDto {
block_time_unix_millis_decimal: summary.block_time().map(|value| return value.unix_millis().to_string()),
content_hash: encode_hex(summary.content_hash().as_bytes()),
format_id: summary.format_id().as_str().to_owned(),
format_version: summary.format_version(),
payload_size_decimal: summary.payload_size_bytes().map(|value| return value.to_string()),
retention_state: retention_state_code(summary.retention_state()).to_owned(),
signature: encode_hex(summary.reference().signature().as_bytes()),
slot_decimal: summary.slot().to_string(),
};
}
fn retention_state_code(state: ksp_store_lib::RawRetentionState) -> &'static str {
return match state {
ksp_store_lib::RawRetentionState::Full => "full",
ksp_store_lib::RawRetentionState::Compacted => "compacted",
ksp_store_lib::RawRetentionState::Archived => "archived",
ksp_store_lib::RawRetentionState::Purged => "purged",
_ => "unknown",
};
}
fn parse_optional_decimal_u64(value: std::option::Option<&str>) -> ksp_core_lib::Result<std::option::Option<u64>> {
return match value {
std::option::Option::Some(text) => match text.parse::<u64>() {
std::result::Result::Ok(parsed) => std::result::Result::Ok(std::option::Option::Some(parsed)),
std::result::Result::Err(_) => std::result::Result::Err(store_query_invalid()),
},
std::option::Option::None => std::result::Result::Ok(std::option::Option::None),
};
}
fn decode_hex_64(value: &str) -> ksp_core_lib::Result<[u8; 64]> {
if value.len() != 128 || !value.is_ascii() {
return std::result::Result::Err(store_query_invalid());
}
let source = value.as_bytes();
let mut decoded = [0_u8; 64];
for index in 0..64 {
let high = decode_hex_nibble(source[index * 2]);
let low = decode_hex_nibble(source[index * 2 + 1]);
let (high, low) = match (high, low) {
(std::option::Option::Some(high), std::option::Option::Some(low)) => (high, low),
_ => return std::result::Result::Err(store_query_invalid()),
};
decoded[index] = (high << 4) | low;
}
return std::result::Result::Ok(decoded);
}
fn decode_hex_nibble(value: u8) -> std::option::Option<u8> {
return match value {
b'0'..=b'9' => std::option::Option::Some(value - b'0'),
b'a'..=b'f' => std::option::Option::Some(value - b'a' + 10),
b'A'..=b'F' => std::option::Option::Some(value - b'A' + 10),
_ => std::option::Option::None,
};
}
fn encode_hex(bytes: &[u8]) -> String {
const HEX: &[u8; 16] = b"0123456789abcdef";
let mut encoded = String::with_capacity(bytes.len() * 2);
for byte in bytes {
let value = *byte;
encoded.push(char::from(HEX[usize::from(value >> 4)]));
encoded.push(char::from(HEX[usize::from(value & 0x0f)]));
}
return encoded;
}
fn store_query_invalid() -> ksp_core_lib::Error {
return ksp_core_lib::Error::new(crate::ERROR_CODE_STORE_QUERY_INVALID, "Store Desk transaction query is invalid");
}
fn store_runtime_unavailable() -> ksp_core_lib::Error {
return ksp_core_lib::Error::new(crate::ERROR_CODE_STORE_RUNTIME_UNAVAILABLE, "Store Desk Store runtime is unavailable");
}
fn store_transaction_not_found() -> ksp_core_lib::Error {
return ksp_core_lib::Error::new(crate::ERROR_CODE_STORE_TRANSACTION_NOT_FOUND, "Store Desk transaction was not found");
}
/// Resolves the composite Store target, opens Store through the facade and captures one initial readiness probe.
pub(crate) async fn initialize_store(management: &ksp_config_lib::ConfigManagement) -> crate::StoreStartup {
let environment = ksp_config_lib::ConfigEnvironment::load();

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-store-desk/src/tauri.rs
// version: 2
// version: 3
//! Tauri runtime assembly for the KSP Store desktop application.
@@ -75,7 +75,14 @@ fn configure_plugins(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<taur
#[allow(clippy::question_mark_used)] // Tauri generates the question-mark operator internally for async command dispatch.
fn configure_commands(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
return builder.invoke_handler(tauri::generate_handler![emit_frontend_log, get_shell_status, splash_frontend_ready, store_runtime_status]);
return builder.invoke_handler(tauri::generate_handler![
emit_frontend_log,
get_shell_status,
splash_frontend_ready,
store_get_transaction_detail,
store_query_transactions,
store_runtime_status,
]);
}
fn configure_setup(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
@@ -167,6 +174,30 @@ fn get_shell_status(state: tauri::State<'_, crate::AppState>) -> std::result::Re
};
}
#[tauri::command]
async fn store_query_transactions(
request: crate::StoreTransactionQueryRequestDto,
state: tauri::State<'_, crate::AppState>,
) -> std::result::Result<crate::StoreTransactionQueryResponseDto, crate::CommandErrorDto> {
let result = state.query_transactions(request).await;
return match result {
std::result::Result::Ok(value) => std::result::Result::Ok(value),
std::result::Result::Err(error) => std::result::Result::Err(project_command_error("store_query_transactions", crate::TRACING_DOMAIN_STORE, &error)),
};
}
#[tauri::command]
async fn store_get_transaction_detail(
request: crate::StoreTransactionDetailRequestDto,
state: tauri::State<'_, crate::AppState>,
) -> std::result::Result<crate::StoreTransactionDetailDto, crate::CommandErrorDto> {
let result = state.transaction_detail(request).await;
return match result {
std::result::Result::Ok(value) => std::result::Result::Ok(value),
std::result::Result::Err(error) => std::result::Result::Err(project_command_error("store_get_transaction_detail", crate::TRACING_DOMAIN_STORE, &error)),
};
}
#[tauri::command]
async fn store_runtime_status(state: tauri::State<'_, crate::AppState>) -> std::result::Result<crate::StoreRuntimeStatusDto, crate::CommandErrorDto> {
return std::result::Result::Ok(state.store_runtime_status().await);