v0.1.0-pre.061
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
<!-- file: kb-app-demo-desktop/frontend/demo_backfill.html -->
|
||||
<!-- version: 6 -->
|
||||
<!-- version: 7 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||
<link rel="icon" href="imgs/favicon.png">
|
||||
<link rel="icon" href="imgs/logo.png">
|
||||
<link rel="stylesheet" href="sass/main.scss">
|
||||
<title>Khadhroony Bot3 — Backfill HTTP</title>
|
||||
</head>
|
||||
@@ -163,14 +163,14 @@
|
||||
<textarea class="form-control font-monospace app-log-output mb-4" id="backfillLogOutput" readonly="">Aucune campagne exécutée.</textarea>
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<h2 class="h5 mb-0">Résumé JSON</h2>
|
||||
<button class="btn btn-sm btn-outline-primary" id="copyBackfillSummaryButton" type="button">Copier</button>
|
||||
</div>
|
||||
<div class="app-json-viewer" id="backfillSummaryOutput"></div>
|
||||
<div class="app-json-viewer" id="backfillSummaryOutput">{"status":"idle","message":"Aucune campagne exécutée."}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="app-footer bg-dark text-light">
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<!-- file: kb-app-demo-desktop/frontend/demo_config.html -->
|
||||
<!-- version: 4 -->
|
||||
<!-- version: 5 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||
<link rel="icon" href="imgs/favicon.png">
|
||||
<link rel="icon" href="imgs/logo.png">
|
||||
<link rel="stylesheet" href="sass/main.scss">
|
||||
<title>Khadhroony Bot3 — Configuration</title>
|
||||
</head>
|
||||
@@ -47,7 +47,7 @@
|
||||
<div class="card shadow-sm border-0 h-100">
|
||||
<div class="card-body">
|
||||
<h2 class="h5 card-title mb-3">Configuration active</h2>
|
||||
<div id="activeProfileJson" class="app-json-viewer" class="app-config-box app-json-viewer mb-0">Chargement...</div>
|
||||
<div id="activeProfileJson" class="app-config-box app-json-viewer mb-0">Chargement...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -56,7 +56,7 @@
|
||||
<div class="card shadow-sm border-0 h-100">
|
||||
<div class="card-body">
|
||||
<h2 class="h5 card-title mb-3">Configuration complète</h2>
|
||||
<div id="fullConfigJson" class="app-json-viewer" class="app-config-box app-json-viewer mb-0">Chargement...</div>
|
||||
<div id="fullConfigJson" class="app-config-box app-json-viewer mb-0">Chargement...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -65,7 +65,7 @@
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<h2 class="h5 card-title mb-3">Schéma JSON embarqué</h2>
|
||||
<div id="schemaJson" class="app-json-viewer" class="app-config-box app-json-viewer mb-0">Chargement...</div>
|
||||
<div id="schemaJson" class="app-config-box app-json-viewer mb-0">Chargement...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<!-- file: kb-app-demo-desktop/frontend/demo_core_extraction.html -->
|
||||
<!-- version: 8 -->
|
||||
<!-- version: 10 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||
<link rel="icon" href="imgs/favicon.png">
|
||||
<link rel="icon" href="imgs/logo.png">
|
||||
<link rel="stylesheet" href="sass/main.scss">
|
||||
<title>Khadhroony Bot3 — Extraction canonical vers core</title>
|
||||
</head>
|
||||
@@ -122,7 +122,8 @@
|
||||
<div class="accordion-body">
|
||||
<p class="text-body-secondary">Sélectionne les transactions raw ayant déjà au moins une instruction core résolue pour ce programme. Ce mode sert aux replays après changement de version ou de hash.</p>
|
||||
<label class="form-label" for="coreExtractionProgramIdInput">Program ID</label>
|
||||
<input class="form-control font-monospace mb-3" id="coreExtractionProgramIdInput" />
|
||||
<input class="form-control font-monospace mb-3" id="coreExtractionProgramIdInput" list="coreExtractionProgramIdOptions" />
|
||||
<datalist id="coreExtractionProgramIdOptions"></datalist>
|
||||
<button class="btn btn-primary core-extraction-start-button" data-core-extraction-mode="program_id" type="button">Extraire par programme</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -141,7 +142,7 @@
|
||||
</div>
|
||||
<div class="col-12 col-xl-5">
|
||||
<h3 class="h6">Résumé JSON</h3>
|
||||
<textarea class="form-control font-monospace" data-json-viewer="true" id="coreExtractionSummaryOutput" readonly="" style="height: 28rem; overflow-y: auto;">Aucun résultat.</textarea>
|
||||
<textarea class="form-control font-monospace" data-json-viewer="true" id="coreExtractionSummaryOutput" readonly="" style="height: 28rem; overflow-y: auto;">{"status":"idle","message":"Aucun résultat."}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<!-- file: kb_app_demo/frontend/demo_decode_replay.html -->
|
||||
<!-- version: 6 -->
|
||||
<!-- version: 7 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||
<link rel="icon" href="imgs/favicon.png">
|
||||
<link rel="icon" href="imgs/logo.png">
|
||||
<link rel="stylesheet" href="sass/main.scss">
|
||||
<title>Khadhroony Bot3 — Décodage et matérialisation</title>
|
||||
</head>
|
||||
@@ -117,9 +117,9 @@
|
||||
<h2 class="h5">Journal</h2>
|
||||
<textarea id="decodeReplayLogOutput" class="form-control font-monospace mb-3" rows="14" readonly>Aucune campagne exécutée.</textarea>
|
||||
<h2 class="h5">Résumé</h2>
|
||||
<textarea id="decodeReplaySummaryOutput" class="form-control font-monospace mb-3" rows="15" readonly data-json-viewer="true">Aucun résultat.</textarea>
|
||||
<textarea id="decodeReplaySummaryOutput" class="form-control font-monospace mb-3" rows="15" readonly data-json-viewer="true">{"status":"idle","message":"Aucun résultat."}</textarea>
|
||||
<h2 class="h5">Diagnostics</h2>
|
||||
<textarea id="decodeReplayDiagnosticsOutput" class="form-control font-monospace" rows="18" readonly data-json-viewer="true">Diagnostics non chargés.</textarea>
|
||||
<textarea id="decodeReplayDiagnosticsOutput" class="form-control font-monospace" rows="18" readonly data-json-viewer="true">{"status":"idle","message":"Diagnostics non chargés."}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -139,7 +139,7 @@
|
||||
</div>
|
||||
<p id="annotationJournalStatus" class="text-body-secondary mb-3">Annotations non chargées.</p>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm table-hover align-middle mb-0">
|
||||
<table id="annotationJournalTable" class="table table-sm table-hover align-middle mb-0 w-100">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Slot</th>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<!-- file: kb-app-demo-desktop/frontend/demo_execution_solana_core.html -->
|
||||
<!-- version: 9 -->
|
||||
<!-- version: 10 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||
<link rel="icon" href="imgs/favicon.png">
|
||||
<link rel="icon" href="imgs/logo.png">
|
||||
<link rel="stylesheet" href="sass/main.scss">
|
||||
<title>Khadhroony Bot3 — Exécution Solana Core Devnet</title>
|
||||
</head>
|
||||
@@ -72,14 +72,14 @@
|
||||
<div class="col-12 col-xl-7">
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<h2 class="h5 mb-3">Résumé</h2><textarea class="form-control font-monospace" data-json-viewer="true" id="executionSummaryOutput" readonly="" rows="14">Aucun résultat.</textarea>
|
||||
<h2 class="h5 mb-3">Résumé</h2><textarea class="form-control font-monospace" data-json-viewer="true" id="executionSummaryOutput" readonly="" rows="14">{"status":"idle","message":"Aucun résultat."}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card shadow-sm border-0 mt-4">
|
||||
<div class="card-body">
|
||||
<h2 class="h5">Plan exact</h2><textarea class="form-control font-monospace" data-json-viewer="true" id="executionPlanOutput" readonly="" rows="12">Aucun plan.</textarea>
|
||||
<h2 class="h5 mt-3">Simulation exacte</h2><textarea class="form-control font-monospace" data-json-viewer="true" id="executionSimulationOutput" readonly="" rows="12">Aucune simulation.</textarea>
|
||||
<h2 class="h5 mt-3">Confirmation et replay</h2><textarea class="form-control font-monospace" data-json-viewer="true" id="executionDiagnosticsOutput" readonly="" rows="12">Aucun diagnostic.</textarea>
|
||||
<h2 class="h5">Plan exact</h2><textarea class="form-control font-monospace" data-json-viewer="true" id="executionPlanOutput" readonly="" rows="12">{"status":"idle","message":"Aucun plan."}</textarea>
|
||||
<h2 class="h5 mt-3">Simulation exacte</h2><textarea class="form-control font-monospace" data-json-viewer="true" id="executionSimulationOutput" readonly="" rows="12">{"status":"idle","message":"Aucune simulation."}</textarea>
|
||||
<h2 class="h5 mt-3">Confirmation et replay</h2><textarea class="form-control font-monospace" data-json-viewer="true" id="executionDiagnosticsOutput" readonly="" rows="12">{"status":"idle","message":"Aucun diagnostic."}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -87,6 +87,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="app-footer bg-dark text-light">
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<!-- file: kb-app-demo-desktop/frontend/demo_execution_spl.html -->
|
||||
<!-- version: 11 -->
|
||||
<!-- version: 14 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||
<link rel="icon" href="imgs/favicon.png">
|
||||
<link rel="icon" href="imgs/logo.png">
|
||||
<link rel="stylesheet" href="sass/main.scss">
|
||||
<title>Khadhroony Bot3 — Exécution SPL Devnet</title>
|
||||
</head>
|
||||
@@ -101,7 +101,7 @@
|
||||
<div class="accordion-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="memoMessageInput">Annotation UTF-8 exacte</label>
|
||||
<textarea class="form-control" id="memoMessageInput" maxlength="566" rows="5">khadhroony-bot2 Memo v4 validation</textarea>
|
||||
<textarea class="form-control" id="memoMessageInput" maxlength="566" rows="5">khadhroony-bot3 Memo v4 validation</textarea>
|
||||
<div class="form-text">566 octets UTF-8 maximum. La matérialisation `transaction_annotation` et le second replay d’idempotence sont obligatoires après envoi.</div>
|
||||
</div>
|
||||
<div class="form-check form-switch mb-3">
|
||||
@@ -168,7 +168,7 @@
|
||||
<label class="form-label" for="ataTokenProgramSelect">Token Program cible</label>
|
||||
<select class="form-select" id="ataTokenProgramSelect">
|
||||
<option value="classic">SPL Token classique</option>
|
||||
<option value="token2022">Token-2022</option>
|
||||
<option value="token_2022">Token-2022</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
@@ -205,31 +205,31 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="splToken2022DecoderHeading"><button aria-controls="splToken2022DecoderCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#splToken2022DecoderCollapse" data-bs-toggle="collapse" type="button"><span class="d-flex flex-wrap align-items-center justify-content-between gap-2 w-100 me-2"><span>Exécution spl_token2022 — scénarios publics</span><span class="badge text-bg-success">Exécutable</span></span></button></h2>
|
||||
<h2 class="accordion-header" id="splToken2022DecoderHeading"><button aria-controls="splToken2022DecoderCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#splToken2022DecoderCollapse" data-bs-toggle="collapse" type="button"><span class="d-flex flex-wrap align-items-center justify-content-between gap-2 w-100 me-2"><span>Exécution spl_token_2022 — scénarios publics</span><span class="badge text-bg-success">Exécutable</span></span></button></h2>
|
||||
<div aria-labelledby="splToken2022DecoderHeading" class="accordion-collapse collapse" data-bs-parent="#decoderExecutionAccordion" id="splToken2022DecoderCollapse">
|
||||
<div class="accordion-body">
|
||||
<div class="alert alert-info">Chaque opération est simulée sur le message exact avant toute signature. Les scénarios sont indépendants et réutilisent la fixture chargée dans les deux terminaux.</div>
|
||||
<div class="d-grid mb-3"><button class="btn btn-outline-secondary" id="loadToken2022FixtureButton" type="button">Charger la fixture Token-2022</button></div>
|
||||
<div class="form-text mb-3" id="token2022FixtureHelp">Aucune fixture chargée.</div>
|
||||
<div class="mb-3"><label class="form-label" for="token2022ScenarioSelect">Scénario</label><select class="form-select" id="token2022ScenarioSelect">
|
||||
<option value="token2022_mint_to_checked">MintToChecked</option>
|
||||
<option value="token2022_transfer_checked">TransferChecked</option>
|
||||
<option value="token2022_approve_checked">ApproveChecked</option>
|
||||
<option value="token2022_revoke">Revoke</option>
|
||||
<option value="token2022_burn_checked">BurnChecked</option>
|
||||
<option value="token2022_freeze_account">FreezeAccount</option>
|
||||
<option value="token2022_thaw_account">ThawAccount</option>
|
||||
<option value="token2022_close_destination">CloseAccount</option>
|
||||
<div class="form-text mb-3" id="token_2022FixtureHelp">Aucune fixture chargée.</div>
|
||||
<div class="mb-3"><label class="form-label" for="token_2022ScenarioSelect">Scénario</label><select class="form-select" id="token_2022ScenarioSelect">
|
||||
<option value="token_2022_mint_to_checked">MintToChecked</option>
|
||||
<option value="token_2022_transfer_checked">TransferChecked</option>
|
||||
<option value="token_2022_approve_checked">ApproveChecked</option>
|
||||
<option value="token_2022_revoke">Revoke</option>
|
||||
<option value="token_2022_burn_checked">BurnChecked</option>
|
||||
<option value="token_2022_freeze_account">FreezeAccount</option>
|
||||
<option value="token_2022_thaw_account">ThawAccount</option>
|
||||
<option value="token_2022_close_destination">CloseAccount</option>
|
||||
</select></div>
|
||||
<div class="mb-3"><label class="form-label" for="token2022SourceInput">Compte source / compte cible</label><input class="form-control font-monospace" id="token2022SourceInput" type="text" /></div>
|
||||
<div class="mb-3"><label class="form-label" for="token2022MintInput">Mint Token-2022</label><input class="form-control font-monospace" id="token2022MintInput" type="text" /></div>
|
||||
<div class="mb-3"><label class="form-label" for="token2022DestinationInput">Compte destination / destination lamports</label><input class="form-control font-monospace" id="token2022DestinationInput" type="text" /></div>
|
||||
<div class="mb-3"><label class="form-label" for="token2022DelegateInput">Delegate</label><input class="form-control font-monospace" id="token2022DelegateInput" type="text" /></div>
|
||||
<div class="mb-3"><label class="form-label" for="token2022AuthorityInput">Autorité</label><input class="form-control font-monospace" id="token2022AuthorityInput" type="text" /></div>
|
||||
<div class="mb-3"><label class="form-label" for="token2022FreezeAuthorityInput">Freeze authority</label><input class="form-control font-monospace" id="token2022FreezeAuthorityInput" type="text" /></div>
|
||||
<div class="mb-3"><label class="form-label" for="token_2022SourceInput">Compte source / compte cible</label><input class="form-control font-monospace" id="token_2022SourceInput" type="text" /></div>
|
||||
<div class="mb-3"><label class="form-label" for="token_2022MintInput">Mint Token-2022</label><input class="form-control font-monospace" id="token_2022MintInput" type="text" /></div>
|
||||
<div class="mb-3"><label class="form-label" for="token_2022DestinationInput">Compte destination / destination lamports</label><input class="form-control font-monospace" id="token_2022DestinationInput" type="text" /></div>
|
||||
<div class="mb-3"><label class="form-label" for="token_2022DelegateInput">Delegate</label><input class="form-control font-monospace" id="token_2022DelegateInput" type="text" /></div>
|
||||
<div class="mb-3"><label class="form-label" for="token_2022AuthorityInput">Autorité</label><input class="form-control font-monospace" id="token_2022AuthorityInput" type="text" /></div>
|
||||
<div class="mb-3"><label class="form-label" for="token_2022FreezeAuthorityInput">Freeze authority</label><input class="form-control font-monospace" id="token_2022FreezeAuthorityInput" type="text" /></div>
|
||||
<div class="row g-3 mb-3">
|
||||
<div class="col-8"><label class="form-label" for="token2022AmountInput">Montant brut</label><input class="form-control" id="token2022AmountInput" type="text" value="1" /></div>
|
||||
<div class="col-4"><label class="form-label" for="token2022DecimalsInput">Décimales</label><input class="form-control" id="token2022DecimalsInput" max="255" min="0" type="number" value="9" /></div>
|
||||
<div class="col-8"><label class="form-label" for="token_2022AmountInput">Montant brut</label><input class="form-control" id="token_2022AmountInput" type="text" value="1" /></div>
|
||||
<div class="col-4"><label class="form-label" for="token_2022DecimalsInput">Décimales</label><input class="form-control" id="token_2022DecimalsInput" max="255" min="0" type="number" value="9" /></div>
|
||||
</div>
|
||||
<div class="d-grid gap-2 d-md-flex">
|
||||
<button class="btn btn-outline-primary flex-fill" id="simulateToken2022Button" type="button">Préflight et simuler</button>
|
||||
@@ -269,7 +269,7 @@
|
||||
</h2>
|
||||
<div class="accordion-collapse collapse" data-bs-parent="#executionDetailsAccordion" id="executionPlanCollapse">
|
||||
<div class="accordion-body">
|
||||
<textarea class="form-control font-monospace" data-json-viewer="true" id="executionPlanOutput" readonly="" rows="16">Aucun plan.</textarea>
|
||||
<textarea class="form-control font-monospace" data-json-viewer="true" id="executionPlanOutput" readonly="" rows="16">{"status":"idle","message":"Aucun plan."}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -279,7 +279,7 @@
|
||||
</h2>
|
||||
<div class="accordion-collapse collapse" data-bs-parent="#executionDetailsAccordion" id="executionSimulationCollapse">
|
||||
<div class="accordion-body">
|
||||
<textarea class="form-control font-monospace" data-json-viewer="true" id="executionSimulationOutput" readonly="" rows="16">Aucune simulation.</textarea>
|
||||
<textarea class="form-control font-monospace" data-json-viewer="true" id="executionSimulationOutput" readonly="" rows="16">{"status":"idle","message":"Aucune simulation."}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -289,7 +289,7 @@
|
||||
</h2>
|
||||
<div class="accordion-collapse collapse" data-bs-parent="#executionDetailsAccordion" id="executionDiagnosticsCollapse">
|
||||
<div class="accordion-body">
|
||||
<textarea class="form-control font-monospace" data-json-viewer="true" id="executionDiagnosticsOutput" readonly="" rows="16">Aucun diagnostic.</textarea>
|
||||
<textarea class="form-control font-monospace" data-json-viewer="true" id="executionDiagnosticsOutput" readonly="" rows="16">{"status":"idle","message":"Aucun diagnostic."}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -411,7 +411,7 @@
|
||||
<div class="card shadow-sm border-0 mt-4">
|
||||
<div class="card-body">
|
||||
<h2 class="h5 mb-3">Résumé</h2>
|
||||
<textarea class="form-control font-monospace" data-json-viewer="true" id="executionSummaryOutput" readonly="" rows="14">Aucun résultat.</textarea>
|
||||
<textarea class="form-control font-monospace" data-json-viewer="true" id="executionSummaryOutput" readonly="" rows="14">{"status":"idle","message":"Aucun résultat."}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card shadow-sm border-0 mt-4">
|
||||
@@ -427,6 +427,7 @@
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="app-footer bg-dark text-light">
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<!-- file: kb-app-demo-desktop/frontend/demo_http.html -->
|
||||
<!-- version: 6 -->
|
||||
<!-- version: 7 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||
<link rel="icon" href="imgs/favicon.png">
|
||||
<link rel="icon" href="imgs/logo.png">
|
||||
<link rel="stylesheet" href="sass/main.scss">
|
||||
<title>Khadhroony Bot3 — HTTP JSON-RPC</title>
|
||||
</head>
|
||||
@@ -61,23 +61,17 @@
|
||||
<div class="col-12 col-xl-7">
|
||||
<div class="card shadow-sm border-0 mb-4">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<h2 class="h5 card-title mb-0">Endpoints HTTP</h2>
|
||||
<button id="copyHttpPoolButton" class="btn btn-sm btn-outline-secondary">Copier</button>
|
||||
</div>
|
||||
<textarea id="httpPoolOutput" class="form-control font-monospace" rows="10" readonly>Chargement...</textarea>
|
||||
<h2 class="h5 card-title">Endpoints HTTP</h2>
|
||||
<div id="httpPoolOutput" class="app-json-viewer">{"status":"loading","message":"Chargement des endpoints HTTP."}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<h2 class="h5 card-title mb-0">Résultat</h2>
|
||||
<div class="d-flex gap-2">
|
||||
<button id="copyHttpResultButton" class="btn btn-sm btn-outline-secondary" type="button">Copier</button>
|
||||
<button id="clearHttpResultButton" class="btn btn-sm btn-outline-secondary" type="button">Effacer</button>
|
||||
</div>
|
||||
<button id="clearHttpResultButton" class="btn btn-sm btn-outline-secondary" type="button">Effacer</button>
|
||||
</div>
|
||||
<textarea id="httpResultOutput" class="form-control font-monospace" style="height: 24rem; overflow-y: auto;" readonly>Aucune requête exécutée.</textarea>
|
||||
<div id="httpResultOutput" class="app-json-viewer">{"status":"idle","message":"Aucune requête exécutée."}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<!-- file: kb_app_demo/frontend/demo_sql_diag.html -->
|
||||
<!-- version: 3 -->
|
||||
<!-- version: 4 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||
<link rel="icon" href="imgs/favicon.png">
|
||||
<link rel="icon" href="imgs/logo.png">
|
||||
<link rel="stylesheet" href="sass/main.scss">
|
||||
<title>Khadhroony Bot3 — SQL diagnostics</title>
|
||||
</head>
|
||||
@@ -64,7 +64,7 @@
|
||||
<div class="card-body">
|
||||
<h2 class="h5 card-title mb-3">Tables raw/core connues</h2>
|
||||
<div class="table-responsive app-table-full-width">
|
||||
<table class="table table-sm align-middle mb-0">
|
||||
<table class="table table-sm align-middle mb-0" id="sqlDiagTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Table</th>
|
||||
@@ -88,7 +88,7 @@
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<h2 class="h5 card-title mb-3">Payload JSON</h2>
|
||||
<div id="sqlDiagJson" class="app-config-box app-json-viewer mb-0">Chargement...</div>
|
||||
<div id="sqlDiagJson" class="app-config-box app-json-viewer mb-0">{"status":"loading","message":"Chargement des données SQL."}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<!-- file: kb_app_demo/frontend/demo_sql_pg_core.html -->
|
||||
<!-- version: 4 -->
|
||||
<!-- version: 5 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||
<link rel="icon" href="imgs/favicon.png">
|
||||
<link rel="icon" href="imgs/logo.png">
|
||||
<link rel="stylesheet" href="sass/main.scss">
|
||||
<title>Khadhroony Bot3 — PostgreSQL core store</title>
|
||||
</head>
|
||||
@@ -51,7 +51,7 @@
|
||||
<div class="card-body">
|
||||
<h2 class="h5 card-title mb-3">Tables core</h2>
|
||||
<div class="table-responsive app-table-full-width">
|
||||
<table class="table table-sm align-middle mb-0">
|
||||
<table class="table table-sm align-middle mb-0" id="sqlCoreTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Table</th>
|
||||
@@ -75,7 +75,7 @@
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<h2 class="h5 card-title mb-3">Payload JSON</h2>
|
||||
<div id="sqlCoreJson" class="app-config-box app-json-viewer mb-0">Chargement...</div>
|
||||
<div id="sqlCoreJson" class="app-config-box app-json-viewer mb-0">{"status":"loading","message":"Chargement des données SQL."}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<!-- file: kb_app_demo/frontend/demo_sql_pg_raw.html -->
|
||||
<!-- version: 5 -->
|
||||
<!-- version: 6 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||
<link rel="icon" href="imgs/favicon.png">
|
||||
<link rel="icon" href="imgs/logo.png">
|
||||
<link rel="stylesheet" href="sass/main.scss">
|
||||
<title>Khadhroony Bot3 — PostgreSQL canonical acquisition</title>
|
||||
</head>
|
||||
@@ -51,7 +51,7 @@
|
||||
<div class="card-body">
|
||||
<h2 class="h5 card-title mb-3">Transactions canoniques et observations</h2>
|
||||
<div class="table-responsive app-table-full-width">
|
||||
<table class="table table-sm align-middle mb-0">
|
||||
<table class="table table-sm align-middle mb-0" id="sqlRawTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Table</th>
|
||||
@@ -75,7 +75,7 @@
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<h2 class="h5 card-title mb-3">Payload JSON</h2>
|
||||
<div id="sqlRawJson" class="app-config-box app-json-viewer mb-0">Chargement...</div>
|
||||
<div id="sqlRawJson" class="app-config-box app-json-viewer mb-0">{"status":"loading","message":"Chargement des données SQL."}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<!-- file: kb_app_demo/frontend/demo_sql_replay_candidates.html -->
|
||||
<!-- version: 8 -->
|
||||
<!-- version: 9 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||
<link rel="icon" href="imgs/favicon.png">
|
||||
<link rel="icon" href="imgs/logo.png">
|
||||
<link rel="stylesheet" href="sass/main.scss">
|
||||
<title>Khadhroony Bot3 — Candidats de replay SQL</title>
|
||||
</head>
|
||||
@@ -431,6 +431,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="app-footer bg-dark text-light">
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<!-- file: kb-app-demo-desktop/frontend/demo_ws.html -->
|
||||
<!-- version: 8 -->
|
||||
<!-- version: 9 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||
<link rel="icon" href="imgs/favicon.png">
|
||||
<link rel="icon" href="imgs/logo.png">
|
||||
<link rel="stylesheet" href="sass/main.scss">
|
||||
<title>Khadhroony Bot3 — WebSocket standard</title>
|
||||
</head>
|
||||
@@ -73,16 +73,13 @@
|
||||
<h2 class="h5 card-title mb-0">Statut</h2>
|
||||
<span id="wsStatusBadge" class="badge text-bg-secondary">Déconnecté</span>
|
||||
</div>
|
||||
<textarea id="wsStatusOutput" class="form-control font-monospace" rows="6" readonly>Déconnecté.</textarea>
|
||||
<div id="wsStatusOutput" class="app-json-viewer">{"connected":false,"subscriptionCount":0,"subscriptions":[]}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card shadow-sm border-0 mb-4">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<h2 class="h5 card-title mb-0">Endpoints WebSocket</h2>
|
||||
<button id="copyWsPoolButton" class="btn btn-sm btn-outline-secondary">Copier</button>
|
||||
</div>
|
||||
<textarea id="wsPoolOutput" class="form-control font-monospace" rows="8" readonly>Chargement...</textarea>
|
||||
<h2 class="h5 card-title">Endpoints WebSocket</h2>
|
||||
<div id="wsPoolOutput" class="app-json-viewer">{"status":"loading","message":"Chargement des endpoints WebSocket."}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card shadow-sm border-0">
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<!-- file: kb-app-demo-desktop/frontend/main.html -->
|
||||
<!-- version: 8 -->
|
||||
<!-- version: 9 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||
<link rel="icon" href="imgs/favicon.png">
|
||||
<link rel="icon" href="imgs/logo.png">
|
||||
<link rel="stylesheet" href="sass/main.scss">
|
||||
<title>Khadhroony Bot3 — Main Window</title>
|
||||
</head>
|
||||
|
||||
@@ -339,7 +339,7 @@ video#vbackground:not([playsinline]) {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.app-json-viewer andypf-json-viewer {
|
||||
.app-json-viewer .app-json-viewer-element {
|
||||
display: block;
|
||||
min-width: 100%;
|
||||
}
|
||||
@@ -394,7 +394,7 @@ video#vbackground:not([playsinline]) {
|
||||
background: var(--bs-body-bg);
|
||||
}
|
||||
|
||||
.app-json-viewer > andypf-json-viewer {
|
||||
.app-json-viewer > .app-json-viewer-element {
|
||||
display: block;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb_demo_app/frontend/sass/_bootswatch.scss
|
||||
// version: 1
|
||||
// file: kb-app-demo-desktop/frontend/sass/_bootswatch.scss
|
||||
// version: 2
|
||||
|
||||
// Pulse 5.3.8
|
||||
// Bootswatch
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb_demo_app/frontend/sass/_fontawesome.scss
|
||||
// version: 1
|
||||
// file: kb-app-demo-desktop/frontend/sass/_fontawesome.scss
|
||||
// version: 2
|
||||
|
||||
//@use '@fortawesome/fontawesome-free/scss/variables' with (
|
||||
// // customizing $font-path - make sure it points to where your webfonts are stored in your project
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb_demo_app/frontend/sass/_simplebar.scss
|
||||
// version: 1
|
||||
// file: kb-app-demo-desktop/frontend/sass/_simplebar.scss
|
||||
// version: 2
|
||||
|
||||
/* Rtl support */
|
||||
[data-simplebar] {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb_demo_app/frontend/sass/_variables.scss
|
||||
// version: 1
|
||||
// file: kb-app-demo-desktop/frontend/sass/_variables.scss
|
||||
// version: 2
|
||||
|
||||
// Pulse 5.3.8
|
||||
// Bootswatch
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/frontend/sass/main.scss
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
@import "bootstrap/scss/functions";
|
||||
@import "variables";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb_app_demo/frontend/sass/splash.scss
|
||||
// version: 4
|
||||
// file: kb-app-demo-desktop/frontend/sass/splash.scss
|
||||
// version: 5
|
||||
|
||||
@font-face {
|
||||
font-family: 'Dos Amazigh';
|
||||
|
||||
@@ -252,19 +252,17 @@ function renderBackfillSummary(value: unknown): void {
|
||||
}
|
||||
container.textContent = "";
|
||||
const viewer = document.createElement("andypf-json-viewer");
|
||||
viewer.classList.add("app-json-viewer-element");
|
||||
viewer.setAttribute("indent", "2");
|
||||
viewer.setAttribute("expanded", "1");
|
||||
viewer.setAttribute("theme", "default-light");
|
||||
viewer.setAttribute("show-data-types", "true");
|
||||
viewer.setAttribute("show-toolbar", "false");
|
||||
viewer.setAttribute("show-copy", "true");
|
||||
viewer.setAttribute("data", JSON.stringify(value ?? { status: "Aucun résultat" }, null, 2));
|
||||
viewer.setAttribute("data", JSON.stringify(value ?? { status: "idle", message: "Aucune campagne exécutée." }, null, 2));
|
||||
container.appendChild(viewer);
|
||||
}
|
||||
|
||||
async function copyText(value: string): Promise<void> {
|
||||
await navigator.clipboard.writeText(value);
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
installFrontendConsoleBridge("kb-app-demo-desktop.frontend.backfill");
|
||||
@@ -298,9 +296,5 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
frontendError("kb-app-demo-desktop.frontend.backfill", `Options loading failed: ${message}`);
|
||||
});
|
||||
|
||||
document.querySelector<HTMLButtonElement>("#copyBackfillSummaryButton")?.addEventListener("click", async () => {
|
||||
const value = document.querySelector("#backfillSummaryOutput andypf-json-viewer")?.getAttribute("data") ?? "";
|
||||
await copyText(value);
|
||||
});
|
||||
renderBackfillSummary(null);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_core_extraction.ts
|
||||
// version: 5
|
||||
// version: 6
|
||||
|
||||
import * as bootstrap from "bootstrap";
|
||||
import "simplebar";
|
||||
@@ -143,6 +143,13 @@ async function loadOptions(): Promise<void> {
|
||||
element<HTMLElement>("#coreExtractionVersionBadge").textContent = `Version ${options.processorVersion}`;
|
||||
element<HTMLInputElement>("#coreExtractionLimitInput").value = String(options.defaultLimit);
|
||||
element<HTMLInputElement>("#coreExtractionConcurrencyInput").value = String(options.defaultMaxConcurrentExtractions);
|
||||
const programOptions = element<HTMLDataListElement>("#coreExtractionProgramIdOptions");
|
||||
programOptions.replaceChildren(...options.programs.map(program => {
|
||||
const option = document.createElement("option");
|
||||
option.value = program.programId;
|
||||
option.label = program.code;
|
||||
return option;
|
||||
}));
|
||||
setRunning(options.running);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_decode_replay.ts
|
||||
// version: 6
|
||||
// version: 7
|
||||
|
||||
import * as bootstrap from "bootstrap";
|
||||
import "simplebar";
|
||||
import ResizeObserver from "resize-observer-polyfill";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import DataTable, { type Api } from "datatables.net-bs5";
|
||||
import "datatables.net-bs5/css/dataTables.bootstrap5.css";
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
import { frontendDebug, frontendError, installFrontendConsoleBridge } from "./frontend_log.ts";
|
||||
import type { DemoDecodeDiagnosticsPayload } from "./bindings/kb_app_demo_desktop/demo_decode_replay/DemoDecodeDiagnosticsPayload.ts";
|
||||
@@ -224,7 +226,11 @@ function shortened(value: string, visible: number): string {
|
||||
return value.length > visible ? `${value.slice(0, visible)}…` : value;
|
||||
}
|
||||
|
||||
let annotationJournalTable: Api<DemoTransactionAnnotationRow> | null = null;
|
||||
|
||||
function renderAnnotations(rows: DemoTransactionAnnotationRow[]): void {
|
||||
annotationJournalTable?.destroy();
|
||||
annotationJournalTable = null;
|
||||
const body = element<HTMLTableSectionElement>("#annotationJournalBody");
|
||||
body.replaceChildren();
|
||||
for (const row of rows) {
|
||||
@@ -241,6 +247,21 @@ function renderAnnotations(rows: DemoTransactionAnnotationRow[]): void {
|
||||
);
|
||||
body.append(tableRow);
|
||||
}
|
||||
annotationJournalTable = new DataTable<DemoTransactionAnnotationRow>("#annotationJournalTable", {
|
||||
autoWidth: false,
|
||||
pageLength: 25,
|
||||
lengthMenu: [10, 25, 50, 100],
|
||||
order: [[0, "desc"]],
|
||||
scrollX: true,
|
||||
language: {
|
||||
emptyTable: "Aucune annotation.",
|
||||
info: "_START_ à _END_ sur _TOTAL_ annotations",
|
||||
infoEmpty: "0 annotation",
|
||||
lengthMenu: "Afficher _MENU_ annotations",
|
||||
search: "Filtrer :",
|
||||
zeroRecords: "Aucune annotation correspondante.",
|
||||
},
|
||||
});
|
||||
element<HTMLElement>("#annotationJournalStatus").textContent = `${rows.length} annotation(s) committed chargée(s).`;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_execution_spl.ts
|
||||
// version: 3
|
||||
// version: 4
|
||||
|
||||
import * as bootstrap from "bootstrap";
|
||||
import "simplebar";
|
||||
@@ -25,9 +25,9 @@ import type { DemoSplAtaDerivationPayload } from "./bindings/kb_app_demo_desktop
|
||||
import type { DemoSplAtaDerivationRequest } from "./bindings/kb_app_demo_desktop/demo_spl_ata/DemoSplAtaDerivationRequest.ts";
|
||||
import type { DemoSplAtaJournalRequest } from "./bindings/kb_app_demo_desktop/demo_spl_ata/DemoSplAtaJournalRequest.ts";
|
||||
import type { DemoSplAtaJournalRow } from "./bindings/kb_app_demo_desktop/demo_spl_ata/DemoSplAtaJournalRow.ts";
|
||||
import type { DemoExecutionSplToken2022Request } from "./bindings/kb_app_demo_desktop/demo_spl_token2022/DemoExecutionSplToken2022Request.ts";
|
||||
import type { DemoExecutionSplToken2022SummaryPayload } from "./bindings/kb_app_demo_desktop/demo_spl_token2022/DemoExecutionSplToken2022SummaryPayload.ts";
|
||||
import type { DemoSplToken2022FixturePayload } from "./bindings/kb_app_demo_desktop/demo_spl_token2022/DemoSplToken2022FixturePayload.ts";
|
||||
import type { DemoExecutionSplToken2022Request } from "./bindings/kb_app_demo_desktop/demo_spl_token_2022/DemoExecutionSplToken2022Request.ts";
|
||||
import type { DemoExecutionSplToken2022SummaryPayload } from "./bindings/kb_app_demo_desktop/demo_spl_token_2022/DemoExecutionSplToken2022SummaryPayload.ts";
|
||||
import type { DemoSplToken2022FixturePayload } from "./bindings/kb_app_demo_desktop/demo_spl_token_2022/DemoSplToken2022FixturePayload.ts";
|
||||
|
||||
|
||||
(window as Window & typeof globalThis & { bootstrap?: typeof bootstrap }).bootstrap = bootstrap;
|
||||
@@ -37,7 +37,7 @@ const logLines: string[] = [];
|
||||
const maximumLogLines = 1200;
|
||||
let running = false;
|
||||
let profileOptions: DemoExecutionSolanaCoreProfileOption[] = [];
|
||||
let token2022Fixture: DemoSplToken2022FixturePayload | null = null;
|
||||
let token_2022Fixture: DemoSplToken2022FixturePayload | null = null;
|
||||
|
||||
function element<T extends HTMLElement>(selector: string): T {
|
||||
const value = document.querySelector<T>(selector);
|
||||
@@ -297,10 +297,18 @@ async function executeAta(submit: boolean): Promise<void> {
|
||||
if (running) {
|
||||
return;
|
||||
}
|
||||
if (submit && !element<HTMLInputElement>("#executionOperatorConfirmedInput").checked) {
|
||||
const message = "La confirmation opérateur est obligatoire avant signature ATA.";
|
||||
appendLog({
|
||||
timestamp: new Date().toISOString(),
|
||||
level: "error",
|
||||
stage: "ata_validation",
|
||||
message,
|
||||
});
|
||||
frontendError("kb-app-demo-desktop.frontend.execution_spl", message);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (submit && !element<HTMLInputElement>("#executionOperatorConfirmedInput").checked) {
|
||||
throw new Error("La confirmation opérateur est obligatoire avant signature ATA.");
|
||||
}
|
||||
const derivation = await deriveAta();
|
||||
const request: DemoExecutionSplAtaRequest = {
|
||||
profileName: element<HTMLSelectElement>("#executionProfileSelect").value,
|
||||
@@ -558,86 +566,86 @@ function renderTokenJournal(rows: DemoSplTokenJournalRow[]): void {
|
||||
|
||||
|
||||
|
||||
function token2022ScenarioAmount(fixture: DemoSplToken2022FixturePayload, scenarioId: string): string {
|
||||
if (scenarioId === "token2022_mint_to_checked") {
|
||||
function token_2022ScenarioAmount(fixture: DemoSplToken2022FixturePayload, scenarioId: string): string {
|
||||
if (scenarioId === "token_2022_mint_to_checked") {
|
||||
return "1";
|
||||
}
|
||||
if (scenarioId === "token2022_approve_checked") {
|
||||
if (scenarioId === "token_2022_approve_checked") {
|
||||
return "2";
|
||||
}
|
||||
if (scenarioId === "token2022_burn_checked") {
|
||||
if (scenarioId === "token_2022_burn_checked") {
|
||||
return "1";
|
||||
}
|
||||
return fixture.defaultAmountRaw;
|
||||
}
|
||||
|
||||
function applyToken2022Fixture(): void {
|
||||
if (!token2022Fixture) {
|
||||
if (!token_2022Fixture) {
|
||||
return;
|
||||
}
|
||||
const scenarioId = element<HTMLSelectElement>("#token2022ScenarioSelect").value;
|
||||
element<HTMLInputElement>("#token2022SourceInput").value = scenarioId === "token2022_close_destination"
|
||||
? token2022Fixture.closeAccount
|
||||
: token2022Fixture.source;
|
||||
element<HTMLInputElement>("#token2022MintInput").value = token2022Fixture.mint;
|
||||
element<HTMLInputElement>("#token2022DestinationInput").value = scenarioId === "token2022_close_destination"
|
||||
? token2022Fixture.authority
|
||||
: token2022Fixture.destination;
|
||||
element<HTMLInputElement>("#token2022DelegateInput").value = token2022Fixture.delegate;
|
||||
element<HTMLInputElement>("#token2022AuthorityInput").value = token2022Fixture.authority;
|
||||
element<HTMLInputElement>("#token2022FreezeAuthorityInput").value = token2022Fixture.freezeAuthority;
|
||||
element<HTMLInputElement>("#token2022AmountInput").value = token2022ScenarioAmount(token2022Fixture, scenarioId);
|
||||
element<HTMLInputElement>("#token2022DecimalsInput").value = String(token2022Fixture.decimals);
|
||||
const scenarioId = element<HTMLSelectElement>("#token_2022ScenarioSelect").value;
|
||||
element<HTMLInputElement>("#token_2022SourceInput").value = scenarioId === "token_2022_close_destination"
|
||||
? token_2022Fixture.closeAccount
|
||||
: token_2022Fixture.source;
|
||||
element<HTMLInputElement>("#token_2022MintInput").value = token_2022Fixture.mint;
|
||||
element<HTMLInputElement>("#token_2022DestinationInput").value = scenarioId === "token_2022_close_destination"
|
||||
? token_2022Fixture.authority
|
||||
: token_2022Fixture.destination;
|
||||
element<HTMLInputElement>("#token_2022DelegateInput").value = token_2022Fixture.delegate;
|
||||
element<HTMLInputElement>("#token_2022AuthorityInput").value = token_2022Fixture.authority;
|
||||
element<HTMLInputElement>("#token_2022FreezeAuthorityInput").value = token_2022Fixture.freezeAuthority;
|
||||
element<HTMLInputElement>("#token_2022AmountInput").value = token_2022ScenarioAmount(token_2022Fixture, scenarioId);
|
||||
element<HTMLInputElement>("#token_2022DecimalsInput").value = String(token_2022Fixture.decimals);
|
||||
}
|
||||
|
||||
async function loadToken2022Fixture(): Promise<void> {
|
||||
try {
|
||||
token2022Fixture = await invoke<DemoSplToken2022FixturePayload>("demo_spl_token2022_fixture", {
|
||||
token_2022Fixture = await invoke<DemoSplToken2022FixturePayload>("demo_spl_token_2022_fixture", {
|
||||
profileName: element<HTMLSelectElement>("#executionProfileSelect").value,
|
||||
});
|
||||
applyToken2022Fixture();
|
||||
element<HTMLElement>("#token2022FixtureHelp").textContent = `Fixture: ${token2022Fixture.fixturePath} — program=${token2022Fixture.programId}`;
|
||||
element<HTMLElement>("#token_2022FixtureHelp").textContent = `Fixture: ${token_2022Fixture.fixturePath} — program=${token_2022Fixture.programId}`;
|
||||
appendLog({
|
||||
timestamp: new Date().toISOString(),
|
||||
level: "info",
|
||||
stage: "token2022_fixture",
|
||||
message: `fixture chargée: mint=${token2022Fixture.mint}, source=${token2022Fixture.source}, destination=${token2022Fixture.destination}`,
|
||||
stage: "token_2022_fixture",
|
||||
message: `fixture chargée: mint=${token_2022Fixture.mint}, source=${token_2022Fixture.source}, destination=${token_2022Fixture.destination}`,
|
||||
});
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
token2022Fixture = null;
|
||||
element<HTMLElement>("#token2022FixtureHelp").textContent = message;
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "token2022_fixture", message });
|
||||
token_2022Fixture = null;
|
||||
element<HTMLElement>("#token_2022FixtureHelp").textContent = message;
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "token_2022_fixture", message });
|
||||
}
|
||||
}
|
||||
|
||||
function buildToken2022Request(submit: boolean): DemoExecutionSplToken2022Request {
|
||||
const scenarioId = element<HTMLSelectElement>("#token2022ScenarioSelect").value;
|
||||
const source = element<HTMLInputElement>("#token2022SourceInput").value.trim();
|
||||
const mint = element<HTMLInputElement>("#token2022MintInput").value.trim();
|
||||
const destination = element<HTMLInputElement>("#token2022DestinationInput").value.trim();
|
||||
const delegate = element<HTMLInputElement>("#token2022DelegateInput").value.trim();
|
||||
const authority = element<HTMLInputElement>("#token2022AuthorityInput").value.trim();
|
||||
const freezeAuthority = element<HTMLInputElement>("#token2022FreezeAuthorityInput").value.trim();
|
||||
const scenarioId = element<HTMLSelectElement>("#token_2022ScenarioSelect").value;
|
||||
const source = element<HTMLInputElement>("#token_2022SourceInput").value.trim();
|
||||
const mint = element<HTMLInputElement>("#token_2022MintInput").value.trim();
|
||||
const destination = element<HTMLInputElement>("#token_2022DestinationInput").value.trim();
|
||||
const delegate = element<HTMLInputElement>("#token_2022DelegateInput").value.trim();
|
||||
const authority = element<HTMLInputElement>("#token_2022AuthorityInput").value.trim();
|
||||
const freezeAuthority = element<HTMLInputElement>("#token_2022FreezeAuthorityInput").value.trim();
|
||||
if (source.length === 0) {
|
||||
throw new Error("Le compte source ou cible Token-2022 est obligatoire.");
|
||||
}
|
||||
if (scenarioId !== "token2022_revoke" && scenarioId !== "token2022_close_destination" && mint.length === 0) {
|
||||
if (scenarioId !== "token_2022_revoke" && scenarioId !== "token_2022_close_destination" && mint.length === 0) {
|
||||
throw new Error("Le mint Token-2022 est obligatoire pour ce scénario.");
|
||||
}
|
||||
if (scenarioId === "token2022_transfer_checked" && destination.length === 0) {
|
||||
if (scenarioId === "token_2022_transfer_checked" && destination.length === 0) {
|
||||
throw new Error("Le compte destination Token-2022 est obligatoire.");
|
||||
}
|
||||
if (scenarioId === "token2022_close_destination" && destination.length === 0) {
|
||||
if (scenarioId === "token_2022_close_destination" && destination.length === 0) {
|
||||
throw new Error("La destination lamports est obligatoire pour CloseAccount.");
|
||||
}
|
||||
if (scenarioId === "token2022_approve_checked" && delegate.length === 0) {
|
||||
if (scenarioId === "token_2022_approve_checked" && delegate.length === 0) {
|
||||
throw new Error("Le delegate est obligatoire pour ApproveChecked.");
|
||||
}
|
||||
if (["token2022_freeze_account", "token2022_thaw_account"].includes(scenarioId) && freezeAuthority.length === 0) {
|
||||
if (["token_2022_freeze_account", "token_2022_thaw_account"].includes(scenarioId) && freezeAuthority.length === 0) {
|
||||
throw new Error("La freeze authority est obligatoire pour FreezeAccount et ThawAccount.");
|
||||
}
|
||||
if (!["token2022_freeze_account", "token2022_thaw_account"].includes(scenarioId) && authority.length === 0) {
|
||||
if (!["token_2022_freeze_account", "token_2022_thaw_account"].includes(scenarioId) && authority.length === 0) {
|
||||
throw new Error("L’autorité Token-2022 est obligatoire.");
|
||||
}
|
||||
return {
|
||||
@@ -649,8 +657,8 @@ function buildToken2022Request(submit: boolean): DemoExecutionSplToken2022Reques
|
||||
delegate,
|
||||
authority,
|
||||
freezeAuthority,
|
||||
amountRaw: element<HTMLInputElement>("#token2022AmountInput").value.trim(),
|
||||
decimals: integerValue("#token2022DecimalsInput"),
|
||||
amountRaw: element<HTMLInputElement>("#token_2022AmountInput").value.trim(),
|
||||
decimals: integerValue("#token_2022DecimalsInput"),
|
||||
submit,
|
||||
operatorConfirmed: element<HTMLInputElement>("#executionOperatorConfirmedInput").checked,
|
||||
forcePostValidationReplay: element<HTMLInputElement>("#executionForceReplayInput").checked,
|
||||
@@ -692,12 +700,12 @@ async function executeToken2022(submit: boolean): Promise<void> {
|
||||
if (submit && !request.operatorConfirmed) {
|
||||
const message = "La confirmation opérateur est obligatoire avant signature Token-2022.";
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify({ warning: message }, null, 2);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "token2022_failed", message });
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "token_2022_failed", message });
|
||||
return;
|
||||
}
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "token2022_failed", message });
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "token_2022_failed", message });
|
||||
return;
|
||||
}
|
||||
setRunning(true);
|
||||
@@ -705,23 +713,23 @@ async function executeToken2022(submit: boolean): Promise<void> {
|
||||
appendLog({
|
||||
timestamp: new Date().toISOString(),
|
||||
level: "info",
|
||||
stage: submit ? "token2022_submit" : "token2022_simulation",
|
||||
stage: submit ? "token_2022_submit" : "token_2022_simulation",
|
||||
message: `${request.scenarioId}, source=${request.source}`,
|
||||
});
|
||||
try {
|
||||
const summary = await invoke<DemoExecutionSplToken2022SummaryPayload>("demo_execution_spl_token2022_execute", { request });
|
||||
const summary = await invoke<DemoExecutionSplToken2022SummaryPayload>("demo_execution_spl_token_2022_execute", { request });
|
||||
displayToken2022Summary(summary);
|
||||
appendLog({
|
||||
timestamp: new Date().toISOString(),
|
||||
level: summary.simulationSuccess ? "info" : "error",
|
||||
stage: "token2022_completed",
|
||||
stage: "token_2022_completed",
|
||||
message: `scenario=${summary.scenarioId}, simulation=${summary.simulationSuccess}, confirmation=${summary.confirmationStatus ?? "none"}, materializations=${summary.materializationCount}, idempotence=${summary.idempotenceValidated}`,
|
||||
signature: summary.transactionSignature,
|
||||
});
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify({ error: message }, null, 2);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "token2022_failed", message });
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "token_2022_failed", message });
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_execution_spl", `Token-2022 execution failed: ${message}`);
|
||||
} finally {
|
||||
setRunning(false);
|
||||
@@ -841,7 +849,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
element<HTMLButtonElement>("#loadToken2022FixtureButton").addEventListener("click", () => {
|
||||
void loadToken2022Fixture();
|
||||
});
|
||||
element<HTMLSelectElement>("#token2022ScenarioSelect").addEventListener("change", applyToken2022Fixture);
|
||||
element<HTMLSelectElement>("#token_2022ScenarioSelect").addEventListener("change", applyToken2022Fixture);
|
||||
element<HTMLButtonElement>("#simulateToken2022Button").addEventListener("click", () => {
|
||||
void executeToken2022(false);
|
||||
});
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_http.ts
|
||||
// version: 5
|
||||
// version: 7
|
||||
|
||||
import * as bootstrap from "bootstrap";
|
||||
import "simplebar";
|
||||
import ResizeObserver from "resize-observer-polyfill";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { frontendDebug, frontendError, installFrontendConsoleBridge } from "./frontend_log.ts";
|
||||
import { renderJsonViewer } from "./json_viewer.ts";
|
||||
import type { DemoHttpExecutionPayload } from "./bindings/kb_app_demo_desktop/demo_http/DemoHttpExecutionPayload.ts";
|
||||
import type { DemoHttpMethodOption } from "./bindings/kb_app_demo_desktop/demo_http/DemoHttpMethodOption.ts";
|
||||
import type { DemoHttpOptionsPayload } from "./bindings/kb_app_demo_desktop/demo_http/DemoHttpOptionsPayload.ts";
|
||||
@@ -17,35 +18,27 @@ import type { DemoHttpRoleOption } from "./bindings/kb_app_demo_desktop/demo_htt
|
||||
|
||||
let roleOptions: DemoHttpRoleOption[] = [];
|
||||
let methodOptions: DemoHttpMethodOption[] = [];
|
||||
let httpResultBuffer = "Aucune requête exécutée.";
|
||||
|
||||
|
||||
function textInputValue(selector: string): string {
|
||||
const element = document.querySelector<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>(selector);
|
||||
return element ? element.value.trim() : "";
|
||||
}
|
||||
|
||||
function writeTextarea(selector: string, value: string): void {
|
||||
const element = document.querySelector<HTMLTextAreaElement>(selector);
|
||||
if (element) {
|
||||
element.value = value;
|
||||
function parseJsonValue(value: string): unknown {
|
||||
try {
|
||||
return JSON.parse(value) as unknown;
|
||||
} catch {
|
||||
return { raw: value };
|
||||
}
|
||||
}
|
||||
|
||||
function writeHttpResult(value: string): void {
|
||||
httpResultBuffer = value;
|
||||
writeTextarea("#httpResultOutput", httpResultBuffer);
|
||||
function writeHttpResult(value: unknown): void {
|
||||
renderJsonViewer("#httpResultOutput", value);
|
||||
}
|
||||
|
||||
function clearHttpResult(): void {
|
||||
httpResultBuffer = "";
|
||||
writeTextarea("#httpResultOutput", httpResultBuffer);
|
||||
}
|
||||
|
||||
function jsonText(value: unknown): string {
|
||||
if (typeof value === "string") {
|
||||
return value;
|
||||
}
|
||||
return JSON.stringify(value, null, 2);
|
||||
writeHttpResult({ status: "idle", message: "Aucune requête exécutée." });
|
||||
}
|
||||
|
||||
function roleSupportsMethod(role: DemoHttpRoleOption, method: DemoHttpMethodOption): boolean {
|
||||
@@ -99,8 +92,8 @@ function refreshMethodFields(): void {
|
||||
}
|
||||
}
|
||||
|
||||
function formatHttpExecutionPayload(payload: DemoHttpExecutionPayload): string {
|
||||
const header = {
|
||||
function formatHttpExecutionPayload(payload: DemoHttpExecutionPayload): unknown {
|
||||
return {
|
||||
endpointName: payload.endpointName,
|
||||
provider: payload.provider,
|
||||
endpointUrl: payload.endpointUrl,
|
||||
@@ -108,16 +101,8 @@ function formatHttpExecutionPayload(payload: DemoHttpExecutionPayload): string {
|
||||
method: payload.method,
|
||||
requestKind: payload.requestKind,
|
||||
methodClass: payload.methodClass,
|
||||
response: parseJsonValue(payload.responseJson),
|
||||
};
|
||||
return `${JSON.stringify(header, null, 2)}\n\n--- response ---\n${payload.responseJson}`;
|
||||
}
|
||||
|
||||
async function copyTextarea(selector: string): Promise<void> {
|
||||
const element = document.querySelector<HTMLTextAreaElement>(selector);
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
await navigator.clipboard.writeText(element.value);
|
||||
}
|
||||
|
||||
async function refreshHttpOptions(): Promise<void> {
|
||||
@@ -132,7 +117,7 @@ async function refreshHttpOptions(): Promise<void> {
|
||||
refreshMethodList();
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
writeHttpResult(`Erreur options HTTP : ${message}`);
|
||||
writeHttpResult({ status: "error", stage: "options", message });
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_http", `HTTP options loading failed: ${message}`);
|
||||
}
|
||||
}
|
||||
@@ -140,10 +125,10 @@ async function refreshHttpOptions(): Promise<void> {
|
||||
async function refreshHttpPool(): Promise<void> {
|
||||
try {
|
||||
const snapshots = await invoke("demo_http_list_pool_clients");
|
||||
writeTextarea("#httpPoolOutput", jsonText(snapshots));
|
||||
renderJsonViewer("#httpPoolOutput", snapshots);
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
writeTextarea("#httpPoolOutput", `Erreur : ${message}`);
|
||||
renderJsonViewer("#httpPoolOutput", { status: "error", message });
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_http", `HTTP pool refresh failed: ${message}`);
|
||||
}
|
||||
}
|
||||
@@ -156,14 +141,14 @@ async function executeHttpRequest(): Promise<void> {
|
||||
configJson: textInputValue("#httpConfigInput") || null,
|
||||
paramsJson: textInputValue("#httpParamsInput") || null,
|
||||
};
|
||||
writeHttpResult("Exécution en cours...");
|
||||
writeHttpResult({ status: "running", message: "Exécution HTTP en cours." });
|
||||
try {
|
||||
const response = await invoke<DemoHttpExecutionPayload>("demo_http_execute_request", { request });
|
||||
writeHttpResult(formatHttpExecutionPayload(response));
|
||||
frontendDebug("kb-app-demo-desktop.frontend.demo_http", `HTTP request completed: ${response.method}`);
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
writeHttpResult(`Erreur : ${message}`);
|
||||
writeHttpResult({ status: "error", message });
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_http", `HTTP request failed: ${message}`);
|
||||
}
|
||||
}
|
||||
@@ -171,6 +156,8 @@ async function executeHttpRequest(): Promise<void> {
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
installFrontendConsoleBridge("kb-app-demo-desktop.frontend.demo_http");
|
||||
frontendDebug("kb-app-demo-desktop.frontend.demo_http", "HTTP demo window loaded");
|
||||
renderJsonViewer("#httpPoolOutput", { status: "loading", message: "Chargement des endpoints HTTP." });
|
||||
clearHttpResult();
|
||||
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
|
||||
Array.from(tooltipTriggerList).map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
|
||||
document.querySelector<HTMLSelectElement>("#httpRoleSelect")?.addEventListener("change", refreshMethodList);
|
||||
@@ -181,12 +168,6 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
document.querySelector<HTMLButtonElement>("#refreshHttpPoolButton")?.addEventListener("click", () => {
|
||||
void refreshHttpPool();
|
||||
});
|
||||
document.querySelector<HTMLButtonElement>("#copyHttpPoolButton")?.addEventListener("click", () => {
|
||||
void copyTextarea("#httpPoolOutput");
|
||||
});
|
||||
document.querySelector<HTMLButtonElement>("#copyHttpResultButton")?.addEventListener("click", () => {
|
||||
void copyTextarea("#httpResultOutput");
|
||||
});
|
||||
document.querySelector<HTMLButtonElement>("#clearHttpResultButton")?.addEventListener("click", clearHttpResult);
|
||||
void refreshHttpOptions();
|
||||
void refreshHttpPool();
|
||||
|
||||
@@ -26,7 +26,7 @@ async function refreshDiagnostics(): Promise<void> {
|
||||
setText("#sqlDiagHealth", payload.healthStatus);
|
||||
setText("#sqlDiagMigration", payload.migrationStatus);
|
||||
setText("#sqlDiagStatus", "OK");
|
||||
renderTables("#sqlDiagTableBody", payload.tables);
|
||||
renderTables("#sqlDiagTable", "#sqlDiagTableBody", payload.tables);
|
||||
latestPayload = payload;
|
||||
renderJsonViewer("#sqlDiagJson", payload);
|
||||
frontendDebug("kb_app_demo.frontend.demo_sql_diag", "SQL diagnostics refreshed");
|
||||
|
||||
@@ -19,7 +19,7 @@ async function refreshCore(): Promise<void> {
|
||||
setText("#sqlCoreProfile", payload.activeProfileName);
|
||||
setText("#sqlCoreDsn", payload.maskedDsn);
|
||||
setText("#sqlCoreStatus", "OK");
|
||||
renderTables("#sqlCoreTableBody", payload.tables);
|
||||
renderTables("#sqlCoreTable", "#sqlCoreTableBody", payload.tables);
|
||||
renderJsonViewer("#sqlCoreJson", payload);
|
||||
frontendDebug("kb_app_demo.frontend.demo_sql_pg_core", "PostgreSQL core diagnostics refreshed");
|
||||
} catch (caughtError) {
|
||||
|
||||
@@ -19,7 +19,7 @@ async function refreshRaw(): Promise<void> {
|
||||
setText("#sqlRawProfile", payload.activeProfileName);
|
||||
setText("#sqlRawDsn", payload.maskedDsn);
|
||||
setText("#sqlRawStatus", "OK");
|
||||
renderTables("#sqlRawTableBody", payload.tables);
|
||||
renderTables("#sqlRawTable", "#sqlRawTableBody", payload.tables);
|
||||
renderJsonViewer("#sqlRawJson", payload);
|
||||
frontendDebug("kb_app_demo.frontend.demo_sql_pg_raw", "PostgreSQL raw diagnostics refreshed");
|
||||
} catch (caughtError) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_sql_replay_candidates.ts
|
||||
// version: 7
|
||||
// version: 8
|
||||
|
||||
import * as bootstrap from "bootstrap";
|
||||
import "simplebar";
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_sql_tables.ts
|
||||
// version: 2
|
||||
// version: 4
|
||||
|
||||
import "@andypf/json-viewer";
|
||||
import DataTable, { type Api } from "datatables.net-bs5";
|
||||
import "datatables.net-bs5/css/dataTables.bootstrap5.css";
|
||||
import { jsonText, renderJsonViewer } from "./json_viewer.ts";
|
||||
import type { DemoSqlTableSnapshot } from "./bindings/kb_app_demo_desktop/demo_sql/DemoSqlTableSnapshot";
|
||||
|
||||
const tableInstances = new Map<string, Api>();
|
||||
|
||||
export function setText(selector: string, value: string): void {
|
||||
const element = document.querySelector<HTMLElement>(selector);
|
||||
if (element) {
|
||||
@@ -11,8 +15,13 @@ export function setText(selector: string, value: string): void {
|
||||
}
|
||||
}
|
||||
|
||||
export function renderTables(selector: string, tables: DemoSqlTableSnapshot[]): void {
|
||||
const tbody = document.querySelector<HTMLTableSectionElement>(selector);
|
||||
export function renderTables(tableSelector: string, bodySelector: string, tables: DemoSqlTableSnapshot[]): void {
|
||||
const existing = tableInstances.get(tableSelector);
|
||||
if (existing) {
|
||||
existing.destroy();
|
||||
tableInstances.delete(tableSelector);
|
||||
}
|
||||
const tbody = document.querySelector<HTMLTableSectionElement>(bodySelector);
|
||||
if (!tbody) {
|
||||
return;
|
||||
}
|
||||
@@ -29,32 +38,28 @@ export function renderTables(selector: string, tables: DemoSqlTableSnapshot[]):
|
||||
row.appendChild(cell(table.latestCreatedAt ?? "—", false));
|
||||
tbody.appendChild(row);
|
||||
}
|
||||
}
|
||||
|
||||
export function jsonText(value: unknown): string {
|
||||
return JSON.stringify(value, null, 2);
|
||||
}
|
||||
|
||||
export function renderJsonViewer(selector: string, value: unknown): void {
|
||||
const container = document.querySelector<HTMLElement>(selector);
|
||||
if (!container) {
|
||||
const tableElement = document.querySelector<HTMLTableElement>(tableSelector);
|
||||
if (!tableElement) {
|
||||
return;
|
||||
}
|
||||
const viewer = document.createElement("andypf-json-viewer");
|
||||
viewer.setAttribute("indent", "2");
|
||||
viewer.setAttribute("expanded", "1");
|
||||
viewer.setAttribute("theme", "default-light");
|
||||
viewer.setAttribute("show-data-types", "true");
|
||||
viewer.setAttribute("show-toolbar", "false");
|
||||
viewer.setAttribute("expand-icon-type", "arrow");
|
||||
viewer.setAttribute("show-copy", "true");
|
||||
viewer.setAttribute("show-size", "true");
|
||||
viewer.setAttribute("expand-empty", "false");
|
||||
viewer.setAttribute("data", jsonText(value));
|
||||
container.textContent = "";
|
||||
container.appendChild(viewer);
|
||||
tableInstances.set(tableSelector, new DataTable(tableElement, {
|
||||
scrollX: true,
|
||||
pageLength: 25,
|
||||
lengthMenu: [10, 25, 50, 100],
|
||||
order: [[0, "asc"]],
|
||||
language: {
|
||||
emptyTable: "Aucune table disponible",
|
||||
info: "Tables _START_ à _END_ sur _TOTAL_",
|
||||
infoEmpty: "Aucune table",
|
||||
lengthMenu: "Afficher _MENU_ tables",
|
||||
search: "Rechercher :",
|
||||
zeroRecords: "Aucune table correspondante",
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
export { jsonText, renderJsonViewer };
|
||||
|
||||
function cell(value: string, code: boolean): HTMLTableCellElement {
|
||||
const td = document.createElement("td");
|
||||
if (code) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_ws.ts
|
||||
// version: 7
|
||||
// version: 8
|
||||
|
||||
import * as bootstrap from "bootstrap";
|
||||
import "simplebar";
|
||||
@@ -7,6 +7,7 @@ import ResizeObserver from "resize-observer-polyfill";
|
||||
import {invoke} from "@tauri-apps/api/core";
|
||||
import {listen} from "@tauri-apps/api/event";
|
||||
import {frontendDebug, frontendError, installFrontendConsoleBridge} from "./frontend_log.ts";
|
||||
import {renderJsonViewer} from "./json_viewer.ts";
|
||||
import type {DemoWsExecutionPayload} from "./bindings/kb_app_demo_desktop/demo_ws/DemoWsExecutionPayload.ts";
|
||||
import type {DemoWsMessagePayload} from "./bindings/kb_app_demo_desktop/demo_ws/DemoWsMessagePayload.ts";
|
||||
import type {DemoWsMethodOption} from "./bindings/kb_app_demo_desktop/demo_ws/DemoWsMethodOption.ts";
|
||||
@@ -81,13 +82,6 @@ function clearWsMessages(): void {
|
||||
writeWsMessages("");
|
||||
}
|
||||
|
||||
function jsonText(value: unknown): string {
|
||||
if (typeof value === "string") {
|
||||
return value;
|
||||
}
|
||||
return JSON.stringify(value, null, 2);
|
||||
}
|
||||
|
||||
function roleSupportsMethod(role: DemoWsRoleOption, method: DemoWsMethodOption): boolean {
|
||||
return role.requestKinds.includes("*") || role.requestKinds.includes(method.requestKind);
|
||||
}
|
||||
@@ -176,7 +170,7 @@ function setConnectedUi(status: DemoWsStatusPayload): void {
|
||||
disconnectButton.disabled = !status.connected;
|
||||
}
|
||||
refreshSubscriptionSelect(status);
|
||||
writeTextarea("#wsStatusOutput", jsonText(status));
|
||||
renderJsonViewer("#wsStatusOutput", status);
|
||||
}
|
||||
|
||||
function formatWsExecutionPayload(payload: DemoWsExecutionPayload): string {
|
||||
@@ -221,10 +215,10 @@ async function refreshWsOptions(): Promise<void> {
|
||||
async function refreshWsPool(): Promise<void> {
|
||||
try {
|
||||
const snapshots = await invoke("demo_ws_list_pool_clients");
|
||||
writeTextarea("#wsPoolOutput", jsonText(snapshots));
|
||||
renderJsonViewer("#wsPoolOutput", snapshots);
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
writeTextarea("#wsPoolOutput", `Erreur : ${message}`);
|
||||
renderJsonViewer("#wsPoolOutput", {status: "error", message});
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_ws", `WebSocket pool refresh failed: ${message}`);
|
||||
}
|
||||
}
|
||||
@@ -235,7 +229,7 @@ async function refreshWsStatus(): Promise<void> {
|
||||
setConnectedUi(status);
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
writeTextarea("#wsStatusOutput", `Erreur statut WebSocket : ${message}`);
|
||||
renderJsonViewer("#wsStatusOutput", {status: "error", message});
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_ws", `WebSocket status failed: ${message}`);
|
||||
}
|
||||
}
|
||||
@@ -330,9 +324,6 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
document.querySelector<HTMLButtonElement>("#refreshWsPoolButton")?.addEventListener("click", () => {
|
||||
void refreshWsPool();
|
||||
});
|
||||
document.querySelector<HTMLButtonElement>("#copyWsPoolButton")?.addEventListener("click", () => {
|
||||
void copyTextarea("#wsPoolOutput");
|
||||
});
|
||||
document.querySelector<HTMLButtonElement>("#copyWsResultButton")?.addEventListener("click", () => {
|
||||
void copyTextarea("#wsResultOutput");
|
||||
});
|
||||
|
||||
@@ -98,6 +98,7 @@ function upgradeJsonTextareas(): void {
|
||||
const container = document.createElement("div");
|
||||
container.className = "app-json-viewer";
|
||||
const viewer = document.createElement("andypf-json-viewer");
|
||||
viewer.classList.add("app-json-viewer-element");
|
||||
viewer.setAttribute("indent", "2");
|
||||
viewer.setAttribute("expanded", "1");
|
||||
viewer.setAttribute("theme", "default-light");
|
||||
@@ -108,7 +109,7 @@ function upgradeJsonTextareas(): void {
|
||||
let currentValue = textarea.value;
|
||||
const render = (value: string): void => {
|
||||
currentValue = value;
|
||||
let parsed: unknown = value;
|
||||
let parsed: unknown;
|
||||
try {
|
||||
parsed = JSON.parse(value) as unknown;
|
||||
} catch {
|
||||
|
||||
28
kb-app-demo-desktop/frontend/ts/json_viewer.ts
Normal file
28
kb-app-demo-desktop/frontend/ts/json_viewer.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/json_viewer.ts
|
||||
// version: 2
|
||||
|
||||
import "@andypf/json-viewer";
|
||||
|
||||
export function jsonText(value: unknown): string {
|
||||
return JSON.stringify(value, null, 2);
|
||||
}
|
||||
|
||||
export function renderJsonViewer(selector: string, value: unknown): void {
|
||||
const container = document.querySelector<HTMLElement>(selector);
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
const viewer = document.createElement("andypf-json-viewer");
|
||||
viewer.classList.add("app-json-viewer-element");
|
||||
viewer.setAttribute("indent", "2");
|
||||
viewer.setAttribute("expanded", "1");
|
||||
viewer.setAttribute("theme", "default-light");
|
||||
viewer.setAttribute("show-data-types", "true");
|
||||
viewer.setAttribute("show-toolbar", "false");
|
||||
viewer.setAttribute("expand-icon-type", "arrow");
|
||||
viewer.setAttribute("show-copy", "true");
|
||||
viewer.setAttribute("show-size", "true");
|
||||
viewer.setAttribute("expand-empty", "false");
|
||||
viewer.setAttribute("data", jsonText(value));
|
||||
container.replaceChildren(viewer);
|
||||
}
|
||||
@@ -178,7 +178,7 @@ pub(crate) struct DemoBackfillSummaryPayload {
|
||||
/// Number of source attempts.
|
||||
#[ts(type = "number")]
|
||||
pub(crate) attempts: u64,
|
||||
/// Whether the operator cancelled the campaign.
|
||||
/// Whether the operator canceled the campaign.
|
||||
pub(crate) cancelled: bool,
|
||||
/// Optional cursor for continuing an older-history scan.
|
||||
pub(crate) resume_before_signature: std::option::Option<std::string::String>,
|
||||
|
||||
@@ -1,11 +1,25 @@
|
||||
// file: kb-app-demo-desktop/src/demo_core_extraction.rs
|
||||
// version: 10
|
||||
// version: 11
|
||||
|
||||
//! Tauri commands and UI payloads for canonical transaction to core extraction.
|
||||
|
||||
use tauri::Emitter; // rust-rules: trait-import
|
||||
use ts_rs::TS; // rust-rules: derive-import
|
||||
|
||||
/// One registered program offered as a non-blocking core extraction suggestion.
|
||||
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_app_demo_desktop/demo_core_extraction/DemoCoreExtractionProgramOption.ts"
|
||||
)]
|
||||
pub(crate) struct DemoCoreExtractionProgramOption {
|
||||
/// Stable registry code.
|
||||
pub(crate) code: std::string::String,
|
||||
/// Canonical Solana program id.
|
||||
pub(crate) program_id: std::string::String,
|
||||
}
|
||||
|
||||
/// Initial options shown by the core extraction demo.
|
||||
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@@ -22,6 +36,8 @@ pub(crate) struct DemoCoreExtractionOptionsPayload {
|
||||
pub(crate) default_max_concurrent_extractions: u32,
|
||||
/// Whether one extraction campaign is currently running.
|
||||
pub(crate) running: bool,
|
||||
/// Registered program ids offered without restricting free text entry.
|
||||
pub(crate) programs: std::vec::Vec<crate::DemoCoreExtractionProgramOption>,
|
||||
}
|
||||
|
||||
/// UI request for one bounded core extraction campaign.
|
||||
@@ -166,6 +182,15 @@ pub(crate) fn demo_core_extraction_options_payload(
|
||||
default_limit: 100,
|
||||
default_max_concurrent_extractions: 4,
|
||||
running: state.demo_core_extraction_running().load(std::sync::atomic::Ordering::Acquire),
|
||||
programs: kb_program_ids::registered_program_ids()
|
||||
.iter()
|
||||
.map(|entry| {
|
||||
return crate::DemoCoreExtractionProgramOption {
|
||||
code: entry.code().to_string(),
|
||||
program_id: entry.program_id().to_string(),
|
||||
};
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/src/demo_decode_replay.rs
|
||||
// version: 30
|
||||
// version: 32
|
||||
|
||||
//! Tauri commands and UI payloads for contextual instruction decode replay.
|
||||
|
||||
@@ -143,9 +143,12 @@ pub(crate) struct DemoDecodeProcessorSummaryPayload {
|
||||
/// Unsupported input count.
|
||||
#[ts(type = "number")]
|
||||
pub(crate) unsupported: u64,
|
||||
/// Failed input count.
|
||||
/// Explicit decoder failure count.
|
||||
#[ts(type = "number")]
|
||||
pub(crate) failed: u64,
|
||||
/// Orchestration, storage or other processing error count.
|
||||
#[ts(type = "number")]
|
||||
pub(crate) processing_errors: u64,
|
||||
/// Materialized output count.
|
||||
#[ts(type = "number")]
|
||||
pub(crate) materialized_outputs: u64,
|
||||
@@ -181,9 +184,12 @@ pub(crate) struct DemoDecodeReplaySummaryPayload {
|
||||
/// Number never started after cancellation.
|
||||
#[ts(type = "number")]
|
||||
pub(crate) not_started: u64,
|
||||
/// Number of failed contextual inputs.
|
||||
/// Number of inputs returning an explicit decoder failure.
|
||||
#[ts(type = "number")]
|
||||
pub(crate) failed_inputs: u64,
|
||||
/// Number of inputs interrupted by orchestration, storage or processing errors.
|
||||
#[ts(type = "number")]
|
||||
pub(crate) processing_error_inputs: u64,
|
||||
/// Whether cancellation was observed.
|
||||
pub(crate) cancelled: bool,
|
||||
/// Per-processor counters.
|
||||
@@ -544,6 +550,7 @@ pub(crate) fn demo_decode_replay_summary_payload(
|
||||
unmatched: summary.unmatched,
|
||||
not_started: summary.not_started,
|
||||
failed_inputs: summary.failed_inputs,
|
||||
processing_error_inputs: summary.processing_error_inputs,
|
||||
cancelled: summary.cancelled,
|
||||
processors: summary
|
||||
.processors
|
||||
@@ -558,6 +565,7 @@ pub(crate) fn demo_decode_replay_summary_payload(
|
||||
ignored: processor.ignored,
|
||||
unsupported: processor.unsupported,
|
||||
failed: processor.failed,
|
||||
processing_errors: processor.processing_errors,
|
||||
materialized_outputs: processor.materialized_outputs,
|
||||
materialization_refused: processor.materialization_refused,
|
||||
};
|
||||
@@ -733,7 +741,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn native_memo_token2022_elgamal_classic_token_and_ata_decoders_are_registered() {
|
||||
fn native_memo_token_2022_elgamal_classic_token_and_ata_decoders_are_registered() {
|
||||
let decoders = crate::available_decoders();
|
||||
assert_eq!(decoders.len(), 7);
|
||||
let mut names = decoders
|
||||
@@ -748,7 +756,7 @@ mod tests {
|
||||
"spl_elgamal_registry".to_string(),
|
||||
"spl_memo".to_string(),
|
||||
"spl_token".to_string(),
|
||||
"spl_token2022".to_string(),
|
||||
"spl_token_2022".to_string(),
|
||||
];
|
||||
expected_names.sort();
|
||||
assert_eq!(names, expected_names);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/src/demo_execution_solana_core.rs
|
||||
// version: 5
|
||||
// version: 6
|
||||
|
||||
//! Tauri adapter for bounded Solana Core execution on Devnet.
|
||||
|
||||
@@ -187,9 +187,12 @@ pub(crate) struct DemoExecutionSolanaCoreSummaryPayload {
|
||||
/// Contextual decode inputs completed after submission.
|
||||
#[ts(type = "number | null")]
|
||||
pub(crate) decode_completed: std::option::Option<u64>,
|
||||
/// Contextual decode input failures after submission.
|
||||
/// Explicit contextual decoder failures after submission.
|
||||
#[ts(type = "number | null")]
|
||||
pub(crate) decode_failed_inputs: std::option::Option<u64>,
|
||||
/// Contextual decode processing or storage errors after submission.
|
||||
#[ts(type = "number | null")]
|
||||
pub(crate) decode_processing_error_inputs: std::option::Option<u64>,
|
||||
/// Pretty JSON representation of the exact execution plan.
|
||||
pub(crate) plan_json: std::string::String,
|
||||
/// Pretty JSON representation of the simulation result.
|
||||
@@ -421,6 +424,8 @@ pub(crate) fn demo_execution_solana_core_summary_payload(
|
||||
let decode_completed = summary.decode_replay.as_ref().map(|value| return value.completed);
|
||||
let decode_failed_inputs =
|
||||
summary.decode_replay.as_ref().map(|value| return value.failed_inputs);
|
||||
let decode_processing_error_inputs =
|
||||
summary.decode_replay.as_ref().map(|value| return value.processing_error_inputs);
|
||||
let diagnostics_value = serde_json::json!({
|
||||
"airdropConfirmation": summary.airdrop_confirmation.as_ref(),
|
||||
"confirmation": summary.confirmation.as_ref(),
|
||||
@@ -449,6 +454,7 @@ pub(crate) fn demo_execution_solana_core_summary_payload(
|
||||
"completed": value.completed,
|
||||
"unmatched": value.unmatched,
|
||||
"failedInputs": value.failed_inputs,
|
||||
"processingErrorInputs": value.processing_error_inputs,
|
||||
"cancelled": value.cancelled
|
||||
});
|
||||
})
|
||||
@@ -477,6 +483,7 @@ pub(crate) fn demo_execution_solana_core_summary_payload(
|
||||
core_extracted,
|
||||
decode_completed,
|
||||
decode_failed_inputs,
|
||||
decode_processing_error_inputs,
|
||||
plan_json,
|
||||
simulation_json,
|
||||
diagnostics_json,
|
||||
@@ -507,9 +514,11 @@ pub(crate) fn demo_execution_solana_core_memo_summary_payload(
|
||||
summary.post_execution.as_ref().is_some_and(|value| return value.materialized);
|
||||
let idempotence_validated = summary.idempotence_replay.as_ref().is_some_and(|replay| {
|
||||
return replay.failed_inputs == 0
|
||||
&& replay.processing_error_inputs == 0
|
||||
&& !replay.cancelled
|
||||
&& replay.processors.iter().all(|processor| {
|
||||
return processor.failed == 0
|
||||
&& processor.processing_errors == 0
|
||||
&& processor.materialized_outputs == 0
|
||||
&& processor.materialization_refused == 0;
|
||||
})
|
||||
@@ -546,6 +555,7 @@ pub(crate) fn demo_execution_solana_core_memo_summary_payload(
|
||||
"selected": value.selected,
|
||||
"completed": value.completed,
|
||||
"failedInputs": value.failed_inputs,
|
||||
"processingErrorInputs": value.processing_error_inputs,
|
||||
"processors": value.processors.iter().map(|processor| {
|
||||
return serde_json::json!({
|
||||
"name": processor.processor_name,
|
||||
@@ -553,6 +563,7 @@ pub(crate) fn demo_execution_solana_core_memo_summary_payload(
|
||||
"decoded": processor.decoded,
|
||||
"skipped": processor.skipped,
|
||||
"failed": processor.failed,
|
||||
"processingErrors": processor.processing_errors,
|
||||
"materializedOutputs": processor.materialized_outputs,
|
||||
"materializationRefused": processor.materialization_refused
|
||||
});
|
||||
@@ -565,6 +576,7 @@ pub(crate) fn demo_execution_solana_core_memo_summary_payload(
|
||||
"selected": value.selected,
|
||||
"completed": value.completed,
|
||||
"failedInputs": value.failed_inputs,
|
||||
"processingErrorInputs": value.processing_error_inputs,
|
||||
"processors": value.processors.iter().map(|processor| {
|
||||
return serde_json::json!({
|
||||
"name": processor.processor_name,
|
||||
@@ -572,6 +584,7 @@ pub(crate) fn demo_execution_solana_core_memo_summary_payload(
|
||||
"decoded": processor.decoded,
|
||||
"skipped": processor.skipped,
|
||||
"failed": processor.failed,
|
||||
"processingErrors": processor.processing_errors,
|
||||
"materializedOutputs": processor.materialized_outputs,
|
||||
"materializationRefused": processor.materialization_refused
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/src/demo_spl_ata.rs
|
||||
// version: 4
|
||||
// version: 7
|
||||
|
||||
//! Thin Tauri adapter for ATA execution, derivation and lifecycle journal reads.
|
||||
|
||||
@@ -19,7 +19,7 @@ pub(crate) struct DemoExecutionSplAtaRequest {
|
||||
pub(crate) wallet_owner: std::string::String,
|
||||
/// Mint account.
|
||||
pub(crate) mint: std::string::String,
|
||||
/// `classic` or `token2022`.
|
||||
/// `classic` or `token_2022`.
|
||||
pub(crate) token_program: std::string::String,
|
||||
/// `create` or `create_idempotent`.
|
||||
pub(crate) mode: std::string::String,
|
||||
@@ -43,7 +43,7 @@ pub(crate) struct DemoSplAtaDerivationRequest {
|
||||
pub(crate) profile_name: std::string::String,
|
||||
/// Mint account.
|
||||
pub(crate) mint: std::string::String,
|
||||
/// `classic` or `token2022`.
|
||||
/// `classic` or `token_2022`.
|
||||
pub(crate) token_program: std::string::String,
|
||||
}
|
||||
|
||||
@@ -185,8 +185,8 @@ pub(crate) fn parse_token_program(
|
||||
) -> std::result::Result<kb_lib::ExSplAssociatedTokenProgram, std::string::String> {
|
||||
return match value.trim() {
|
||||
"classic" => std::result::Result::Ok(kb_lib::ExSplAssociatedTokenProgram::Classic),
|
||||
"token2022" => std::result::Result::Ok(kb_lib::ExSplAssociatedTokenProgram::Token2022),
|
||||
_ => std::result::Result::Err("Token Program must be classic or token2022".to_string()),
|
||||
"token_2022" => std::result::Result::Ok(kb_lib::ExSplAssociatedTokenProgram::Token2022),
|
||||
_ => std::result::Result::Err("Token Program must be classic or token_2022".to_string()),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -247,8 +247,10 @@ pub(crate) fn demo_spl_ata_summary_payload(
|
||||
});
|
||||
let idempotence_validated = summary.idempotence_replay.as_ref().is_some_and(|replay| {
|
||||
return replay.failed_inputs == 0
|
||||
&& replay.processing_error_inputs == 0
|
||||
&& replay.processors.iter().all(|processor| {
|
||||
return processor.failed == 0
|
||||
&& processor.processing_errors == 0
|
||||
&& processor.materialized_outputs == 0
|
||||
&& processor.materialization_refused == 0;
|
||||
});
|
||||
@@ -289,6 +291,7 @@ pub(crate) fn demo_spl_ata_summary_payload(
|
||||
"completed": value.completed,
|
||||
"unmatched": value.unmatched,
|
||||
"failedInputs": value.failed_inputs,
|
||||
"processingErrorInputs": value.processing_error_inputs,
|
||||
"cancelled": value.cancelled
|
||||
});
|
||||
}),
|
||||
@@ -299,6 +302,7 @@ pub(crate) fn demo_spl_ata_summary_payload(
|
||||
"completed": value.completed,
|
||||
"unmatched": value.unmatched,
|
||||
"failedInputs": value.failed_inputs,
|
||||
"processingErrorInputs": value.processing_error_inputs,
|
||||
"cancelled": value.cancelled,
|
||||
"materializedOutputs": value.processors.iter().map(|processor| {
|
||||
return processor.materialized_outputs;
|
||||
@@ -397,15 +401,15 @@ pub(crate) fn journal_row(row: kb_store::MaterializedEventQueryRow) -> crate::De
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn classic_and_token2022_derivations_are_distinct_and_canonical() {
|
||||
fn classic_and_token_2022_derivations_are_distinct_and_canonical() {
|
||||
let wallet = kb_program_ids::SYSTEM_PROGRAM_ID;
|
||||
let mint = "So11111111111111111111111111111111111111112";
|
||||
let classic = crate::derive_ata(wallet, mint, kb_program_ids::SPL_TOKEN_PROGRAM_ID)
|
||||
.unwrap_or_else(|error| panic!("classic derivation failed: {error}"));
|
||||
let token2022 = crate::derive_ata(wallet, mint, kb_program_ids::SPL_TOKEN2022_PROGRAM_ID)
|
||||
let token_2022 = crate::derive_ata(wallet, mint, kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID)
|
||||
.unwrap_or_else(|error| panic!("Token-2022 derivation failed: {error}"));
|
||||
assert_eq!(classic, "aqxoAhCwpy3oB1BpNw9hL1HdLYLgPpbPjzxDrrQj3Fs");
|
||||
assert_eq!(token2022, "2sZUUBGq1i6aE47ZoxCaCW89jmYm2EXLPPmNMgMDXHMS");
|
||||
assert_eq!(token_2022, "2sZUUBGq1i6aE47ZoxCaCW89jmYm2EXLPPmNMgMDXHMS");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/src/demo_spl_token.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
//! Thin Tauri adapter for classic SPL Token execution and materialized journals.
|
||||
|
||||
@@ -172,9 +172,11 @@ pub(crate) fn demo_spl_token_summary_payload(
|
||||
let decode_replayed = post_execution.is_some_and(|value| return value.decode_replayed);
|
||||
let idempotence_validated = summary.idempotence_replay.as_ref().is_some_and(|replay| {
|
||||
return replay.failed_inputs == 0
|
||||
&& replay.processing_error_inputs == 0
|
||||
&& !replay.cancelled
|
||||
&& replay.processors.iter().all(|processor| {
|
||||
return processor.failed == 0
|
||||
&& processor.processing_errors == 0
|
||||
&& processor.materialized_outputs == 0
|
||||
&& processor.materialization_refused == 0;
|
||||
});
|
||||
@@ -248,6 +250,7 @@ fn replay_diagnostics(summary: &kb_pipeline::DecodeReplaySummary) -> serde_json:
|
||||
"selected": summary.selected,
|
||||
"completed": summary.completed,
|
||||
"failedInputs": summary.failed_inputs,
|
||||
"processingErrorInputs": summary.processing_error_inputs,
|
||||
"cancelled": summary.cancelled,
|
||||
"processors": summary.processors.iter().map(|processor| {
|
||||
return serde_json::json!({
|
||||
@@ -256,6 +259,7 @@ fn replay_diagnostics(summary: &kb_pipeline::DecodeReplaySummary) -> serde_json:
|
||||
"decoded": processor.decoded,
|
||||
"skipped": processor.skipped,
|
||||
"failed": processor.failed,
|
||||
"processingErrors": processor.processing_errors,
|
||||
"materializedOutputs": processor.materialized_outputs,
|
||||
"materializationRefused": processor.materialization_refused
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/src/demo_spl_token2022.rs
|
||||
// version: 4
|
||||
// file: kb-app-demo-desktop/src/demo_spl_token_2022.rs
|
||||
// version: 6
|
||||
|
||||
//! Thin Tauri adapter for independent public Token-2022 Devnet validation scenarios.
|
||||
|
||||
@@ -10,7 +10,7 @@ use ts_rs::TS; // rust-rules: derive-import
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_app_demo_desktop/demo_spl_token2022/DemoSplToken2022FixturePayload.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_app_demo_desktop/demo_spl_token_2022/DemoSplToken2022FixturePayload.ts"
|
||||
)]
|
||||
pub(crate) struct DemoSplToken2022FixturePayload {
|
||||
/// Fixture file used by the application.
|
||||
@@ -42,7 +42,7 @@ pub(crate) struct DemoSplToken2022FixturePayload {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_app_demo_desktop/demo_spl_token2022/DemoExecutionSplToken2022Request.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_app_demo_desktop/demo_spl_token_2022/DemoExecutionSplToken2022Request.ts"
|
||||
)]
|
||||
pub(crate) struct DemoExecutionSplToken2022Request {
|
||||
/// Selected Devnet profile.
|
||||
@@ -78,7 +78,7 @@ pub(crate) struct DemoExecutionSplToken2022Request {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_app_demo_desktop/demo_spl_token2022/DemoExecutionSplToken2022SummaryPayload.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_app_demo_desktop/demo_spl_token_2022/DemoExecutionSplToken2022SummaryPayload.ts"
|
||||
)]
|
||||
pub(crate) struct DemoExecutionSplToken2022SummaryPayload {
|
||||
/// Stable scenario identifier.
|
||||
@@ -137,14 +137,14 @@ pub(crate) fn operation_from_request(
|
||||
multisig_signers: std::vec::Vec::new(),
|
||||
};
|
||||
let value = match request.scenario_id.trim() {
|
||||
"token2022_mint_to_checked" => kb_lib::ExSplTokenSingleOperation::MintToChecked {
|
||||
"token_2022_mint_to_checked" => kb_lib::ExSplTokenSingleOperation::MintToChecked {
|
||||
mint: kb_lib::MdPubkey(request.mint.trim().to_string()),
|
||||
destination: kb_lib::MdPubkey(request.source.trim().to_string()),
|
||||
authority,
|
||||
amount: kb_lib::ExSplTokenAmount(request.amount_raw.trim().to_string()),
|
||||
decimals: request.decimals,
|
||||
},
|
||||
"token2022_transfer_checked" => kb_lib::ExSplTokenSingleOperation::TransferChecked {
|
||||
"token_2022_transfer_checked" => kb_lib::ExSplTokenSingleOperation::TransferChecked {
|
||||
source: kb_lib::MdPubkey(request.source.trim().to_string()),
|
||||
mint: kb_lib::MdPubkey(request.mint.trim().to_string()),
|
||||
destination: kb_lib::MdPubkey(request.destination.trim().to_string()),
|
||||
@@ -152,7 +152,7 @@ pub(crate) fn operation_from_request(
|
||||
amount: kb_lib::ExSplTokenAmount(request.amount_raw.trim().to_string()),
|
||||
decimals: request.decimals,
|
||||
},
|
||||
"token2022_approve_checked" => kb_lib::ExSplTokenSingleOperation::ApproveChecked {
|
||||
"token_2022_approve_checked" => kb_lib::ExSplTokenSingleOperation::ApproveChecked {
|
||||
source: kb_lib::MdPubkey(request.source.trim().to_string()),
|
||||
mint: kb_lib::MdPubkey(request.mint.trim().to_string()),
|
||||
delegate: kb_lib::MdPubkey(request.delegate.trim().to_string()),
|
||||
@@ -160,28 +160,28 @@ pub(crate) fn operation_from_request(
|
||||
amount: kb_lib::ExSplTokenAmount(request.amount_raw.trim().to_string()),
|
||||
decimals: request.decimals,
|
||||
},
|
||||
"token2022_revoke" => kb_lib::ExSplTokenSingleOperation::Revoke {
|
||||
"token_2022_revoke" => kb_lib::ExSplTokenSingleOperation::Revoke {
|
||||
source: kb_lib::MdPubkey(request.source.trim().to_string()),
|
||||
authority,
|
||||
},
|
||||
"token2022_burn_checked" => kb_lib::ExSplTokenSingleOperation::BurnChecked {
|
||||
"token_2022_burn_checked" => kb_lib::ExSplTokenSingleOperation::BurnChecked {
|
||||
source: kb_lib::MdPubkey(request.source.trim().to_string()),
|
||||
mint: kb_lib::MdPubkey(request.mint.trim().to_string()),
|
||||
authority,
|
||||
amount: kb_lib::ExSplTokenAmount(request.amount_raw.trim().to_string()),
|
||||
decimals: request.decimals,
|
||||
},
|
||||
"token2022_freeze_account" => kb_lib::ExSplTokenSingleOperation::FreezeAccount {
|
||||
"token_2022_freeze_account" => kb_lib::ExSplTokenSingleOperation::FreezeAccount {
|
||||
account: kb_lib::MdPubkey(request.source.trim().to_string()),
|
||||
mint: kb_lib::MdPubkey(request.mint.trim().to_string()),
|
||||
authority: freeze_authority,
|
||||
},
|
||||
"token2022_thaw_account" => kb_lib::ExSplTokenSingleOperation::ThawAccount {
|
||||
"token_2022_thaw_account" => kb_lib::ExSplTokenSingleOperation::ThawAccount {
|
||||
account: kb_lib::MdPubkey(request.source.trim().to_string()),
|
||||
mint: kb_lib::MdPubkey(request.mint.trim().to_string()),
|
||||
authority: freeze_authority,
|
||||
},
|
||||
"token2022_close_destination" => kb_lib::ExSplTokenSingleOperation::CloseAccount {
|
||||
"token_2022_close_destination" => kb_lib::ExSplTokenSingleOperation::CloseAccount {
|
||||
account: kb_lib::MdPubkey(request.source.trim().to_string()),
|
||||
destination: kb_lib::MdPubkey(request.destination.trim().to_string()),
|
||||
authority,
|
||||
@@ -197,7 +197,7 @@ pub(crate) fn operation_from_request(
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn demo_spl_token2022_summary_payload(
|
||||
pub(crate) fn demo_spl_token_2022_summary_payload(
|
||||
scenario_id: std::string::String,
|
||||
operation: std::string::String,
|
||||
summary: kb_pipeline_demo_scenarios::DevnetSplToken2022ExecutionSummary,
|
||||
@@ -216,9 +216,11 @@ pub(crate) fn demo_spl_token2022_summary_payload(
|
||||
let decode_replayed = post_execution.is_some_and(|value| return value.decode_replayed);
|
||||
let idempotence_validated = summary.idempotence_replay.as_ref().is_some_and(|replay| {
|
||||
return replay.failed_inputs == 0
|
||||
&& replay.processing_error_inputs == 0
|
||||
&& !replay.cancelled
|
||||
&& replay.processors.iter().all(|processor| {
|
||||
return processor.failed == 0
|
||||
&& processor.processing_errors == 0
|
||||
&& processor.materialized_outputs == 0
|
||||
&& processor.materialization_refused == 0;
|
||||
});
|
||||
@@ -340,6 +342,7 @@ fn decode_replay_summary_json(summary: &kb_pipeline::DecodeReplaySummary) -> ser
|
||||
"ignored": processor.ignored,
|
||||
"unsupported": processor.unsupported,
|
||||
"failed": processor.failed,
|
||||
"processingErrors": processor.processing_errors,
|
||||
"materializedOutputs": processor.materialized_outputs,
|
||||
"materializationRefused": processor.materialization_refused
|
||||
});
|
||||
@@ -354,6 +357,7 @@ fn decode_replay_summary_json(summary: &kb_pipeline::DecodeReplaySummary) -> ser
|
||||
"unmatched": summary.unmatched,
|
||||
"notStarted": summary.not_started,
|
||||
"failedInputs": summary.failed_inputs,
|
||||
"processingErrorInputs": summary.processing_error_inputs,
|
||||
"cancelled": summary.cancelled,
|
||||
"processors": processors,
|
||||
"startedAt": summary.started_at,
|
||||
@@ -384,14 +388,14 @@ mod tests {
|
||||
#[test]
|
||||
fn every_public_scenario_builds_one_typed_operation() {
|
||||
for scenario in [
|
||||
"token2022_mint_to_checked",
|
||||
"token2022_transfer_checked",
|
||||
"token2022_approve_checked",
|
||||
"token2022_revoke",
|
||||
"token2022_burn_checked",
|
||||
"token2022_freeze_account",
|
||||
"token2022_thaw_account",
|
||||
"token2022_close_destination",
|
||||
"token_2022_mint_to_checked",
|
||||
"token_2022_transfer_checked",
|
||||
"token_2022_approve_checked",
|
||||
"token_2022_revoke",
|
||||
"token_2022_burn_checked",
|
||||
"token_2022_freeze_account",
|
||||
"token_2022_thaw_account",
|
||||
"token_2022_close_destination",
|
||||
] {
|
||||
assert!(crate::operation_from_request(&request(scenario)).is_ok());
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/src/demo_sql_common.rs
|
||||
// version: 10
|
||||
// version: 11
|
||||
|
||||
//! Shared SQL demo helpers and serializable payloads.
|
||||
|
||||
@@ -138,7 +138,10 @@ pub(crate) async fn initialize_postgres_schema_for_startup(
|
||||
tracing::debug!(target: crate::TRACING_TARGET, backend = profile.database.backend.as_str(), "database backend is not postgres; skip SQL schema initialization");
|
||||
return;
|
||||
}
|
||||
let options_result = postgres_store_options_from_profile(profile, false);
|
||||
let options_result = postgres_store_options_from_profile(
|
||||
profile,
|
||||
profile.database.postgres.auto_initialize_schema,
|
||||
);
|
||||
let mut options = match options_result {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/src/demo_ws.rs
|
||||
// version: 16
|
||||
// version: 17
|
||||
|
||||
//! Standard Solana WebSocket demo commands backed by `kb_onchain_transport::WsSession`.
|
||||
|
||||
@@ -922,7 +922,7 @@ mod tests {
|
||||
);
|
||||
let program = super::build_standard_ws_request(
|
||||
"programSubscribe",
|
||||
std::option::Option::Some(kb_program_ids::SPL_TOKEN2022_PROGRAM_ID.to_string()),
|
||||
std::option::Option::Some(kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID.to_string()),
|
||||
std::option::Option::None,
|
||||
std::option::Option::Some(r#"{"encoding":"jsonParsed"}"#.to_string()),
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/src/lib.rs
|
||||
// version: 11
|
||||
// version: 13
|
||||
|
||||
//! Tauri desktop demo application for `khadhroony-bot3`.
|
||||
|
||||
@@ -18,7 +18,7 @@ mod demo_execution_spl;
|
||||
mod demo_http;
|
||||
mod demo_spl_ata;
|
||||
mod demo_spl_token;
|
||||
mod demo_spl_token2022;
|
||||
mod demo_spl_token_2022;
|
||||
mod demo_sql_common;
|
||||
mod demo_sql_diag;
|
||||
mod demo_sql_pg_core;
|
||||
@@ -66,6 +66,8 @@ pub(crate) use self::demo_core_extraction::DemoCoreExtractionObserver;
|
||||
/// Internal demo core extraction item.
|
||||
pub(crate) use self::demo_core_extraction::DemoCoreExtractionOptionsPayload;
|
||||
/// Internal demo core extraction item.
|
||||
pub(crate) use self::demo_core_extraction::DemoCoreExtractionProgramOption;
|
||||
/// Internal demo core extraction item.
|
||||
pub(crate) use self::demo_core_extraction::DemoCoreExtractionProgressPayload;
|
||||
/// Internal demo core extraction item.
|
||||
pub(crate) use self::demo_core_extraction::DemoCoreExtractionRequest;
|
||||
@@ -95,7 +97,7 @@ pub(crate) use self::demo_decode_replay::DemoDecodeReplayDecoderOption;
|
||||
pub(crate) use self::demo_decode_replay::DemoDecodeReplayObserver;
|
||||
/// Internal demo decode replay item.
|
||||
pub(crate) use self::demo_decode_replay::DemoDecodeReplayOptionsPayload;
|
||||
/// One known program suggested by the free-form Program ID field.
|
||||
/// Internal demo decode replay program option.
|
||||
pub(crate) use self::demo_decode_replay::DemoDecodeReplayProgramOption;
|
||||
/// Internal demo decode replay item.
|
||||
pub(crate) use self::demo_decode_replay::DemoDecodeReplayProgressPayload;
|
||||
@@ -220,17 +222,17 @@ pub(crate) use self::demo_spl_token::payload_matches;
|
||||
/// Loads a bounded, typed journal of committed classic SPL Token projections.
|
||||
pub(crate) use self::demo_spl_token::validate_journal_request;
|
||||
/// Request for one independent public Token-2022 Devnet scenario.
|
||||
pub(crate) use self::demo_spl_token2022::DemoExecutionSplToken2022Request;
|
||||
pub(crate) use self::demo_spl_token_2022::DemoExecutionSplToken2022Request;
|
||||
/// UI-safe result of one public Token-2022 Devnet orchestration.
|
||||
pub(crate) use self::demo_spl_token2022::DemoExecutionSplToken2022SummaryPayload;
|
||||
pub(crate) use self::demo_spl_token_2022::DemoExecutionSplToken2022SummaryPayload;
|
||||
/// Public values loaded from one persisted Token-2022 validation fixture.
|
||||
pub(crate) use self::demo_spl_token2022::DemoSplToken2022FixturePayload;
|
||||
pub(crate) use self::demo_spl_token_2022::DemoSplToken2022FixturePayload;
|
||||
/// ????
|
||||
pub(crate) use self::demo_spl_token2022::demo_spl_token2022_summary_payload;
|
||||
pub(crate) use self::demo_spl_token_2022::demo_spl_token_2022_summary_payload;
|
||||
/// ????
|
||||
pub(crate) use self::demo_spl_token2022::operation_from_request;
|
||||
pub(crate) use self::demo_spl_token_2022::operation_from_request;
|
||||
/// ????
|
||||
pub(crate) use self::demo_spl_token2022::parse_fixture;
|
||||
pub(crate) use self::demo_spl_token_2022::parse_fixture;
|
||||
/// UI-safe SQL table diagnostic snapshot.
|
||||
pub(crate) use self::demo_sql_common::DemoSqlTableSnapshot;
|
||||
/// Connects to the configured PostgreSQL store.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/src/tauri.rs
|
||||
// version: 15
|
||||
// version: 17
|
||||
|
||||
//! Tauri runtime assembly and private command wrappers.
|
||||
|
||||
@@ -76,8 +76,8 @@ pub fn run() -> kb_core::Result<()> {
|
||||
demo_execution_spl_validation_scenarios,
|
||||
demo_execution_spl_token_execute,
|
||||
demo_spl_token_journal,
|
||||
demo_execution_spl_token2022_execute,
|
||||
demo_spl_token2022_fixture,
|
||||
demo_execution_spl_token_2022_execute,
|
||||
demo_spl_token_2022_fixture,
|
||||
demo_spl_ata_derive,
|
||||
demo_execution_spl_ata_execute,
|
||||
demo_spl_ata_journal,
|
||||
@@ -424,6 +424,7 @@ async fn demo_decode_replay_execute(
|
||||
unmatched = summary.unmatched,
|
||||
not_started = summary.not_started,
|
||||
failed_inputs = summary.failed_inputs,
|
||||
processing_error_inputs = summary.processing_error_inputs,
|
||||
cancelled = summary.cancelled,
|
||||
processors = ?summary.processors,
|
||||
"contextual decode replay command completed"
|
||||
@@ -1326,13 +1327,13 @@ fn demo_execution_spl_validation_scenarios()
|
||||
label: scenario.label,
|
||||
family: match scenario.family {
|
||||
kb_pipeline_demo_scenarios::DevnetSplValidationFamily::Token2022Public => {
|
||||
"token2022_public".to_string()
|
||||
"token_2022_public".to_string()
|
||||
},
|
||||
kb_pipeline_demo_scenarios::DevnetSplValidationFamily::ElGamalRegistry => {
|
||||
"elgamal_registry".to_string()
|
||||
},
|
||||
kb_pipeline_demo_scenarios::DevnetSplValidationFamily::Token2022Confidential => {
|
||||
"token2022_confidential".to_string()
|
||||
"token_2022_confidential".to_string()
|
||||
},
|
||||
},
|
||||
operation_code: scenario.operation_code,
|
||||
@@ -1712,7 +1713,7 @@ async fn demo_spl_ata_journal(
|
||||
|
||||
/// Executes one public Token-2022 simulation or explicitly authorized Devnet submission.
|
||||
#[tauri::command]
|
||||
async fn demo_execution_spl_token2022_execute(
|
||||
async fn demo_execution_spl_token_2022_execute(
|
||||
app_handle: tauri::AppHandle,
|
||||
state: tauri::State<'_, crate::AppState>,
|
||||
request: crate::DemoExecutionSplToken2022Request,
|
||||
@@ -1775,7 +1776,7 @@ async fn demo_execution_spl_token2022_execute(
|
||||
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_spl_token2022(
|
||||
let summary = match kb_pipeline_demo_scenarios::execute_devnet_spl_token_2022(
|
||||
&http_pool,
|
||||
&store,
|
||||
&profile,
|
||||
@@ -1790,7 +1791,7 @@ async fn demo_execution_spl_token2022_execute(
|
||||
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::demo_spl_token2022_summary_payload(
|
||||
return std::result::Result::Ok(crate::demo_spl_token_2022_summary_payload(
|
||||
request.scenario_id,
|
||||
operation_code,
|
||||
summary,
|
||||
@@ -1799,7 +1800,7 @@ async fn demo_execution_spl_token2022_execute(
|
||||
|
||||
/// Loads public Token-2022 fixture values without reading private key bytes.
|
||||
#[tauri::command]
|
||||
fn demo_spl_token2022_fixture(
|
||||
fn demo_spl_token_2022_fixture(
|
||||
state: tauri::State<'_, crate::AppState>,
|
||||
profile_name: std::string::String,
|
||||
) -> std::result::Result<crate::DemoSplToken2022FixturePayload, std::string::String> {
|
||||
@@ -1813,7 +1814,7 @@ fn demo_spl_token2022_fixture(
|
||||
} else {
|
||||
crate::workspace_root_dir().join(configured)
|
||||
};
|
||||
let fixture_path = wallet_dir.join("spl_token2022_validation").join("fixture.env");
|
||||
let fixture_path = wallet_dir.join("spl_token_2022_validation").join("fixture.env");
|
||||
let contents = match std::fs::read_to_string(&fixture_path) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/vite.config.ts
|
||||
// version: 6
|
||||
// version: 7
|
||||
|
||||
import { defineConfig, normalizePath } from "vite";
|
||||
import { NodePackageImporter } from "sass-embedded";
|
||||
@@ -40,7 +40,7 @@ export default defineConfig(() => ({
|
||||
entryFileNames: 'js/[name]-[hash].js',
|
||||
chunkFileNames: 'js/chunks/[name]-[hash].js',
|
||||
assetFileNames: (assetInfo) => {
|
||||
const originalName = assetInfo.name ?? '';
|
||||
const originalName = assetInfo.names[0] ?? '';
|
||||
const ext = originalName.substring(originalName.lastIndexOf('.') + 1).toLowerCase();
|
||||
if (ext === 'js') {
|
||||
return 'js/[name]-[hash][extname]';
|
||||
|
||||
Reference in New Issue
Block a user