v0.4.7-pre.013
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/src/demo_execution_metadata.rs
|
||||
// version: 2
|
||||
// version: 12
|
||||
|
||||
//! Thin desktop adapters for metadata execution demo scenarios.
|
||||
|
||||
@@ -13,8 +13,16 @@
|
||||
pub(crate) struct DemoExecutionMetadataScenarioPayload {
|
||||
/// Stable scenario identifier.
|
||||
pub id: std::string::String,
|
||||
/// Operator-visible scenario label.
|
||||
pub label: std::string::String,
|
||||
/// Stable asset-family code.
|
||||
pub asset_family: std::string::String,
|
||||
/// Stable fixture graph code.
|
||||
pub fixture_kind: std::string::String,
|
||||
/// Required initial lifecycle state.
|
||||
pub initial_state: std::string::String,
|
||||
/// Expected terminal lifecycle state.
|
||||
pub resulting_state: std::string::String,
|
||||
/// Stable execution-mode code.
|
||||
pub mode: std::string::String,
|
||||
/// Ordered operation codes.
|
||||
@@ -29,6 +37,486 @@ pub(crate) struct DemoExecutionMetadataScenarioPayload {
|
||||
pub validation_status: std::string::String,
|
||||
/// Required evidence kinds.
|
||||
pub required_evidence: std::vec::Vec<std::string::String>,
|
||||
/// Canonical account projections expected when materialization is enabled.
|
||||
pub materialization_targets: std::vec::Vec<std::string::String>,
|
||||
}
|
||||
|
||||
/// UI-safe result of one prepared Metaplex Create fixture.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, ts_rs::TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_app_demo_desktop/demo_execution_metadata/DemoExecutionMetadataCreateFixturePayload.ts"
|
||||
)]
|
||||
pub(crate) struct DemoExecutionMetadataCreateFixturePayload {
|
||||
/// Fixture mint address.
|
||||
pub mint: std::string::String,
|
||||
/// Canonical metadata PDA.
|
||||
pub metadata: std::string::String,
|
||||
/// Canonical master-edition PDA.
|
||||
pub master_edition: std::string::String,
|
||||
/// Wallet authority.
|
||||
pub authority: std::string::String,
|
||||
/// Generated typed Create operation JSON.
|
||||
pub operation_json: std::string::String,
|
||||
/// Whether the mint account was newly created.
|
||||
pub mint_created: bool,
|
||||
}
|
||||
|
||||
/// UI-safe prepared step for one coherent Metaplex Devnet scenario.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, ts_rs::TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_app_demo_desktop/demo_execution_metadata/DemoExecutionMetadataPreparedStepPayload.ts"
|
||||
)]
|
||||
pub(crate) struct DemoExecutionMetadataPreparedStepPayload {
|
||||
/// Stable scenario identifier.
|
||||
pub scenario_id: std::string::String,
|
||||
/// Zero-based step index.
|
||||
pub step_index: usize,
|
||||
/// Stable operation name accepted by the executor JSON contract.
|
||||
pub operation: std::string::String,
|
||||
/// Operator-visible step label.
|
||||
pub label: std::string::String,
|
||||
/// Prepared typed operation JSON.
|
||||
pub operation_json: std::string::String,
|
||||
/// Automatically generated bounded preflight reads.
|
||||
pub preflight_reads_json: std::string::String,
|
||||
/// Automatically generated bounded postcondition reads.
|
||||
pub postcondition_reads_json: std::string::String,
|
||||
/// Whether this step can be simulated immediately.
|
||||
pub simulation_ready: bool,
|
||||
/// Whether this step can be submitted immediately.
|
||||
pub submission_ready: bool,
|
||||
/// Fixture state used to prepare the step.
|
||||
pub fixture_state: std::string::String,
|
||||
}
|
||||
|
||||
/// Request for one real Devnet Metaplex execution from the desktop panel.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, ts_rs::TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_app_demo_desktop/demo_execution_metadata/DemoExecutionMetadataRequest.ts"
|
||||
)]
|
||||
pub(crate) struct DemoExecutionMetadataRequest {
|
||||
/// Devnet profile selected by the operator.
|
||||
pub profile_name: std::string::String,
|
||||
/// Stable execution identifier shown in diagnostics.
|
||||
pub intent_id: std::string::String,
|
||||
/// Serialized typed current Metaplex operation.
|
||||
pub operation_json: std::string::String,
|
||||
/// Serialized bounded preflight read requests.
|
||||
pub preflight_reads_json: std::string::String,
|
||||
/// Serialized bounded postcondition read requests.
|
||||
pub postcondition_reads_json: std::string::String,
|
||||
/// Whether signing and submission are explicitly requested.
|
||||
pub submit: bool,
|
||||
/// Explicit operator confirmation for submission.
|
||||
pub operator_confirmed: bool,
|
||||
/// Materializes confirmed Metaplex account snapshots after submission.
|
||||
pub materialize_after_confirmation: bool,
|
||||
}
|
||||
|
||||
/// UI-safe result of one real Devnet Metaplex execution.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, ts_rs::TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_app_demo_desktop/demo_execution_metadata/DemoExecutionMetadataSummaryPayload.ts"
|
||||
)]
|
||||
pub(crate) struct DemoExecutionMetadataSummaryPayload {
|
||||
/// Selected profile name.
|
||||
pub profile_name: std::string::String,
|
||||
/// Exact cluster code.
|
||||
pub cluster: std::string::String,
|
||||
/// Genesis hash observed from RPC.
|
||||
pub genesis_hash: std::string::String,
|
||||
/// Wallet public key used by the runner.
|
||||
pub wallet_public_key: std::string::String,
|
||||
/// Wallet balance before execution.
|
||||
pub balance_lamports: std::string::String,
|
||||
/// Whether the real RPC simulation succeeded.
|
||||
pub simulation_success: bool,
|
||||
/// Optional submitted signature.
|
||||
pub transaction_signature: std::option::Option<std::string::String>,
|
||||
/// Optional terminal confirmation status.
|
||||
pub confirmation_status: std::option::Option<std::string::String>,
|
||||
/// Exact prepared plan as formatted JSON.
|
||||
pub plan_json: std::string::String,
|
||||
/// Stateful preflight as formatted JSON.
|
||||
pub preflight_json: std::string::String,
|
||||
/// Real RPC simulation as formatted JSON.
|
||||
pub simulation_json: std::string::String,
|
||||
/// Before/after state and readiness diagnostics as formatted JSON.
|
||||
pub evidence_json: std::string::String,
|
||||
/// Whether post-confirmation account materialization was requested.
|
||||
pub materialization_requested: bool,
|
||||
/// Number of canonical post-confirmation snapshots materialized.
|
||||
pub materialized_snapshot_count: usize,
|
||||
}
|
||||
|
||||
/// Returns Devnet profile options dedicated to the Metadata execution panel.
|
||||
pub(crate) fn demo_execution_metadata_options(
|
||||
state: tauri::State<'_, crate::AppState>,
|
||||
) -> crate::DemoExecutionSolanaCoreOptionsPayload {
|
||||
return crate::demo_execution_solana_core_options(state);
|
||||
}
|
||||
|
||||
/// Executes one real Devnet Metaplex simulation or explicitly confirmed submission.
|
||||
pub(crate) async fn demo_execution_metadata_execute(
|
||||
app_handle: tauri::AppHandle,
|
||||
state: tauri::State<'_, crate::AppState>,
|
||||
request: crate::DemoExecutionMetadataRequest,
|
||||
) -> std::result::Result<crate::DemoExecutionMetadataSummaryPayload, std::string::String> {
|
||||
let acquire_result = state.demo_execution_solana_core_running().compare_exchange(
|
||||
false,
|
||||
true,
|
||||
std::sync::atomic::Ordering::AcqRel,
|
||||
std::sync::atomic::Ordering::Acquire,
|
||||
);
|
||||
if acquire_result.is_err() {
|
||||
return std::result::Result::Err("a Devnet execution is already running".to_string());
|
||||
}
|
||||
let _run_guard = crate::DemoExecutionSolanaCoreRunGuard {
|
||||
running: state.demo_execution_solana_core_running(),
|
||||
};
|
||||
state
|
||||
.demo_execution_solana_core_cancel_requested()
|
||||
.store(false, std::sync::atomic::Ordering::Release);
|
||||
let profile =
|
||||
match crate::select_devnet_profile(state.app_config(), request.profile_name.as_str()) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let http_pool = match kb_onchain_transport::HttpEndpointPool::from_profile(&profile) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error.to_string()),
|
||||
};
|
||||
let mut execution_request = match kb_pipeline_demo_scenarios::DevnetMetaplexTokenMetadataExecutionRequest::from_operation_json(
|
||||
request.intent_id,
|
||||
request.operation_json.as_str(),
|
||||
) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error.to_string()),
|
||||
};
|
||||
execution_request.preflight_reads =
|
||||
match parse_stateful_reads(request.preflight_reads_json.as_str()) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
execution_request.postcondition_reads =
|
||||
match parse_stateful_reads(request.postcondition_reads_json.as_str()) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
execution_request.submit = request.submit;
|
||||
execution_request.operator_confirmed = request.operator_confirmed;
|
||||
execution_request.materialize_after_confirmation = request.materialize_after_confirmation;
|
||||
if let std::result::Result::Err(error) = execution_request.validate() {
|
||||
return std::result::Result::Err(error.to_string());
|
||||
}
|
||||
let observer = crate::DemoExecutionSolanaCoreObserver {
|
||||
app_handle,
|
||||
cancel_requested: state.demo_execution_solana_core_cancel_requested(),
|
||||
};
|
||||
let workspace_root = crate::workspace_root_dir();
|
||||
let summary = match kb_pipeline_demo_scenarios::execute_devnet_metaplex_token_metadata(
|
||||
&http_pool,
|
||||
&profile,
|
||||
workspace_root.as_path(),
|
||||
&execution_request,
|
||||
&observer,
|
||||
)
|
||||
.await
|
||||
{
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error.to_string()),
|
||||
};
|
||||
let transaction_signature =
|
||||
summary.send_result.as_ref().map(|value| return value.signature.0.clone());
|
||||
let confirmation_status =
|
||||
summary.confirmation.as_ref().map(|value| return format!("{:?}", value.status));
|
||||
let evidence_json = crate::pretty_json(&serde_json::json!({
|
||||
"before": &summary.before,
|
||||
"readiness": &summary.readiness,
|
||||
"sendResult": &summary.send_result,
|
||||
"confirmation": &summary.confirmation,
|
||||
"after": &summary.after,
|
||||
"materializationRequested": summary.materialization_requested,
|
||||
"materializedSnapshots": &summary.materialized_snapshots
|
||||
}));
|
||||
return std::result::Result::Ok(crate::DemoExecutionMetadataSummaryPayload {
|
||||
profile_name: summary.profile_name,
|
||||
cluster: format!("{:?}", summary.cluster).to_lowercase(),
|
||||
genesis_hash: summary.genesis_hash,
|
||||
wallet_public_key: summary.wallet.public_key,
|
||||
balance_lamports: summary.balance_lamports.to_string(),
|
||||
simulation_success: summary.simulation.success,
|
||||
transaction_signature,
|
||||
confirmation_status,
|
||||
plan_json: crate::pretty_json(&summary.plan),
|
||||
preflight_json: crate::pretty_json(&summary.stateful_preflight),
|
||||
simulation_json: crate::pretty_json(&summary.simulation),
|
||||
evidence_json,
|
||||
materialization_requested: summary.materialization_requested,
|
||||
materialized_snapshot_count: summary.materialized_snapshots.len(),
|
||||
});
|
||||
}
|
||||
|
||||
fn parse_stateful_reads(
|
||||
value: &str,
|
||||
) -> std::result::Result<
|
||||
std::vec::Vec<kb_pipeline::MetaplexTokenMetadataStatefulReadRequest>,
|
||||
std::string::String,
|
||||
> {
|
||||
if value.trim().is_empty() {
|
||||
return std::result::Result::Ok(std::vec::Vec::new());
|
||||
}
|
||||
return match serde_json::from_str(value) {
|
||||
std::result::Result::Ok(parsed) => std::result::Result::Ok(parsed),
|
||||
std::result::Result::Err(error) => {
|
||||
std::result::Result::Err(format!("invalid Metaplex stateful reads JSON: {error}"))
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/// Creates or reuses the Devnet mint fixture used by the named Create scenario.
|
||||
pub(crate) async fn demo_execution_metadata_prepare_create_fixture(
|
||||
state: tauri::State<'_, crate::AppState>,
|
||||
profile_name: std::string::String,
|
||||
) -> std::result::Result<crate::DemoExecutionMetadataCreateFixturePayload, std::string::String> {
|
||||
let profile = match crate::select_devnet_profile(state.app_config(), profile_name.as_str()) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let configured = std::path::PathBuf::from(profile.wallet.wallet_dir.as_str());
|
||||
let wallet_dir = if configured.is_absolute() {
|
||||
configured
|
||||
} else {
|
||||
crate::workspace_root_dir().join(configured)
|
||||
};
|
||||
let http_pool = match kb_onchain_transport::HttpEndpointPool::from_profile(&profile) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error.to_string()),
|
||||
};
|
||||
let workspace_root = crate::workspace_root_dir();
|
||||
let summary = match kb_pipeline_demo_scenarios::prepare_metaplex_create_fixture(
|
||||
&http_pool,
|
||||
&profile,
|
||||
workspace_root.as_path(),
|
||||
&kb_pipeline_demo_scenarios::MetaplexCreateFixturePreparationOptions::new(wallet_dir),
|
||||
)
|
||||
.await
|
||||
{
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error.to_string()),
|
||||
};
|
||||
return std::result::Result::Ok(crate::DemoExecutionMetadataCreateFixturePayload {
|
||||
mint: summary.mint,
|
||||
metadata: summary.metadata,
|
||||
master_edition: summary.master_edition,
|
||||
authority: summary.authority,
|
||||
operation_json: summary.operation_json,
|
||||
mint_created: summary.mint_created,
|
||||
});
|
||||
}
|
||||
|
||||
/// Prepares one coherent scenario step and all of its stateful reads.
|
||||
pub(crate) async fn demo_execution_metadata_prepare_step(
|
||||
state: tauri::State<'_, crate::AppState>,
|
||||
profile_name: std::string::String,
|
||||
scenario_id: std::string::String,
|
||||
step_index: usize,
|
||||
previous_operation_json: std::option::Option<std::string::String>,
|
||||
) -> std::result::Result<crate::DemoExecutionMetadataPreparedStepPayload, std::string::String> {
|
||||
let scenario = kb_pipeline_demo_scenarios::metaplex_token_metadata_devnet_scenarios()
|
||||
.into_iter()
|
||||
.find(|candidate| return candidate.id == scenario_id);
|
||||
let scenario = match scenario {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => {
|
||||
return std::result::Result::Err(format!(
|
||||
"unknown Metaplex Devnet scenario `{scenario_id}`"
|
||||
));
|
||||
},
|
||||
};
|
||||
let operation_code = match scenario.operation_codes.get(step_index) {
|
||||
std::option::Option::Some(value) => value.clone(),
|
||||
std::option::Option::None => {
|
||||
return std::result::Result::Err(format!(
|
||||
"scenario `{}` has no step at index {step_index}",
|
||||
scenario.id
|
||||
));
|
||||
},
|
||||
};
|
||||
let operation_suffix = match operation_code.rsplit('.').next() {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => operation_code.as_str(),
|
||||
};
|
||||
let operation = if operation_suffix == "update" {
|
||||
"update_as_update_authority_v2".to_string()
|
||||
} else {
|
||||
operation_suffix.to_string()
|
||||
};
|
||||
if operation != "create" && operation != "update_as_update_authority_v2" {
|
||||
return std::result::Result::Err(format!(
|
||||
"scenario step `{operation}` is declared but its Devnet fixture builder is not implemented yet"
|
||||
));
|
||||
}
|
||||
let (fixture_mint, fixture_metadata, fixture_master_edition, operation_json, fixture_state) =
|
||||
if operation == "create" {
|
||||
let fixture =
|
||||
match crate::demo_execution_metadata_prepare_create_fixture(state, profile_name)
|
||||
.await
|
||||
{
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
(
|
||||
fixture.mint,
|
||||
fixture.metadata,
|
||||
fixture.master_edition,
|
||||
fixture.operation_json,
|
||||
if fixture.mint_created {
|
||||
"mint_prepared".to_string()
|
||||
} else {
|
||||
"mint_reused".to_string()
|
||||
},
|
||||
)
|
||||
} else {
|
||||
let previous = match previous_operation_json {
|
||||
std::option::Option::Some(value) if !value.trim().is_empty() => value,
|
||||
_ => {
|
||||
return std::result::Result::Err(
|
||||
"prepare and submit the Create step before preparing Update".to_string(),
|
||||
);
|
||||
},
|
||||
};
|
||||
let previous_value: serde_json::Value = match serde_json::from_str(previous.as_str()) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(format!(
|
||||
"invalid previous scenario operation JSON: {error}"
|
||||
));
|
||||
},
|
||||
};
|
||||
let string_field = |name: &str| -> std::result::Result<
|
||||
std::string::String,
|
||||
std::string::String,
|
||||
> {
|
||||
return match previous_value.get(name).and_then(serde_json::Value::as_str) {
|
||||
std::option::Option::Some(value) => std::result::Result::Ok(value.to_string()),
|
||||
std::option::Option::None => std::result::Result::Err(format!(
|
||||
"previous Create step does not contain `{name}`"
|
||||
)),
|
||||
};
|
||||
};
|
||||
let mint = match string_field("mint") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let metadata = match string_field("metadata") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let master_edition = match string_field("master_edition") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let authority = match string_field("authority") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let value = serde_json::json!({
|
||||
"operation": "update_as_update_authority_v2",
|
||||
"authority": authority.clone(),
|
||||
"mint": mint.clone(),
|
||||
"metadata": metadata.clone(),
|
||||
"edition": null,
|
||||
"token": null,
|
||||
"authorization_rules_program": null,
|
||||
"authorization_rules": null,
|
||||
"update_args": {
|
||||
"AsUpdateAuthorityV2": {
|
||||
"new_update_authority": null,
|
||||
"data": null,
|
||||
"primary_sale_happened": true,
|
||||
"is_mutable": null,
|
||||
"collection": "None",
|
||||
"collection_details": "None",
|
||||
"uses": "None",
|
||||
"rule_set": "None",
|
||||
"token_standard": null,
|
||||
"authorization_data": null
|
||||
}
|
||||
}
|
||||
});
|
||||
(
|
||||
mint,
|
||||
metadata,
|
||||
master_edition,
|
||||
crate::pretty_json(&value),
|
||||
"metadata_created".to_string(),
|
||||
)
|
||||
};
|
||||
let metadata_read = serde_json::json!({
|
||||
"query_role": "http_queries",
|
||||
"account": fixture_metadata.clone(),
|
||||
"kind": { "kind": "metadata" },
|
||||
"min_context_slot": null,
|
||||
"max_data_bytes": 65536
|
||||
});
|
||||
let edition_read = serde_json::json!({
|
||||
"query_role": "http_queries",
|
||||
"account": fixture_master_edition.clone(),
|
||||
"kind": { "kind": "edition", "mint": fixture_mint.clone() },
|
||||
"min_context_slot": null,
|
||||
"max_data_bytes": 65536
|
||||
});
|
||||
let preflight_reads = if operation == "create" {
|
||||
serde_json::json!([])
|
||||
} else {
|
||||
serde_json::json!([metadata_read.clone()])
|
||||
};
|
||||
let postcondition_reads = if operation == "create" {
|
||||
serde_json::json!([metadata_read, edition_read])
|
||||
} else {
|
||||
serde_json::json!([metadata_read])
|
||||
};
|
||||
return std::result::Result::Ok(crate::DemoExecutionMetadataPreparedStepPayload {
|
||||
scenario_id: scenario.id,
|
||||
step_index,
|
||||
operation: operation.clone(),
|
||||
label: format!("Étape {} — {}", step_index + 1, operation),
|
||||
operation_json,
|
||||
preflight_reads_json: crate::pretty_json(&preflight_reads),
|
||||
postcondition_reads_json: crate::pretty_json(&postcondition_reads),
|
||||
simulation_ready: true,
|
||||
submission_ready: true,
|
||||
fixture_state,
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns current operation names accepted by automatic Devnet campaigns.
|
||||
pub(crate) fn demo_execution_metadata_current_operations() -> std::vec::Vec<std::string::String> {
|
||||
return kb_pipeline_demo_scenarios::metaplex_token_metadata_current_operation_names()
|
||||
.iter()
|
||||
.map(|value| return (*value).to_string())
|
||||
.collect();
|
||||
}
|
||||
|
||||
/// Returns one generated typed JSON template for a named current operation.
|
||||
pub(crate) fn demo_execution_metadata_operation_template(
|
||||
operation: std::string::String,
|
||||
) -> std::result::Result<std::string::String, std::string::String> {
|
||||
return match kb_pipeline_demo_scenarios::metaplex_token_metadata_current_operation_json_template(
|
||||
operation.as_str(),
|
||||
) {
|
||||
std::result::Result::Ok(value) => std::result::Result::Ok(value),
|
||||
std::result::Result::Err(error) => std::result::Result::Err(error.to_string()),
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the canonical Metaplex scenario inventory for the desktop panel.
|
||||
@@ -68,7 +556,11 @@ pub(crate) fn demo_execution_metadata_scenarios() -> std::result::Result<
|
||||
};
|
||||
payloads.push(crate::DemoExecutionMetadataScenarioPayload {
|
||||
id: scenario.id,
|
||||
label: scenario.label,
|
||||
asset_family: asset_family_code(scenario.asset_family),
|
||||
fixture_kind: fixture_kind_code(scenario.fixture_kind),
|
||||
initial_state: fixture_state_code(scenario.initial_state),
|
||||
resulting_state: fixture_state_code(scenario.resulting_state),
|
||||
mode: scenario_mode_code(scenario.mode),
|
||||
operation_codes: scenario.operation_codes,
|
||||
requires_collection: scenario.requires_collection,
|
||||
@@ -76,6 +568,7 @@ pub(crate) fn demo_execution_metadata_scenarios() -> std::result::Result<
|
||||
requires_postcondition: scenario.requires_postcondition,
|
||||
validation_status,
|
||||
required_evidence,
|
||||
materialization_targets: scenario.materialization_targets,
|
||||
});
|
||||
}
|
||||
return std::result::Result::Ok(payloads);
|
||||
@@ -99,6 +592,18 @@ fn asset_family_code(
|
||||
};
|
||||
}
|
||||
|
||||
fn fixture_kind_code(
|
||||
value: kb_pipeline_demo_scenarios::MetaplexTokenMetadataFixtureKind,
|
||||
) -> std::string::String {
|
||||
return format!("{value:?}").to_lowercase();
|
||||
}
|
||||
|
||||
fn fixture_state_code(
|
||||
value: kb_pipeline_demo_scenarios::MetaplexTokenMetadataFixtureState,
|
||||
) -> std::string::String {
|
||||
return format!("{value:?}").to_lowercase();
|
||||
}
|
||||
|
||||
fn scenario_mode_code(
|
||||
value: kb_pipeline_demo_scenarios::MetaplexTokenMetadataScenarioMode,
|
||||
) -> std::string::String {
|
||||
@@ -154,7 +659,10 @@ mod tests {
|
||||
return;
|
||||
},
|
||||
};
|
||||
assert_eq!(payloads.len(), 10);
|
||||
let expected_count =
|
||||
kb_pipeline_demo_scenarios::metaplex_token_metadata_synthetic_scenarios().len()
|
||||
+ kb_pipeline_demo_scenarios::metaplex_token_metadata_devnet_scenarios().len();
|
||||
assert_eq!(payloads.len(), expected_count);
|
||||
assert!(payloads.iter().all(|payload| return !payload.operation_codes.is_empty()));
|
||||
assert!(payloads.iter().all(|payload| return payload.requires_postcondition));
|
||||
assert!(
|
||||
@@ -167,10 +675,41 @@ mod tests {
|
||||
.iter()
|
||||
.filter(|payload| return payload.mode == "network_simulation")
|
||||
.count(),
|
||||
5
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_stateful_reads_are_accepted() {
|
||||
let parsed = super::parse_stateful_reads(" ");
|
||||
assert!(parsed.is_ok());
|
||||
let values = match parsed {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
assert_eq!(std::option::Option::Some(error), std::option::Option::None);
|
||||
return;
|
||||
},
|
||||
};
|
||||
assert_eq!(values.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn metadata_frontend_contains_every_required_runtime_control() {
|
||||
let source = std::include_str!("../frontend/demo_execution_metadata.html");
|
||||
for id in [
|
||||
"metadataProfileSelect",
|
||||
"metadataDevnetScenarioSelect",
|
||||
"metadataStepSelect",
|
||||
"prepareMetadataScenarioStepButton",
|
||||
"metadataExecutionLogOutput",
|
||||
"metadataProfileHelp",
|
||||
"simulateMetadataButton",
|
||||
"submitMetadataButton",
|
||||
] {
|
||||
assert!(source.contains(format!("id=\"{id}\"").as_str()));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn programmable_and_collection_requirements_remain_explicit() {
|
||||
let payloads = match crate::demo_execution_metadata_scenarios() {
|
||||
@@ -180,13 +719,7 @@ mod tests {
|
||||
return;
|
||||
},
|
||||
};
|
||||
assert_eq!(payloads.iter().filter(|payload| return payload.requires_collection).count(), 2);
|
||||
assert_eq!(
|
||||
payloads
|
||||
.iter()
|
||||
.filter(|payload| return payload.requires_programmable_rules)
|
||||
.count(),
|
||||
2
|
||||
);
|
||||
assert!(payloads.iter().any(|payload| return payload.requires_collection));
|
||||
assert!(payloads.iter().any(|payload| return payload.requires_programmable_rules));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/src/lib.rs
|
||||
// version: 26
|
||||
// version: 29
|
||||
|
||||
//! Tauri desktop demo application for `khadhroony-bot3`.
|
||||
|
||||
@@ -127,8 +127,28 @@ pub(crate) use self::demo_devnet_common::DemoExecutionDevnetStoreReadinessPayloa
|
||||
pub(crate) use self::demo_devnet_common::devnet_store_readiness_payload;
|
||||
/// Serializes a diagnostic value to indented JSON without panicking.
|
||||
pub(crate) use self::demo_devnet_common::pretty_json;
|
||||
/// UI-safe result of one prepared Metaplex Create fixture.
|
||||
pub(crate) use self::demo_execution_metadata::DemoExecutionMetadataCreateFixturePayload;
|
||||
/// Prepared coherent Metaplex scenario step.
|
||||
pub(crate) use self::demo_execution_metadata::DemoExecutionMetadataPreparedStepPayload;
|
||||
/// Request for one real Devnet Metaplex execution from the desktop panel.
|
||||
pub(crate) use self::demo_execution_metadata::DemoExecutionMetadataRequest;
|
||||
/// UI-safe Metaplex scenario row.
|
||||
pub(crate) use self::demo_execution_metadata::DemoExecutionMetadataScenarioPayload;
|
||||
/// UI-safe result of one real Devnet Metaplex execution.
|
||||
pub(crate) use self::demo_execution_metadata::DemoExecutionMetadataSummaryPayload;
|
||||
/// Returns current Metaplex operation names accepted by Devnet campaigns.
|
||||
pub(crate) use self::demo_execution_metadata::demo_execution_metadata_current_operations;
|
||||
/// Executes one real Devnet Metaplex simulation or submission.
|
||||
pub(crate) use self::demo_execution_metadata::demo_execution_metadata_execute;
|
||||
/// Returns one generated operation JSON template.
|
||||
pub(crate) use self::demo_execution_metadata::demo_execution_metadata_operation_template;
|
||||
/// Returns Devnet profile options dedicated to the Metadata execution panel.
|
||||
pub(crate) use self::demo_execution_metadata::demo_execution_metadata_options;
|
||||
/// Creates or reuses the Devnet mint fixture used by the Create scenario.
|
||||
pub(crate) use self::demo_execution_metadata::demo_execution_metadata_prepare_create_fixture;
|
||||
/// Prepares one coherent scenario step and its automatic stateful reads.
|
||||
pub(crate) use self::demo_execution_metadata::demo_execution_metadata_prepare_step;
|
||||
/// Returns the canonical Metaplex scenario inventory for the desktop panel.
|
||||
pub(crate) use self::demo_execution_metadata::demo_execution_metadata_scenarios;
|
||||
/// Request sent by the Memo v4 Devnet execution panel.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/src/tauri.rs
|
||||
// version: 26
|
||||
// version: 30
|
||||
|
||||
//! Tauri runtime assembly and private command wrappers.
|
||||
|
||||
@@ -30,8 +30,24 @@ pub fn run() -> kb_core::Result<()> {
|
||||
let mut builder = tauri::Builder::default();
|
||||
builder = builder.manage(app_state);
|
||||
builder = builder.invoke_handler(tauri::generate_handler![
|
||||
demo_backfill_cancel,
|
||||
splash_frontend_ready,
|
||||
emit_frontend_log,
|
||||
load_project_readme,
|
||||
open_demo_config_window,
|
||||
load_demo_config,
|
||||
open_demo_http_window,
|
||||
demo_http_list_pool_clients,
|
||||
demo_http_options,
|
||||
demo_http_execute_request,
|
||||
open_demo_ws_window,
|
||||
demo_ws_list_pool_clients,
|
||||
demo_ws_options,
|
||||
demo_ws_status,
|
||||
demo_ws_connect,
|
||||
demo_ws_unsubscribe,
|
||||
demo_ws_disconnect,
|
||||
open_demo_backfill_window,
|
||||
demo_backfill_cancel,
|
||||
demo_backfill_options,
|
||||
demo_backfill_execute,
|
||||
open_demo_core_extraction_window,
|
||||
@@ -44,32 +60,6 @@ pub fn run() -> kb_core::Result<()> {
|
||||
demo_decode_replay_cancel,
|
||||
demo_decode_replay_diagnostics,
|
||||
demo_decode_replay_annotations,
|
||||
open_demo_execution_solana_core_window,
|
||||
demo_execution_devnet_prepare_profile,
|
||||
demo_execution_solana_core_options,
|
||||
demo_execution_solana_core_generate_recipient,
|
||||
demo_execution_solana_core_execute,
|
||||
demo_execution_spl_memo_execute,
|
||||
demo_execution_solana_core_cancel,
|
||||
demo_execution_spl_validation_scenarios,
|
||||
open_demo_execution_spl_window,
|
||||
open_demo_execution_metadata_window,
|
||||
demo_execution_metadata_scenarios,
|
||||
demo_execution_spl_token_execute,
|
||||
demo_spl_token_journal,
|
||||
demo_spl_ata_derive,
|
||||
demo_execution_spl_ata_execute,
|
||||
demo_spl_ata_journal,
|
||||
demo_execution_spl_token_2022_execute,
|
||||
demo_spl_token_2022_fixture,
|
||||
open_demo_config_window,
|
||||
load_demo_config,
|
||||
emit_frontend_log,
|
||||
load_project_readme,
|
||||
open_demo_http_window,
|
||||
demo_http_list_pool_clients,
|
||||
demo_http_options,
|
||||
demo_http_execute_request,
|
||||
open_demo_sql_diag_window,
|
||||
load_demo_sql_diag,
|
||||
open_demo_sql_pg_raw_window,
|
||||
@@ -82,14 +72,30 @@ pub fn run() -> kb_core::Result<()> {
|
||||
load_demo_sql_replay_transactions,
|
||||
load_demo_sql_replay_programs,
|
||||
load_demo_sql_replay_entities,
|
||||
open_demo_ws_window,
|
||||
demo_ws_list_pool_clients,
|
||||
demo_ws_options,
|
||||
demo_ws_status,
|
||||
demo_ws_connect,
|
||||
demo_ws_unsubscribe,
|
||||
demo_ws_disconnect,
|
||||
splash_frontend_ready,
|
||||
open_demo_execution_solana_core_window,
|
||||
demo_execution_devnet_prepare_profile,
|
||||
demo_execution_solana_core_options,
|
||||
demo_execution_solana_core_generate_recipient,
|
||||
demo_execution_solana_core_execute,
|
||||
demo_execution_spl_memo_execute,
|
||||
demo_execution_solana_core_cancel,
|
||||
demo_execution_spl_validation_scenarios,
|
||||
open_demo_execution_spl_window,
|
||||
demo_execution_spl_token_execute,
|
||||
demo_spl_token_journal,
|
||||
demo_spl_ata_derive,
|
||||
demo_execution_spl_ata_execute,
|
||||
demo_spl_ata_journal,
|
||||
demo_execution_spl_token_2022_execute,
|
||||
demo_spl_token_2022_fixture,
|
||||
open_demo_execution_metadata_window,
|
||||
demo_execution_metadata_scenarios,
|
||||
demo_execution_metadata_options,
|
||||
demo_execution_metadata_current_operations,
|
||||
demo_execution_metadata_operation_template,
|
||||
demo_execution_metadata_prepare_create_fixture,
|
||||
demo_execution_metadata_prepare_step,
|
||||
demo_execution_metadata_execute,
|
||||
]);
|
||||
builder = builder.on_window_event(|window, event| {
|
||||
if window.label() != "main" || !matches!(event, tauri::WindowEvent::Destroyed) {
|
||||
@@ -615,6 +621,13 @@ fn open_demo_execution_metadata_window(
|
||||
);
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn demo_execution_metadata_options(
|
||||
state: tauri::State<'_, crate::AppState>,
|
||||
) -> crate::DemoExecutionSolanaCoreOptionsPayload {
|
||||
return crate::demo_execution_metadata_options(state);
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn demo_execution_metadata_scenarios() -> std::result::Result<
|
||||
std::vec::Vec<crate::DemoExecutionMetadataScenarioPayload>,
|
||||
@@ -623,6 +636,53 @@ fn demo_execution_metadata_scenarios() -> std::result::Result<
|
||||
return crate::demo_execution_metadata_scenarios();
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn demo_execution_metadata_current_operations() -> std::vec::Vec<std::string::String> {
|
||||
return crate::demo_execution_metadata_current_operations();
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn demo_execution_metadata_operation_template(
|
||||
operation: std::string::String,
|
||||
) -> std::result::Result<std::string::String, std::string::String> {
|
||||
return crate::demo_execution_metadata_operation_template(operation);
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn demo_execution_metadata_prepare_create_fixture(
|
||||
state: tauri::State<'_, crate::AppState>,
|
||||
profile_name: std::string::String,
|
||||
) -> std::result::Result<crate::DemoExecutionMetadataCreateFixturePayload, std::string::String> {
|
||||
return crate::demo_execution_metadata_prepare_create_fixture(state, profile_name).await;
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn demo_execution_metadata_prepare_step(
|
||||
state: tauri::State<'_, crate::AppState>,
|
||||
profile_name: std::string::String,
|
||||
scenario_id: std::string::String,
|
||||
step_index: usize,
|
||||
previous_operation_json: std::option::Option<std::string::String>,
|
||||
) -> std::result::Result<crate::DemoExecutionMetadataPreparedStepPayload, std::string::String> {
|
||||
return crate::demo_execution_metadata_prepare_step(
|
||||
state,
|
||||
profile_name,
|
||||
scenario_id,
|
||||
step_index,
|
||||
previous_operation_json,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn demo_execution_metadata_execute(
|
||||
app_handle: tauri::AppHandle,
|
||||
state: tauri::State<'_, crate::AppState>,
|
||||
request: crate::DemoExecutionMetadataRequest,
|
||||
) -> std::result::Result<crate::DemoExecutionMetadataSummaryPayload, std::string::String> {
|
||||
return crate::demo_execution_metadata_execute(app_handle, state, request).await;
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn demo_execution_spl_token_execute(
|
||||
app_handle: tauri::AppHandle,
|
||||
|
||||
Reference in New Issue
Block a user