v0.2.12-pre.003
This commit is contained in:
@@ -53,6 +53,7 @@
|
||||
"icons/favicon.ico"
|
||||
],
|
||||
"resources": {
|
||||
"../../config/composite.ksp-app-solprices-desk.json": "config/composite.ksp-app-solprices-desk.json",
|
||||
"../../config/composite.ksp-app-wallet-desk.json": "config/composite.ksp-app-wallet-desk.json",
|
||||
"../../config/std.logging.json": "config/std.logging.json",
|
||||
"../../config/std.offchain_transport.json": "config/std.offchain_transport.json",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-config-desk/tests/desktop_contract.rs
|
||||
// version: 8
|
||||
// version: 9
|
||||
|
||||
//! Desktop build/shell contract audits for Config Desk.
|
||||
|
||||
@@ -150,7 +150,11 @@ fn pre_018_packaged_runtime_bundles_config_resources_and_activates_shared_writab
|
||||
let resources = tauri.pointer("/bundle/resources").and_then(serde_json::Value::as_object);
|
||||
assert!(resources.is_some(), "packaged Config resources map must exist");
|
||||
if let std::option::Option::Some(resources) = resources {
|
||||
assert_eq!(resources.len(), 10);
|
||||
assert_eq!(resources.len(), 11);
|
||||
assert_eq!(
|
||||
resources.get("../../config/composite.ksp-app-solprices-desk.json").and_then(serde_json::Value::as_str),
|
||||
std::option::Option::Some("config/composite.ksp-app-solprices-desk.json"),
|
||||
);
|
||||
assert_eq!(resources.get("../../config/std.logging.json").and_then(serde_json::Value::as_str), std::option::Option::Some("config/std.logging.json"));
|
||||
assert_eq!(
|
||||
resources.get("../../config/std.offchain_transport.json").and_then(serde_json::Value::as_str),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/ksp-app-solprices-desk/frontend/main.html -->
|
||||
<!-- version: 3 -->
|
||||
<!-- version: 4 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
@@ -47,14 +47,14 @@
|
||||
<div class="d-flex align-items-center justify-content-between mb-4">
|
||||
<div>
|
||||
<h1 class="h3 mb-1">Prices</h1>
|
||||
<p class="text-body-secondary mb-0">Scaffold desktop actif. Le runtime Off-chain et la table SOL/USD arrivent dans les tranches suivantes.</p>
|
||||
<p class="text-body-secondary mb-0">Composition Config/Off-chain active. La projection provider-neutral du registry arrive dans la tranche suivante.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-placeholder">
|
||||
<div>
|
||||
<i class="fa-solid fa-chart-line fa-3x text-body-secondary mb-3" aria-hidden="true"></i>
|
||||
<h2 class="h5">Surface prix volontairement inactive</h2>
|
||||
<p class="text-body-secondary mb-0">`pre.002` ne crée ni `MarketPriceService`, ni table provider, ni refresh réseau.</p>
|
||||
<p class="text-body-secondary mb-0">`pre.003` initialise le service via Config, mais ne crée encore ni lignes provider, ni observation affichée, ni refresh réseau déclenché par l’UI.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -62,7 +62,7 @@
|
||||
<div class="d-flex align-items-center justify-content-between mb-4">
|
||||
<div>
|
||||
<h1 class="h3 mb-1">Diagnostics</h1>
|
||||
<p class="text-body-secondary mb-0">État sûr du scaffold uniquement.</p>
|
||||
<p class="text-body-secondary mb-0">État sûr du bootstrap Config, Logging et Off-chain Transport.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card shadow-sm">
|
||||
@@ -75,6 +75,10 @@
|
||||
<dd id="runtimeShellPhase" class="col-sm-7">—</dd>
|
||||
<dt class="col-sm-5">Documents Config</dt>
|
||||
<dd id="runtimeConfigDocuments" class="col-sm-7">—</dd>
|
||||
<dt class="col-sm-5">Profil composite</dt>
|
||||
<dd id="runtimeCompositeProfile" class="col-sm-7">—</dd>
|
||||
<dt class="col-sm-5">Profil Off-chain</dt>
|
||||
<dd id="runtimeOffchainProfile" class="col-sm-7">—</dd>
|
||||
<dt class="col-sm-5">Profil Logging</dt>
|
||||
<dd id="runtimeLoggingProfile" class="col-sm-7">—</dd>
|
||||
<dt class="col-sm-5">Fallback Logging</dt>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-solprices-desk/frontend/ts/main.ts
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
import "bootstrap";
|
||||
import ResizeObserver from "resize-observer-polyfill";
|
||||
@@ -44,6 +44,7 @@ function bindNavigation(): void {
|
||||
document.querySelectorAll<HTMLButtonElement>("[data-view]").forEach(button => {
|
||||
button.addEventListener("click", () => {
|
||||
const viewId = button.dataset.view;
|
||||
frontendDebug("main", "SOL Prices Desk navigation control clicked", { viewId: viewId ?? "unknown" });
|
||||
if (isViewId(viewId)) {
|
||||
activateView(viewId, "user");
|
||||
}
|
||||
@@ -54,6 +55,8 @@ function bindNavigation(): void {
|
||||
|
||||
function renderRuntimeStatus(status: RuntimeStatusDto): void {
|
||||
const values: Record<string, string> = {
|
||||
runtimeCompositeProfile: status.activeCompositeProfile,
|
||||
runtimeOffchainProfile: status.activeOffchainProfile,
|
||||
runtimeVersion: status.applicationVersion,
|
||||
runtimeShellPhase: status.shellPhase,
|
||||
runtimeConfigDocuments: status.configDocumentCount.toString(),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ksp-app-solprices-desk",
|
||||
"private": true,
|
||||
"version": "0.2.12-pre.2.fix.1",
|
||||
"version": "0.2.12-pre.3",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-solprices-desk/src/app_state.rs
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
//! Shared backend state owned by the SOL Prices Desk Tauri application.
|
||||
|
||||
@@ -7,12 +7,13 @@
|
||||
pub(crate) struct AppState {
|
||||
config_management: ksp_config_lib::ConfigManagement,
|
||||
logging_runtime: std::sync::Mutex<LoggingRuntimeState>,
|
||||
offchain_transport_startup: crate::OffchainTransportStartup,
|
||||
splash_settings: crate::SplashSettings,
|
||||
splash_sequence_started: std::sync::atomic::AtomicBool,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
/// Initializes Config ownership, Logging and the common desktop splash state without creating the Off-chain runtime reserved for `pre.003`.
|
||||
impl crate::AppState {
|
||||
/// Initializes Config ownership, composite-managed Logging and the Config-selected Off-chain Transport runtime.
|
||||
pub(crate) fn initialize(arguments: &[std::ffi::OsString]) -> ksp_core_lib::Result<Self> {
|
||||
let config_management = crate::config_management(arguments);
|
||||
let config_management = match config_management {
|
||||
@@ -29,6 +30,11 @@ impl AppState {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let offchain_transport_startup = crate::initialize_offchain_transport(&config_management);
|
||||
let offchain_transport_startup = match offchain_transport_startup {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let splash_settings = crate::SplashSettings::load();
|
||||
let splash_settings = match splash_settings {
|
||||
std::result::Result::Ok(value) => value,
|
||||
@@ -46,12 +52,13 @@ impl AppState {
|
||||
fallback_active: logging_startup.fallback_active,
|
||||
startup_diagnostic: logging_startup.startup_diagnostic,
|
||||
}),
|
||||
offchain_transport_startup,
|
||||
splash_settings,
|
||||
splash_sequence_started: std::sync::atomic::AtomicBool::new(false),
|
||||
});
|
||||
}
|
||||
|
||||
/// Builds the safe scaffold runtime status exposed before market-price composition is introduced.
|
||||
/// Builds the safe runtime status exposed before provider rows and refresh commands are introduced.
|
||||
pub(crate) fn runtime_status(&self) -> ksp_core_lib::Result<crate::RuntimeStatusDto> {
|
||||
let document_count = self.config_management.engine().registry().descriptors().count();
|
||||
let document_count = u32::try_from(document_count);
|
||||
@@ -61,7 +68,7 @@ impl AppState {
|
||||
return std::result::Result::Err(
|
||||
ksp_core_lib::Error::new(
|
||||
crate::ERROR_CODE_APP_STATE_INVALID,
|
||||
"Config registry contains too many descriptors for the SOL Prices Desk scaffold DTO",
|
||||
"Config registry contains too many descriptors for the SOL Prices Desk runtime DTO",
|
||||
)
|
||||
.with_source(error),
|
||||
);
|
||||
@@ -78,12 +85,15 @@ impl AppState {
|
||||
},
|
||||
};
|
||||
let _keep_guard_alive = &runtime.guard;
|
||||
let offchain = self.offchain_transport_startup.resolved();
|
||||
return std::result::Result::Ok(crate::RuntimeStatusDto {
|
||||
application_version: env!("CARGO_PKG_VERSION").to_owned(),
|
||||
active_composite_profile: self.offchain_transport_startup.composite_profile_id().to_owned(),
|
||||
active_logging_profile: runtime.active_profile_id.clone(),
|
||||
active_offchain_profile: offchain.profile_id().to_owned(),
|
||||
application_version: env!("CARGO_PKG_VERSION").to_owned(),
|
||||
config_document_count: document_count,
|
||||
fallback_logging_active: runtime.fallback_active,
|
||||
shell_phase: "pre.002-scaffold".to_owned(),
|
||||
shell_phase: "pre.003-offchain-bootstrap".to_owned(),
|
||||
startup_diagnostic: runtime.startup_diagnostic.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// file: crates/ksp-app-solprices-desk/src/bootstrap.rs
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
//! Config and Logging bootstrap for the SOL Prices Desk scaffold.
|
||||
//! Config composite and Logging bootstrap for SOL Prices Desk.
|
||||
|
||||
/// Crate-internal Logging startup state shared by the application state.
|
||||
pub(crate) struct LoggingStartup {
|
||||
@@ -43,7 +43,51 @@ pub(crate) fn config_management(arguments: &[std::ffi::OsString]) -> ksp_core_li
|
||||
return std::result::Result::Ok(ksp_config_lib::ConfigManagement::new(engine));
|
||||
}
|
||||
|
||||
/// Initializes Logging from the standard Config document until the SOL Prices composite is introduced by `pre.003`.
|
||||
/// Loads the concrete SOL Prices Desk Config composite using its registered logical `file_id` and autonomous default profile.
|
||||
pub(crate) fn load_solprices_desk_composite(management: &ksp_config_lib::ConfigManagement) -> ksp_core_lib::Result<ksp_config_lib::ResolvedConfigComposite> {
|
||||
let file_id = ksp_config_lib::ConfigFileId::new(ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK);
|
||||
let file_id = match file_id {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
return management.engine().load_resolved_composite(&file_id, std::option::Option::None);
|
||||
}
|
||||
|
||||
/// Returns one required standard profile from the SOL Prices Desk composite after validating the referenced logical `file_id`.
|
||||
pub(crate) fn required_composite_component_profile(
|
||||
composite: &ksp_config_lib::ResolvedConfigComposite,
|
||||
component_id: &str,
|
||||
expected_file_id: &str,
|
||||
) -> ksp_core_lib::Result<ksp_config_lib::ResolvedConfigProfile> {
|
||||
let component = composite.component(component_id);
|
||||
let component = match component {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => {
|
||||
return std::result::Result::Err(
|
||||
ksp_core_lib::Error::new(crate::ERROR_CODE_CONFIG_COMPOSITE_INVALID, "SOL Prices Desk composite is missing a required component")
|
||||
.with_context("composite_file_id", composite.file_id().as_str())
|
||||
.with_context("composite_profile_id", composite.profile_id())
|
||||
.with_context("component_id", component_id),
|
||||
);
|
||||
},
|
||||
};
|
||||
if component.resolved().file_id().as_str() != expected_file_id {
|
||||
return std::result::Result::Err(
|
||||
ksp_core_lib::Error::new(
|
||||
crate::ERROR_CODE_CONFIG_COMPOSITE_INVALID,
|
||||
"SOL Prices Desk composite component references an unexpected Config document",
|
||||
)
|
||||
.with_context("composite_file_id", composite.file_id().as_str())
|
||||
.with_context("composite_profile_id", composite.profile_id())
|
||||
.with_context("component_id", component_id)
|
||||
.with_context("expected_file_id", expected_file_id)
|
||||
.with_context("actual_file_id", component.resolved().file_id().as_str()),
|
||||
);
|
||||
}
|
||||
return std::result::Result::Ok(component.resolved().clone());
|
||||
}
|
||||
|
||||
/// Initializes Logging from the SOL Prices Desk composite, with the same bounded fallback policy as the other KSP desks.
|
||||
pub(crate) fn initialize_logging(
|
||||
management: &ksp_config_lib::ConfigManagement,
|
||||
runtime_identity: &ksp_logging_lib::LoggingRuntimeIdentity,
|
||||
@@ -54,7 +98,7 @@ pub(crate) fn initialize_logging(
|
||||
let guard = ksp_logging_lib::initialize_with_identity(&settings, runtime_identity);
|
||||
match guard {
|
||||
std::result::Result::Ok(guard) => {
|
||||
ksp_logging_lib::info!(target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_BOOTSTRAP, active_profile = active_profile_id.as_str(), "initialized SOL Prices Desk scaffold logging from managed configuration");
|
||||
ksp_logging_lib::info!(target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_BOOTSTRAP, active_profile = active_profile_id.as_str(), "initialized SOL Prices Desk logging from composite-managed configuration");
|
||||
std::result::Result::Ok(LoggingStartup {
|
||||
guard,
|
||||
active_profile_id: std::option::Option::Some(active_profile_id),
|
||||
@@ -86,7 +130,25 @@ fn resolve_logging_startup(management: &ksp_config_lib::ConfigManagement) -> Log
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return fallback_startup_plan(error),
|
||||
};
|
||||
let resolved = management.engine().load_resolved_logging_config(std::option::Option::None, &environment);
|
||||
let composite = crate::load_solprices_desk_composite(management);
|
||||
let composite = match composite {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return fallback_startup_plan(error),
|
||||
};
|
||||
let logging_profile = crate::required_composite_component_profile(&composite, crate::COMPOSITE_COMPONENT_ID_LOGGING, ksp_config_lib::FILE_ID_STD_LOGGING);
|
||||
let logging_profile = match logging_profile {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return fallback_startup_plan(error),
|
||||
};
|
||||
let offchain_profile = crate::required_composite_component_profile(
|
||||
&composite,
|
||||
crate::COMPOSITE_COMPONENT_ID_OFFCHAIN_TRANSPORT,
|
||||
ksp_config_lib::FILE_ID_STD_OFFCHAIN_TRANSPORT,
|
||||
);
|
||||
if let std::result::Result::Err(error) = offchain_profile {
|
||||
return fallback_startup_plan(error);
|
||||
}
|
||||
let resolved = management.engine().resolve_logging_config_profile(&logging_profile, &environment);
|
||||
let resolved = match resolved {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return fallback_startup_plan(error),
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
// file: crates/ksp-app-solprices-desk/src/constants.rs
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
//! Application-owned tracing targets and domains.
|
||||
//! Application-owned composition identifiers, tracing targets and domains.
|
||||
|
||||
/// Composite-local identifier for the standard Logging component.
|
||||
pub(crate) const COMPOSITE_COMPONENT_ID_LOGGING: &str = "logging";
|
||||
/// Composite-local identifier for the standard Off-chain Transport component.
|
||||
pub(crate) const COMPOSITE_COMPONENT_ID_OFFCHAIN_TRANSPORT: &str = "offchain_transport";
|
||||
/// Structured domain used while bootstrapping Config and Logging.
|
||||
pub(crate) const TRACING_DOMAIN_BOOTSTRAP: &str = "solprices.bootstrap";
|
||||
/// Structured domain used by technical frontend events.
|
||||
pub(crate) const TRACING_DOMAIN_FRONTEND: &str = "frontend";
|
||||
/// Structured domain used by the Config-selected Off-chain Transport runtime.
|
||||
pub(crate) const TRACING_DOMAIN_OFFCHAIN_TRANSPORT: &str = "solprices.offchain_transport";
|
||||
/// Structured domain used by the SOL Prices Desk shell.
|
||||
pub(crate) const TRACING_DOMAIN_SHELL: &str = "solprices.shell";
|
||||
/// Structured domain used by Tauri window lifecycle operations.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// file: crates/ksp-app-solprices-desk/src/dto_common.rs
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
//! Common Tauri DTOs shared by the SOL Prices Desk scaffold.
|
||||
//! Common Tauri DTOs shared by the SOL Prices Desk bootstrap shell.
|
||||
|
||||
use ts_rs::TS; // rust-rules: trait-import
|
||||
|
||||
@@ -18,7 +18,7 @@ pub(crate) struct CommandErrorDto {
|
||||
pub(crate) message: String,
|
||||
}
|
||||
|
||||
impl CommandErrorDto {
|
||||
impl crate::CommandErrorDto {
|
||||
/// Builds a bounded safe projection from a KSP error.
|
||||
#[must_use]
|
||||
pub(crate) fn from_error(error: &ksp_core_lib::Error) -> Self {
|
||||
@@ -30,20 +30,24 @@ impl CommandErrorDto {
|
||||
}
|
||||
}
|
||||
|
||||
/// Safe scaffold/runtime snapshot exposed to the SOL Prices Desk shell before Off-chain bootstrap exists.
|
||||
/// Safe Config/bootstrap snapshot exposed before market-price provider rows exist.
|
||||
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_solprices_desk/dto_common/RuntimeStatusDto.ts")]
|
||||
pub(crate) struct RuntimeStatusDto {
|
||||
/// Cargo application version.
|
||||
pub(crate) application_version: String,
|
||||
/// SOL Prices Desk composite profile selected for this launch.
|
||||
pub(crate) active_composite_profile: String,
|
||||
/// Active configured Logging profile, or `None` while transient fallback Logging is active.
|
||||
pub(crate) active_logging_profile: std::option::Option<String>,
|
||||
/// Number of logical Config resources registered by the current scaffold runtime.
|
||||
/// Standard Off-chain Transport profile selected by the active composite.
|
||||
pub(crate) active_offchain_profile: String,
|
||||
/// Cargo application version.
|
||||
pub(crate) application_version: String,
|
||||
/// Number of logical Config resources registered by the current runtime.
|
||||
pub(crate) config_document_count: u32,
|
||||
/// Whether SOL Prices Desk had to install its transient in-memory Logging fallback.
|
||||
pub(crate) fallback_logging_active: bool,
|
||||
/// Current implementation phase exposed by the scaffold shell.
|
||||
/// Current implementation phase exposed by the bootstrap shell.
|
||||
pub(crate) shell_phase: String,
|
||||
/// Safe startup diagnostic that caused fallback Logging, when applicable.
|
||||
pub(crate) startup_diagnostic: std::option::Option<CommandErrorDto>,
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
// file: crates/ksp-app-solprices-desk/src/errors.rs
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
//! Application-local error codes for SOL Prices Desk scaffold and desktop runtime surfaces.
|
||||
//! Application-local error codes for SOL Prices Desk composition and desktop runtime surfaces.
|
||||
|
||||
/// Shared SOL Prices Desk application state is internally inconsistent.
|
||||
pub(crate) const ERROR_CODE_APP_STATE_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("solprices_desk", "app_state_invalid");
|
||||
/// Shared SOL Prices Desk runtime state cannot be locked safely.
|
||||
pub(crate) const ERROR_CODE_APP_STATE_LOCK_FAILED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("solprices_desk", "app_state_lock_failed");
|
||||
/// The SOL Prices Desk Config composite is missing or misroutes one required standard component.
|
||||
pub(crate) const ERROR_CODE_CONFIG_COMPOSITE_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("solprices_desk", "config_composite_invalid");
|
||||
/// Frontend logging requested an unsupported level.
|
||||
pub(crate) const ERROR_CODE_FRONTEND_LOG_LEVEL_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("solprices_desk", "frontend_log_level_invalid");
|
||||
/// Frontend logging requested a target outside the application whitelist.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-solprices-desk/src/lib.rs
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
//! Tauri desktop application scaffold for provider-neutral SOL/USD price visualization.
|
||||
|
||||
@@ -14,6 +14,7 @@ mod dto_common;
|
||||
mod errors;
|
||||
mod frontend_logging;
|
||||
mod logging_runtime;
|
||||
mod offchain_runtime;
|
||||
mod splash;
|
||||
mod tauri;
|
||||
mod tw_main;
|
||||
@@ -30,10 +31,20 @@ pub(crate) use self::bootstrap::LoggingStartup;
|
||||
pub(crate) use self::bootstrap::config_management;
|
||||
/// Initializes the scaffold Logging runtime from Config, with a bounded in-memory fallback.
|
||||
pub(crate) use self::bootstrap::initialize_logging;
|
||||
/// Loads the SOL Prices Desk composite selected by its registered logical file identifier.
|
||||
pub(crate) use self::bootstrap::load_solprices_desk_composite;
|
||||
/// Resolves one required standard Config profile from the SOL Prices Desk composite.
|
||||
pub(crate) use self::bootstrap::required_composite_component_profile;
|
||||
/// Composite-local identifier for the standard Logging component.
|
||||
pub(crate) use self::constants::COMPOSITE_COMPONENT_ID_LOGGING;
|
||||
/// Composite-local identifier for the standard Off-chain Transport component.
|
||||
pub(crate) use self::constants::COMPOSITE_COMPONENT_ID_OFFCHAIN_TRANSPORT;
|
||||
/// Structured domain used while bootstrapping Config and Logging.
|
||||
pub(crate) use self::constants::TRACING_DOMAIN_BOOTSTRAP;
|
||||
/// Structured domain used by technical frontend events.
|
||||
pub(crate) use self::constants::TRACING_DOMAIN_FRONTEND;
|
||||
/// Structured domain used by the Config-selected Off-chain Transport runtime.
|
||||
pub(crate) use self::constants::TRACING_DOMAIN_OFFCHAIN_TRANSPORT;
|
||||
/// Structured domain used by the SOL Prices Desk shell.
|
||||
pub(crate) use self::constants::TRACING_DOMAIN_SHELL;
|
||||
/// Structured domain used by Tauri window lifecycle operations.
|
||||
@@ -54,6 +65,8 @@ pub(crate) use self::dto_common::RuntimeStatusDto;
|
||||
pub(crate) use self::errors::ERROR_CODE_APP_STATE_INVALID;
|
||||
/// Shared SOL Prices Desk runtime state cannot be locked safely.
|
||||
pub(crate) use self::errors::ERROR_CODE_APP_STATE_LOCK_FAILED;
|
||||
/// The SOL Prices Desk Config composite is missing or misroutes a required component.
|
||||
pub(crate) use self::errors::ERROR_CODE_CONFIG_COMPOSITE_INVALID;
|
||||
/// Frontend logging requested an unsupported level.
|
||||
pub(crate) use self::errors::ERROR_CODE_FRONTEND_LOG_LEVEL_INVALID;
|
||||
/// Frontend logging requested a target outside the application whitelist.
|
||||
@@ -76,6 +89,10 @@ pub(crate) use self::frontend_logging::FrontendLogPayloadDto;
|
||||
pub(crate) use self::frontend_logging::emit_frontend_log_event;
|
||||
/// Creates the stable runtime identity for this SOL Prices Desk process launch.
|
||||
pub(crate) use self::logging_runtime::launch_identity;
|
||||
/// Resolved composite and Off-chain Transport configuration retained by SOL Prices Desk.
|
||||
pub(crate) use self::offchain_runtime::OffchainTransportStartup;
|
||||
/// Resolves the composite-selected Off-chain Transport profile and constructs the Config-owned service.
|
||||
pub(crate) use self::offchain_runtime::initialize_offchain_transport;
|
||||
/// Command emitted by Rust to the splash frontend.
|
||||
pub(crate) use self::splash::SplashOrderDto;
|
||||
/// Runtime timings used by the common desk splash lifecycle.
|
||||
|
||||
59
crates/ksp-app-solprices-desk/src/offchain_runtime.rs
Normal file
59
crates/ksp-app-solprices-desk/src/offchain_runtime.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
// file: crates/ksp-app-solprices-desk/src/offchain_runtime.rs
|
||||
// version: 1
|
||||
|
||||
//! Config-owned Off-chain Transport bootstrap for SOL Prices Desk.
|
||||
|
||||
/// Resolved SOL Prices Desk composite and Off-chain Transport configuration retained by application state.
|
||||
pub(crate) struct OffchainTransportStartup {
|
||||
composite_profile_id: String,
|
||||
resolved: ksp_config_lib::ResolvedOffchainTransportConfig,
|
||||
}
|
||||
|
||||
impl crate::OffchainTransportStartup {
|
||||
/// Returns the composite profile selected for this application launch.
|
||||
#[must_use]
|
||||
pub(crate) fn composite_profile_id(&self) -> &str {
|
||||
return self.composite_profile_id.as_str();
|
||||
}
|
||||
|
||||
/// Returns the Config-resolved Off-chain Transport runtime configuration.
|
||||
#[must_use]
|
||||
pub(crate) const fn resolved(&self) -> &ksp_config_lib::ResolvedOffchainTransportConfig {
|
||||
return &self.resolved;
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves the composite-selected Off-chain Transport profile and constructs the provider-neutral service owned by Config.
|
||||
pub(crate) fn initialize_offchain_transport(management: &ksp_config_lib::ConfigManagement) -> ksp_core_lib::Result<crate::OffchainTransportStartup> {
|
||||
let environment = ksp_config_lib::ConfigEnvironment::load();
|
||||
let environment = match environment {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let composite = crate::load_solprices_desk_composite(management);
|
||||
let composite = match composite {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let logging_profile = crate::required_composite_component_profile(&composite, crate::COMPOSITE_COMPONENT_ID_LOGGING, ksp_config_lib::FILE_ID_STD_LOGGING);
|
||||
if let std::result::Result::Err(error) = logging_profile {
|
||||
return std::result::Result::Err(error);
|
||||
}
|
||||
let offchain_profile = crate::required_composite_component_profile(
|
||||
&composite,
|
||||
crate::COMPOSITE_COMPONENT_ID_OFFCHAIN_TRANSPORT,
|
||||
ksp_config_lib::FILE_ID_STD_OFFCHAIN_TRANSPORT,
|
||||
);
|
||||
let offchain_profile = match offchain_profile {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let resolved = management.engine().resolve_offchain_transport_config_profile(&offchain_profile, &environment);
|
||||
let resolved = match resolved {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let provider_count = resolved.service().registry().len();
|
||||
ksp_logging_lib::info!(target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_OFFCHAIN_TRANSPORT, composite_profile = composite.profile_id(), offchain_profile = resolved.profile_id(), provider_count, "initialized SOL Prices Desk Off-chain Transport from composite-managed configuration");
|
||||
return std::result::Result::Ok(crate::OffchainTransportStartup { composite_profile_id: composite.profile_id().to_owned(), resolved });
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "KSP SOL Prices Desk",
|
||||
"version": "0.2.12-pre.2.fix.1",
|
||||
"version": "0.2.12-pre.3",
|
||||
"identifier": "com.sasedev.ksp-app-solprices-desk",
|
||||
"build": {
|
||||
"beforeDevCommand": {
|
||||
@@ -53,6 +53,7 @@
|
||||
"icons/favicon.ico"
|
||||
],
|
||||
"resources": {
|
||||
"../../config/composite.ksp-app-solprices-desk.json": "config/composite.ksp-app-solprices-desk.json",
|
||||
"../../config/composite.ksp-app-wallet-desk.json": "config/composite.ksp-app-wallet-desk.json",
|
||||
"../../config/std.logging.json": "config/std.logging.json",
|
||||
"../../config/std.offchain_transport.json": "config/std.offchain_transport.json",
|
||||
|
||||
94
crates/ksp-app-solprices-desk/tests/config_composition.rs
Normal file
94
crates/ksp-app-solprices-desk/tests/config_composition.rs
Normal file
@@ -0,0 +1,94 @@
|
||||
// file: crates/ksp-app-solprices-desk/tests/config_composition.rs
|
||||
// version: 1
|
||||
|
||||
//! Config composition contracts for SOL Prices Desk `0.2.12-pre.003`.
|
||||
|
||||
fn workspace_engine() -> ksp_core_lib::Result<ksp_config_lib::ConfigDocumentEngine> {
|
||||
let workspace = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..");
|
||||
let bootstrap = ksp_config_lib::ConfigBootstrapOptions::from_paths(workspace.join("config"), workspace.join("config/schemas"));
|
||||
let bootstrap = match bootstrap {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let registry = ksp_config_lib::ConfigFileRegistry::defaults();
|
||||
return match registry {
|
||||
std::result::Result::Ok(value) => std::result::Result::Ok(ksp_config_lib::ConfigDocumentEngine::new(bootstrap, value)),
|
||||
std::result::Result::Err(error) => std::result::Result::Err(error),
|
||||
};
|
||||
}
|
||||
|
||||
fn assert_component(composite: &ksp_config_lib::ResolvedConfigComposite, component_id: &str, file_id: &str, profile_id: &str) {
|
||||
let component = composite.component(component_id);
|
||||
assert!(component.is_some(), "missing component {component_id}");
|
||||
if let std::option::Option::Some(component) = component {
|
||||
assert_eq!(component.resolved().file_id().as_str(), file_id);
|
||||
assert_eq!(component.resolved().profile_id(), profile_id);
|
||||
assert_eq!(component.resolved().selection_source(), ksp_config_lib::ConfigProfileSelectionSource::Composite);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn solprices_desk_composite_profiles_select_logging_and_offchain_transport_by_file_id() {
|
||||
let engine = workspace_engine();
|
||||
assert!(engine.is_ok(), "workspace Config engine should be constructible: {engine:?}");
|
||||
let engine = match engine {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let file_id = ksp_config_lib::ConfigFileId::new(ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK);
|
||||
assert!(file_id.is_ok(), "SOL Prices Desk composite file_id should be valid: {file_id:?}");
|
||||
let file_id = match file_id {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
for (selection, expected_composite_profile, expected_offchain_profile) in [
|
||||
(std::option::Option::None, "public_keyless", "public_keyless"),
|
||||
(std::option::Option::Some("all_free"), "all_free", "all_free"),
|
||||
(std::option::Option::Some("tests"), "tests", "public_keyless"),
|
||||
] {
|
||||
let composite = engine.load_resolved_composite(&file_id, selection);
|
||||
assert!(composite.is_ok(), "committed SOL Prices Desk composite profile should resolve: {composite:?}");
|
||||
if let std::result::Result::Ok(composite) = composite {
|
||||
assert_eq!(composite.profile_id(), expected_composite_profile);
|
||||
assert_component(&composite, "logging", ksp_config_lib::FILE_ID_STD_LOGGING, "console_info");
|
||||
assert_component(&composite, "offchain_transport", ksp_config_lib::FILE_ID_STD_OFFCHAIN_TRANSPORT, expected_offchain_profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn solprices_desk_default_composite_builds_provider_neutral_offchain_service() {
|
||||
let engine = workspace_engine();
|
||||
let engine = match engine {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let file_id = ksp_config_lib::ConfigFileId::new(ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK);
|
||||
let file_id = match file_id {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let composite = engine.load_resolved_composite(&file_id, std::option::Option::None);
|
||||
let composite = match composite {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let component = composite.component("offchain_transport");
|
||||
let component = match component {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
let environment = ksp_config_lib::ConfigEnvironment::load();
|
||||
assert!(environment.is_ok(), "Config environment should load for the public_keyless profile: {environment:?}");
|
||||
let environment = match environment {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let resolved = engine.resolve_offchain_transport_config_profile(component.resolved(), &environment);
|
||||
assert!(resolved.is_ok(), "public_keyless composite-selected Off-chain Transport should map: {resolved:?}");
|
||||
if let std::result::Result::Ok(resolved) = resolved {
|
||||
assert_eq!(resolved.profile_id(), "public_keyless");
|
||||
assert_eq!(resolved.selection_source(), ksp_config_lib::ConfigProfileSelectionSource::Composite);
|
||||
assert_eq!(resolved.service().registry().len(), 8);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// file: crates/ksp-app-solprices-desk/tests/desktop_contract.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
//! Desktop scaffold and shared-template contract audits for SOL Prices Desk `0.2.12-pre.002` and its fixes.
|
||||
//! Desktop scaffold, shared-template and Config packaging contract audits for SOL Prices Desk `0.2.12`.
|
||||
|
||||
fn app_root() -> std::path::PathBuf {
|
||||
return std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
@@ -37,9 +37,9 @@ fn pre_002_shell_uses_reserved_ports_windows_and_owned_backend_paths() {
|
||||
let tauri = read_json(root.join("tauri.conf.json").as_path());
|
||||
assert_eq!(tauri.pointer("/productName").and_then(serde_json::Value::as_str), std::option::Option::Some("KSP SOL Prices Desk"));
|
||||
assert_eq!(tauri.pointer("/identifier").and_then(serde_json::Value::as_str), std::option::Option::Some("com.sasedev.ksp-app-solprices-desk"));
|
||||
assert_eq!(tauri.pointer("/version").and_then(serde_json::Value::as_str), std::option::Option::Some("0.2.12-pre.2.fix.1"));
|
||||
assert_eq!(tauri.pointer("/version").and_then(serde_json::Value::as_str), std::option::Option::Some("0.2.12-pre.3"));
|
||||
let package = read_json(root.join("package.json").as_path());
|
||||
assert_eq!(package.pointer("/version").and_then(serde_json::Value::as_str), std::option::Option::Some("0.2.12-pre.2.fix.1"));
|
||||
assert_eq!(package.pointer("/version").and_then(serde_json::Value::as_str), std::option::Option::Some("0.2.12-pre.3"));
|
||||
assert_eq!(tauri.pointer("/build/devUrl").and_then(serde_json::Value::as_str), std::option::Option::Some("http://localhost:1434"));
|
||||
assert_eq!(tauri.pointer("/build/beforeDevCommand/script").and_then(serde_json::Value::as_str), std::option::Option::Some("npm run dev"));
|
||||
assert_eq!(tauri.pointer("/build/beforeDevCommand/cwd").and_then(serde_json::Value::as_str), std::option::Option::Some("."));
|
||||
@@ -86,14 +86,17 @@ fn pre_002_package_is_mixed_lib_bin_and_frontend_is_scaffold_only() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_002_packaging_contains_current_ten_config_resources_only() {
|
||||
fn pre_003_packaging_contains_current_eleven_config_resources() {
|
||||
let root = app_root();
|
||||
let tauri = read_json(root.join("tauri.conf.json").as_path());
|
||||
let resources = tauri.pointer("/bundle/resources").and_then(serde_json::Value::as_object);
|
||||
assert!(resources.is_some());
|
||||
if let std::option::Option::Some(resources) = resources {
|
||||
assert_eq!(resources.len(), 10);
|
||||
assert!(!resources.contains_key("../../config/composite.ksp-app-solprices-desk.json"));
|
||||
assert_eq!(resources.len(), 11);
|
||||
assert_eq!(
|
||||
resources.get("../../config/composite.ksp-app-solprices-desk.json").and_then(serde_json::Value::as_str),
|
||||
std::option::Option::Some("config/composite.ksp-app-solprices-desk.json"),
|
||||
);
|
||||
assert!(resources.contains_key("../../config/std.offchain_transport.json"));
|
||||
assert!(resources.contains_key("../../config/schemas/std.offchain_transport.schema.json"));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// file: crates/ksp-app-solprices-desk/tests/desktop_security.rs
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
//! Security and ownership canaries for the non-functional SOL Prices Desk scaffold.
|
||||
//! Security, ownership and frontend instrumentation canaries for SOL Prices Desk.
|
||||
|
||||
fn app_root() -> std::path::PathBuf {
|
||||
return std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
@@ -69,7 +69,7 @@ fn pre_002_frontend_has_no_network_persistence_or_native_dialog_surface() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_002_tauri_commands_remain_centralized_and_price_runtime_is_absent() {
|
||||
fn pre_003_tauri_commands_remain_centralized_and_refresh_runtime_is_absent() {
|
||||
let root = app_root();
|
||||
let mut rust_files = std::vec::Vec::new();
|
||||
collect_files(root.join("src").as_path(), "rs", &mut rust_files);
|
||||
@@ -82,8 +82,25 @@ fn pre_002_tauri_commands_remain_centralized_and_price_runtime_is_absent() {
|
||||
} else {
|
||||
assert_eq!(count, 0, "{} declares a Tauri command outside tauri.rs", path.display());
|
||||
}
|
||||
assert!(!source.contains("MarketPriceService"), "{} advances market-price runtime before pre.003", path.display());
|
||||
assert!(!source.contains("MarketPriceRuntime"), "{} advances application price-state runtime before pre.004", path.display());
|
||||
assert!(!source.contains("refresh_market_price"), "{} advances refresh commands before their planned tranche", path.display());
|
||||
}
|
||||
assert_eq!(command_count, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_003_frontend_control_interactions_are_logged_without_business_values() {
|
||||
let root = app_root();
|
||||
let main = read_text(root.join("frontend/ts/main.ts").as_path());
|
||||
let invoke = read_text(root.join("frontend/ts/invoke.ts").as_path());
|
||||
assert!(main.contains(r#"button.addEventListener("click""#));
|
||||
assert!(main.contains("SOL Prices Desk navigation control clicked"));
|
||||
assert!(main.contains("frontendDebug"));
|
||||
assert!(main.contains("SOL Prices Desk view activated"));
|
||||
assert!(invoke.contains("Frontend IPC command requested"));
|
||||
assert!(invoke.contains("Frontend IPC command completed"));
|
||||
assert!(invoke.contains("frontendTrace"));
|
||||
for forbidden in ["JSON.stringify(status)", "JSON.stringify(payload)", "apiKey", "authorization"] {
|
||||
assert!(!main.contains(forbidden), "main frontend logging must not serialize business/secret values: {forbidden}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
"icons/favicon.ico"
|
||||
],
|
||||
"resources": {
|
||||
"../../config/composite.ksp-app-solprices-desk.json": "config/composite.ksp-app-solprices-desk.json",
|
||||
"../../config/composite.ksp-app-wallet-desk.json": "config/composite.ksp-app-wallet-desk.json",
|
||||
"../../config/std.logging.json": "config/std.logging.json",
|
||||
"../../config/std.offchain_transport.json": "config/std.offchain_transport.json",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-wallet-desk/tests/desktop_contract.rs
|
||||
// version: 23
|
||||
// version: 24
|
||||
|
||||
//! Desktop build, shell and Config-status contract audits for Wallet Desk.
|
||||
|
||||
@@ -472,7 +472,11 @@ fn pre_018_packaged_runtime_bundles_config_resources_and_keeps_wallet_desk_versi
|
||||
let resources = tauri.pointer("/bundle/resources").and_then(serde_json::Value::as_object);
|
||||
assert!(resources.is_some(), "packaged Wallet Desk Config resources map must exist");
|
||||
if let std::option::Option::Some(resources) = resources {
|
||||
assert_eq!(resources.len(), 10);
|
||||
assert_eq!(resources.len(), 11);
|
||||
assert_eq!(
|
||||
resources.get("../../config/composite.ksp-app-solprices-desk.json").and_then(serde_json::Value::as_str),
|
||||
std::option::Option::Some("config/composite.ksp-app-solprices-desk.json"),
|
||||
);
|
||||
assert_eq!(
|
||||
resources.get("../../config/composite.ksp-app-wallet-desk.json").and_then(serde_json::Value::as_str),
|
||||
std::option::Option::Some("config/composite.ksp-app-wallet-desk.json"),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-wallet-desk/tests/release_compliance.rs
|
||||
// version: 6
|
||||
// version: 7
|
||||
|
||||
//! Release-wide deterministic compliance canaries for Wallet Desk.
|
||||
|
||||
@@ -198,7 +198,7 @@ fn packaged_resources_include_only_registered_config_sources_and_schemas() {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
assert_eq!(resources.len(), 10);
|
||||
assert_eq!(resources.len(), 11);
|
||||
for (source, destination) in resources {
|
||||
let destination = destination.as_str();
|
||||
assert!(destination.is_some(), "resource destination must be textual");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-config-lib/src/lib.rs
|
||||
// version: 19
|
||||
// version: 20
|
||||
|
||||
#![warn(missing_docs)]
|
||||
#![deny(unreachable_pub)]
|
||||
@@ -150,6 +150,8 @@ pub use self::registry::ConfigFileId;
|
||||
pub use self::registry::ConfigFileKind;
|
||||
/// Registry of KSP-known logical Config files and their replaceable physical filenames.
|
||||
pub use self::registry::ConfigFileRegistry;
|
||||
/// Default physical filename for the SOL Prices Desk composite configuration document.
|
||||
pub use self::registry::DEFAULT_COMPOSITE_KSP_APP_SOLPRICES_DESK_FILENAME;
|
||||
/// Default physical filename for the Wallet Desk composite configuration document.
|
||||
pub use self::registry::DEFAULT_COMPOSITE_KSP_APP_WALLET_DESK_FILENAME;
|
||||
/// Default physical filename for the generic composite JSON Schema document.
|
||||
@@ -170,6 +172,8 @@ pub use self::registry::DEFAULT_STD_TRANSPORT_SCHEMA_FILENAME;
|
||||
pub use self::registry::DEFAULT_STD_WALLET_FILENAME;
|
||||
/// Default physical filename for the standard Wallet JSON Schema document.
|
||||
pub use self::registry::DEFAULT_STD_WALLET_SCHEMA_FILENAME;
|
||||
/// Logical file identifier for the SOL Prices Desk composite configuration document.
|
||||
pub use self::registry::FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK;
|
||||
/// Logical file identifier for the Wallet Desk composite configuration document.
|
||||
pub use self::registry::FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK;
|
||||
/// Logical file identifier for the generic composite JSON Schema document.
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// file: crates/ksp-config-lib/src/registry.rs
|
||||
// version: 11
|
||||
// version: 12
|
||||
|
||||
/// Bootstrap argument used to replace a known Config filename mapping.
|
||||
pub const ARG_FILE_MAP: &str = "--filemap";
|
||||
/// Default physical filename for the SOL Prices Desk composite configuration document.
|
||||
pub const DEFAULT_COMPOSITE_KSP_APP_SOLPRICES_DESK_FILENAME: &str = "composite.ksp-app-solprices-desk.json";
|
||||
/// Default physical filename for the Wallet Desk composite configuration document.
|
||||
pub const DEFAULT_COMPOSITE_KSP_APP_WALLET_DESK_FILENAME: &str = "composite.ksp-app-wallet-desk.json";
|
||||
/// Default physical filename for the generic composite JSON Schema document.
|
||||
@@ -23,6 +25,8 @@ pub const DEFAULT_STD_TRANSPORT_SCHEMA_FILENAME: &str = "std.transport.schema.js
|
||||
pub const DEFAULT_STD_WALLET_FILENAME: &str = "std.wallet.json";
|
||||
/// Default physical filename for the standard Wallet JSON Schema document.
|
||||
pub const DEFAULT_STD_WALLET_SCHEMA_FILENAME: &str = "std.wallet.schema.json";
|
||||
/// Logical file identifier for the SOL Prices Desk composite configuration document.
|
||||
pub const FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK: &str = "cfg.composite.ksp-app-solprices-desk";
|
||||
/// Logical file identifier for the Wallet Desk composite configuration document.
|
||||
pub const FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK: &str = "cfg.composite.ksp-app-wallet-desk";
|
||||
/// Logical file identifier for the generic composite JSON Schema document.
|
||||
@@ -148,13 +152,23 @@ pub struct ConfigFileRegistry {
|
||||
impl ConfigFileRegistry {
|
||||
/// Creates the registry containing the KSP default file mappings known in the current release.
|
||||
pub fn defaults() -> ksp_core_lib::Result<Self> {
|
||||
let composite = ConfigFileDescriptor::new(
|
||||
let solprices_composite = ConfigFileDescriptor::new(
|
||||
FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK,
|
||||
ConfigFileKind::Config,
|
||||
DEFAULT_COMPOSITE_KSP_APP_SOLPRICES_DESK_FILENAME,
|
||||
std::option::Option::Some(FILE_ID_SCHEMA_COMPOSITE),
|
||||
);
|
||||
let solprices_composite = match solprices_composite {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let wallet_composite = ConfigFileDescriptor::new(
|
||||
FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK,
|
||||
ConfigFileKind::Config,
|
||||
DEFAULT_COMPOSITE_KSP_APP_WALLET_DESK_FILENAME,
|
||||
std::option::Option::Some(FILE_ID_SCHEMA_COMPOSITE),
|
||||
);
|
||||
let composite = match composite {
|
||||
let wallet_composite = match wallet_composite {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
@@ -233,7 +247,8 @@ impl ConfigFileRegistry {
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
return crate::build_registry([
|
||||
composite,
|
||||
solprices_composite,
|
||||
wallet_composite,
|
||||
composite_schema,
|
||||
logging,
|
||||
logging_schema,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-config-lib/tests/ownership.rs
|
||||
// version: 7
|
||||
// version: 8
|
||||
|
||||
//! Workspace ownership audits for KSP application configuration boundaries.
|
||||
|
||||
@@ -262,6 +262,7 @@ fn workspace_crates_do_not_hardcode_config_managed_physical_files() {
|
||||
};
|
||||
for token in [
|
||||
"\".env\"",
|
||||
"\"composite.ksp-app-solprices-desk.json\"",
|
||||
"\"composite.ksp-app-wallet-desk.json\"",
|
||||
"\"composite.schema.json\"",
|
||||
"\"std.logging.json\"",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-config-lib/tests/public_api.rs
|
||||
// version: 24
|
||||
// version: 25
|
||||
|
||||
//! Integration tests for the public `ksp-config-lib` bootstrap, registry, JSON/profile/composite, environment-resolution, sensitivity,
|
||||
//! Logging/Transport adapters and management contracts.
|
||||
@@ -80,18 +80,19 @@ fn registry_descriptor_inventory_is_available_from_crate_root() {
|
||||
assert!(registry.is_ok(), "public registry should remain constructible: {registry:?}");
|
||||
if let std::result::Result::Ok(registry) = registry {
|
||||
let descriptors: std::vec::Vec<&ksp_config_lib::ConfigFileDescriptor> = registry.descriptors().collect();
|
||||
assert_eq!(descriptors.len(), 10);
|
||||
assert_eq!(descriptors[0].file_id().as_str(), ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK);
|
||||
assert_eq!(descriptors[1].file_id().as_str(), ksp_config_lib::FILE_ID_STD_LOGGING);
|
||||
assert_eq!(descriptors[2].file_id().as_str(), ksp_config_lib::FILE_ID_STD_OFFCHAIN_TRANSPORT);
|
||||
assert_eq!(descriptors[3].file_id().as_str(), ksp_config_lib::FILE_ID_STD_TRANSPORT);
|
||||
assert_eq!(descriptors[4].file_id().as_str(), ksp_config_lib::FILE_ID_STD_WALLET);
|
||||
assert_eq!(descriptors[5].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_COMPOSITE);
|
||||
assert_eq!(descriptors[6].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_LOGGING);
|
||||
assert_eq!(descriptors[7].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_OFFCHAIN_TRANSPORT);
|
||||
assert_eq!(descriptors[8].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_TRANSPORT);
|
||||
assert_eq!(descriptors[9].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_WALLET);
|
||||
let schema_file_id = descriptors[4].schema_file_id();
|
||||
assert_eq!(descriptors.len(), 11);
|
||||
assert_eq!(descriptors[0].file_id().as_str(), ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK);
|
||||
assert_eq!(descriptors[1].file_id().as_str(), ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK);
|
||||
assert_eq!(descriptors[2].file_id().as_str(), ksp_config_lib::FILE_ID_STD_LOGGING);
|
||||
assert_eq!(descriptors[3].file_id().as_str(), ksp_config_lib::FILE_ID_STD_OFFCHAIN_TRANSPORT);
|
||||
assert_eq!(descriptors[4].file_id().as_str(), ksp_config_lib::FILE_ID_STD_TRANSPORT);
|
||||
assert_eq!(descriptors[5].file_id().as_str(), ksp_config_lib::FILE_ID_STD_WALLET);
|
||||
assert_eq!(descriptors[6].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_COMPOSITE);
|
||||
assert_eq!(descriptors[7].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_LOGGING);
|
||||
assert_eq!(descriptors[8].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_OFFCHAIN_TRANSPORT);
|
||||
assert_eq!(descriptors[9].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_TRANSPORT);
|
||||
assert_eq!(descriptors[10].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_WALLET);
|
||||
let schema_file_id = descriptors[5].schema_file_id();
|
||||
assert!(schema_file_id.is_some(), "public Wallet descriptor should preserve schema association");
|
||||
if let std::option::Option::Some(schema_file_id) = schema_file_id {
|
||||
assert_eq!(schema_file_id.as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_WALLET);
|
||||
@@ -160,6 +161,8 @@ fn composite_schema_and_provenance_contracts_are_available_from_crate_root() {
|
||||
assert_eq!(descriptor.kind(), ksp_config_lib::ConfigFileKind::Schema);
|
||||
}
|
||||
}
|
||||
assert_eq!(ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK, "cfg.composite.ksp-app-solprices-desk");
|
||||
assert_eq!(ksp_config_lib::DEFAULT_COMPOSITE_KSP_APP_SOLPRICES_DESK_FILENAME, "composite.ksp-app-solprices-desk.json");
|
||||
assert_ne!(ksp_config_lib::ConfigProfileSelectionSource::Composite, ksp_config_lib::ConfigProfileSelectionSource::Explicit);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-config-lib/unit_tests/offchain_transport.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
const TEST_PAIR: &str = "Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE";
|
||||
|
||||
@@ -31,6 +31,45 @@ fn committed_public_keyless_profile_maps_all_eight_providers_without_secret_envi
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn committed_solprices_composite_preserves_offchain_profile_and_composite_provenance() {
|
||||
let engine = committed_engine();
|
||||
let engine = match engine {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let file_id = crate::ConfigFileId::new(crate::FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK);
|
||||
assert!(file_id.is_ok(), "SOL Prices Desk composite file_id should be valid: {file_id:?}");
|
||||
let file_id = match file_id {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let composite = engine.load_resolved_composite(&file_id, std::option::Option::None);
|
||||
assert!(composite.is_ok(), "committed SOL Prices Desk composite should resolve: {composite:?}");
|
||||
let composite = match composite {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(composite.profile_id(), "public_keyless");
|
||||
let component = composite.component("offchain_transport");
|
||||
assert!(component.is_some(), "SOL Prices Desk composite should expose offchain_transport");
|
||||
let component = match component {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
assert_eq!(component.resolved().file_id().as_str(), crate::FILE_ID_STD_OFFCHAIN_TRANSPORT);
|
||||
assert_eq!(component.resolved().profile_id(), "public_keyless");
|
||||
assert_eq!(component.resolved().selection_source(), crate::ConfigProfileSelectionSource::Composite);
|
||||
let environment = crate::ConfigEnvironment::from_maps(std::collections::BTreeMap::new(), std::collections::BTreeMap::new());
|
||||
let resolved = engine.resolve_offchain_transport_config_profile(component.resolved(), &environment);
|
||||
assert!(resolved.is_ok(), "composite-selected Off-chain Transport should map: {resolved:?}");
|
||||
if let std::result::Result::Ok(resolved) = resolved {
|
||||
assert_eq!(resolved.profile_id(), "public_keyless");
|
||||
assert_eq!(resolved.selection_source(), crate::ConfigProfileSelectionSource::Composite);
|
||||
assert_eq!(resolved.service().registry().len(), 8);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn committed_all_free_profile_requires_config_owned_secrets_and_public_pair_provenance() {
|
||||
let engine = committed_engine();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-config-lib/unit_tests/registry.rs
|
||||
// version: 9
|
||||
// version: 10
|
||||
|
||||
#[test]
|
||||
fn descriptors_expose_complete_registry_in_deterministic_file_id_order() {
|
||||
@@ -7,23 +7,25 @@ fn descriptors_expose_complete_registry_in_deterministic_file_id_order() {
|
||||
assert!(registry.is_ok(), "default registry should be valid: {registry:?}");
|
||||
if let std::result::Result::Ok(registry) = registry {
|
||||
let descriptors: std::vec::Vec<&crate::ConfigFileDescriptor> = registry.descriptors().collect();
|
||||
assert_eq!(descriptors.len(), 10);
|
||||
assert_eq!(descriptors[0].file_id().as_str(), crate::FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK);
|
||||
assert_eq!(descriptors[0].filename(), std::path::Path::new(crate::DEFAULT_COMPOSITE_KSP_APP_WALLET_DESK_FILENAME));
|
||||
assert_eq!(descriptors.len(), 11);
|
||||
assert_eq!(descriptors[0].file_id().as_str(), crate::FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK);
|
||||
assert_eq!(descriptors[0].filename(), std::path::Path::new(crate::DEFAULT_COMPOSITE_KSP_APP_SOLPRICES_DESK_FILENAME));
|
||||
assert_eq!(descriptors[0].schema_file_id().map(crate::ConfigFileId::as_str), std::option::Option::Some(crate::FILE_ID_SCHEMA_COMPOSITE));
|
||||
assert_eq!(descriptors[1].file_id().as_str(), crate::FILE_ID_STD_LOGGING);
|
||||
assert_eq!(descriptors[2].file_id().as_str(), crate::FILE_ID_STD_OFFCHAIN_TRANSPORT);
|
||||
assert_eq!(descriptors[3].file_id().as_str(), crate::FILE_ID_STD_TRANSPORT);
|
||||
assert_eq!(descriptors[4].file_id().as_str(), crate::FILE_ID_STD_WALLET);
|
||||
assert_eq!(descriptors[4].filename(), std::path::Path::new(crate::DEFAULT_STD_WALLET_FILENAME));
|
||||
assert_eq!(descriptors[4].schema_file_id().map(crate::ConfigFileId::as_str), std::option::Option::Some(crate::FILE_ID_SCHEMA_STD_WALLET));
|
||||
assert_eq!(descriptors[5].file_id().as_str(), crate::FILE_ID_SCHEMA_COMPOSITE);
|
||||
assert_eq!(descriptors[6].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_LOGGING);
|
||||
assert_eq!(descriptors[7].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_OFFCHAIN_TRANSPORT);
|
||||
assert_eq!(descriptors[8].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_TRANSPORT);
|
||||
assert_eq!(descriptors[9].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_WALLET);
|
||||
assert!(descriptors[0..5].iter().all(|descriptor| return descriptor.kind() == crate::ConfigFileKind::Config));
|
||||
assert!(descriptors[5..10].iter().all(|descriptor| return descriptor.kind() == crate::ConfigFileKind::Schema));
|
||||
assert_eq!(descriptors[1].file_id().as_str(), crate::FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK);
|
||||
assert_eq!(descriptors[1].filename(), std::path::Path::new(crate::DEFAULT_COMPOSITE_KSP_APP_WALLET_DESK_FILENAME));
|
||||
assert_eq!(descriptors[2].file_id().as_str(), crate::FILE_ID_STD_LOGGING);
|
||||
assert_eq!(descriptors[3].file_id().as_str(), crate::FILE_ID_STD_OFFCHAIN_TRANSPORT);
|
||||
assert_eq!(descriptors[4].file_id().as_str(), crate::FILE_ID_STD_TRANSPORT);
|
||||
assert_eq!(descriptors[5].file_id().as_str(), crate::FILE_ID_STD_WALLET);
|
||||
assert_eq!(descriptors[5].filename(), std::path::Path::new(crate::DEFAULT_STD_WALLET_FILENAME));
|
||||
assert_eq!(descriptors[5].schema_file_id().map(crate::ConfigFileId::as_str), std::option::Option::Some(crate::FILE_ID_SCHEMA_STD_WALLET));
|
||||
assert_eq!(descriptors[6].file_id().as_str(), crate::FILE_ID_SCHEMA_COMPOSITE);
|
||||
assert_eq!(descriptors[7].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_LOGGING);
|
||||
assert_eq!(descriptors[8].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_OFFCHAIN_TRANSPORT);
|
||||
assert_eq!(descriptors[9].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_TRANSPORT);
|
||||
assert_eq!(descriptors[10].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_WALLET);
|
||||
assert!(descriptors[0..6].iter().all(|descriptor| return descriptor.kind() == crate::ConfigFileKind::Config));
|
||||
assert!(descriptors[6..11].iter().all(|descriptor| return descriptor.kind() == crate::ConfigFileKind::Schema));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,24 +339,33 @@ fn absolute_fixture_path() -> std::path::PathBuf {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn defaults_register_generic_composite_schema_and_wallet_desk_runtime_composite() {
|
||||
fn defaults_register_generic_composite_schema_and_both_runtime_composites() {
|
||||
let registry = crate::ConfigFileRegistry::defaults();
|
||||
let schema_id = crate::ConfigFileId::new(crate::FILE_ID_SCHEMA_COMPOSITE);
|
||||
let runtime_id = crate::ConfigFileId::new(crate::FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK);
|
||||
let solprices_id = crate::ConfigFileId::new(crate::FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK);
|
||||
let wallet_id = crate::ConfigFileId::new(crate::FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK);
|
||||
assert!(registry.is_ok(), "default registry should be valid: {registry:?}");
|
||||
assert!(schema_id.is_ok(), "composite schema file_id should be valid: {schema_id:?}");
|
||||
assert!(runtime_id.is_ok(), "Wallet Desk composite runtime file_id should be valid: {runtime_id:?}");
|
||||
if let (std::result::Result::Ok(registry), std::result::Result::Ok(schema_id), std::result::Result::Ok(runtime_id)) = (registry, schema_id, runtime_id) {
|
||||
assert!(solprices_id.is_ok(), "SOL Prices Desk composite runtime file_id should be valid: {solprices_id:?}");
|
||||
assert!(wallet_id.is_ok(), "Wallet Desk composite runtime file_id should be valid: {wallet_id:?}");
|
||||
if let (std::result::Result::Ok(registry), std::result::Result::Ok(schema_id), std::result::Result::Ok(solprices_id), std::result::Result::Ok(wallet_id)) =
|
||||
(registry, schema_id, solprices_id, wallet_id)
|
||||
{
|
||||
let schema = registry.descriptor(&schema_id);
|
||||
let runtime = registry.descriptor(&runtime_id);
|
||||
let solprices = registry.descriptor(&solprices_id);
|
||||
let wallet = registry.descriptor(&wallet_id);
|
||||
assert!(schema.is_ok(), "generic composite schema should be registered: {schema:?}");
|
||||
assert!(runtime.is_ok(), "Wallet Desk runtime composite should be registered: {runtime:?}");
|
||||
if let (std::result::Result::Ok(schema), std::result::Result::Ok(runtime)) = (schema, runtime) {
|
||||
assert!(solprices.is_ok(), "SOL Prices Desk runtime composite should be registered: {solprices:?}");
|
||||
assert!(wallet.is_ok(), "Wallet Desk runtime composite should be registered: {wallet:?}");
|
||||
if let (std::result::Result::Ok(schema), std::result::Result::Ok(solprices), std::result::Result::Ok(wallet)) = (schema, solprices, wallet) {
|
||||
assert_eq!(schema.kind(), crate::ConfigFileKind::Schema);
|
||||
assert_eq!(schema.filename(), std::path::Path::new(crate::DEFAULT_COMPOSITE_SCHEMA_FILENAME));
|
||||
assert_eq!(runtime.kind(), crate::ConfigFileKind::Config);
|
||||
assert_eq!(runtime.filename(), std::path::Path::new(crate::DEFAULT_COMPOSITE_KSP_APP_WALLET_DESK_FILENAME));
|
||||
assert_eq!(runtime.schema_file_id(), std::option::Option::Some(&schema_id));
|
||||
assert_eq!(solprices.kind(), crate::ConfigFileKind::Config);
|
||||
assert_eq!(solprices.filename(), std::path::Path::new(crate::DEFAULT_COMPOSITE_KSP_APP_SOLPRICES_DESK_FILENAME));
|
||||
assert_eq!(solprices.schema_file_id(), std::option::Option::Some(&schema_id));
|
||||
assert_eq!(wallet.kind(), crate::ConfigFileKind::Config);
|
||||
assert_eq!(wallet.filename(), std::path::Path::new(crate::DEFAULT_COMPOSITE_KSP_APP_WALLET_DESK_FILENAME));
|
||||
assert_eq!(wallet.schema_file_id(), std::option::Option::Some(&schema_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user