v0.2.7-pre.014
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/ksp-app-config-desk/README.md -->
|
||||
<!-- version: 27 -->
|
||||
<!-- version: 28 -->
|
||||
|
||||
# `ksp-app-config-desk`
|
||||
|
||||
@@ -78,7 +78,7 @@ Les DTO Rust applicatifs restent la source de vérité et les bindings généré
|
||||
|
||||
## Robustesse desktop et extensibilité
|
||||
|
||||
`pre.018` rend le fallback de bootstrap Logging testable avant installation du subscriber : la résolution produit d'abord un plan `managed` ou `fallback`, puis seulement l'initialisation runtime est tentée. Une source Logging invalide peut ainsi être couverte par test sans installer un subscriber global dans le processus de tests. Le fallback reste transitoire, console-only, niveau `Info`, sans file sink.
|
||||
Le fallback de bootstrap Logging est testable avant installation du subscriber : la résolution produit d'abord un plan `managed` ou `fallback`, puis seulement l'initialisation runtime est tentée. Une source Logging invalide peut ainsi être couverte par test sans installer un subscriber global dans le processus de tests. Le fallback reste transitoire, console-only, niveau `Info`, sans file sink.
|
||||
|
||||
Le frontend possède désormais `shell_registry.ts`. Le registre décrit les vues du shell et les adapters d'éditeurs spécialisés par `file_id`. Le panneau Documents reste générique ; lorsqu'un document possède un adapter enregistré, **Ouvrir l'éditeur spécialisé** déclenche la navigation par événement de registre. `cfg.std.logging -> Logging` est le premier adapter. Ajouter un futur éditeur ne demande donc pas de réécrire le moteur Documents ni la logique générale d'activation des panneaux.
|
||||
|
||||
@@ -123,11 +123,11 @@ main -> ksp-app-config-desk.frontend.main
|
||||
splash -> ksp-app-config-desk.frontend.splash
|
||||
```
|
||||
|
||||
Rust valide le niveau et le `targetId`, choisit un callsite statique puis émet exclusivement via les macros de `ksp-logging-lib`. Le package applicatif n'importe pas directement `tracing`. Le pont actuel garantit donc le trajet WebView -> Rust tout en conservant l'affichage local des appels `console.*` dans la console WebKit. Le retour général Rust -> console WebKit est volontairement hors périmètre de `0.1.4` : une future intégration devra passer par une couche possédée par `ksp-logging-lib`, sans second subscriber, double émission ni boucle avec le bridge KSP. Le panneau **Test Logging** complète désormais ce bridge : il peut émettre des événements backend via `ksp-logging-lib` avec target KSP statique et domain contrôlé, ou réutiliser le bridge frontend existant avec son target/domain fixes.
|
||||
Rust valide le niveau et le `targetId`, choisit un callsite statique puis émet exclusivement via les macros de `ksp-logging-lib`. Le package applicatif n'importe pas directement `tracing`. Le pont actuel garantit donc le trajet WebView -> Rust tout en conservant l'affichage local des appels `console.*` dans la console WebKit. Le retour général Rust -> console WebKit reste volontairement hors de la surface actuelle : une future intégration devra passer par une couche possédée par `ksp-logging-lib`, sans second subscriber, double émission ni boucle avec le bridge KSP. Le panneau **Test Logging** complète désormais ce bridge : il peut émettre des événements backend via `ksp-logging-lib` avec target KSP statique et domain contrôlé, ou réutiliser le bridge frontend existant avec son target/domain fixes.
|
||||
|
||||
## Panneau Test Logging
|
||||
|
||||
`pre.017` ajoute une surface de validation volontairement explicite. Le champ **Message** est le contenu qui sera réellement journalisé ; il ne doit donc jamais recevoir de Secret. **Log backend** appelle `emit_logging_test`, qui valide le niveau (`trace/debug/info/warn/error/tous`), choisit un target statique (`ksp-app-config-desk` ou `ksp-app-config-desk.logging-test`) et applique un domain absent, connu ou personnalisé borné avant d'émettre exclusivement avec les macros `ksp-logging-lib`. Le résultat retourne uniquement des métadonnées sûres : nombre d'événements, niveau demandé, target/domain effectifs et génération runtime.
|
||||
Le panneau fournit une surface de validation volontairement explicite. Le champ **Message** est le contenu qui sera réellement journalisé ; il ne doit donc jamais recevoir de Secret. **Log backend** appelle `emit_logging_test`, qui valide le niveau (`trace/debug/info/warn/error/tous`), choisit un target statique (`ksp-app-config-desk` ou `ksp-app-config-desk.logging-test`) et applique un domain absent, connu ou personnalisé borné avant d'émettre exclusivement avec les macros `ksp-logging-lib`. Le résultat retourne uniquement des métadonnées sûres : nombre d'événements, niveau demandé, target/domain effectifs et génération runtime.
|
||||
|
||||
**Log via bridge frontend** réutilise le bridge déjà installé. Son contrat reste volontairement fixe : `target=ksp-app-config-desk.frontend.main`, `domain=frontend`. Cela permet de comparer dans le même panneau le routing backend et le chemin WebView -> Rust -> `ksp-logging-lib`, avant et après modification/hot reload des filtres.
|
||||
|
||||
@@ -171,13 +171,13 @@ La vue **Logging** charge le document standard exclusivement avec `ConfigManagem
|
||||
|
||||
Le panneau expose `format_version`, `logs_directory`, `default_profile`, tous les profils, la console, les fichiers persistants, les filtres locaux, les target overrides et les listes de targets/domains. Le frontend maintient un brouillon typé : create/clone/rename/delete de profils, 0/1/N file sinks et target filters restent locaux jusqu'à **Sauvegarder et appliquer**. Le backend reconstruit les types publics Config et appelle `ConfigManagement::save_logging_document()`, qui valide la totalité du candidat avant remplacement atomique. Après persistence, Config Desk recharge un `ConfigEnvironment` frais, résout le `default_profile`, puis appelle `ksp_logging_lib::reinitialize()` sur le `LoggingGuard` actif. Le hot reload est immédiat et `logging_generation` avance uniquement après succès. Si l'application runtime échoue, l'ancien runtime reste actif et la source précédente est restaurée. **Recharger le document** ne modifie que le brouillon/source persistée.
|
||||
|
||||
`pre.016` distingue en plus le **profil default persistant** du **profil runtime actif**. La section **Runtime actif** expose le profil actuellement appliqué, `selection_source` (`default_profile`, `explicit` ou `fallback`), la génération, l'état console, les compteurs de lignes abandonnées et les file sinks réellement actifs. Un profil déjà persisté peut être appliqué explicitement sans modifier `default_profile` ni écrire le document ; cette action est désactivée tant que le brouillon contient des changements non sauvegardés.
|
||||
Le panneau distingue le **profil default persistant** du **profil runtime actif**. La section **Runtime actif** expose le profil actuellement appliqué, `selection_source` (`default_profile`, `explicit` ou `fallback`), la génération, l'état console, les compteurs de lignes abandonnées et les file sinks réellement actifs. Un profil déjà persisté peut être appliqué explicitement sans modifier `default_profile` ni écrire le document ; cette action est désactivée tant que le brouillon contient des changements non sauvegardés.
|
||||
|
||||
Chaque lancement de Config Desk crée aussi une `LoggingRuntimeIdentity` stable : `application_id` + timestamp UTC de démarrage + PID. `ksp-logging-lib` utilise cette identité pour préfixer les noms des fichiers actifs et la conserve pendant tous les hot reloads du même processus. Deux lancements distincts ne partagent donc plus le même fichier persistant, même avec une rotation `daily`. Avec la configuration de release `info/ksp-info.log`, un prefix effectif peut être `ksp-app-config-desk.20260816-182519.123Z-p4242.ksp-info.log`. Le path Config reste inchangé ; l'identité appartient au runtime, pas au document source.
|
||||
|
||||
## Baseline Logging de release
|
||||
|
||||
La configuration canonique livrée avec `0.1.4` revient à une baseline opératoire `info` conformément à KSP-APP-031 : console `info`, sink général `info/ksp-info.log` au niveau `info`, et overrides `ksp-config-lib`, `ksp-logging-lib`, `ksp-app-config-desk` à `info`. Le `default_filter` reste `warn` pour les autres targets KSP. Les niveaux `debug`/`trace` restent disponibles et peuvent être remontés temporairement depuis Config Desk lors d’un développement ou diagnostic, puis redescendus avant la release suivante.
|
||||
La configuration canonique de release utilise une baseline opératoire `info` conformément à KSP-APP-031 : console `info`, sink général `info/ksp-info.log` au niveau `info`, et overrides `ksp-config-lib`, `ksp-logging-lib`, `ksp-app-config-desk` à `info`. Le `default_filter` reste `warn` pour les autres targets KSP. Les niveaux `debug`/`trace` restent disponibles et peuvent être remontés temporairement depuis Config Desk lors d’un développement ou diagnostic, puis redescendus avant la release suivante.
|
||||
|
||||
## Traçabilité frontend
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/ksp-app-config-desk/USAGE.md -->
|
||||
<!-- version: 27 -->
|
||||
<!-- version: 28 -->
|
||||
|
||||
# Utilisation de `ksp-app-config-desk`
|
||||
|
||||
@@ -85,7 +85,7 @@ splash
|
||||
|
||||
Ils sont convertis côté Rust vers des targets KSP statiques `ksp-app-config-desk.frontend*` et émis uniquement via `ksp-logging-lib`. Un niveau différent de `trace`, `debug`, `info`, `warn` ou `error`, ou un `targetId` non whitelisté, est rejeté avec un `CommandErrorDto` sûr.
|
||||
|
||||
`main.ts` et `splash.ts` installent aussi le bridge `console.*`; l'échec éventuel d'un `invoke` est écrit uniquement sur la console WebView originale afin d'éviter une boucle de logging. Ce bridge conserve les messages JavaScript dans la console WebKit et les transmet vers Rust. Le retour général Rust -> console WebKit est reporté hors `0.1.4`; il devra être ajouté ultérieurement sous ownership de `ksp-logging-lib`, sans installer de subscriber Tauri parallèle ni créer de boucle avec ce bridge.
|
||||
`main.ts` et `splash.ts` installent aussi le bridge `console.*`; l'échec éventuel d'un `invoke` est écrit uniquement sur la console WebView originale afin d'éviter une boucle de logging. Ce bridge conserve les messages JavaScript dans la console WebKit et les transmet vers Rust. Le retour général Rust -> console WebKit reste hors de la surface actuelle ; il devra être ajouté ultérieurement sous ownership de `ksp-logging-lib`, sans installer de subscriber Tauri parallèle ni créer de boucle avec ce bridge.
|
||||
|
||||
## Bindings TS-RS
|
||||
|
||||
@@ -287,7 +287,7 @@ Si la résolution ou la préparation du profil explicite échoue, `ksp_logging_l
|
||||
|
||||
## Baseline Logging de release
|
||||
|
||||
Après les tests `debug`/`trace`, la configuration canonique `0.1.4` revient à :
|
||||
Après les tests `debug`/`trace`, la configuration canonique revient à :
|
||||
|
||||
```text
|
||||
default_filter = warn
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!-- file: crates/ksp-app-wallet-desk/README.md -->
|
||||
<!-- version: 2 -->
|
||||
<!-- version: 3 -->
|
||||
|
||||
# `ksp-app-wallet-desk`
|
||||
|
||||
`ksp-app-wallet-desk` est l'application desktop spécialisée stable d'administration et de validation des wallets KSP depuis KSP `0.2.6`.
|
||||
`ksp-app-wallet-desk` est l'application desktop spécialisée stable d'administration et de validation des wallets KSP.
|
||||
|
||||
La crate est un package Tauri mixte :
|
||||
|
||||
@@ -29,7 +29,7 @@ Le frontend ne reçoit jamais les keypairs, ciphertexts, passwords Config, paths
|
||||
|
||||
## `.kspwallet` V1/V2
|
||||
|
||||
La release `0.2.6` conserve V1 et ajoute V2 :
|
||||
La surface courante conserve V1 et utilise V2 comme format natif par défaut :
|
||||
|
||||
```text
|
||||
V1 : JSON UTF-8 historique, lecture explicite toujours supportée
|
||||
@@ -45,9 +45,9 @@ Wallet Desk consomme uniquement les APIs non versionnées de `ksp-wallet-lib` :
|
||||
|
||||
`ksp-wallet-lib` conserve parallèlement les APIs explicites `_v1` / `_v2` pour les consumers qui doivent imposer un format. `DEFAULT_WALLET_FORMAT` et `LATEST_SUPPORTED_WALLET_FORMAT` sont des politiques distinctes ; l'apparition future d'un V3 n'impose donc pas de modifier automatiquement le format créé par les APIs génériques.
|
||||
|
||||
La migration V1 -> V2 est une opération explicite OWNER-authentifiée possédée par `ksp-wallet-lib`. Wallet Desk `0.2.6` ne migre jamais silencieusement un wallet lors de sa sélection, inspection ou ouverture.
|
||||
La migration V1 -> V2 est une opération explicite OWNER-authentifiée possédée par `ksp-wallet-lib`. Wallet Desk ne migre jamais silencieusement un wallet lors de sa sélection, inspection ou ouverture.
|
||||
|
||||
## Capacités fonctionnelles `0.2.6`
|
||||
## Capacités fonctionnelles
|
||||
|
||||
La surface validée comprend :
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/ksp-config-lib/README.md -->
|
||||
<!-- version: 7 -->
|
||||
<!-- version: 8 -->
|
||||
|
||||
# ksp-config-lib
|
||||
|
||||
@@ -86,7 +86,7 @@ Le document Logging refuse les valeurs de sensibilité `Secret` dans sa configur
|
||||
## Documentation
|
||||
|
||||
- [`USAGE.md`](USAGE.md) — construction du moteur, résolution runtime et management ;
|
||||
- [`TODO.md`](TODO.md) — points explicitement différés après `0.1.3` ;
|
||||
- [`TODO.md`](TODO.md) — points explicitement différés ;
|
||||
- [`../../docs/plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md`](../../docs/plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md) — plan historique détaillé de la fondation Config ;
|
||||
- [`../../config/std.logging.json`](../../config/std.logging.json) — document standard Logging ;
|
||||
- [`../../config/std.transport.json`](../../config/std.transport.json) — document standard Transport V2 HTTP + WebSocket, avec lecture backward du V1 HTTP-only ;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/ksp-config-lib/USAGE.md -->
|
||||
<!-- version: 7 -->
|
||||
<!-- version: 8 -->
|
||||
|
||||
# Utilisation de ksp-config-lib
|
||||
|
||||
@@ -140,7 +140,7 @@ let ws_settings = transport.ws_settings();
|
||||
let _ = (http_settings, ws_settings);
|
||||
```
|
||||
|
||||
`std.transport` V2 conserve `retry` et `profiles[].endpoints[]` pour HTTP, ajoute `ws_defaults` et `profiles[].ws_endpoints[]`, puis exige `kind = "solana_standard"` en `0.2.7`. Un `ws_endpoints[].session` optionnel surcharge seulement les paramètres génériques de `WsSessionSettings`.
|
||||
`std.transport` V2 conserve `retry` et `profiles[].endpoints[]` pour HTTP, ajoute `ws_defaults` et `profiles[].ws_endpoints[]`, puis exige actuellement `kind = "solana_standard"`. Un `ws_endpoints[].session` optionnel surcharge seulement les paramètres génériques de `WsSessionSettings`.
|
||||
|
||||
Le même schema enregistré conserve la lecture stricte du V1 historique : dans ce cas `http_settings()` reste disponible et `ws_settings()` retourne `None`. Aucun `WsTransportSettings` vide n'est inventé pour simuler l'absence de WebSocket.
|
||||
|
||||
|
||||
135
crates/ksp-core-lib/README.md
Normal file
135
crates/ksp-core-lib/README.md
Normal file
@@ -0,0 +1,135 @@
|
||||
<!-- file: crates/ksp-core-lib/README.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# `ksp-core-lib`
|
||||
|
||||
`ksp-core-lib` porte les contrats fondamentaux partagés par les couches KSP sans dépendre des domaines de plus haut niveau.
|
||||
|
||||
La crate possède actuellement trois responsabilités :
|
||||
|
||||
- le type d'erreur commun KSP ;
|
||||
- le type Solana `Pubkey` réexporté comme primitive d'adresse canonique ;
|
||||
- le registre KSP des Program IDs Solana fondamentaux et leur taxonomie.
|
||||
|
||||
## Frontière architecturale
|
||||
|
||||
Core reste une couche basse. Elle ne possède ni configuration, ni logging runtime, ni transport réseau, ni wallet, ni stockage, ni logique de décodage/exécution.
|
||||
|
||||
Les crates de niveau supérieur peuvent dépendre de Core et réutiliser ses contrats ; Core ne doit pas introduire de dépendance inverse vers ces couches.
|
||||
|
||||
La seule dépendance runtime externe directe actuelle est `solana-pubkey`, utilisée pour la primitive `Pubkey`.
|
||||
|
||||
## Erreur commune KSP
|
||||
|
||||
Le contrat d'erreur public repose sur :
|
||||
|
||||
```text
|
||||
ErrorCode
|
||||
ErrorContext
|
||||
Error
|
||||
Result<T>
|
||||
```
|
||||
|
||||
`ErrorCode` sépare un `domain` stable d'un `code` stable. `Error` ajoute :
|
||||
|
||||
- un message humain ;
|
||||
- des champs de contexte ordonnés ;
|
||||
- une source d'erreur standard optionnelle compatible `Send + Sync`.
|
||||
|
||||
L'affichage d'une erreur reste compact :
|
||||
|
||||
```text
|
||||
<domain>.<code>: <message>
|
||||
```
|
||||
|
||||
Les consommateurs ajoutent uniquement des contextes sûrs. Les secrets, credentials, key material, URLs sensibles ou payloads massifs ne doivent pas être copiés dans le message ou le contexte d'une erreur.
|
||||
|
||||
## `Pubkey`
|
||||
|
||||
La crate réexporte :
|
||||
|
||||
```rust
|
||||
ksp_core_lib::Pubkey
|
||||
```
|
||||
|
||||
Les autres crates KSP utilisent cette primitive lorsqu'un contrat public a besoin d'une adresse Solana générique. Elles évitent ainsi de multiplier les propriétaires de type pour la même notion.
|
||||
|
||||
## Program IDs fondamentaux
|
||||
|
||||
Core possède 18 Program IDs Solana fondamentaux sous deux formes cohérentes :
|
||||
|
||||
```text
|
||||
PRGID_* -> Base58 &str
|
||||
PRGIDPK_* -> Pubkey typé
|
||||
```
|
||||
|
||||
Les deux formes sont déclarées depuis une même valeur grâce à `declare_program_id!`.
|
||||
|
||||
Le registre couvre notamment :
|
||||
|
||||
- System, Vote, Stake, Config et Feature ;
|
||||
- Address Lookup Table et Compute Budget ;
|
||||
- les loaders natif, BPF v1, BPF v2, BPF upgradeable et Loader v4 ;
|
||||
- les precompiles Ed25519, Secp256k1 et Secp256r1 ;
|
||||
- Slashing ;
|
||||
- ZK ElGamal Proof et ZK Token Proof.
|
||||
|
||||
Le registre n'est pas un catalogue général de tous les programmes Solana. Les protocoles, applications et Program IDs de domaines futurs sont ajoutés dans les couches propriétaires appropriées lorsqu'un besoin réel existe.
|
||||
|
||||
## Registre et taxonomie
|
||||
|
||||
Chaque entrée est exposée sous `ProgramIdEntry` avec :
|
||||
|
||||
```text
|
||||
code
|
||||
name
|
||||
program_id
|
||||
pubkey
|
||||
domain
|
||||
family
|
||||
protocol
|
||||
subfamily
|
||||
program_version
|
||||
kind
|
||||
```
|
||||
|
||||
`ProgramIdKind` distingue actuellement :
|
||||
|
||||
```text
|
||||
Program
|
||||
Loader
|
||||
Precompile
|
||||
EnshrinedProgram
|
||||
```
|
||||
|
||||
La lecture du registre s'effectue par :
|
||||
|
||||
```text
|
||||
entries()
|
||||
native_program_ids()
|
||||
program_ids(filter)
|
||||
program_ids_by_domain(...)
|
||||
program_ids_by_family(...)
|
||||
program_ids_by_protocol(...)
|
||||
find_program_id(...)
|
||||
find_program_pubkey(...)
|
||||
```
|
||||
|
||||
`ProgramIdFilter` permet de combiner les axes `domain`, `family`, `protocol`, `subfamily`, `program_version` et `kind`.
|
||||
|
||||
## Garanties validées
|
||||
|
||||
Les tests publics et unitaires verrouillent notamment :
|
||||
|
||||
- la correspondance Base58 / `Pubkey` des constantes ;
|
||||
- l'unicité des codes, Program IDs et pubkeys du registre ;
|
||||
- les 18 entrées fondamentales ;
|
||||
- les recherches textuelles et typées ;
|
||||
- les vues et filtres taxonomiques ;
|
||||
- l'absence des comptes well-known qui ne sont pas des programmes ;
|
||||
- le contrat `Error`, son ordre de contexte et sa chaîne `source()` ;
|
||||
- `Error: Send + Sync`.
|
||||
|
||||
## Documentation
|
||||
|
||||
- [`USAGE.md`](USAGE.md) — exemples d'utilisation de l'erreur commune, de `Pubkey`, des Program IDs et du registre.
|
||||
265
crates/ksp-core-lib/USAGE.md
Normal file
265
crates/ksp-core-lib/USAGE.md
Normal file
@@ -0,0 +1,265 @@
|
||||
<!-- file: crates/ksp-core-lib/USAGE.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Utilisation de `ksp-core-lib`
|
||||
|
||||
## Utiliser le type d'erreur commun
|
||||
|
||||
Une crate KSP définit des codes stables puis retourne `ksp_core_lib::Result<T>` :
|
||||
|
||||
```rust
|
||||
const ERROR_CODE_LOAD_FAILED: ksp_core_lib::ErrorCode =
|
||||
ksp_core_lib::ErrorCode::new("store", "load_failed");
|
||||
|
||||
fn load_value() -> ksp_core_lib::Result<u64> {
|
||||
let error = ksp_core_lib::Error::new(
|
||||
ERROR_CODE_LOAD_FAILED,
|
||||
"unable to load value",
|
||||
)
|
||||
.with_context("operation", "load_value");
|
||||
|
||||
return std::result::Result::Err(error);
|
||||
}
|
||||
```
|
||||
|
||||
Le domaine et le code sont accessibles séparément :
|
||||
|
||||
```rust
|
||||
let code = ERROR_CODE_LOAD_FAILED;
|
||||
assert_eq!(code.domain(), "store");
|
||||
assert_eq!(code.code(), "load_failed");
|
||||
```
|
||||
|
||||
Le message et les champs de contexte restent accessibles sans parser `Display` :
|
||||
|
||||
```rust
|
||||
let error = ksp_core_lib::Error::new(
|
||||
ERROR_CODE_LOAD_FAILED,
|
||||
"unable to load value",
|
||||
)
|
||||
.with_context("component", "postgres")
|
||||
.with_context("operation", "load_value");
|
||||
|
||||
assert_eq!(error.code(), ERROR_CODE_LOAD_FAILED);
|
||||
assert_eq!(error.message(), "unable to load value");
|
||||
assert_eq!(error.context()[0].key(), "component");
|
||||
assert_eq!(error.context()[0].value(), "postgres");
|
||||
```
|
||||
|
||||
Un `ErrorContext` peut aussi être construit indépendamment lorsqu’un caller prépare explicitement son contexte :
|
||||
|
||||
```rust
|
||||
let context = ksp_core_lib::ErrorContext::new(
|
||||
"operation",
|
||||
"load_value",
|
||||
);
|
||||
|
||||
assert_eq!(context.key(), "operation");
|
||||
assert_eq!(context.value(), "load_value");
|
||||
```
|
||||
|
||||
Les valeurs de contexte doivent être sûres à exposer. Ne pas y placer de secret, credential, seed, key material, URL contenant une clé API ou payload brut volumineux.
|
||||
|
||||
## Conserver une erreur source
|
||||
|
||||
Une erreur externe compatible `Send + Sync + 'static` peut rester dans la chaîne standard :
|
||||
|
||||
```rust
|
||||
#[derive(Debug)]
|
||||
struct SourceError;
|
||||
|
||||
impl std::fmt::Display for SourceError {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
return formatter.write_str("source failure");
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for SourceError {}
|
||||
|
||||
let error = ksp_core_lib::Error::new(
|
||||
ERROR_CODE_LOAD_FAILED,
|
||||
"unable to load value",
|
||||
)
|
||||
.with_source(SourceError);
|
||||
|
||||
let source = std::error::Error::source(&error);
|
||||
assert!(source.is_some());
|
||||
```
|
||||
|
||||
La source sert au chaînage d'erreurs ; son contenu ne doit pas être recopié sans contrôle dans un contexte ou un log public.
|
||||
|
||||
## Utiliser `Pubkey`
|
||||
|
||||
Core réexporte la primitive Solana utilisée par les contrats KSP :
|
||||
|
||||
```rust
|
||||
let system = ksp_core_lib::Pubkey::from_str_const(
|
||||
ksp_core_lib::PRGID_SOLANA_SYSTEM,
|
||||
);
|
||||
|
||||
assert_eq!(system, ksp_core_lib::PRGIDPK_SOLANA_SYSTEM);
|
||||
```
|
||||
|
||||
Une crate consommatrice peut donc utiliser `ksp_core_lib::Pubkey` dans sa propre API sans dépendre directement de `solana-pubkey` lorsque Core est déjà le propriétaire architectural de cette primitive.
|
||||
|
||||
## Utiliser les constantes Program ID
|
||||
|
||||
Chaque Program ID Core possède une forme texte et une forme typée :
|
||||
|
||||
```rust
|
||||
let system_text: &str = ksp_core_lib::PRGID_SOLANA_SYSTEM;
|
||||
let system_pubkey: ksp_core_lib::Pubkey =
|
||||
ksp_core_lib::PRGIDPK_SOLANA_SYSTEM;
|
||||
|
||||
assert_eq!(
|
||||
system_pubkey,
|
||||
ksp_core_lib::Pubkey::from_str_const(system_text),
|
||||
);
|
||||
```
|
||||
|
||||
Les constantes `PRGID_*` sont utiles pour les wires, diagnostics sûrs ou comparaisons texte. Les constantes `PRGIDPK_*` sont préférées dès qu'un contrat manipule une adresse Solana typée.
|
||||
|
||||
## Déclarer une paire texte / `Pubkey`
|
||||
|
||||
`declare_program_id!` permet à une couche KSP propriétaire d'un Program ID de déclarer les deux représentations depuis une seule valeur Base58 :
|
||||
|
||||
```rust
|
||||
ksp_core_lib::declare_program_id!(
|
||||
PRGID_EXAMPLE,
|
||||
PRGIDPK_EXAMPLE,
|
||||
"11111111111111111111111111111111"
|
||||
);
|
||||
|
||||
assert_eq!(PRGID_EXAMPLE, ksp_core_lib::PRGID_SOLANA_SYSTEM);
|
||||
assert_eq!(PRGIDPK_EXAMPLE, ksp_core_lib::PRGIDPK_SOLANA_SYSTEM);
|
||||
```
|
||||
|
||||
La macro ne signifie pas que toute nouvelle constante doit être ajoutée au registre Core. La couche propriétaire du domaine décide où vit le nouveau Program ID.
|
||||
|
||||
## Parcourir le registre canonique
|
||||
|
||||
`entries()` retourne le registre complet en ordre déterministe :
|
||||
|
||||
```rust
|
||||
for entry in ksp_core_lib::entries() {
|
||||
let code = entry.code();
|
||||
let name = entry.name();
|
||||
let text = entry.program_id();
|
||||
let pubkey = entry.pubkey();
|
||||
let domain = entry.domain();
|
||||
let family = entry.family();
|
||||
let protocol = entry.protocol();
|
||||
let subfamily = entry.subfamily();
|
||||
let program_version = entry.program_version();
|
||||
let kind = entry.kind();
|
||||
|
||||
let _ = (
|
||||
code,
|
||||
name,
|
||||
text,
|
||||
pubkey,
|
||||
domain,
|
||||
family,
|
||||
protocol,
|
||||
subfamily,
|
||||
program_version,
|
||||
kind,
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
`native_program_ids()` fournit la vue des Program IDs Solana fondamentaux actuellement enregistrés :
|
||||
|
||||
```rust
|
||||
let count = ksp_core_lib::native_program_ids().count();
|
||||
assert_eq!(count, 18);
|
||||
```
|
||||
|
||||
## Rechercher une entrée
|
||||
|
||||
Recherche par représentation Base58 :
|
||||
|
||||
```rust
|
||||
let entry = ksp_core_lib::find_program_id(
|
||||
ksp_core_lib::PRGID_SOLANA_SYSTEM,
|
||||
);
|
||||
|
||||
let entry = match entry {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
|
||||
assert_eq!(entry.code(), "solana.system");
|
||||
```
|
||||
|
||||
Recherche par `Pubkey` :
|
||||
|
||||
```rust
|
||||
let entry = ksp_core_lib::find_program_pubkey(
|
||||
&ksp_core_lib::PRGIDPK_SOLANA_VOTE,
|
||||
);
|
||||
|
||||
assert!(entry.is_some());
|
||||
```
|
||||
|
||||
Une recherche inconnue retourne `None`; le registre n'invente pas une entrée générique.
|
||||
|
||||
## Filtrer par axe simple
|
||||
|
||||
Les helpers spécialisés conviennent aux filtres simples :
|
||||
|
||||
```rust
|
||||
let loaders = ksp_core_lib::program_ids_by_family("loader");
|
||||
for loader in loaders {
|
||||
assert_eq!(loader.family(), "loader");
|
||||
}
|
||||
```
|
||||
|
||||
Les vues disponibles peuvent être consommées directement :
|
||||
|
||||
```rust
|
||||
let solana_entries = ksp_core_lib::program_ids_by_domain("solana").count();
|
||||
let loaders = ksp_core_lib::program_ids_by_family("loader").count();
|
||||
let solana_protocol = ksp_core_lib::program_ids_by_protocol("solana").count();
|
||||
|
||||
assert_eq!(solana_entries, 18);
|
||||
assert_eq!(loaders, 5);
|
||||
assert_eq!(solana_protocol, 18);
|
||||
```
|
||||
|
||||
## Combiner plusieurs axes
|
||||
|
||||
`ProgramIdFilter` compose les contraintes sans allocation de collection intermédiaire :
|
||||
|
||||
```rust
|
||||
let filter = ksp_core_lib::ProgramIdFilter::new()
|
||||
.with_domain("solana")
|
||||
.with_family("loader")
|
||||
.with_protocol("solana")
|
||||
.with_subfamily("bpf")
|
||||
.with_program_version("v2")
|
||||
.with_kind(ksp_core_lib::ProgramIdKind::Loader);
|
||||
|
||||
for entry in ksp_core_lib::program_ids(filter) {
|
||||
assert_eq!(entry.domain(), "solana");
|
||||
assert_eq!(entry.family(), "loader");
|
||||
assert_eq!(entry.protocol(), "solana");
|
||||
assert_eq!(entry.subfamily(), std::option::Option::Some("bpf"));
|
||||
assert_eq!(entry.program_version(), std::option::Option::Some("v2"));
|
||||
assert_eq!(entry.kind(), ksp_core_lib::ProgramIdKind::Loader);
|
||||
}
|
||||
```
|
||||
|
||||
Un `ProgramIdFilter::new()` vide correspond à toutes les entrées du registre.
|
||||
|
||||
## Choisir entre texte, `Pubkey` et descriptor
|
||||
|
||||
Utiliser :
|
||||
|
||||
```text
|
||||
PRGID_* / &str pour une représentation Base58 canonique
|
||||
PRGIDPK_* / Pubkey pour un contrat Solana typé
|
||||
ProgramIdEntry lorsqu'il faut aussi la taxonomie KSP
|
||||
```
|
||||
|
||||
Ne pas reparcourir les constantes ou reconstruire une taxonomie parallèle dans une crate consommatrice lorsque le registre Core fournit déjà l'information requise.
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/ksp-logging-lib/USAGE.md -->
|
||||
<!-- version: 7 -->
|
||||
<!-- version: 8 -->
|
||||
|
||||
# Utilisation de ksp-logging-lib
|
||||
|
||||
@@ -48,7 +48,7 @@ Les fichiers persistants interdisent `ansi = true`.
|
||||
|
||||
## Runtime multi-output et routing `domain`
|
||||
|
||||
`0.1.3-pre.005` active le multi-sink, les formats et le routing niveau/target ; `0.1.3-pre.006` complète le routing structuré `domain`. Le runtime supporte donc réellement :
|
||||
Le runtime supporte le multi-sink, les formats, le routing niveau/target et le routing structuré `domain` :
|
||||
|
||||
- plusieurs fichiers simultanés ;
|
||||
- les formats `Human`, `Compact`, `Pretty` et `Json` ;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!-- file: crates/ksp-onchain-transport-lib/README.md -->
|
||||
<!-- version: 18 -->
|
||||
<!-- version: 19 -->
|
||||
|
||||
# `ksp-onchain-transport-lib`
|
||||
|
||||
`ksp-onchain-transport-lib` est la bibliothèque KSP propriétaire du transport on-chain Solana. Sa première surface est le transport HTTP JSON-RPC ; les extensions WebSocket et gRPC sont introduites séparément lorsque leur release les cible.
|
||||
`ksp-onchain-transport-lib` est la bibliothèque KSP propriétaire du transport on-chain Solana. Elle fournit le transport HTTP JSON-RPC complet et le moteur WebSocket Solana standard ; les extensions provider-specific et gRPC sont ajoutées séparément lorsqu’une release les cible.
|
||||
|
||||
## Responsabilités
|
||||
|
||||
@@ -19,7 +19,8 @@ La crate possède :
|
||||
- les enveloppes JSON-RPC 2.0 et leur validation ;
|
||||
- le registre audité des méthodes Solana HTTP ;
|
||||
- l'exécution générique des méthodes standard supportées ;
|
||||
- les wrappers typés explicitement livrés par KSP ;
|
||||
- les wrappers typés HTTP et WebSocket explicitement livrés par KSP ;
|
||||
- les sessions physiques WebSocket, subscriptions logiques, reconnect/resubscribe et backpressure bornés ;
|
||||
- les snapshots runtime sûrs ;
|
||||
- l'observabilité Transport via `ksp-logging-lib`.
|
||||
|
||||
@@ -70,23 +71,23 @@ Le registre porte notamment :
|
||||
- remplacement historique éventuel ;
|
||||
- release de couverture typée KSP.
|
||||
|
||||
La release stable `0.2.4` complète la surface typée des **52 méthodes courantes** :
|
||||
La surface HTTP typée couvre les **52 méthodes courantes** :
|
||||
|
||||
```text
|
||||
0.2.1 foundation : 4
|
||||
0.2.2 Accounts/Tokens/Cluster : 22
|
||||
0.2.3 Transactions : 11
|
||||
0.2.4 Blocks/Economics : 15
|
||||
total : 52
|
||||
foundation : 4
|
||||
Accounts/Tokens/Cluster : 22
|
||||
Transactions : 11
|
||||
Blocks/Economics : 15
|
||||
total : 52
|
||||
```
|
||||
|
||||
`0.2.4` ajoute les dix wrappers Blocks et les cinq wrappers Economics. Les points sensibles restent notamment `getBlock` moderne + bare encoding legacy deprecated, les quatre `transactionDetails`, les versions transaction numériques génériques, `numRewardPartitions`, `commissionBps`, les overloads de `getBlocks`, les ranges de production, les valeurs d'inflation/minimum de délégation fournies par le runtime et les `null` positionnels de `getInflationReward`.
|
||||
Les dix wrappers Blocks et les cinq wrappers Economics couvrent notamment `getBlock` moderne + bare encoding legacy deprecated, les quatre `transactionDetails`, les versions transaction numériques génériques, `numRewardPartitions`, `commissionBps`, les overloads de `getBlocks`, les ranges de production, les valeurs d'inflation/minimum de délégation fournies par le runtime et les `null` positionnels de `getInflationReward`.
|
||||
|
||||
`KSP-TRANSPORT-007` impose qu'un wrapper typé couvre toutes les possibilités RPC supportées retenues par l'audit : paramètres/options, overloads et formes legacy encore supportées, contraintes déterministes utiles et variantes de réponse pertinentes sans perte. Le réaudit final `0.2.4` agrège le réaudit 37/37 de `0.2.3` avec les 15 nouveaux wrappers et porte la preuve stable à **52/52**.
|
||||
`KSP-TRANSPORT-007` impose qu'un wrapper typé couvre toutes les possibilités RPC supportées retenues par l'audit : paramètres/options, overloads et formes legacy encore supportées, contraintes déterministes utiles et variantes de réponse pertinentes sans perte. Les canaris de release portent la preuve globale à **52/52** méthodes courantes typées.
|
||||
|
||||
Les 14 méthodes historiques restent découvrables pour la compliance mais sont `Removed` et ne sont pas simulées comme appelables.
|
||||
|
||||
## Foundation WebSocket `0.2.7-pre.004`
|
||||
## Moteur WebSocket standard
|
||||
|
||||
La première session physique WebSocket est matérialisée sans introduire de pool/scheduler automatique ni de registry de subscriptions anticipé.
|
||||
|
||||
@@ -99,25 +100,25 @@ La première session physique WebSocket est matérialisée sans introduire de po
|
||||
- publie `WsSessionSnapshot` via un état compact `watch` ;
|
||||
- applique aux sockets les plafonds KSP de message, frame et write buffer ;
|
||||
- ne projette jamais l'URL dans `Debug`, snapshot, erreurs KSP ou logs ;
|
||||
- répond aux `Ping` reçus et tolère les `Pong`; le lifecycle complet `Close`/shutdown a été durci ensuite en `pre.005`.
|
||||
- répond aux `Ping` reçus et tolère les `Pong`; le lifecycle `Close`/shutdown est borné et explicite.
|
||||
|
||||
Le chemin JSON-RPC générique reste `pub(crate)`. Il sert de primitive au moteur typed de subscriptions et **ne constitue pas une API publique raw provider-extension**. Le registry subscriptions et le mapping remote/local sont matérialisés en `pre.006`, reconnect/resubscribe est actif depuis `pre.007` et le backpressure borné par subscription est effectif depuis `pre.008`.
|
||||
Le chemin JSON-RPC générique reste `pub(crate)`. Il sert de primitive au moteur typed de subscriptions et **ne constitue pas une API publique raw provider-extension**. Le registry de subscriptions et le mapping remote/local, le reconnect/resubscribe et le backpressure borné par subscription font partie du moteur standard.
|
||||
|
||||
Les tests déterministes utilisent un serveur WebSocket local et prouvent le handshake, le round-trip JSON-RPC, le dispatch de réponses hors ordre, l'isolation des erreurs RPC applicatives, deux sessions physiques distinctes sur la même URL et la redaction des erreurs de connexion.
|
||||
|
||||
### Durcissement `0.2.7-pre.005`
|
||||
### Limites, control frames et shutdown
|
||||
|
||||
La session physique dispose désormais de `WsSession::close().await`. Le signal de shutdown est distinct de la command queue, passe l'état en `Closing`, annule les requests JSON-RPC en attente, envoie un Close WebSocket best-effort sous `close_timeout`, puis publie `Closed`. Un peer qui ne répond pas au Close ne peut donc pas bloquer indéfiniment le shutdown.
|
||||
|
||||
Les limites `max_message_size`, `max_frame_size`, `max_write_buffer_size` et `max_pending_requests` sont couvertes par des fixtures adversariales locales. Les requests outbound qui dépassent les bornes message/frame sont rejetées avant écriture ; les frames/messages inbound surdimensionnés sont rejetés par Tungstenite avant parse JSON. Les timeouts pending libèrent leur capacité sans faire tomber une session encore saine.
|
||||
|
||||
Ping/Pong/Close sont traités comme control frames : le Pong automatique Tungstenite est flushé et aucun heartbeat applicatif périodique n'est ajouté. Depuis `pre.007`, un Close distant inattendu, EOF, erreur I/O/TLS/WebSocket ou violation protocolaire structurelle entre dans le reconnect borné ; `Closed` reste réservé au shutdown local explicite ou à la disparition des handles.
|
||||
Ping/Pong/Close sont traités comme control frames : le Pong automatique Tungstenite est flushé et aucun heartbeat applicatif périodique n'est ajouté. Un Close distant inattendu, EOF, erreur I/O/TLS/WebSocket ou violation protocolaire structurelle entre dans le reconnect borné ; `Closed` reste réservé au shutdown local explicite ou à la disparition des handles.
|
||||
|
||||
### Registry de subscriptions `0.2.7-pre.006`
|
||||
### Registry de subscriptions
|
||||
|
||||
Le même actor possède maintenant le registre des subscriptions logiques, sans exposer les IDs numériques distants. Chaque subscription reçoit un `WsSubscriptionId` local stable, et le mapping `remote_subscription_id -> WsSubscriptionId` reste strictement runtime/interne.
|
||||
|
||||
La création générique typed reste `pub(crate)` et n'est jamais exposée comme API raw provider-extension. À partir de `pre.009`, les wrappers standard publics l'utilisent derrière leurs DTOs et paramètres typés. Le handle public `WsSubscription<T>` expose uniquement :
|
||||
La création générique typed reste `pub(crate)` et n'est jamais exposée comme API raw provider-extension. Les wrappers standard publics l’utilisent derrière leurs DTOs et paramètres typés. Le handle public `WsSubscription<T>` expose uniquement :
|
||||
|
||||
- `id()` et `kind()` ;
|
||||
- `state()` ;
|
||||
@@ -126,7 +127,7 @@ La création générique typed reste `pub(crate)` et n'est jamais exposée comme
|
||||
|
||||
L'ACK de subscribe est traité atomiquement dans l'actor : le remote ID est lié au local ID avant que la notification suivante puisse être dispatchée. Les notifications inconnues/stale sont ignorées avec un diagnostic sûr. Un mismatch de méthode de notification ou un échec de décodage typed termine uniquement la subscription concernée ; la session physique reste `Active`.
|
||||
|
||||
### Reconnect et resubscribe `0.2.7-pre.007`
|
||||
### Reconnect et resubscribe
|
||||
|
||||
Une perte de connexion physique invalide immédiatement les remote subscription IDs et incrémente `continuity_gap_count`. Le runtime utilise `WsReconnectSettings` pour appliquer un nombre fini de tentatives avec backoff exponentiel borné et sans jitter. Le shutdown surveille les phases de backoff et de handshake et interrompt la reprise sans reconnecter uniquement pour nettoyer des subscriptions.
|
||||
|
||||
@@ -136,7 +137,7 @@ Avec `WsResubscribePolicy::Never`, la session physique peut se reconnecter mais
|
||||
|
||||
Le compteur de continuity gaps est un signal d'observabilité, pas une garantie de livraison. Transport n'ajoute aucun backfill HTTP et ne promet aucune continuité lossless pendant l'intervalle de déconnexion.
|
||||
|
||||
### Backpressure et libération de capacité `0.2.7-pre.008`
|
||||
### Backpressure et libération de capacité
|
||||
|
||||
Chaque subscription dispose de sa propre queue typed bornée par `notification_queue_capacity`. Le runtime ne droppe jamais silencieusement une notification lorsque cette queue est pleine : il incrémente `WsSessionSnapshot::overflow_count()`, fait passer uniquement le handle lent à `Failed`, publie `ERROR_CODE_WS_BACKPRESSURE_OVERFLOW` via `WsSubscription::terminal_error_code()` et programme un `*Unsubscribe` distant best-effort. Les autres subscriptions et la session physique restent utilisables.
|
||||
|
||||
@@ -146,7 +147,7 @@ Les autres terminaisons en échec publient également un code KSP sûr sur le ha
|
||||
|
||||
Les fixtures adversariales prouvent l'isolation d'un consumer lent, la survie d'une subscription saine, le cleanup distant best-effort, la réutilisation de capacité après unsubscribe ou abandon du receiver et la conservation du compteur d'overflow à travers les snapshots. Aucune promesse de livraison lossless n'est ajoutée.
|
||||
|
||||
### Wrappers stables lot A `0.2.7-pre.009`
|
||||
### Wrappers stables : account, program et logs
|
||||
|
||||
Les trois premiers wrappers WebSocket standards sont publics sur `WsSession` :
|
||||
|
||||
@@ -162,9 +163,9 @@ logs_subscribe -> WsSubscription<SolanaRpcResponse<SolanaLogsNotification>>
|
||||
|
||||
`SolanaLogsSubscribeFilter` rend les trois filtres upstream explicites : `All`, `AllWithVotes` et `Mentions(Pubkey)`. La variante `Mentions` encode par construction exactement une adresse. `SolanaLogsNotification` conserve la signature opaque, le `err` nullable et l'ordre des messages `logs`, enveloppés dans `SolanaRpcResponse`.
|
||||
|
||||
L'unsubscribe de ces trois familles passe toujours par `WsSubscription::unsubscribe()`: le caller ne voit ni ne fournit l'ID serveur. Les paramètres initiaux restent conservés par l'actor pour le resubscribe déterministe acquis en `pre.007`, et toutes les règles de backpressure/terminal error acquises en `pre.008` s'appliquent sans branche spéciale aux nouveaux DTOs publics.
|
||||
L'unsubscribe de ces trois familles passe toujours par `WsSubscription::unsubscribe()`: le caller ne voit ni ne fournit l'ID serveur. Les paramètres initiaux restent conservés par l’actor pour le resubscribe déterministe, et toutes les règles de backpressure/terminal error s’appliquent sans branche spéciale aux DTOs publics.
|
||||
|
||||
### Wrappers stables lot B `0.2.7-pre.010`
|
||||
### Wrappers stables : signature, slot et root
|
||||
|
||||
Le second lot stable complète les subscriptions standard non instables :
|
||||
|
||||
@@ -178,9 +179,9 @@ root_subscribe -> WsSubscription<u64>
|
||||
|
||||
Une cancellation effectuée avant cette terminaison continue d'utiliser `WsSubscription::unsubscribe()` et émet `signatureUnsubscribe` avec le remote ID détenu uniquement par l'actor. Après la notification terminale, `unsubscribe()` devient local-only et retourne `false`, puisque la subscription est déjà fermée côté serveur et côté KSP.
|
||||
|
||||
`slot_subscribe()` et `root_subscribe()` n'acceptent aucun paramètre. `SolanaSlotNotification` conserve exactement `slot`, `parent` et `root`; `root_subscribe()` délivre directement le root `u64`. Ces deux subscriptions restent continues et utilisent donc le reconnect/resubscribe standard de `pre.007`.
|
||||
`slot_subscribe()` et `root_subscribe()` n'acceptent aucun paramètre. `SolanaSlotNotification` conserve exactement `slot`, `parent` et `root`; `root_subscribe()` délivre directement le root `u64`. Ces deux subscriptions restent continues et utilisent donc le reconnect/resubscribe standard.
|
||||
|
||||
### Wrappers unstable `0.2.7-pre.011`
|
||||
### Wrappers unstable : block, slotsUpdates et vote
|
||||
|
||||
Les trois familles standard restantes complètent désormais l'inventaire **9/9 subscribe + 9/9 unsubscribe via handles** :
|
||||
|
||||
@@ -264,9 +265,9 @@ Les trois tests sont `ignored` par défaut. Les deux smokes Transport appartienn
|
||||
- [`USAGE.md`](USAGE.md) — consommation directe, Config -> Transport, API typed/raw, smokes et inspection runtime ;
|
||||
- [`../../docs/plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md`](../../docs/plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md) — foundation HTTP stable ;
|
||||
- [`../../docs/plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md`](../../docs/plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md) — extension typed Accounts/Tokens/Cluster ;
|
||||
- [`../../docs/validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md`](../../docs/validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md) — matrice finale validée `0.2.2` ;
|
||||
- [`../../docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md`](../../docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md) — plan historique clôturé de `0.2.3` ;
|
||||
- [`../../docs/validation/006-V0_2_3_HTTP_TRANSACTIONS.md`](../../docs/validation/006-V0_2_3_HTTP_TRANSACTIONS.md) — matrice finale validée `0.2.3` ;
|
||||
- [`../../docs/validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md`](../../docs/validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md) — matrice finale validée Accounts/Tokens/Cluster ;
|
||||
- [`../../docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md`](../../docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md) — plan historique clôturé Transactions ;
|
||||
- [`../../docs/validation/006-V0_2_3_HTTP_TRANSACTIONS.md`](../../docs/validation/006-V0_2_3_HTTP_TRANSACTIONS.md) — matrice finale validée Transactions ;
|
||||
- [`../../docs/plans/011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md`](../../docs/plans/011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md) — plan Blocks/Economics et compliance HTTP finale ;
|
||||
- [`../../docs/validation/007-V0_2_4_HTTP_FINAL_COMPLIANCE.md`](../../docs/validation/007-V0_2_4_HTTP_FINAL_COMPLIANCE.md) — matrice finale validée `52/52 + 14/14` et audit `KSP-TRANSPORT-007` global ;
|
||||
- [`../../config/std.transport.json`](../../config/std.transport.json) — configuration standard HTTP + WebSocket V2, avec lecture backward V1 HTTP-only.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/ksp-onchain-transport-lib/USAGE.md -->
|
||||
<!-- version: 18 -->
|
||||
<!-- version: 19 -->
|
||||
|
||||
# Utilisation de `ksp-onchain-transport-lib`
|
||||
|
||||
@@ -67,7 +67,7 @@ Le document standard peut contenir une URL provenant d'un `KSP_SECRET_*`. La val
|
||||
|
||||
## 3. Session physique WebSocket
|
||||
|
||||
À partir de `0.2.7-pre.004`, un consumer peut créer explicitement une session physique :
|
||||
Un consumer peut créer explicitement une session physique WebSocket :
|
||||
|
||||
```rust
|
||||
let ws_url = match ksp_onchain_transport_lib::WsEndpointUrl::parse("wss://api.devnet.solana.com") {
|
||||
@@ -92,7 +92,7 @@ let snapshot = session.snapshot();
|
||||
|
||||
Deux appels `WsSession::connect` avec le même endpoint créent volontairement deux connexions physiques distinctes. Il n'existe encore aucun pool de sessions automatique.
|
||||
|
||||
Le socket brut et la primitive JSON-RPC générique ne sont pas publics. Le moteur générique de subscription typed existe depuis `pre.006` mais sa création reste `pub(crate)` même après l'ouverture des premiers wrappers standards en `pre.009`; il ne constitue donc pas une escape hatch provider-specific.
|
||||
Le socket brut et la primitive JSON-RPC générique ne sont pas publics. Le moteur générique de subscription typed reste `pub(crate)` ; il ne constitue donc pas une escape hatch provider-specific.
|
||||
|
||||
`WsSubscription<T>` est le handle public commun retourné par les wrappers standards. Il porte un `WsSubscriptionId` local stable, jamais le remote ID numérique du serveur. Les notifications arrivent via un receiver typed borné et `unsubscribe().await` exécute le `*Unsubscribe` correspondant en préservant son résultat booléen.
|
||||
|
||||
@@ -100,7 +100,7 @@ Le snapshot de session expose les subscriptions actuellement enregistrées via `
|
||||
|
||||
### Premiers wrappers standards publics
|
||||
|
||||
Depuis `0.2.7-pre.009`, trois familles stables peuvent être créées directement sur la session :
|
||||
Trois familles stables peuvent être créées directement sur la session :
|
||||
|
||||
```rust
|
||||
let account = match "11111111111111111111111111111111".parse::<ksp_core_lib::Pubkey>() {
|
||||
@@ -128,7 +128,7 @@ Les trois wrappers retournent le même handle `WsSubscription<T>` : reconnect, r
|
||||
|
||||
### Lot stable B : signature, slot et root
|
||||
|
||||
Depuis `0.2.7-pre.010`, la session expose également :
|
||||
La session expose également les familles stables suivantes :
|
||||
|
||||
```rust
|
||||
let signature_config = ksp_onchain_transport_lib::SolanaSignatureSubscribeConfig::new(
|
||||
@@ -156,7 +156,7 @@ Avec `enableReceivedNotification = true`, `ReceivedSignature` peut arriver avant
|
||||
|
||||
### Familles unstable : block, slotsUpdates et vote
|
||||
|
||||
Depuis `0.2.7-pre.011`, les trois familles unstable standard sont également typées. Leur utilisation déclenche un warning KSP centralisé :
|
||||
Les trois familles unstable standard sont également typées. Leur utilisation déclenche un warning KSP centralisé :
|
||||
|
||||
```rust
|
||||
let block_config = ksp_onchain_transport_lib::SolanaBlockSubscribeConfig::new(
|
||||
@@ -185,7 +185,7 @@ Les trois familles utilisent le même `WsSubscription::unsubscribe().await`; auc
|
||||
|
||||
### Reconnect automatique borné
|
||||
|
||||
Depuis `0.2.7-pre.007`, les settings de session contrôlent réellement le reconnect physique. Une perte de socket publie `Reconnecting { attempt }`, invalide les remote IDs et incrémente `continuity_gap_count`. Avec la policy par défaut `ActiveSubscriptions`, les handles logiques gardent leur `WsSubscriptionId` et passent temporairement en `Resubscribing`; l'actor recrée leurs subscriptions dans l'ordre local avant de republier `Active`.
|
||||
Les settings de session contrôlent le reconnect physique. Une perte de socket publie `Reconnecting { attempt }`, invalide les remote IDs et incrémente `continuity_gap_count`. Avec la policy par défaut `ActiveSubscriptions`, les handles logiques gardent leur `WsSubscriptionId` et passent temporairement en `Resubscribing`; l'actor recrée leurs subscriptions dans l'ordre local avant de republier `Active`.
|
||||
|
||||
`WsResubscribePolicy::Never` reconnecte uniquement la session physique : les subscriptions existantes deviennent terminales et doivent être recréées explicitement par le consumer. Dans les deux modes, les requests applicatives qui étaient en vol lors de la coupure échouent et ne sont pas rejouées implicitement.
|
||||
|
||||
@@ -193,7 +193,7 @@ Depuis `0.2.7-pre.007`, les settings de session contrôlent réellement le recon
|
||||
|
||||
### Backpressure par subscription
|
||||
|
||||
Depuis `0.2.7-pre.008`, `WsSessionSettings::notification_queue_capacity()` borne réellement la queue de chaque `WsSubscription<T>`. Le consumer doit donc drainer `recv()` selon son débit métier. Une queue pleine ne bloque pas l'actor et n'affecte pas les autres subscriptions : la subscription lente devient terminale avec `state() == Failed` et `terminal_error_code() == Some(ERROR_CODE_WS_BACKPRESSURE_OVERFLOW)`, tandis que `WsSessionSnapshot::overflow_count()` est incrémenté.
|
||||
`WsSessionSettings::notification_queue_capacity()` borne la queue de chaque `WsSubscription<T>`. Le consumer doit donc drainer `recv()` selon son débit métier. Une queue pleine ne bloque pas l'actor et n'affecte pas les autres subscriptions : la subscription lente devient terminale avec `state() == Failed` et `terminal_error_code() == Some(ERROR_CODE_WS_BACKPRESSURE_OVERFLOW)`, tandis que `WsSessionSnapshot::overflow_count()` est incrémenté.
|
||||
|
||||
Un échec terminal non lié à l'overflow expose lui aussi un `ErrorCode` KSP sûr via `terminal_error_code()`. Une fermeture normale conserve `None`. Cette projection ne contient ni payload de notification, ni remote subscription ID, ni URL d'endpoint.
|
||||
|
||||
@@ -203,7 +203,7 @@ Le consumer doit traiter `overflow_count` et `continuity_gap_count` comme deux s
|
||||
|
||||
### Fermeture explicite
|
||||
|
||||
À partir de `0.2.7-pre.005`, fermer explicitement la session est la voie normale de shutdown :
|
||||
Fermer explicitement la session est la voie normale de shutdown :
|
||||
|
||||
```rust
|
||||
let session = ksp_onchain_transport_lib::WsSession::connect(endpoint).await?;
|
||||
@@ -238,7 +238,7 @@ let balance = pool
|
||||
.await;
|
||||
```
|
||||
|
||||
Les quatre canaris `0.2.1` restent disponibles. `0.2.2` ajoute les wrappers typés Accounts, Tokens et Cluster. Exemples représentatifs :
|
||||
Les wrappers foundation, Accounts, Tokens et Cluster sont disponibles directement sur le pool. Exemples représentatifs :
|
||||
|
||||
```rust
|
||||
let account = pool
|
||||
@@ -248,7 +248,7 @@ let epoch = pool.get_epoch_info(&role, None).await;
|
||||
let vote_accounts = pool.get_vote_accounts(&role, None).await;
|
||||
```
|
||||
|
||||
La release stable `0.2.4` contient les **52 wrappers typés courants** : 4 foundation + 22 Accounts/Tokens/Cluster + 11 Transactions + 10 Blocks + 5 Economics. Les DTOs Transport conservent les `null`, options, overloads et formes wire sans décodage Program/SPL métier.
|
||||
La surface HTTP contient **52 wrappers typés courants** : 4 foundation + 22 Accounts/Tokens/Cluster + 11 Transactions + 10 Blocks + 5 Economics. Les DTOs Transport conservent les `null`, options, overloads et formes wire sans décodage Program/SPL métier.
|
||||
|
||||
Exemples Transaction représentatifs :
|
||||
|
||||
@@ -334,7 +334,7 @@ La configuration standard route les événements `info` de Transport vers un fic
|
||||
|
||||
## 10. Smokes Devnet opt-in
|
||||
|
||||
Le smoke **Transport HTTP pur** construit ses settings programmatiquement et exerce un sous-ensemble représentatif d'Accounts/Tokens/Cluster, trois reads Transactions, puis des reads Blocks/Economics de la release stable `0.2.4` :
|
||||
Le smoke **Transport HTTP pur** construit ses settings programmatiquement et exerce un sous-ensemble représentatif d'Accounts/Tokens/Cluster, trois reads Transactions, puis des reads Blocks/Economics :
|
||||
|
||||
```bash
|
||||
cargo test -p ksp-onchain-transport-lib --test transport_devnet_smoke -- --ignored --nocapture
|
||||
@@ -350,7 +350,7 @@ cargo test -p ksp-onchain-transport-lib --test websocket_devnet_smoke -- --ignor
|
||||
|
||||
Il n'utilise ni `blockSubscribe`, ni `slotsUpdatesSubscribe`, ni `voteSubscribe` : ces familles restent unstable et leur disponibilité dépend des capabilities du validator. Le smoke live n'est donc pas un gate de disponibilité de ces extensions.
|
||||
|
||||
Le smoke historique de **composition Config -> Transport** reste également disponible :
|
||||
Le smoke de **composition Config -> Transport** reste également disponible :
|
||||
|
||||
```bash
|
||||
cargo test -p ksp-config-lib --test transport_devnet_smoke -- --ignored --nocapture
|
||||
@@ -360,7 +360,7 @@ Il valide le profil committé `devnet_public` et les quatre canaris foundation.
|
||||
|
||||
Les endpoints publics Solana sont rate-limités et non destinés à la production. Un échec réseau externe n'est pas assimilé automatiquement à une régression locale ; les fixtures HTTP et WebSocket locales restent les gates reproductibles.
|
||||
|
||||
Pour l'audit final de dépendances de `0.2.7`, inspecter également le graphe effectif après résolution Cargo :
|
||||
Pour auditer les dépendances, inspecter également le graphe effectif après résolution Cargo :
|
||||
|
||||
```bash
|
||||
cargo tree -p ksp-onchain-transport-lib
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<!-- file: crates/ksp-wallet-lib/README.md -->
|
||||
<!-- version: 5 -->
|
||||
<!-- version: 6 -->
|
||||
|
||||
# `ksp-wallet-lib`
|
||||
|
||||
Statut : **stable depuis KSP `0.2.5` ; surface V2/multi-version stable depuis `0.2.6`**.
|
||||
Statut : **stable ; surface V1/V2 et façade multi-version validées**.
|
||||
|
||||
`ksp-wallet-lib` est la bibliothèque KSP propriétaire du Wallet Solana natif. Elle possède le format autonome `.kspwallet` V1 et le format binaire V2 canonique, les capacités indépendantes VIEW/OWNER, la protection du secret Solana, la signature, l'administration des metadata, les rotations de credentials, la persistence native et les adapters d'import/export explicitement supportés. Depuis KSP `0.2.6`, les APIs non versionnées créent/importent en V2 par default explicite et lisent V1/V2 par détection bornée. La migration V1 -> V2 est explicite et OWNER-authentifiée, sans migration à l'ouverture.
|
||||
`ksp-wallet-lib` est la bibliothèque KSP propriétaire du Wallet Solana natif. Elle possède le format autonome `.kspwallet` V1 et le format binaire V2 canonique, les capacités indépendantes VIEW/OWNER, la protection du secret Solana, la signature, l'administration des metadata, les rotations de credentials, la persistence native et les adapters d'import/export explicitement supportés. Les APIs non versionnées créent/importent en V2 par default explicite et lisent V1/V2 par détection bornée. La migration V1 -> V2 est explicite et OWNER-authentifiée, sans migration à l'ouverture.
|
||||
|
||||
La crate est volontairement indépendante de Config, du réseau et de Tauri. Un consumer fournit les chemins, passwords et metadata ; Wallet ouvre, protège, signe et persiste sans décider d'une policy de dépense ni contacter un RPC.
|
||||
|
||||
@@ -191,13 +191,13 @@ Elles couvrent le wire, Argon2id/XChaCha20-Poly1305, l'ouverture VIEW/OWNER, la
|
||||
|
||||
- [`USAGE.md`](USAGE.md) — exemples des principales surfaces publiques ;
|
||||
- [`../../docs/formats/KSPWALLET_V1.md`](../../docs/formats/KSPWALLET_V1.md) — spécification normative indépendante de Rust ;
|
||||
- [`../../docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md`](../../docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md) — plan historique et threat model de `0.2.5` ;
|
||||
- [`../../docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md`](../../docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md) — plan historique et threat model de la fondation Wallet ;
|
||||
- [`../../docs/validation/008-V0_2_5_WALLET_SECURITY_COMPLIANCE.md`](../../docs/validation/008-V0_2_5_WALLET_SECURITY_COMPLIANCE.md) — matrice de sécurité/interoperabilité/compliance ;
|
||||
- [`../../prompts/011-V0_2_6_START_PROMPT.md`](../../prompts/011-V0_2_6_START_PROMPT.md) — reprise vers Wallet Desk après publication stable de `0.2.5`.
|
||||
- [`../../prompts/011-V0_2_6_START_PROMPT.md`](../../prompts/011-V0_2_6_START_PROMPT.md) — prompt historique de reprise vers Wallet Desk.
|
||||
|
||||
## V2 stable depuis `0.2.6`
|
||||
## Wire/runtime V2 et façade multi-version
|
||||
|
||||
`pre.015` a figé le wire structurel V2, son codec et ses transcripts/AAD. `pre.016` matérialise le runtime V2 complet et la façade multi-version :
|
||||
Le wire structurel V2, son codec et ses transcripts/AAD sont figés ; le runtime V2 complet et la façade multi-version exposent :
|
||||
|
||||
```text
|
||||
DEFAULT_WALLET_FORMAT = V2
|
||||
@@ -211,7 +211,7 @@ open/inspect génériques -> détection V1/V2
|
||||
open/inspect _v1/_v2 -> format forcé strict
|
||||
```
|
||||
|
||||
`WalletOwner` et `WalletView` conservent le format natif qu'ils ont ouvert : metadata, rotations OWNER/VIEW, disable/recreate VIEW, self-rotation VIEW, signature et export ne transcodent jamais implicitement le fichier. Le default est une décision explicite et ne suit pas automatiquement une future V3. `pre.017` matérialise la migration authentifiée V1 -> V2 comme opération séparée ; aucune lecture ou mutation ordinaire ne migre implicitement.
|
||||
`WalletOwner` et `WalletView` conservent le format natif qu'ils ont ouvert : metadata, rotations OWNER/VIEW, disable/recreate VIEW, self-rotation VIEW, signature et export ne transcodent jamais implicitement le fichier. Le default est une décision explicite et ne suit pas automatiquement une future V3. La migration authentifiée V1 -> V2 est une opération séparée ; aucune lecture ou mutation ordinaire ne migre implicitement.
|
||||
### Migration explicite V1 -> V2
|
||||
|
||||
```text
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/ksp-wallet-lib/USAGE.md -->
|
||||
<!-- version: 5 -->
|
||||
<!-- version: 6 -->
|
||||
|
||||
# Utilisation de `ksp-wallet-lib`
|
||||
|
||||
@@ -278,9 +278,9 @@ ksp-onchain-transport-lib
|
||||
-> utilise cette Pubkey pour getBalance et autres lectures réseau
|
||||
```
|
||||
|
||||
Cette composition est le rôle de `0.2.6 — ksp-app-wallet-desk`, pas de `ksp-wallet-lib`.
|
||||
Cette composition appartient à `ksp-app-wallet-desk`, pas à `ksp-wallet-lib`.
|
||||
|
||||
## Wire/runtime V2 stable (`0.2.6`)
|
||||
## Wire/runtime V2
|
||||
|
||||
Le codec structurel V2 reste disponible directement pour les outils qui travaillent explicitement au niveau wire :
|
||||
|
||||
|
||||
Reference in New Issue
Block a user