0.5.1-pre.006
This commit is contained in:
@@ -14,10 +14,15 @@ KS_SECRET_POSTGRES_DEVNET_URL=postgres://solana:solana@localhost:5432/khadhroony
|
|||||||
# PostgreSQL database reserved for automated integration tests.
|
# PostgreSQL database reserved for automated integration tests.
|
||||||
KS_SECRET_POSTGRES_TEST_URL=postgres://solana:solana@localhost:5432/khadhroony_test
|
KS_SECRET_POSTGRES_TEST_URL=postgres://solana:solana@localhost:5432/khadhroony_test
|
||||||
|
|
||||||
# Optional independent configuration-file overrides.
|
# Optional binary composition override for the desktop demo.
|
||||||
# KS_CONFIG_PATH=config/app.config.json
|
# KB_APP_DEMO_DESKTOP_CONFIG_PATH=config/kb-app-demo-desktop.default.config.json
|
||||||
|
|
||||||
|
# Optional direct logging configuration override. When absent, the desktop uses the path declared by its composition.
|
||||||
# KS_LOGGING_CONFIG_PATH=config/logging.config.json
|
# KS_LOGGING_CONFIG_PATH=config/logging.config.json
|
||||||
|
|
||||||
|
# Optional composition override used by opt-in Devnet scenario tests and the scenarios CLI.
|
||||||
|
# KS_DEVNET_CONFIG_PATH=config/ks-pipeline-demo-scenarios.default.config.json
|
||||||
|
|
||||||
# Optional Devnet profile selected by CLI and opt-in scenario tests.
|
# Optional Devnet profile selected by CLI and opt-in scenario tests.
|
||||||
# When absent, the first compatible Devnet profile is selected.
|
# When absent, the first compatible Devnet profile is selected.
|
||||||
# KS_DEVNET_PROFILE=local_devnet
|
# KS_DEVNET_PROFILE=local_devnet
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# file: Cargo.toml
|
# file: Cargo.toml
|
||||||
# version: 49
|
# version: 50
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "3"
|
resolver = "3"
|
||||||
@@ -18,7 +18,7 @@ members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.5.1-pre.5"
|
version = "0.5.1-pre.6"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-bot3"
|
repository = "https://git.sasedev.com/Sasedev/khadhroony-bot3"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: ROADMAP.md -->
|
<!-- file: ROADMAP.md -->
|
||||||
<!-- version: 36 -->
|
<!-- version: 37 -->
|
||||||
|
|
||||||
# ROADMAP — khadhroony-bot3
|
# ROADMAP — khadhroony-bot3
|
||||||
|
|
||||||
@@ -91,8 +91,10 @@ Cette version effectue la migration de namespace des bibliothèques Solana et re
|
|||||||
- imposer `KS_*` aux variables possédées par les composants Solana généralistes et réserver `KB_*` aux variables réellement possédées par `kb-app-demo-desktop` ou de futures crates spécifiques au Bot ;
|
- imposer `KS_*` aux variables possédées par les composants Solana généralistes et réserver `KB_*` aux variables réellement possédées par `kb-app-demo-desktop` ou de futures crates spécifiques au Bot ;
|
||||||
- appliquer symétriquement les classes `*_SECRET_*`, `*_PUBLIC_*` et internes aux namespaces `KS_*` et `KB_*`, avec exposition publique uniquement via une surface explicitement autorisée ;
|
- appliquer symétriquement les classes `*_SECRET_*`, `*_PUBLIC_*` et internes aux namespaces `KS_*` et `KB_*`, avec exposition publique uniquement via une surface explicitement autorisée ;
|
||||||
- préserver la sensibilité après substitution : toute valeur composée contenant un `KS_SECRET_*` ou `KB_SECRET_*` reste secrète ;
|
- préserver la sensibilité après substitution : toute valeur composée contenant un `KS_SECRET_*` ou `KB_SECRET_*` reste secrète ;
|
||||||
- séparer la configuration généraliste et la configuration logging dans des documents et schémas indépendants ;
|
- remplacer la configuration monolithique par des compositions propres aux binaires (`<binary>.default.config.json`) qui sélectionnent des documents/profils spécialisés partageables ;
|
||||||
- permettre des profils logging indépendants des profils réseau/applicatifs ;
|
- séparer au minimum logging, transport, listeners, store, wallet et politiques d’exécution selon leur ownership réel ; `logs_directory` appartient au logging, `wallets_directory` au wallet et les permissions d’envoi à la politique d’exécution ;
|
||||||
|
- permettre des sélections de profils logging, transport et listeners indépendantes de la composition active du binaire ;
|
||||||
|
- permettre aux futurs workers et applications de réutiliser les documents généralistes `ks-*` tout en ajoutant une configuration dédiée sans enregistrer leur identité dans `ks-config` ;
|
||||||
- distinguer configuration source, configuration runtime résolue et DTO publics/diagnostiques ;
|
- distinguer configuration source, configuration runtime résolue et DTO publics/diagnostiques ;
|
||||||
- interdire qu'un secret résolu soit renvoyé en clair par logs, erreurs, diagnostics, UI, sérialisation ou payload Tauri ;
|
- interdire qu'un secret résolu soit renvoyé en clair par logs, erreurs, diagnostics, UI, sérialisation ou payload Tauri ;
|
||||||
- garder exemples, schémas JSON, TS-RS et documentation synchronisés.
|
- garder exemples, schémas JSON, TS-RS et documentation synchronisés.
|
||||||
|
|||||||
132
config/README.md
132
config/README.md
@@ -1,86 +1,110 @@
|
|||||||
<!-- file: config/README.md -->
|
<!-- file: config/README.md -->
|
||||||
<!-- version: 20 -->
|
<!-- version: 21 -->
|
||||||
|
|
||||||
# Configuration locale
|
# Configuration locale
|
||||||
|
|
||||||
Ce dossier contient les deux documents de configuration runtime, leurs exemples et leurs schémas JSON indépendants.
|
Ce dossier contient les compositions propres aux binaires, les documents de configuration partagés, leurs exemples et les schémas JSON actifs.
|
||||||
|
|
||||||
## Fichiers chargés par défaut
|
## Principe de composition
|
||||||
|
|
||||||
- `app.config.json` : configuration générale Khadhroony Solana ;
|
Un binaire ne possède pas une copie complète de toutes les configurations partagées. Il charge un fichier de composition `<binary>.default.config.json` qui référence les documents spécialisés et sélectionne explicitement un profil dans chacun.
|
||||||
- `logging.config.json` : configuration logging/tracing ;
|
|
||||||
- `schemas/app.config.schema.json` : schéma du document général ;
|
|
||||||
- `schemas/logging.config.schema.json` : schéma du document logging.
|
|
||||||
|
|
||||||
Les chemins par défaut peuvent être remplacés indépendamment par :
|
Le desktop utilise par défaut :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
KS_CONFIG_PATH
|
config/kb-app-demo-desktop.default.config.json
|
||||||
KS_LOGGING_CONFIG_PATH
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Exemples conformes
|
Le CLI des scénarios possède également une composition explicite :
|
||||||
|
|
||||||
- `example.app.config.json` : exemple général minimal conforme ;
|
|
||||||
- `example.logging.config.json` : exemple logging minimal conforme.
|
|
||||||
|
|
||||||
Les exemples servent de référence de structure. Ils ne sont pas sélectionnés automatiquement au démarrage.
|
|
||||||
|
|
||||||
## Sélection indépendante des profils
|
|
||||||
|
|
||||||
Chaque document possède son propre `active_profile` :
|
|
||||||
|
|
||||||
```text
|
```text
|
||||||
app.config.json
|
config/ks-pipeline-demo-scenarios.default.config.json
|
||||||
active_profile = mainnet_research
|
|
||||||
|
|
||||||
logging.config.json
|
|
||||||
active_profile = mainnet_research
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Ces valeurs sont indépendantes. Changer le profil applicatif ne change pas implicitement le profil logging, et inversement. Les noms peuvent être identiques pour faciliter l’exploitation sans créer de couplage contractuel.
|
La composition desktop peut être remplacée par `KB_APP_DEMO_DESKTOP_CONFIG_PATH`. Les tests/scénarios Devnet opt-in peuvent remplacer leur composition avec `KS_DEVNET_CONFIG_PATH`.
|
||||||
|
|
||||||
Le document général ne contient plus de propriété `logging`. Les routes, niveaux, formats et filtres sont exclusivement possédés par `logging.config.json` et `ks-logging`.
|
## Documents partagés actuels
|
||||||
|
|
||||||
## Variables d’environnement
|
|
||||||
|
|
||||||
`app.config.json` référence notamment :
|
|
||||||
|
|
||||||
```text
|
```text
|
||||||
KS_SECRET_HELIUS_API_KEY
|
config/
|
||||||
KS_SECRET_POSTGRES_MAINNET_URL
|
├── kb-app-demo-desktop.default.config.json
|
||||||
KS_SECRET_POSTGRES_DEVNET_URL
|
├── ks-pipeline-demo-scenarios.default.config.json
|
||||||
|
├── logging.config.json
|
||||||
|
├── transport.config.json
|
||||||
|
├── listeners.config.json
|
||||||
|
├── example.kb-app-demo-desktop.default.config.json
|
||||||
|
├── example.logging.config.json
|
||||||
|
├── example.transport.config.json
|
||||||
|
├── example.listeners.config.json
|
||||||
|
└── schemas/
|
||||||
|
├── composition.config.schema.json
|
||||||
|
├── logging.config.schema.json
|
||||||
|
├── transport.config.schema.json
|
||||||
|
├── listeners.config.schema.json
|
||||||
|
└── resolved.app.config.schema.json
|
||||||
```
|
```
|
||||||
|
|
||||||
`KS_SECRET_POSTGRES_TEST_URL` reste réservé aux tests d’intégration PostgreSQL. Le fichier réel `.env` reste local et ignoré par Git ; `.env.example` est le modèle versionné.
|
`resolved.app.config.schema.json` décrit uniquement le contrat runtime `AppConfig/ProfileConfig` reconstruit par `ks-config`. Il ne correspond pas à un fichier runtime chargé directement.
|
||||||
|
|
||||||
La classification `KS_SECRET_*` / `KS_PUBLIC_*` / `KS_*` et `KB_SECRET_*` / `KB_PUBLIC_*` / `KB_*` est normative. Le camouflage et la propagation de sensibilité dans les valeurs composées sont traités dans la prerelease suivante ; aucun secret ne doit être écrit en clair dans un fichier versionné.
|
## Sélection des profils
|
||||||
|
|
||||||
## Schémas
|
Les documents partagés conservent un `active_profile` pour les consommateurs autonomes. Une composition binaire peut cependant sélectionner un autre profil explicitement :
|
||||||
|
|
||||||
Les schémas runtime sont localisés exclusivement sous `config/schemas/`.
|
```text
|
||||||
|
composition profile mainnet_research
|
||||||
|
logging_profile = mainnet_research
|
||||||
|
transport_profile = mainnet_research
|
||||||
|
listeners_profile = mainnet_research
|
||||||
|
```
|
||||||
|
|
||||||
`ks-config` embarque `schemas/app.config.schema.json`. `ks-logging` embarque `schemas/logging.config.schema.json`. Les fichiers embarqués et leurs versions sur disque doivent rester identiques.
|
Lorsqu'une composition est utilisée, sa sélection explicite prime pour le binaire. Le même `transport.config.json` ou `listeners.config.json` peut donc être réutilisé par plusieurs binaires avec des combinaisons différentes.
|
||||||
|
|
||||||
## Migration depuis le format combiné
|
## Transport
|
||||||
|
|
||||||
L’ancien `example.config.json` combinait configuration générale et logging dans chaque profil. La migration consiste à :
|
`transport.config.json` possède les endpoints HTTP et WebSocket, leurs providers, clusters, timeouts, capacités, rôles, limites et politique de reconnexion propre aux endpoints.
|
||||||
|
|
||||||
1. conserver dans `app.config.json` les sections `app`, `database`, `data`, `solana`, `wallet`, `execution` et `demo` ;
|
`ks-onchain-transport` peut consommer directement un `TransportProfileConfig`. Un futur worker n'a donc pas besoin de dépendre d'un `ProfileConfig` applicatif complet pour construire ses pools réseau.
|
||||||
2. extraire chaque ancien bloc `logging` vers le profil homonyme de `logging.config.json` ;
|
|
||||||
3. sélectionner explicitement un `active_profile` dans chacun des deux documents ;
|
## Listeners
|
||||||
4. supprimer l’ancien fichier combiné une fois la migration validée.
|
|
||||||
|
`listeners.config.json` possède les ensembles de listeners Solana :
|
||||||
|
|
||||||
|
- `logsSubscribe` par mention de programme ;
|
||||||
|
- `programSubscribe` ;
|
||||||
|
- `accountSubscribe` ;
|
||||||
|
- commitment et rôles d'endpoint associés.
|
||||||
|
|
||||||
|
La séparation prépare les futurs workers de capture, qui pourront associer un profil transport et un profil listeners sans recopier les définitions dans leur propre configuration.
|
||||||
|
|
||||||
|
## Logging
|
||||||
|
|
||||||
|
`logging.config.json` reste possédé par `ks-logging`. Une composition sélectionne le profil logging souhaité. `KS_LOGGING_CONFIG_PATH` reste un override direct du chemin logging pour l'exploitation ; sans override, le chemin déclaré par la composition est utilisé.
|
||||||
|
|
||||||
|
## Configuration encore transitoire dans la composition
|
||||||
|
|
||||||
|
Après `pre.006`, les sections suivantes restent temporairement dans les profils de composition :
|
||||||
|
|
||||||
|
- `database` et `data` ;
|
||||||
|
- `wallet` ;
|
||||||
|
- `execution` ;
|
||||||
|
- `demo`.
|
||||||
|
|
||||||
|
Elles seront séparées dans la prerelease suivante. En particulier, `demo` est propre au desktop et ne doit pas rester durablement dans un contrat généraliste `ks-config`.
|
||||||
|
|
||||||
|
## Variables d'environnement
|
||||||
|
|
||||||
|
Les composants `ks-*` utilisent `KS_SECRET_*`, `KS_PUBLIC_*` ou `KS_*`. Les besoins réellement spécifiques à une application `kb-*` utilisent `KB_SECRET_*`, `KB_PUBLIC_*` ou `KB_*`.
|
||||||
|
|
||||||
|
Les secrets ne sont jamais écrits en clair dans le dépôt. La propagation de sensibilité et les DTO publics sûrs sont traités après la fin du découpage des fichiers de configuration.
|
||||||
|
|
||||||
|
## Exemples et schémas
|
||||||
|
|
||||||
|
Les exemples sous `config/` sont des références conformes et ne sont pas chargés automatiquement. Tous les schémas actifs résident exclusivement sous `config/schemas/`.
|
||||||
|
|
||||||
|
Les fichiers historiques `app.config.json`, `example.app.config.json`, `schemas/app.config.schema.json`, `example.config.json` et `schema.config.json` sont obsolètes et ne doivent pas coexister avec cette architecture.
|
||||||
|
|
||||||
## Logging de développement
|
## Logging de développement
|
||||||
|
|
||||||
Le fichier `logging.config.json` conserve actuellement les routes globales ainsi que trois fichiers dédiés par crate opérationnelle utilisant `tracing` : `debug.log`, `info.log` et `error.jsonl`.
|
Le fichier `logging.config.json` conserve les routes globales ainsi que trois fichiers dédiés par crate opérationnelle utilisant `tracing` : `debug.log`, `info.log` et `error.jsonl`.
|
||||||
|
|
||||||
Les matérialisateurs consolidés disposent de leurs routes sous les targets `ks-lib-materializer.*`. Les tests de `ks-logging` découvrent dynamiquement les crates déclarant `tracing.workspace = true` et vérifient les routes canoniques du document logging par défaut.
|
|
||||||
|
|
||||||
Les logs ne doivent contenir ni secret, ni DSN non masqué, ni keypair, ni payload de configuration résolue complet.
|
Les logs ne doivent contenir ni secret, ni DSN non masqué, ni keypair, ni payload de configuration résolue complet.
|
||||||
|
|
||||||
## Limites du profil public Devnet
|
|
||||||
|
|
||||||
`api.devnet.solana.com` est un endpoint public partagé. Les limites configurées par rôle ne sont pas des quotas indépendants fournis par le serveur : leur débit cumulé doit rester sous la limite globale de l’endpoint, et chaque méthode RPC doit également rester sous sa propre limite.
|
|
||||||
|
|
||||||
Le profil `local_devnet` de `app.config.json` utilise donc volontairement des valeurs conservatrices pour les rôles HTTP. Un warning `retry_http_json_rpc_after_rate_limit` reste possible sur un service partagé ; il indique que le cooldown et le retry borné ont été activés.
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
74
config/example.kb-app-demo-desktop.default.config.json
Normal file
74
config/example.kb-app-demo-desktop.default.config.json
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
{
|
||||||
|
"active_profile": "local_devnet",
|
||||||
|
"sources": {
|
||||||
|
"logging": "config/logging.config.json",
|
||||||
|
"transport": "config/transport.config.json",
|
||||||
|
"listeners": "config/listeners.config.json"
|
||||||
|
},
|
||||||
|
"profiles": [
|
||||||
|
{
|
||||||
|
"name": "local_devnet",
|
||||||
|
"app": {
|
||||||
|
"name": "khadhroony-bot3",
|
||||||
|
"environment": "development",
|
||||||
|
"auto_reconnect_default": false
|
||||||
|
},
|
||||||
|
"logging_profile": "local_devnet",
|
||||||
|
"transport_profile": "local_devnet",
|
||||||
|
"listeners_profile": "local_devnet",
|
||||||
|
"database": {
|
||||||
|
"enabled": true,
|
||||||
|
"backend": "postgres",
|
||||||
|
"postgres": {
|
||||||
|
"url": "${KS_SECRET_POSTGRES_DEVNET_URL}",
|
||||||
|
"max_connections": 8,
|
||||||
|
"connect_timeout_ms": 5000,
|
||||||
|
"auto_initialize_schema": true
|
||||||
|
},
|
||||||
|
"sqlite": {
|
||||||
|
"path": "data/local.sqlite",
|
||||||
|
"create_if_missing": true,
|
||||||
|
"busy_timeout_ms": 5000,
|
||||||
|
"max_connections": 1,
|
||||||
|
"auto_initialize_schema": true,
|
||||||
|
"use_wal": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"wallets_directory": "wallets",
|
||||||
|
"logs_directory": "logs"
|
||||||
|
},
|
||||||
|
"wallet": {
|
||||||
|
"wallet_dir": "wallets/temporary/local_devnet",
|
||||||
|
"cluster": "devnet",
|
||||||
|
"temporary_wallet_enabled": true,
|
||||||
|
"temporary_wallet_alias": "local-devnet-operator",
|
||||||
|
"temporary_wallet_persist": true,
|
||||||
|
"localnet_send_enabled": false,
|
||||||
|
"devnet_send_enabled": true,
|
||||||
|
"testnet_send_enabled": false,
|
||||||
|
"mainnet_send_enabled": false
|
||||||
|
},
|
||||||
|
"execution": {
|
||||||
|
"dry_run_default": true,
|
||||||
|
"require_simulation": true,
|
||||||
|
"require_operator_confirmation": true,
|
||||||
|
"localnet_max_spend_lamports": 0,
|
||||||
|
"devnet_max_spend_lamports": 100000000,
|
||||||
|
"testnet_max_spend_lamports": 0,
|
||||||
|
"mainnet_max_spend_lamports": 0,
|
||||||
|
"max_fee_lamports": 1000000,
|
||||||
|
"max_compute_unit_price_micro_lamports": 100000,
|
||||||
|
"recent_blockhash_max_age_slots": 150,
|
||||||
|
"send_max_retries": 3,
|
||||||
|
"confirmation_poll_interval_ms": 500,
|
||||||
|
"confirmation_max_attempts": 120,
|
||||||
|
"devnet_airdrop_max_lamports": 2000000000
|
||||||
|
},
|
||||||
|
"demo": {
|
||||||
|
"live_demo_enabled": true,
|
||||||
|
"trading_demo_enabled": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
29
config/example.listeners.config.json
Normal file
29
config/example.listeners.config.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"active_profile": "local_devnet",
|
||||||
|
"profiles": [
|
||||||
|
{
|
||||||
|
"name": "local_devnet",
|
||||||
|
"enabled": true,
|
||||||
|
"default_commitment": "confirmed",
|
||||||
|
"log_listeners": [
|
||||||
|
{
|
||||||
|
"name": "pump_swap_logs",
|
||||||
|
"enabled": false,
|
||||||
|
"endpoint_role": "program_logs",
|
||||||
|
"program_id": "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA",
|
||||||
|
"purpose": "Détecter les swaps, créations de pool et changements de liquidité Pump Swap."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"program_listeners": [
|
||||||
|
{
|
||||||
|
"name": "pump_fun_program_accounts",
|
||||||
|
"enabled": false,
|
||||||
|
"endpoint_role": "program_logs",
|
||||||
|
"program_id": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
|
||||||
|
"purpose": "Détecter les changements de comptes utiles à la création ou migration de tokens Pump Fun."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"account_listeners": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
157
config/example.transport.config.json
Normal file
157
config/example.transport.config.json
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
{
|
||||||
|
"active_profile": "local_devnet",
|
||||||
|
"profiles": [
|
||||||
|
{
|
||||||
|
"name": "local_devnet",
|
||||||
|
"http_endpoints": [
|
||||||
|
{
|
||||||
|
"name": "devnet_public_http",
|
||||||
|
"enabled": true,
|
||||||
|
"provider": "solana-public",
|
||||||
|
"cluster": "devnet",
|
||||||
|
"url": "https://api.devnet.solana.com",
|
||||||
|
"connect_timeout_ms": 4000,
|
||||||
|
"request_timeout_ms": 10000,
|
||||||
|
"max_idle_connections_per_host": 4,
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "http_queries",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"get_account_info",
|
||||||
|
"get_balance",
|
||||||
|
"get_block_commitment",
|
||||||
|
"get_block_height",
|
||||||
|
"get_block_production",
|
||||||
|
"get_blocks",
|
||||||
|
"get_blocks_with_limit",
|
||||||
|
"get_cluster_nodes",
|
||||||
|
"get_epoch_info",
|
||||||
|
"get_epoch_schedule",
|
||||||
|
"get_fee_for_message",
|
||||||
|
"get_first_available_block",
|
||||||
|
"get_genesis_hash",
|
||||||
|
"get_health",
|
||||||
|
"get_highest_snapshot_slot",
|
||||||
|
"get_identity",
|
||||||
|
"get_inflation_governor",
|
||||||
|
"get_inflation_rate",
|
||||||
|
"get_inflation_reward",
|
||||||
|
"get_largest_accounts",
|
||||||
|
"get_latest_blockhash",
|
||||||
|
"get_leader_schedule",
|
||||||
|
"get_max_retransmit_slot",
|
||||||
|
"get_max_shred_insert_slot",
|
||||||
|
"get_minimum_balance_for_rent_exemption",
|
||||||
|
"get_multiple_accounts",
|
||||||
|
"get_recent_performance_samples",
|
||||||
|
"get_recent_prioritization_fees",
|
||||||
|
"get_signature_statuses",
|
||||||
|
"get_slot",
|
||||||
|
"get_slot_leader",
|
||||||
|
"get_slot_leaders",
|
||||||
|
"get_stake_activation",
|
||||||
|
"get_stake_minimum_delegation",
|
||||||
|
"get_supply",
|
||||||
|
"get_token_account_balance",
|
||||||
|
"get_token_accounts_by_delegate",
|
||||||
|
"get_token_accounts_by_owner",
|
||||||
|
"get_token_largest_accounts",
|
||||||
|
"get_token_supply",
|
||||||
|
"get_transaction",
|
||||||
|
"get_transaction_count",
|
||||||
|
"get_version",
|
||||||
|
"get_vote_accounts",
|
||||||
|
"is_blockhash_valid",
|
||||||
|
"request_airdrop"
|
||||||
|
],
|
||||||
|
"priority": 10,
|
||||||
|
"requests_per_second": 3,
|
||||||
|
"burst_capacity": 3,
|
||||||
|
"max_concurrent_requests": 2,
|
||||||
|
"max_subscriptions": 0,
|
||||||
|
"pause_after_rate_limit_ms": 10000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "http_transactions",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"simulate_transaction",
|
||||||
|
"send_transaction",
|
||||||
|
"get_signature_statuses"
|
||||||
|
],
|
||||||
|
"priority": 20,
|
||||||
|
"requests_per_second": 1,
|
||||||
|
"burst_capacity": 1,
|
||||||
|
"max_concurrent_requests": 1,
|
||||||
|
"max_subscriptions": 0,
|
||||||
|
"pause_after_rate_limit_ms": 10000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ws_endpoints": [
|
||||||
|
{
|
||||||
|
"name": "devnet_public_ws",
|
||||||
|
"enabled": true,
|
||||||
|
"provider": "solana-public",
|
||||||
|
"cluster": "devnet",
|
||||||
|
"url": "wss://api.devnet.solana.com",
|
||||||
|
"connect_timeout_ms": 5000,
|
||||||
|
"request_timeout_ms": 10000,
|
||||||
|
"unsubscribe_timeout_ms": 1500,
|
||||||
|
"write_channel_capacity": 256,
|
||||||
|
"event_channel_capacity": 1024,
|
||||||
|
"auto_reconnect": false,
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "slot_notifications",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"slot_subscribe",
|
||||||
|
"slots_updates_subscribe"
|
||||||
|
],
|
||||||
|
"priority": 10,
|
||||||
|
"requests_per_second": 4,
|
||||||
|
"burst_capacity": 8,
|
||||||
|
"max_concurrent_requests": 4,
|
||||||
|
"max_subscriptions": 16,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "program_logs",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"logs_subscribe_mentions",
|
||||||
|
"program_subscribe",
|
||||||
|
"account_subscribe",
|
||||||
|
"signature_subscribe",
|
||||||
|
"block_subscribe",
|
||||||
|
"vote_subscribe"
|
||||||
|
],
|
||||||
|
"priority": 20,
|
||||||
|
"requests_per_second": 2,
|
||||||
|
"burst_capacity": 4,
|
||||||
|
"max_concurrent_requests": 2,
|
||||||
|
"max_subscriptions": 64,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "root_notifications",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"root_subscribe"
|
||||||
|
],
|
||||||
|
"priority": 15,
|
||||||
|
"requests_per_second": 4,
|
||||||
|
"burst_capacity": 8,
|
||||||
|
"max_concurrent_requests": 4,
|
||||||
|
"max_subscriptions": 16,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
202
config/kb-app-demo-desktop.default.config.json
Normal file
202
config/kb-app-demo-desktop.default.config.json
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
{
|
||||||
|
"active_profile": "mainnet_research",
|
||||||
|
"sources": {
|
||||||
|
"logging": "config/logging.config.json",
|
||||||
|
"transport": "config/transport.config.json",
|
||||||
|
"listeners": "config/listeners.config.json"
|
||||||
|
},
|
||||||
|
"profiles": [
|
||||||
|
{
|
||||||
|
"name": "local_devnet",
|
||||||
|
"app": {
|
||||||
|
"name": "khadhroony-bot3",
|
||||||
|
"environment": "development",
|
||||||
|
"auto_reconnect_default": false
|
||||||
|
},
|
||||||
|
"logging_profile": "local_devnet",
|
||||||
|
"transport_profile": "local_devnet",
|
||||||
|
"listeners_profile": "local_devnet",
|
||||||
|
"database": {
|
||||||
|
"enabled": true,
|
||||||
|
"backend": "postgres",
|
||||||
|
"postgres": {
|
||||||
|
"url": "${KS_SECRET_POSTGRES_DEVNET_URL}",
|
||||||
|
"max_connections": 8,
|
||||||
|
"connect_timeout_ms": 5000,
|
||||||
|
"auto_initialize_schema": true
|
||||||
|
},
|
||||||
|
"sqlite": {
|
||||||
|
"path": "data/local.sqlite",
|
||||||
|
"create_if_missing": true,
|
||||||
|
"busy_timeout_ms": 5000,
|
||||||
|
"max_connections": 1,
|
||||||
|
"auto_initialize_schema": true,
|
||||||
|
"use_wal": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"wallets_directory": "wallets",
|
||||||
|
"logs_directory": "logs"
|
||||||
|
},
|
||||||
|
"wallet": {
|
||||||
|
"wallet_dir": "wallets/temporary/local_devnet",
|
||||||
|
"cluster": "devnet",
|
||||||
|
"temporary_wallet_enabled": true,
|
||||||
|
"temporary_wallet_alias": "local-devnet-operator",
|
||||||
|
"temporary_wallet_persist": true,
|
||||||
|
"localnet_send_enabled": false,
|
||||||
|
"devnet_send_enabled": true,
|
||||||
|
"testnet_send_enabled": false,
|
||||||
|
"mainnet_send_enabled": false
|
||||||
|
},
|
||||||
|
"execution": {
|
||||||
|
"dry_run_default": true,
|
||||||
|
"require_simulation": true,
|
||||||
|
"require_operator_confirmation": true,
|
||||||
|
"localnet_max_spend_lamports": 0,
|
||||||
|
"devnet_max_spend_lamports": 100000000,
|
||||||
|
"testnet_max_spend_lamports": 0,
|
||||||
|
"mainnet_max_spend_lamports": 0,
|
||||||
|
"max_fee_lamports": 1000000,
|
||||||
|
"max_compute_unit_price_micro_lamports": 100000,
|
||||||
|
"recent_blockhash_max_age_slots": 150,
|
||||||
|
"send_max_retries": 3,
|
||||||
|
"confirmation_poll_interval_ms": 500,
|
||||||
|
"confirmation_max_attempts": 120,
|
||||||
|
"devnet_airdrop_max_lamports": 2000000000
|
||||||
|
},
|
||||||
|
"demo": {
|
||||||
|
"live_demo_enabled": true,
|
||||||
|
"trading_demo_enabled": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mainnet_research",
|
||||||
|
"app": {
|
||||||
|
"name": "khadhroony-bot3",
|
||||||
|
"environment": "research",
|
||||||
|
"auto_reconnect_default": false
|
||||||
|
},
|
||||||
|
"logging_profile": "mainnet_research",
|
||||||
|
"transport_profile": "mainnet_research",
|
||||||
|
"listeners_profile": "mainnet_research",
|
||||||
|
"database": {
|
||||||
|
"enabled": true,
|
||||||
|
"backend": "postgres",
|
||||||
|
"postgres": {
|
||||||
|
"url": "${KS_SECRET_POSTGRES_MAINNET_URL}",
|
||||||
|
"max_connections": 16,
|
||||||
|
"connect_timeout_ms": 5000,
|
||||||
|
"auto_initialize_schema": true
|
||||||
|
},
|
||||||
|
"sqlite": {
|
||||||
|
"path": "data/mainnet-import.sqlite",
|
||||||
|
"create_if_missing": true,
|
||||||
|
"busy_timeout_ms": 5000,
|
||||||
|
"max_connections": 1,
|
||||||
|
"auto_initialize_schema": true,
|
||||||
|
"use_wal": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"wallets_directory": "wallets",
|
||||||
|
"logs_directory": "logs"
|
||||||
|
},
|
||||||
|
"wallet": {
|
||||||
|
"wallet_dir": "wallets/temporary/mainnet_research",
|
||||||
|
"cluster": "mainnet-beta",
|
||||||
|
"temporary_wallet_enabled": false,
|
||||||
|
"temporary_wallet_alias": "mainnet_research-disabled",
|
||||||
|
"temporary_wallet_persist": false,
|
||||||
|
"localnet_send_enabled": false,
|
||||||
|
"devnet_send_enabled": false,
|
||||||
|
"testnet_send_enabled": false,
|
||||||
|
"mainnet_send_enabled": false
|
||||||
|
},
|
||||||
|
"execution": {
|
||||||
|
"dry_run_default": true,
|
||||||
|
"require_simulation": true,
|
||||||
|
"require_operator_confirmation": true,
|
||||||
|
"localnet_max_spend_lamports": 0,
|
||||||
|
"devnet_max_spend_lamports": 0,
|
||||||
|
"testnet_max_spend_lamports": 0,
|
||||||
|
"mainnet_max_spend_lamports": 0,
|
||||||
|
"max_fee_lamports": 1000000,
|
||||||
|
"max_compute_unit_price_micro_lamports": 100000,
|
||||||
|
"recent_blockhash_max_age_slots": 150,
|
||||||
|
"send_max_retries": 3,
|
||||||
|
"confirmation_poll_interval_ms": 500,
|
||||||
|
"confirmation_max_attempts": 120,
|
||||||
|
"devnet_airdrop_max_lamports": 0
|
||||||
|
},
|
||||||
|
"demo": {
|
||||||
|
"live_demo_enabled": true,
|
||||||
|
"trading_demo_enabled": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mainnet",
|
||||||
|
"app": {
|
||||||
|
"name": "khadhroony-bot3",
|
||||||
|
"environment": "mainnet",
|
||||||
|
"auto_reconnect_default": false
|
||||||
|
},
|
||||||
|
"logging_profile": "mainnet",
|
||||||
|
"transport_profile": "mainnet",
|
||||||
|
"listeners_profile": "mainnet",
|
||||||
|
"database": {
|
||||||
|
"enabled": true,
|
||||||
|
"backend": "postgres",
|
||||||
|
"postgres": {
|
||||||
|
"url": "${KS_SECRET_POSTGRES_MAINNET_URL}",
|
||||||
|
"max_connections": 16,
|
||||||
|
"connect_timeout_ms": 5000,
|
||||||
|
"auto_initialize_schema": true
|
||||||
|
},
|
||||||
|
"sqlite": {
|
||||||
|
"path": "data/mainnet.sqlite",
|
||||||
|
"create_if_missing": true,
|
||||||
|
"busy_timeout_ms": 5000,
|
||||||
|
"max_connections": 1,
|
||||||
|
"auto_initialize_schema": true,
|
||||||
|
"use_wal": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"wallets_directory": "wallets",
|
||||||
|
"logs_directory": "logs"
|
||||||
|
},
|
||||||
|
"wallet": {
|
||||||
|
"wallet_dir": "wallets/temporary/mainnet",
|
||||||
|
"cluster": "mainnet-beta",
|
||||||
|
"temporary_wallet_enabled": false,
|
||||||
|
"temporary_wallet_alias": "mainnet-disabled",
|
||||||
|
"temporary_wallet_persist": false,
|
||||||
|
"localnet_send_enabled": false,
|
||||||
|
"devnet_send_enabled": false,
|
||||||
|
"testnet_send_enabled": false,
|
||||||
|
"mainnet_send_enabled": false
|
||||||
|
},
|
||||||
|
"execution": {
|
||||||
|
"dry_run_default": true,
|
||||||
|
"require_simulation": true,
|
||||||
|
"require_operator_confirmation": true,
|
||||||
|
"localnet_max_spend_lamports": 0,
|
||||||
|
"devnet_max_spend_lamports": 0,
|
||||||
|
"testnet_max_spend_lamports": 0,
|
||||||
|
"mainnet_max_spend_lamports": 0,
|
||||||
|
"max_fee_lamports": 1000000,
|
||||||
|
"max_compute_unit_price_micro_lamports": 100000,
|
||||||
|
"recent_blockhash_max_age_slots": 150,
|
||||||
|
"send_max_retries": 3,
|
||||||
|
"confirmation_poll_interval_ms": 500,
|
||||||
|
"confirmation_max_attempts": 120,
|
||||||
|
"devnet_airdrop_max_lamports": 0
|
||||||
|
},
|
||||||
|
"demo": {
|
||||||
|
"live_demo_enabled": true,
|
||||||
|
"trading_demo_enabled": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
202
config/ks-pipeline-demo-scenarios.default.config.json
Normal file
202
config/ks-pipeline-demo-scenarios.default.config.json
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
{
|
||||||
|
"active_profile": "local_devnet",
|
||||||
|
"sources": {
|
||||||
|
"logging": "config/logging.config.json",
|
||||||
|
"transport": "config/transport.config.json",
|
||||||
|
"listeners": "config/listeners.config.json"
|
||||||
|
},
|
||||||
|
"profiles": [
|
||||||
|
{
|
||||||
|
"name": "local_devnet",
|
||||||
|
"app": {
|
||||||
|
"name": "khadhroony-bot3",
|
||||||
|
"environment": "development",
|
||||||
|
"auto_reconnect_default": false
|
||||||
|
},
|
||||||
|
"logging_profile": "local_devnet",
|
||||||
|
"transport_profile": "local_devnet",
|
||||||
|
"listeners_profile": "local_devnet",
|
||||||
|
"database": {
|
||||||
|
"enabled": true,
|
||||||
|
"backend": "postgres",
|
||||||
|
"postgres": {
|
||||||
|
"url": "${KS_SECRET_POSTGRES_DEVNET_URL}",
|
||||||
|
"max_connections": 8,
|
||||||
|
"connect_timeout_ms": 5000,
|
||||||
|
"auto_initialize_schema": true
|
||||||
|
},
|
||||||
|
"sqlite": {
|
||||||
|
"path": "data/local.sqlite",
|
||||||
|
"create_if_missing": true,
|
||||||
|
"busy_timeout_ms": 5000,
|
||||||
|
"max_connections": 1,
|
||||||
|
"auto_initialize_schema": true,
|
||||||
|
"use_wal": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"wallets_directory": "wallets",
|
||||||
|
"logs_directory": "logs"
|
||||||
|
},
|
||||||
|
"wallet": {
|
||||||
|
"wallet_dir": "wallets/temporary/local_devnet",
|
||||||
|
"cluster": "devnet",
|
||||||
|
"temporary_wallet_enabled": true,
|
||||||
|
"temporary_wallet_alias": "local-devnet-operator",
|
||||||
|
"temporary_wallet_persist": true,
|
||||||
|
"localnet_send_enabled": false,
|
||||||
|
"devnet_send_enabled": true,
|
||||||
|
"testnet_send_enabled": false,
|
||||||
|
"mainnet_send_enabled": false
|
||||||
|
},
|
||||||
|
"execution": {
|
||||||
|
"dry_run_default": true,
|
||||||
|
"require_simulation": true,
|
||||||
|
"require_operator_confirmation": true,
|
||||||
|
"localnet_max_spend_lamports": 0,
|
||||||
|
"devnet_max_spend_lamports": 100000000,
|
||||||
|
"testnet_max_spend_lamports": 0,
|
||||||
|
"mainnet_max_spend_lamports": 0,
|
||||||
|
"max_fee_lamports": 1000000,
|
||||||
|
"max_compute_unit_price_micro_lamports": 100000,
|
||||||
|
"recent_blockhash_max_age_slots": 150,
|
||||||
|
"send_max_retries": 3,
|
||||||
|
"confirmation_poll_interval_ms": 500,
|
||||||
|
"confirmation_max_attempts": 120,
|
||||||
|
"devnet_airdrop_max_lamports": 2000000000
|
||||||
|
},
|
||||||
|
"demo": {
|
||||||
|
"live_demo_enabled": true,
|
||||||
|
"trading_demo_enabled": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mainnet_research",
|
||||||
|
"app": {
|
||||||
|
"name": "khadhroony-bot3",
|
||||||
|
"environment": "research",
|
||||||
|
"auto_reconnect_default": false
|
||||||
|
},
|
||||||
|
"logging_profile": "mainnet_research",
|
||||||
|
"transport_profile": "mainnet_research",
|
||||||
|
"listeners_profile": "mainnet_research",
|
||||||
|
"database": {
|
||||||
|
"enabled": true,
|
||||||
|
"backend": "postgres",
|
||||||
|
"postgres": {
|
||||||
|
"url": "${KS_SECRET_POSTGRES_MAINNET_URL}",
|
||||||
|
"max_connections": 16,
|
||||||
|
"connect_timeout_ms": 5000,
|
||||||
|
"auto_initialize_schema": true
|
||||||
|
},
|
||||||
|
"sqlite": {
|
||||||
|
"path": "data/mainnet-import.sqlite",
|
||||||
|
"create_if_missing": true,
|
||||||
|
"busy_timeout_ms": 5000,
|
||||||
|
"max_connections": 1,
|
||||||
|
"auto_initialize_schema": true,
|
||||||
|
"use_wal": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"wallets_directory": "wallets",
|
||||||
|
"logs_directory": "logs"
|
||||||
|
},
|
||||||
|
"wallet": {
|
||||||
|
"wallet_dir": "wallets/temporary/mainnet_research",
|
||||||
|
"cluster": "mainnet-beta",
|
||||||
|
"temporary_wallet_enabled": false,
|
||||||
|
"temporary_wallet_alias": "mainnet_research-disabled",
|
||||||
|
"temporary_wallet_persist": false,
|
||||||
|
"localnet_send_enabled": false,
|
||||||
|
"devnet_send_enabled": false,
|
||||||
|
"testnet_send_enabled": false,
|
||||||
|
"mainnet_send_enabled": false
|
||||||
|
},
|
||||||
|
"execution": {
|
||||||
|
"dry_run_default": true,
|
||||||
|
"require_simulation": true,
|
||||||
|
"require_operator_confirmation": true,
|
||||||
|
"localnet_max_spend_lamports": 0,
|
||||||
|
"devnet_max_spend_lamports": 0,
|
||||||
|
"testnet_max_spend_lamports": 0,
|
||||||
|
"mainnet_max_spend_lamports": 0,
|
||||||
|
"max_fee_lamports": 1000000,
|
||||||
|
"max_compute_unit_price_micro_lamports": 100000,
|
||||||
|
"recent_blockhash_max_age_slots": 150,
|
||||||
|
"send_max_retries": 3,
|
||||||
|
"confirmation_poll_interval_ms": 500,
|
||||||
|
"confirmation_max_attempts": 120,
|
||||||
|
"devnet_airdrop_max_lamports": 0
|
||||||
|
},
|
||||||
|
"demo": {
|
||||||
|
"live_demo_enabled": true,
|
||||||
|
"trading_demo_enabled": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mainnet",
|
||||||
|
"app": {
|
||||||
|
"name": "khadhroony-bot3",
|
||||||
|
"environment": "mainnet",
|
||||||
|
"auto_reconnect_default": false
|
||||||
|
},
|
||||||
|
"logging_profile": "mainnet",
|
||||||
|
"transport_profile": "mainnet",
|
||||||
|
"listeners_profile": "mainnet",
|
||||||
|
"database": {
|
||||||
|
"enabled": true,
|
||||||
|
"backend": "postgres",
|
||||||
|
"postgres": {
|
||||||
|
"url": "${KS_SECRET_POSTGRES_MAINNET_URL}",
|
||||||
|
"max_connections": 16,
|
||||||
|
"connect_timeout_ms": 5000,
|
||||||
|
"auto_initialize_schema": true
|
||||||
|
},
|
||||||
|
"sqlite": {
|
||||||
|
"path": "data/mainnet.sqlite",
|
||||||
|
"create_if_missing": true,
|
||||||
|
"busy_timeout_ms": 5000,
|
||||||
|
"max_connections": 1,
|
||||||
|
"auto_initialize_schema": true,
|
||||||
|
"use_wal": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"wallets_directory": "wallets",
|
||||||
|
"logs_directory": "logs"
|
||||||
|
},
|
||||||
|
"wallet": {
|
||||||
|
"wallet_dir": "wallets/temporary/mainnet",
|
||||||
|
"cluster": "mainnet-beta",
|
||||||
|
"temporary_wallet_enabled": false,
|
||||||
|
"temporary_wallet_alias": "mainnet-disabled",
|
||||||
|
"temporary_wallet_persist": false,
|
||||||
|
"localnet_send_enabled": false,
|
||||||
|
"devnet_send_enabled": false,
|
||||||
|
"testnet_send_enabled": false,
|
||||||
|
"mainnet_send_enabled": false
|
||||||
|
},
|
||||||
|
"execution": {
|
||||||
|
"dry_run_default": true,
|
||||||
|
"require_simulation": true,
|
||||||
|
"require_operator_confirmation": true,
|
||||||
|
"localnet_max_spend_lamports": 0,
|
||||||
|
"devnet_max_spend_lamports": 0,
|
||||||
|
"testnet_max_spend_lamports": 0,
|
||||||
|
"mainnet_max_spend_lamports": 0,
|
||||||
|
"max_fee_lamports": 1000000,
|
||||||
|
"max_compute_unit_price_micro_lamports": 100000,
|
||||||
|
"recent_blockhash_max_age_slots": 150,
|
||||||
|
"send_max_retries": 3,
|
||||||
|
"confirmation_poll_interval_ms": 500,
|
||||||
|
"confirmation_max_attempts": 120,
|
||||||
|
"devnet_airdrop_max_lamports": 0
|
||||||
|
},
|
||||||
|
"demo": {
|
||||||
|
"live_demo_enabled": true,
|
||||||
|
"trading_demo_enabled": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
91
config/listeners.config.json
Normal file
91
config/listeners.config.json
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
{
|
||||||
|
"active_profile": "mainnet_research",
|
||||||
|
"profiles": [
|
||||||
|
{
|
||||||
|
"name": "local_devnet",
|
||||||
|
"enabled": true,
|
||||||
|
"default_commitment": "confirmed",
|
||||||
|
"log_listeners": [
|
||||||
|
{
|
||||||
|
"name": "pump_swap_logs",
|
||||||
|
"enabled": false,
|
||||||
|
"endpoint_role": "program_logs",
|
||||||
|
"program_id": "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA",
|
||||||
|
"purpose": "Détecter les swaps, créations de pool et changements de liquidité Pump Swap."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"program_listeners": [
|
||||||
|
{
|
||||||
|
"name": "pump_fun_program_accounts",
|
||||||
|
"enabled": false,
|
||||||
|
"endpoint_role": "program_logs",
|
||||||
|
"program_id": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
|
||||||
|
"purpose": "Détecter les changements de comptes utiles à la création ou migration de tokens Pump Fun."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"account_listeners": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mainnet_research",
|
||||||
|
"enabled": true,
|
||||||
|
"default_commitment": "confirmed",
|
||||||
|
"log_listeners": [
|
||||||
|
{
|
||||||
|
"name": "pump_swap_logs",
|
||||||
|
"enabled": true,
|
||||||
|
"endpoint_role": "program_logs",
|
||||||
|
"program_id": "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA",
|
||||||
|
"purpose": "Détecter les swaps, créations de pool et changements de liquidité Pump Swap."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "raydium_cpmm_logs",
|
||||||
|
"enabled": true,
|
||||||
|
"endpoint_role": "program_logs",
|
||||||
|
"program_id": "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C",
|
||||||
|
"purpose": "Détecter les créations de pools et swaps Raydium CPMM."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"program_listeners": [
|
||||||
|
{
|
||||||
|
"name": "pump_fun_program_accounts",
|
||||||
|
"enabled": true,
|
||||||
|
"endpoint_role": "program_logs",
|
||||||
|
"program_id": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
|
||||||
|
"purpose": "Détecter les changements de comptes utiles à la création ou migration de tokens Pump Fun."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"account_listeners": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mainnet",
|
||||||
|
"enabled": true,
|
||||||
|
"default_commitment": "confirmed",
|
||||||
|
"log_listeners": [
|
||||||
|
{
|
||||||
|
"name": "pump_swap_logs",
|
||||||
|
"enabled": true,
|
||||||
|
"endpoint_role": "program_logs",
|
||||||
|
"program_id": "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA",
|
||||||
|
"purpose": "Détecter les swaps, créations de pool et changements de liquidité Pump Swap."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "raydium_cpmm_logs",
|
||||||
|
"enabled": true,
|
||||||
|
"endpoint_role": "program_logs",
|
||||||
|
"program_id": "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C",
|
||||||
|
"purpose": "Détecter les créations de pools et swaps Raydium CPMM."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"program_listeners": [
|
||||||
|
{
|
||||||
|
"name": "pump_fun_program_accounts",
|
||||||
|
"enabled": true,
|
||||||
|
"endpoint_role": "program_logs",
|
||||||
|
"program_id": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
|
||||||
|
"purpose": "Détecter les changements de comptes utiles à la création ou migration de tokens Pump Fun."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"account_listeners": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
366
config/schemas/composition.config.schema.json
Normal file
366
config/schemas/composition.config.schema.json
Normal file
@@ -0,0 +1,366 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "https://khadhroony.local/schemas/composition.config.schema.json",
|
||||||
|
"title": "Khadhroony binary composition configuration",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"active_profile",
|
||||||
|
"sources",
|
||||||
|
"profiles"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"active_profile": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"sources": {
|
||||||
|
"$ref": "#/$defs/sources"
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/$defs/profile"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"$defs": {
|
||||||
|
"non_empty_string": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1
|
||||||
|
},
|
||||||
|
"app_section": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"environment",
|
||||||
|
"auto_reconnect_default"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"environment": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"auto_reconnect_default": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"database": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"enabled",
|
||||||
|
"backend",
|
||||||
|
"postgres",
|
||||||
|
"sqlite"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"backend": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"postgres",
|
||||||
|
"sqlite"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"postgres": {
|
||||||
|
"$ref": "#/$defs/postgres"
|
||||||
|
},
|
||||||
|
"sqlite": {
|
||||||
|
"$ref": "#/$defs/sqlite"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"postgres": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"url",
|
||||||
|
"max_connections",
|
||||||
|
"connect_timeout_ms",
|
||||||
|
"auto_initialize_schema"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"url": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"max_connections": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"connect_timeout_ms": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"auto_initialize_schema": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sqlite": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"path",
|
||||||
|
"create_if_missing",
|
||||||
|
"busy_timeout_ms",
|
||||||
|
"max_connections",
|
||||||
|
"auto_initialize_schema",
|
||||||
|
"use_wal"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"path": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"create_if_missing": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"busy_timeout_ms": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"max_connections": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"auto_initialize_schema": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"use_wal": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"wallets_directory",
|
||||||
|
"logs_directory"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"wallets_directory": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"logs_directory": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"wallet": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"wallet_dir",
|
||||||
|
"cluster",
|
||||||
|
"temporary_wallet_enabled",
|
||||||
|
"temporary_wallet_alias",
|
||||||
|
"temporary_wallet_persist",
|
||||||
|
"localnet_send_enabled",
|
||||||
|
"devnet_send_enabled",
|
||||||
|
"testnet_send_enabled",
|
||||||
|
"mainnet_send_enabled"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"wallet_dir": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"cluster": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"temporary_wallet_enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"temporary_wallet_alias": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1,
|
||||||
|
"maxLength": 64,
|
||||||
|
"pattern": "^[A-Za-z0-9][A-Za-z0-9_-]*$"
|
||||||
|
},
|
||||||
|
"temporary_wallet_persist": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"localnet_send_enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"devnet_send_enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"testnet_send_enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"mainnet_send_enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"execution": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"dry_run_default",
|
||||||
|
"require_simulation",
|
||||||
|
"require_operator_confirmation",
|
||||||
|
"localnet_max_spend_lamports",
|
||||||
|
"devnet_max_spend_lamports",
|
||||||
|
"testnet_max_spend_lamports",
|
||||||
|
"mainnet_max_spend_lamports",
|
||||||
|
"max_fee_lamports",
|
||||||
|
"max_compute_unit_price_micro_lamports",
|
||||||
|
"recent_blockhash_max_age_slots",
|
||||||
|
"send_max_retries",
|
||||||
|
"confirmation_poll_interval_ms",
|
||||||
|
"confirmation_max_attempts",
|
||||||
|
"devnet_airdrop_max_lamports"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"dry_run_default": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"require_simulation": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"require_operator_confirmation": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"localnet_max_spend_lamports": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
|
"devnet_max_spend_lamports": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
|
"testnet_max_spend_lamports": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
|
"mainnet_max_spend_lamports": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
|
"max_fee_lamports": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"max_compute_unit_price_micro_lamports": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
|
"recent_blockhash_max_age_slots": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"send_max_retries": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 4294967295
|
||||||
|
},
|
||||||
|
"confirmation_poll_interval_ms": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1,
|
||||||
|
"maximum": 60000
|
||||||
|
},
|
||||||
|
"confirmation_max_attempts": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1,
|
||||||
|
"maximum": 10000
|
||||||
|
},
|
||||||
|
"devnet_airdrop_max_lamports": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"demo": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"live_demo_enabled",
|
||||||
|
"trading_demo_enabled"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"live_demo_enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"trading_demo_enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sources": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"logging",
|
||||||
|
"transport",
|
||||||
|
"listeners"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"logging": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"transport": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"listeners": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"app",
|
||||||
|
"logging_profile",
|
||||||
|
"transport_profile",
|
||||||
|
"listeners_profile",
|
||||||
|
"database",
|
||||||
|
"data",
|
||||||
|
"wallet",
|
||||||
|
"execution",
|
||||||
|
"demo"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"$ref": "#/$defs/app_section"
|
||||||
|
},
|
||||||
|
"logging_profile": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"transport_profile": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"listeners_profile": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"database": {
|
||||||
|
"$ref": "#/$defs/database"
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"$ref": "#/$defs/data"
|
||||||
|
},
|
||||||
|
"wallet": {
|
||||||
|
"$ref": "#/$defs/wallet"
|
||||||
|
},
|
||||||
|
"execution": {
|
||||||
|
"$ref": "#/$defs/execution"
|
||||||
|
},
|
||||||
|
"demo": {
|
||||||
|
"$ref": "#/$defs/demo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
154
config/schemas/listeners.config.schema.json
Normal file
154
config/schemas/listeners.config.schema.json
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "https://khadhroony.local/schemas/listeners.config.schema.json",
|
||||||
|
"title": "Khadhroony Solana listener configuration",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"active_profile",
|
||||||
|
"profiles"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"active_profile": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/$defs/profile"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"$defs": {
|
||||||
|
"non_empty_string": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1
|
||||||
|
},
|
||||||
|
"log_listener": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"enabled",
|
||||||
|
"endpoint_role",
|
||||||
|
"program_id",
|
||||||
|
"purpose"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"endpoint_role": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"program_id": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"purpose": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"program_listener": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"enabled",
|
||||||
|
"endpoint_role",
|
||||||
|
"program_id",
|
||||||
|
"purpose"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"endpoint_role": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"program_id": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"purpose": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"account_listener": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"enabled",
|
||||||
|
"endpoint_role",
|
||||||
|
"account_pubkey",
|
||||||
|
"purpose"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"endpoint_role": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"account_pubkey": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"purpose": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"enabled",
|
||||||
|
"default_commitment",
|
||||||
|
"log_listeners",
|
||||||
|
"program_listeners",
|
||||||
|
"account_listeners"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"default_commitment": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"log_listeners": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/$defs/log_listener"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"program_listeners": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/$defs/program_listener"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"account_listeners": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/$defs/account_listener"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"$id": "https://khadhroony.local/schema/app.config.schema.json",
|
"$id": "https://khadhroony.local/schemas/resolved.app.config.schema.json",
|
||||||
"title": "Khadhroony Solana application configuration",
|
"title": "Khadhroony Solana resolved runtime application configuration",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": [
|
"required": [
|
||||||
227
config/schemas/transport.config.schema.json
Normal file
227
config/schemas/transport.config.schema.json
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "https://khadhroony.local/schemas/transport.config.schema.json",
|
||||||
|
"title": "Khadhroony Solana transport configuration",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"active_profile",
|
||||||
|
"profiles"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"active_profile": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/$defs/profile"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"$defs": {
|
||||||
|
"non_empty_string": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1
|
||||||
|
},
|
||||||
|
"http_endpoint": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"enabled",
|
||||||
|
"provider",
|
||||||
|
"cluster",
|
||||||
|
"url",
|
||||||
|
"connect_timeout_ms",
|
||||||
|
"request_timeout_ms",
|
||||||
|
"max_idle_connections_per_host",
|
||||||
|
"roles"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"provider": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"cluster": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^https?://"
|
||||||
|
},
|
||||||
|
"connect_timeout_ms": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"request_timeout_ms": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"max_idle_connections_per_host": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"roles": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/$defs/endpoint_role"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ws_endpoint": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"enabled",
|
||||||
|
"provider",
|
||||||
|
"cluster",
|
||||||
|
"url",
|
||||||
|
"connect_timeout_ms",
|
||||||
|
"request_timeout_ms",
|
||||||
|
"unsubscribe_timeout_ms",
|
||||||
|
"write_channel_capacity",
|
||||||
|
"event_channel_capacity",
|
||||||
|
"auto_reconnect",
|
||||||
|
"roles"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"provider": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"cluster": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^wss?://"
|
||||||
|
},
|
||||||
|
"connect_timeout_ms": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"request_timeout_ms": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"unsubscribe_timeout_ms": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"write_channel_capacity": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"event_channel_capacity": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"auto_reconnect": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"roles": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/$defs/endpoint_role"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"endpoint_role": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"role",
|
||||||
|
"enabled",
|
||||||
|
"request_kinds",
|
||||||
|
"priority",
|
||||||
|
"requests_per_second",
|
||||||
|
"burst_capacity",
|
||||||
|
"max_concurrent_requests",
|
||||||
|
"max_subscriptions",
|
||||||
|
"pause_after_rate_limit_ms"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"role": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"request_kinds": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"priority": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"requests_per_second": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"burst_capacity": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"max_concurrent_requests": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"max_subscriptions": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"pause_after_rate_limit_ms": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"http_endpoints",
|
||||||
|
"ws_endpoints"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"$ref": "#/$defs/non_empty_string"
|
||||||
|
},
|
||||||
|
"http_endpoints": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/$defs/http_endpoint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ws_endpoints": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/$defs/ws_endpoint"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
847
config/transport.config.json
Normal file
847
config/transport.config.json
Normal file
@@ -0,0 +1,847 @@
|
|||||||
|
{
|
||||||
|
"active_profile": "mainnet_research",
|
||||||
|
"profiles": [
|
||||||
|
{
|
||||||
|
"name": "local_devnet",
|
||||||
|
"http_endpoints": [
|
||||||
|
{
|
||||||
|
"name": "devnet_public_http",
|
||||||
|
"enabled": true,
|
||||||
|
"provider": "solana-public",
|
||||||
|
"cluster": "devnet",
|
||||||
|
"url": "https://api.devnet.solana.com",
|
||||||
|
"connect_timeout_ms": 4000,
|
||||||
|
"request_timeout_ms": 10000,
|
||||||
|
"max_idle_connections_per_host": 4,
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "http_queries",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"get_account_info",
|
||||||
|
"get_balance",
|
||||||
|
"get_block_commitment",
|
||||||
|
"get_block_height",
|
||||||
|
"get_block_production",
|
||||||
|
"get_blocks",
|
||||||
|
"get_blocks_with_limit",
|
||||||
|
"get_cluster_nodes",
|
||||||
|
"get_epoch_info",
|
||||||
|
"get_epoch_schedule",
|
||||||
|
"get_fee_for_message",
|
||||||
|
"get_first_available_block",
|
||||||
|
"get_genesis_hash",
|
||||||
|
"get_health",
|
||||||
|
"get_highest_snapshot_slot",
|
||||||
|
"get_identity",
|
||||||
|
"get_inflation_governor",
|
||||||
|
"get_inflation_rate",
|
||||||
|
"get_inflation_reward",
|
||||||
|
"get_largest_accounts",
|
||||||
|
"get_latest_blockhash",
|
||||||
|
"get_leader_schedule",
|
||||||
|
"get_max_retransmit_slot",
|
||||||
|
"get_max_shred_insert_slot",
|
||||||
|
"get_minimum_balance_for_rent_exemption",
|
||||||
|
"get_multiple_accounts",
|
||||||
|
"get_recent_performance_samples",
|
||||||
|
"get_recent_prioritization_fees",
|
||||||
|
"get_signature_statuses",
|
||||||
|
"get_slot",
|
||||||
|
"get_slot_leader",
|
||||||
|
"get_slot_leaders",
|
||||||
|
"get_stake_activation",
|
||||||
|
"get_stake_minimum_delegation",
|
||||||
|
"get_supply",
|
||||||
|
"get_token_account_balance",
|
||||||
|
"get_token_accounts_by_delegate",
|
||||||
|
"get_token_accounts_by_owner",
|
||||||
|
"get_token_largest_accounts",
|
||||||
|
"get_token_supply",
|
||||||
|
"get_transaction",
|
||||||
|
"get_transaction_count",
|
||||||
|
"get_version",
|
||||||
|
"get_vote_accounts",
|
||||||
|
"is_blockhash_valid",
|
||||||
|
"request_airdrop"
|
||||||
|
],
|
||||||
|
"priority": 10,
|
||||||
|
"requests_per_second": 3,
|
||||||
|
"burst_capacity": 3,
|
||||||
|
"max_concurrent_requests": 2,
|
||||||
|
"max_subscriptions": 0,
|
||||||
|
"pause_after_rate_limit_ms": 10000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "http_transactions",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"simulate_transaction",
|
||||||
|
"send_transaction",
|
||||||
|
"get_signature_statuses"
|
||||||
|
],
|
||||||
|
"priority": 20,
|
||||||
|
"requests_per_second": 1,
|
||||||
|
"burst_capacity": 1,
|
||||||
|
"max_concurrent_requests": 1,
|
||||||
|
"max_subscriptions": 0,
|
||||||
|
"pause_after_rate_limit_ms": 10000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ws_endpoints": [
|
||||||
|
{
|
||||||
|
"name": "devnet_public_ws",
|
||||||
|
"enabled": true,
|
||||||
|
"provider": "solana-public",
|
||||||
|
"cluster": "devnet",
|
||||||
|
"url": "wss://api.devnet.solana.com",
|
||||||
|
"connect_timeout_ms": 5000,
|
||||||
|
"request_timeout_ms": 10000,
|
||||||
|
"unsubscribe_timeout_ms": 1500,
|
||||||
|
"write_channel_capacity": 256,
|
||||||
|
"event_channel_capacity": 1024,
|
||||||
|
"auto_reconnect": false,
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "slot_notifications",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"slot_subscribe",
|
||||||
|
"slots_updates_subscribe"
|
||||||
|
],
|
||||||
|
"priority": 10,
|
||||||
|
"requests_per_second": 4,
|
||||||
|
"burst_capacity": 8,
|
||||||
|
"max_concurrent_requests": 4,
|
||||||
|
"max_subscriptions": 16,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "program_logs",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"logs_subscribe_mentions",
|
||||||
|
"program_subscribe",
|
||||||
|
"account_subscribe",
|
||||||
|
"signature_subscribe",
|
||||||
|
"block_subscribe",
|
||||||
|
"vote_subscribe"
|
||||||
|
],
|
||||||
|
"priority": 20,
|
||||||
|
"requests_per_second": 2,
|
||||||
|
"burst_capacity": 4,
|
||||||
|
"max_concurrent_requests": 2,
|
||||||
|
"max_subscriptions": 64,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "root_notifications",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"root_subscribe"
|
||||||
|
],
|
||||||
|
"priority": 15,
|
||||||
|
"requests_per_second": 4,
|
||||||
|
"burst_capacity": 8,
|
||||||
|
"max_concurrent_requests": 4,
|
||||||
|
"max_subscriptions": 16,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mainnet_research",
|
||||||
|
"http_endpoints": [
|
||||||
|
{
|
||||||
|
"name": "mainnet_public_http",
|
||||||
|
"enabled": true,
|
||||||
|
"provider": "solana-public",
|
||||||
|
"cluster": "mainnet-beta",
|
||||||
|
"url": "https://api.mainnet.solana.com",
|
||||||
|
"connect_timeout_ms": 4000,
|
||||||
|
"request_timeout_ms": 10000,
|
||||||
|
"max_idle_connections_per_host": 4,
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "http_queries",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"get_account_info",
|
||||||
|
"get_balance",
|
||||||
|
"get_block_commitment",
|
||||||
|
"get_block_height",
|
||||||
|
"get_block_production",
|
||||||
|
"get_blocks",
|
||||||
|
"get_blocks_with_limit",
|
||||||
|
"get_cluster_nodes",
|
||||||
|
"get_epoch_info",
|
||||||
|
"get_epoch_schedule",
|
||||||
|
"get_fee_for_message",
|
||||||
|
"get_first_available_block",
|
||||||
|
"get_genesis_hash",
|
||||||
|
"get_health",
|
||||||
|
"get_highest_snapshot_slot",
|
||||||
|
"get_identity",
|
||||||
|
"get_inflation_governor",
|
||||||
|
"get_inflation_rate",
|
||||||
|
"get_inflation_reward",
|
||||||
|
"get_largest_accounts",
|
||||||
|
"get_latest_blockhash",
|
||||||
|
"get_leader_schedule",
|
||||||
|
"get_max_retransmit_slot",
|
||||||
|
"get_max_shred_insert_slot",
|
||||||
|
"get_minimum_balance_for_rent_exemption",
|
||||||
|
"get_multiple_accounts",
|
||||||
|
"get_recent_performance_samples",
|
||||||
|
"get_recent_prioritization_fees",
|
||||||
|
"get_signature_statuses",
|
||||||
|
"get_slot",
|
||||||
|
"get_slot_leader",
|
||||||
|
"get_slot_leaders",
|
||||||
|
"get_stake_activation",
|
||||||
|
"get_stake_minimum_delegation",
|
||||||
|
"get_supply",
|
||||||
|
"get_token_account_balance",
|
||||||
|
"get_token_accounts_by_delegate",
|
||||||
|
"get_token_accounts_by_owner",
|
||||||
|
"get_token_largest_accounts",
|
||||||
|
"get_token_supply",
|
||||||
|
"get_transaction_count",
|
||||||
|
"get_version",
|
||||||
|
"get_vote_accounts",
|
||||||
|
"is_blockhash_valid",
|
||||||
|
"request_airdrop"
|
||||||
|
],
|
||||||
|
"priority": 50,
|
||||||
|
"requests_per_second": 4,
|
||||||
|
"burst_capacity": 8,
|
||||||
|
"max_concurrent_requests": 4,
|
||||||
|
"max_subscriptions": 0,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "http_fallback",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"get_account_info",
|
||||||
|
"get_balance",
|
||||||
|
"get_block_commitment",
|
||||||
|
"get_block_height",
|
||||||
|
"get_block_production",
|
||||||
|
"get_blocks",
|
||||||
|
"get_blocks_with_limit",
|
||||||
|
"get_cluster_nodes",
|
||||||
|
"get_epoch_info",
|
||||||
|
"get_epoch_schedule",
|
||||||
|
"get_fee_for_message",
|
||||||
|
"get_first_available_block",
|
||||||
|
"get_genesis_hash",
|
||||||
|
"get_health",
|
||||||
|
"get_highest_snapshot_slot",
|
||||||
|
"get_identity",
|
||||||
|
"get_inflation_governor",
|
||||||
|
"get_inflation_rate",
|
||||||
|
"get_inflation_reward",
|
||||||
|
"get_largest_accounts",
|
||||||
|
"get_latest_blockhash",
|
||||||
|
"get_leader_schedule",
|
||||||
|
"get_max_retransmit_slot",
|
||||||
|
"get_max_shred_insert_slot",
|
||||||
|
"get_minimum_balance_for_rent_exemption",
|
||||||
|
"get_multiple_accounts",
|
||||||
|
"get_recent_performance_samples",
|
||||||
|
"get_recent_prioritization_fees",
|
||||||
|
"get_signature_statuses",
|
||||||
|
"get_slot",
|
||||||
|
"get_slot_leader",
|
||||||
|
"get_slot_leaders",
|
||||||
|
"get_stake_activation",
|
||||||
|
"get_stake_minimum_delegation",
|
||||||
|
"get_supply",
|
||||||
|
"get_token_account_balance",
|
||||||
|
"get_token_accounts_by_delegate",
|
||||||
|
"get_token_accounts_by_owner",
|
||||||
|
"get_token_largest_accounts",
|
||||||
|
"get_token_supply",
|
||||||
|
"get_transaction_count",
|
||||||
|
"get_version",
|
||||||
|
"get_vote_accounts",
|
||||||
|
"is_blockhash_valid",
|
||||||
|
"request_airdrop"
|
||||||
|
],
|
||||||
|
"priority": 90,
|
||||||
|
"requests_per_second": 4,
|
||||||
|
"burst_capacity": 8,
|
||||||
|
"max_concurrent_requests": 4,
|
||||||
|
"max_subscriptions": 0,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "helius_primary_http",
|
||||||
|
"enabled": true,
|
||||||
|
"provider": "helius",
|
||||||
|
"cluster": "mainnet-beta",
|
||||||
|
"url": "https://mainnet.helius-rpc.com/?api-key=${KS_SECRET_HELIUS_API_KEY}",
|
||||||
|
"connect_timeout_ms": 4000,
|
||||||
|
"request_timeout_ms": 10000,
|
||||||
|
"max_idle_connections_per_host": 8,
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "http_queries",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"get_account_info",
|
||||||
|
"get_balance",
|
||||||
|
"get_block_commitment",
|
||||||
|
"get_block_height",
|
||||||
|
"get_block_production",
|
||||||
|
"get_blocks",
|
||||||
|
"get_blocks_with_limit",
|
||||||
|
"get_cluster_nodes",
|
||||||
|
"get_epoch_info",
|
||||||
|
"get_epoch_schedule",
|
||||||
|
"get_fee_for_message",
|
||||||
|
"get_first_available_block",
|
||||||
|
"get_genesis_hash",
|
||||||
|
"get_health",
|
||||||
|
"get_highest_snapshot_slot",
|
||||||
|
"get_identity",
|
||||||
|
"get_inflation_governor",
|
||||||
|
"get_inflation_rate",
|
||||||
|
"get_inflation_reward",
|
||||||
|
"get_largest_accounts",
|
||||||
|
"get_latest_blockhash",
|
||||||
|
"get_leader_schedule",
|
||||||
|
"get_max_retransmit_slot",
|
||||||
|
"get_max_shred_insert_slot",
|
||||||
|
"get_minimum_balance_for_rent_exemption",
|
||||||
|
"get_multiple_accounts",
|
||||||
|
"get_recent_performance_samples",
|
||||||
|
"get_recent_prioritization_fees",
|
||||||
|
"get_signature_statuses",
|
||||||
|
"get_slot",
|
||||||
|
"get_slot_leader",
|
||||||
|
"get_slot_leaders",
|
||||||
|
"get_stake_activation",
|
||||||
|
"get_stake_minimum_delegation",
|
||||||
|
"get_supply",
|
||||||
|
"get_token_account_balance",
|
||||||
|
"get_token_accounts_by_delegate",
|
||||||
|
"get_token_accounts_by_owner",
|
||||||
|
"get_token_largest_accounts",
|
||||||
|
"get_token_supply",
|
||||||
|
"get_transaction_count",
|
||||||
|
"get_version",
|
||||||
|
"get_vote_accounts",
|
||||||
|
"is_blockhash_valid",
|
||||||
|
"request_airdrop"
|
||||||
|
],
|
||||||
|
"priority": 10,
|
||||||
|
"requests_per_second": 8,
|
||||||
|
"burst_capacity": 8,
|
||||||
|
"max_concurrent_requests": 4,
|
||||||
|
"max_subscriptions": 0,
|
||||||
|
"pause_after_rate_limit_ms": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "http_heavy",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"get_block",
|
||||||
|
"get_program_accounts",
|
||||||
|
"get_signatures_for_address",
|
||||||
|
"get_transaction"
|
||||||
|
],
|
||||||
|
"priority": 20,
|
||||||
|
"requests_per_second": 2,
|
||||||
|
"burst_capacity": 1,
|
||||||
|
"max_concurrent_requests": 2,
|
||||||
|
"max_subscriptions": 0,
|
||||||
|
"pause_after_rate_limit_ms": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "history_backfill",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"get_block",
|
||||||
|
"get_program_accounts",
|
||||||
|
"get_signatures_for_address",
|
||||||
|
"get_transaction"
|
||||||
|
],
|
||||||
|
"priority": 30,
|
||||||
|
"requests_per_second": 4,
|
||||||
|
"burst_capacity": 8,
|
||||||
|
"max_concurrent_requests": 4,
|
||||||
|
"max_subscriptions": 0,
|
||||||
|
"pause_after_rate_limit_ms": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "http_transactions",
|
||||||
|
"enabled": false,
|
||||||
|
"request_kinds": [
|
||||||
|
"simulate_transaction",
|
||||||
|
"send_transaction",
|
||||||
|
"get_signature_statuses"
|
||||||
|
],
|
||||||
|
"priority": 40,
|
||||||
|
"requests_per_second": 1,
|
||||||
|
"burst_capacity": 1,
|
||||||
|
"max_concurrent_requests": 1,
|
||||||
|
"max_subscriptions": 0,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ws_endpoints": [
|
||||||
|
{
|
||||||
|
"name": "mainnet_public_ws_slots",
|
||||||
|
"enabled": true,
|
||||||
|
"provider": "solana-public",
|
||||||
|
"cluster": "mainnet-beta",
|
||||||
|
"url": "wss://api.mainnet.solana.com",
|
||||||
|
"connect_timeout_ms": 5000,
|
||||||
|
"request_timeout_ms": 10000,
|
||||||
|
"unsubscribe_timeout_ms": 1500,
|
||||||
|
"write_channel_capacity": 256,
|
||||||
|
"event_channel_capacity": 1024,
|
||||||
|
"auto_reconnect": false,
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "slot_notifications",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"slot_subscribe",
|
||||||
|
"slots_updates_subscribe"
|
||||||
|
],
|
||||||
|
"priority": 10,
|
||||||
|
"requests_per_second": 4,
|
||||||
|
"burst_capacity": 8,
|
||||||
|
"max_concurrent_requests": 4,
|
||||||
|
"max_subscriptions": 16,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "root_notifications",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"root_subscribe"
|
||||||
|
],
|
||||||
|
"priority": 20,
|
||||||
|
"requests_per_second": 4,
|
||||||
|
"burst_capacity": 8,
|
||||||
|
"max_concurrent_requests": 4,
|
||||||
|
"max_subscriptions": 16,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "helius_primary_ws_programs",
|
||||||
|
"enabled": true,
|
||||||
|
"provider": "helius",
|
||||||
|
"cluster": "mainnet-beta",
|
||||||
|
"url": "wss://mainnet.helius-rpc.com/?api-key=${KS_SECRET_HELIUS_API_KEY}",
|
||||||
|
"connect_timeout_ms": 5000,
|
||||||
|
"request_timeout_ms": 10000,
|
||||||
|
"unsubscribe_timeout_ms": 1500,
|
||||||
|
"write_channel_capacity": 512,
|
||||||
|
"event_channel_capacity": 4096,
|
||||||
|
"auto_reconnect": false,
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "logs_subscribe",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"logs_subscribe_mentions"
|
||||||
|
],
|
||||||
|
"priority": 10,
|
||||||
|
"requests_per_second": 2,
|
||||||
|
"burst_capacity": 4,
|
||||||
|
"max_concurrent_requests": 2,
|
||||||
|
"max_subscriptions": 128,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "program_subscribe",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"program_subscribe"
|
||||||
|
],
|
||||||
|
"priority": 20,
|
||||||
|
"requests_per_second": 2,
|
||||||
|
"burst_capacity": 4,
|
||||||
|
"max_concurrent_requests": 2,
|
||||||
|
"max_subscriptions": 128,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "account_subscribe",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"account_subscribe"
|
||||||
|
],
|
||||||
|
"priority": 30,
|
||||||
|
"requests_per_second": 2,
|
||||||
|
"burst_capacity": 4,
|
||||||
|
"max_concurrent_requests": 2,
|
||||||
|
"max_subscriptions": 128,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mainnet",
|
||||||
|
"http_endpoints": [
|
||||||
|
{
|
||||||
|
"name": "mainnet_public_http",
|
||||||
|
"enabled": true,
|
||||||
|
"provider": "solana-public",
|
||||||
|
"cluster": "mainnet-beta",
|
||||||
|
"url": "https://api.mainnet.solana.com",
|
||||||
|
"connect_timeout_ms": 4000,
|
||||||
|
"request_timeout_ms": 10000,
|
||||||
|
"max_idle_connections_per_host": 4,
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "http_queries",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"get_account_info",
|
||||||
|
"get_balance",
|
||||||
|
"get_block_commitment",
|
||||||
|
"get_block_height",
|
||||||
|
"get_block_production",
|
||||||
|
"get_blocks",
|
||||||
|
"get_blocks_with_limit",
|
||||||
|
"get_cluster_nodes",
|
||||||
|
"get_epoch_info",
|
||||||
|
"get_epoch_schedule",
|
||||||
|
"get_fee_for_message",
|
||||||
|
"get_first_available_block",
|
||||||
|
"get_genesis_hash",
|
||||||
|
"get_health",
|
||||||
|
"get_highest_snapshot_slot",
|
||||||
|
"get_identity",
|
||||||
|
"get_inflation_governor",
|
||||||
|
"get_inflation_rate",
|
||||||
|
"get_inflation_reward",
|
||||||
|
"get_largest_accounts",
|
||||||
|
"get_latest_blockhash",
|
||||||
|
"get_leader_schedule",
|
||||||
|
"get_max_retransmit_slot",
|
||||||
|
"get_max_shred_insert_slot",
|
||||||
|
"get_minimum_balance_for_rent_exemption",
|
||||||
|
"get_multiple_accounts",
|
||||||
|
"get_recent_performance_samples",
|
||||||
|
"get_recent_prioritization_fees",
|
||||||
|
"get_signature_statuses",
|
||||||
|
"get_slot",
|
||||||
|
"get_slot_leader",
|
||||||
|
"get_slot_leaders",
|
||||||
|
"get_stake_activation",
|
||||||
|
"get_stake_minimum_delegation",
|
||||||
|
"get_supply",
|
||||||
|
"get_token_account_balance",
|
||||||
|
"get_token_accounts_by_delegate",
|
||||||
|
"get_token_accounts_by_owner",
|
||||||
|
"get_token_largest_accounts",
|
||||||
|
"get_token_supply",
|
||||||
|
"get_transaction_count",
|
||||||
|
"get_version",
|
||||||
|
"get_vote_accounts",
|
||||||
|
"is_blockhash_valid",
|
||||||
|
"request_airdrop"
|
||||||
|
],
|
||||||
|
"priority": 50,
|
||||||
|
"requests_per_second": 4,
|
||||||
|
"burst_capacity": 8,
|
||||||
|
"max_concurrent_requests": 4,
|
||||||
|
"max_subscriptions": 0,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "http_fallback",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"get_account_info",
|
||||||
|
"get_balance",
|
||||||
|
"get_block_commitment",
|
||||||
|
"get_block_height",
|
||||||
|
"get_block_production",
|
||||||
|
"get_blocks",
|
||||||
|
"get_blocks_with_limit",
|
||||||
|
"get_cluster_nodes",
|
||||||
|
"get_epoch_info",
|
||||||
|
"get_epoch_schedule",
|
||||||
|
"get_fee_for_message",
|
||||||
|
"get_first_available_block",
|
||||||
|
"get_genesis_hash",
|
||||||
|
"get_health",
|
||||||
|
"get_highest_snapshot_slot",
|
||||||
|
"get_identity",
|
||||||
|
"get_inflation_governor",
|
||||||
|
"get_inflation_rate",
|
||||||
|
"get_inflation_reward",
|
||||||
|
"get_largest_accounts",
|
||||||
|
"get_latest_blockhash",
|
||||||
|
"get_leader_schedule",
|
||||||
|
"get_max_retransmit_slot",
|
||||||
|
"get_max_shred_insert_slot",
|
||||||
|
"get_minimum_balance_for_rent_exemption",
|
||||||
|
"get_multiple_accounts",
|
||||||
|
"get_recent_performance_samples",
|
||||||
|
"get_recent_prioritization_fees",
|
||||||
|
"get_signature_statuses",
|
||||||
|
"get_slot",
|
||||||
|
"get_slot_leader",
|
||||||
|
"get_slot_leaders",
|
||||||
|
"get_stake_activation",
|
||||||
|
"get_stake_minimum_delegation",
|
||||||
|
"get_supply",
|
||||||
|
"get_token_account_balance",
|
||||||
|
"get_token_accounts_by_delegate",
|
||||||
|
"get_token_accounts_by_owner",
|
||||||
|
"get_token_largest_accounts",
|
||||||
|
"get_token_supply",
|
||||||
|
"get_transaction_count",
|
||||||
|
"get_version",
|
||||||
|
"get_vote_accounts",
|
||||||
|
"is_blockhash_valid",
|
||||||
|
"request_airdrop"
|
||||||
|
],
|
||||||
|
"priority": 90,
|
||||||
|
"requests_per_second": 4,
|
||||||
|
"burst_capacity": 8,
|
||||||
|
"max_concurrent_requests": 4,
|
||||||
|
"max_subscriptions": 0,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "helius_primary_http",
|
||||||
|
"enabled": true,
|
||||||
|
"provider": "helius",
|
||||||
|
"cluster": "mainnet-beta",
|
||||||
|
"url": "https://mainnet.helius-rpc.com/?api-key=${KS_SECRET_HELIUS_API_KEY}",
|
||||||
|
"connect_timeout_ms": 4000,
|
||||||
|
"request_timeout_ms": 10000,
|
||||||
|
"max_idle_connections_per_host": 8,
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "http_queries",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"get_account_info",
|
||||||
|
"get_balance",
|
||||||
|
"get_block_commitment",
|
||||||
|
"get_block_height",
|
||||||
|
"get_block_production",
|
||||||
|
"get_blocks",
|
||||||
|
"get_blocks_with_limit",
|
||||||
|
"get_cluster_nodes",
|
||||||
|
"get_epoch_info",
|
||||||
|
"get_epoch_schedule",
|
||||||
|
"get_fee_for_message",
|
||||||
|
"get_first_available_block",
|
||||||
|
"get_genesis_hash",
|
||||||
|
"get_health",
|
||||||
|
"get_highest_snapshot_slot",
|
||||||
|
"get_identity",
|
||||||
|
"get_inflation_governor",
|
||||||
|
"get_inflation_rate",
|
||||||
|
"get_inflation_reward",
|
||||||
|
"get_largest_accounts",
|
||||||
|
"get_latest_blockhash",
|
||||||
|
"get_leader_schedule",
|
||||||
|
"get_max_retransmit_slot",
|
||||||
|
"get_max_shred_insert_slot",
|
||||||
|
"get_minimum_balance_for_rent_exemption",
|
||||||
|
"get_multiple_accounts",
|
||||||
|
"get_recent_performance_samples",
|
||||||
|
"get_recent_prioritization_fees",
|
||||||
|
"get_signature_statuses",
|
||||||
|
"get_slot",
|
||||||
|
"get_slot_leader",
|
||||||
|
"get_slot_leaders",
|
||||||
|
"get_stake_activation",
|
||||||
|
"get_stake_minimum_delegation",
|
||||||
|
"get_supply",
|
||||||
|
"get_token_account_balance",
|
||||||
|
"get_token_accounts_by_delegate",
|
||||||
|
"get_token_accounts_by_owner",
|
||||||
|
"get_token_largest_accounts",
|
||||||
|
"get_token_supply",
|
||||||
|
"get_transaction_count",
|
||||||
|
"get_version",
|
||||||
|
"get_vote_accounts",
|
||||||
|
"is_blockhash_valid",
|
||||||
|
"request_airdrop"
|
||||||
|
],
|
||||||
|
"priority": 10,
|
||||||
|
"requests_per_second": 8,
|
||||||
|
"burst_capacity": 8,
|
||||||
|
"max_concurrent_requests": 4,
|
||||||
|
"max_subscriptions": 0,
|
||||||
|
"pause_after_rate_limit_ms": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "http_heavy",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"get_block",
|
||||||
|
"get_program_accounts",
|
||||||
|
"get_signatures_for_address",
|
||||||
|
"get_transaction"
|
||||||
|
],
|
||||||
|
"priority": 20,
|
||||||
|
"requests_per_second": 2,
|
||||||
|
"burst_capacity": 1,
|
||||||
|
"max_concurrent_requests": 2,
|
||||||
|
"max_subscriptions": 0,
|
||||||
|
"pause_after_rate_limit_ms": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "history_backfill",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"get_block",
|
||||||
|
"get_program_accounts",
|
||||||
|
"get_signatures_for_address",
|
||||||
|
"get_transaction"
|
||||||
|
],
|
||||||
|
"priority": 30,
|
||||||
|
"requests_per_second": 4,
|
||||||
|
"burst_capacity": 8,
|
||||||
|
"max_concurrent_requests": 4,
|
||||||
|
"max_subscriptions": 0,
|
||||||
|
"pause_after_rate_limit_ms": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "http_transactions",
|
||||||
|
"enabled": false,
|
||||||
|
"request_kinds": [
|
||||||
|
"simulate_transaction",
|
||||||
|
"send_transaction",
|
||||||
|
"get_signature_statuses"
|
||||||
|
],
|
||||||
|
"priority": 40,
|
||||||
|
"requests_per_second": 1,
|
||||||
|
"burst_capacity": 1,
|
||||||
|
"max_concurrent_requests": 1,
|
||||||
|
"max_subscriptions": 0,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ws_endpoints": [
|
||||||
|
{
|
||||||
|
"name": "mainnet_public_ws_slots",
|
||||||
|
"enabled": true,
|
||||||
|
"provider": "solana-public",
|
||||||
|
"cluster": "mainnet-beta",
|
||||||
|
"url": "wss://api.mainnet.solana.com",
|
||||||
|
"connect_timeout_ms": 5000,
|
||||||
|
"request_timeout_ms": 10000,
|
||||||
|
"unsubscribe_timeout_ms": 1500,
|
||||||
|
"write_channel_capacity": 256,
|
||||||
|
"event_channel_capacity": 1024,
|
||||||
|
"auto_reconnect": false,
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "slot_notifications",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"slot_subscribe",
|
||||||
|
"slots_updates_subscribe"
|
||||||
|
],
|
||||||
|
"priority": 10,
|
||||||
|
"requests_per_second": 4,
|
||||||
|
"burst_capacity": 8,
|
||||||
|
"max_concurrent_requests": 4,
|
||||||
|
"max_subscriptions": 16,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "root_notifications",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"root_subscribe"
|
||||||
|
],
|
||||||
|
"priority": 20,
|
||||||
|
"requests_per_second": 4,
|
||||||
|
"burst_capacity": 8,
|
||||||
|
"max_concurrent_requests": 4,
|
||||||
|
"max_subscriptions": 16,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "helius_primary_ws_programs",
|
||||||
|
"enabled": true,
|
||||||
|
"provider": "helius",
|
||||||
|
"cluster": "mainnet-beta",
|
||||||
|
"url": "wss://mainnet.helius-rpc.com/?api-key=${KS_SECRET_HELIUS_API_KEY}",
|
||||||
|
"connect_timeout_ms": 5000,
|
||||||
|
"request_timeout_ms": 10000,
|
||||||
|
"unsubscribe_timeout_ms": 1500,
|
||||||
|
"write_channel_capacity": 512,
|
||||||
|
"event_channel_capacity": 4096,
|
||||||
|
"auto_reconnect": false,
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "logs_subscribe",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"logs_subscribe_mentions"
|
||||||
|
],
|
||||||
|
"priority": 10,
|
||||||
|
"requests_per_second": 2,
|
||||||
|
"burst_capacity": 4,
|
||||||
|
"max_concurrent_requests": 2,
|
||||||
|
"max_subscriptions": 128,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "program_subscribe",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"program_subscribe"
|
||||||
|
],
|
||||||
|
"priority": 20,
|
||||||
|
"requests_per_second": 2,
|
||||||
|
"burst_capacity": 4,
|
||||||
|
"max_concurrent_requests": 2,
|
||||||
|
"max_subscriptions": 128,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "account_subscribe",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"account_subscribe"
|
||||||
|
],
|
||||||
|
"priority": 30,
|
||||||
|
"requests_per_second": 2,
|
||||||
|
"burst_capacity": 4,
|
||||||
|
"max_concurrent_requests": 2,
|
||||||
|
"max_subscriptions": 128,
|
||||||
|
"pause_after_rate_limit_ms": 3000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/architecture/ARCHITECTURE.md -->
|
<!-- file: docs/architecture/ARCHITECTURE.md -->
|
||||||
<!-- version: 7 -->
|
<!-- version: 8 -->
|
||||||
|
|
||||||
# Architecture générale
|
# Architecture générale
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ Cette représentation indique les relations dominantes. Elle ne remplace pas le
|
|||||||
### 2.1 Fondations
|
### 2.1 Fondations
|
||||||
|
|
||||||
- `ks-core` fournit les erreurs et identités transversales minimales.
|
- `ks-core` fournit les erreurs et identités transversales minimales.
|
||||||
- `ks-config` charge, résout et valide la configuration.
|
- `ks-config` charge, résout et valide les compositions propres aux binaires ainsi que les documents de configuration Solana partagés.
|
||||||
- `ks-logging` initialise le logging et le tracing.
|
- `ks-logging` initialise le logging et le tracing.
|
||||||
- `ks-program-ids` centralise les identifiants de programmes et comptes connus.
|
- `ks-program-ids` centralise les identifiants de programmes et comptes connus.
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/architecture/CRATE_MAP.md -->
|
<!-- file: docs/architecture/CRATE_MAP.md -->
|
||||||
<!-- version: 5 -->
|
<!-- version: 6 -->
|
||||||
|
|
||||||
# Carte des crates
|
# Carte des crates
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
| Crate | Type | Responsabilité principale | État documentaire |
|
| Crate | Type | Responsabilité principale | État documentaire |
|
||||||
|------------------------------|------------------------|--------------------------------------------------------------------|------------------------------------------|
|
|------------------------------|------------------------|--------------------------------------------------------------------|------------------------------------------|
|
||||||
| `ks-core` | bibliothèque | erreurs, résultat et identité de module partagés | README/TODO/USAGE/CHANGELOG présents |
|
| `ks-core` | bibliothèque | erreurs, résultat et identité de module partagés | README/TODO/USAGE/CHANGELOG présents |
|
||||||
| `ks-config` | bibliothèque | configuration JSON, environnement, validation et profils | migration/restructuration en `0.5.1` |
|
| `ks-config` | bibliothèque | compositions binaires, documents JSON partagés, environnement, validation et profils | migration/restructuration en `0.5.1` |
|
||||||
| `ks-lib` | bibliothèque | modèles, décodeurs, exécuteurs et matérialisateurs consolidés | README/TODO/USAGE/CHANGELOG présents |
|
| `ks-lib` | bibliothèque | modèles, décodeurs, exécuteurs et matérialisateurs consolidés | README/TODO/USAGE/CHANGELOG présents |
|
||||||
| `ks-logging` | bibliothèque | initialisation du logging et du tracing | README/TODO/USAGE/CHANGELOG présents |
|
| `ks-logging` | bibliothèque | initialisation du logging et du tracing | README/TODO/USAGE/CHANGELOG présents |
|
||||||
| `ks-program-ids` | bibliothèque | registre des programmes et comptes Solana connus | README/TODO/USAGE/CHANGELOG présents |
|
| `ks-program-ids` | bibliothèque | registre des programmes et comptes Solana connus | README/TODO/USAGE/CHANGELOG présents |
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/architecture/PIPELINE_ARCHITECTURE.md -->
|
<!-- file: docs/architecture/PIPELINE_ARCHITECTURE.md -->
|
||||||
<!-- version: 6 -->
|
<!-- version: 7 -->
|
||||||
|
|
||||||
# Architecture du pipeline
|
# Architecture du pipeline
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ Le pipeline assemble les contrôles préalables, plans préparés, signataires,
|
|||||||
ks-onchain-transport -> acquisition et appels RPC
|
ks-onchain-transport -> acquisition et appels RPC
|
||||||
ks-store -> lecture/écriture canonique et replay
|
ks-store -> lecture/écriture canonique et replay
|
||||||
ks-lib -> contrats et implémentations métier
|
ks-lib -> contrats et implémentations métier
|
||||||
ks-config -> profils et paramètres opérationnels
|
ks-config -> compositions binaires, profils partagés et paramètres opérationnels
|
||||||
ks-logging -> observabilité
|
ks-logging -> observabilité
|
||||||
ks-wallet -> signataires lorsque requis
|
ks-wallet -> signataires lorsque requis
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/decisions/KHADHROONY_SOLANA_NAMESPACE_POLICY.md -->
|
<!-- file: docs/decisions/KHADHROONY_SOLANA_NAMESPACE_POLICY.md -->
|
||||||
<!-- version: 6 -->
|
<!-- version: 7 -->
|
||||||
|
|
||||||
# Politique de namespace Khadhroony Solana
|
# Politique de namespace Khadhroony Solana
|
||||||
|
|
||||||
@@ -63,19 +63,25 @@ La classification d'une valeur sensible doit survivre à la substitution. Une ch
|
|||||||
|
|
||||||
## 5. Configuration source, runtime et publique
|
## 5. Configuration source, runtime et publique
|
||||||
|
|
||||||
La restructuration `0.5.1` doit séparer au minimum :
|
La restructuration `0.5.1` utilise des compositions propres aux binaires et des documents spécialisés partagés :
|
||||||
|
|
||||||
- la configuration généraliste dans `config/app.config.json`, avec son schéma sous `config/schemas/app.config.schema.json` ;
|
- `config/kb-app-demo-desktop.default.config.json` compose les besoins du desktop ;
|
||||||
- la configuration logging dans `config/logging.config.json`, avec son schéma sous `config/schemas/logging.config.schema.json` et des profils logging sélectionnables indépendamment des profils réseau/applicatifs ;
|
- `config/ks-pipeline-demo-scenarios.default.config.json` compose les besoins du CLI/scénarios ;
|
||||||
- des exemples conformes mais non chargés par défaut sous `config/example.app.config.json` et `config/example.logging.config.json`.
|
- `config/logging.config.json` appartient à `ks-logging` ;
|
||||||
|
- `config/transport.config.json` contient les profils HTTP/WebSocket partagés ;
|
||||||
|
- `config/listeners.config.json` contient les profils de subscriptions Solana partagés ;
|
||||||
|
- tous les schémas actifs résident sous `config/schemas/`.
|
||||||
|
|
||||||
D'autres documents spécialisés ne sont créés que si l'audit démontre une responsabilité, un cycle de vie ou une validation réellement indépendants.
|
Le fichier de composition sélectionne explicitement les profils spécialisés. Un nouveau worker ou binaire doit pouvoir fournir son propre `<binary>.default.config.json` et une configuration dédiée sans modifier `ks-config` pour enregistrer son existence.
|
||||||
|
|
||||||
|
`AppConfig/ProfileConfig` reste temporairement un contrat runtime résolu afin de préserver les consommateurs pendant la migration. Il n'est plus un document source chargé directement ; son schéma de compatibilité est `config/schemas/resolved.app.config.schema.json` et ses fixtures sont sous `test-fixtures/config/`.
|
||||||
|
|
||||||
La conception doit distinguer :
|
La conception doit distinguer :
|
||||||
|
|
||||||
1. la représentation source, qui peut contenir des références `${KS_*}` ou `${KB_*}` selon le propriétaire du contrat ;
|
1. la représentation source, composée de documents indépendants pouvant contenir des références `${KS_*}` ou `${KB_*}` selon le propriétaire du contrat ;
|
||||||
2. la représentation runtime résolue, qui peut porter des secrets ;
|
2. la composition propre au binaire, qui choisit les documents et profils ;
|
||||||
3. la représentation publique/diagnostique, construite explicitement et incapable d'exposer une valeur secrète résolue.
|
3. la représentation runtime résolue, qui peut porter des secrets ;
|
||||||
|
4. la représentation publique/diagnostique, construite explicitement et incapable d'exposer une valeur secrète résolue.
|
||||||
|
|
||||||
Une configuration runtime complète ne doit jamais être sérialisée puis « nettoyée » après coup pour produire un payload public.
|
Une configuration runtime complète ne doit jamais être sérialisée puis « nettoyée » après coup pour produire un payload public.
|
||||||
|
|
||||||
|
|||||||
@@ -1,95 +1,134 @@
|
|||||||
<!-- file: docs/guides/CONFIGURATION.md -->
|
<!-- file: docs/guides/CONFIGURATION.md -->
|
||||||
<!-- version: 5 -->
|
<!-- version: 6 -->
|
||||||
|
|
||||||
# Guide de configuration
|
# Guide de configuration
|
||||||
|
|
||||||
## Objectif
|
## Objectif
|
||||||
|
|
||||||
Ce guide décrit le chargement des documents de configuration après leur séparation. La référence d’API générale reste `ks-config/USAGE.md` et la configuration logging appartient à `ks-logging`.
|
La configuration est organisée autour de compositions propres aux binaires et de documents spécialisés réutilisables. Un binaire choisit les fichiers partagés et les profils dont il a besoin au lieu de recopier une configuration monolithique.
|
||||||
|
|
||||||
## Fichiers actifs
|
## Fichiers actifs
|
||||||
|
|
||||||
- `config/app.config.json` : configuration générale chargée par défaut ;
|
Compositions :
|
||||||
- `config/logging.config.json` : configuration logging chargée par défaut ;
|
|
||||||
- `config/example.app.config.json` et `config/example.logging.config.json` : exemples minimaux conformes ;
|
|
||||||
- `config/schemas/app.config.schema.json` : schéma général ;
|
|
||||||
- `config/schemas/logging.config.schema.json` : schéma logging ;
|
|
||||||
- `.env`, ou le fichier sélectionné par `KS_ENV_FILE` : valeurs d’environnement non versionnées ;
|
|
||||||
- `.env.example` : noms de variables attendues sans secrets réels.
|
|
||||||
|
|
||||||
`KS_CONFIG_PATH` et `KS_LOGGING_CONFIG_PATH` permettent de remplacer indépendamment les deux chemins par défaut.
|
- `config/kb-app-demo-desktop.default.config.json` : composition par défaut du desktop ;
|
||||||
|
- `config/ks-pipeline-demo-scenarios.default.config.json` : composition par défaut du CLI/scénarios.
|
||||||
|
|
||||||
## Configuration générale
|
Documents partagés :
|
||||||
|
|
||||||
L’API recommandée reste `ks_config::read_config_json_file_with_environment`. Elle :
|
- `config/logging.config.json` ;
|
||||||
|
- `config/transport.config.json` ;
|
||||||
|
- `config/listeners.config.json`.
|
||||||
|
|
||||||
1. charge `.env`, ou le fichier sélectionné par `KS_ENV_FILE`, sans écraser les variables du processus ;
|
Exemples :
|
||||||
2. lit le JSON général ;
|
|
||||||
3. résout les placeholders `${KS_*}` / `${KB_*}` ;
|
|
||||||
4. valide `config/schemas/app.config.schema.json` ;
|
|
||||||
5. désérialise `AppConfig` et applique les invariants métier ;
|
|
||||||
6. laisse `active_profile` sélectionner le profil applicatif actif.
|
|
||||||
|
|
||||||
```rust
|
- `config/example.kb-app-demo-desktop.default.config.json` ;
|
||||||
let config = match ks_config::read_config_json_file_with_environment(
|
- `config/example.logging.config.json` ;
|
||||||
std::path::Path::new("config/app.config.json"),
|
- `config/example.transport.config.json` ;
|
||||||
std::path::Path::new("."),
|
- `config/example.listeners.config.json`.
|
||||||
) {
|
|
||||||
std::result::Result::Ok(value) => value,
|
Schémas :
|
||||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
||||||
};
|
- `config/schemas/composition.config.schema.json` ;
|
||||||
let profile = match ks_config::active_profile(&config) {
|
- `config/schemas/logging.config.schema.json` ;
|
||||||
std::result::Result::Ok(value) => value,
|
- `config/schemas/transport.config.schema.json` ;
|
||||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
- `config/schemas/listeners.config.schema.json` ;
|
||||||
};
|
- `config/schemas/resolved.app.config.schema.json` pour le contrat runtime reconstruit.
|
||||||
|
|
||||||
|
`.env`, ou le fichier sélectionné par `KS_ENV_FILE`, fournit les valeurs non versionnées.
|
||||||
|
|
||||||
|
## Composition d'un binaire
|
||||||
|
|
||||||
|
Une composition définit :
|
||||||
|
|
||||||
|
1. son `active_profile` ;
|
||||||
|
2. les chemins des documents partagés ;
|
||||||
|
3. pour chaque profil, le `logging_profile`, `transport_profile` et `listeners_profile` à sélectionner ;
|
||||||
|
4. temporairement, les sections qui n'ont pas encore leur document spécialisé.
|
||||||
|
|
||||||
|
Exemple conceptuel :
|
||||||
|
|
||||||
|
```text
|
||||||
|
kb-app-demo-desktop.default.config.json
|
||||||
|
sources.logging -> config/logging.config.json
|
||||||
|
sources.transport -> config/transport.config.json
|
||||||
|
sources.listeners -> config/listeners.config.json
|
||||||
|
|
||||||
|
profile mainnet_research
|
||||||
|
logging_profile -> mainnet_research
|
||||||
|
transport_profile -> mainnet_research
|
||||||
|
listeners_profile -> mainnet_research
|
||||||
```
|
```
|
||||||
|
|
||||||
Le profil général ne contient plus de bloc `logging`.
|
Les `active_profile` propres aux documents partagés restent utiles lorsqu'ils sont chargés seuls. Dans une composition, la référence explicite du binaire prime.
|
||||||
|
|
||||||
## Configuration logging
|
## Desktop
|
||||||
|
|
||||||
`ks_logging::read_logging_json_file_with_environment` charge séparément le document logging et `ks_logging::active_logging_profile` sélectionne son profil actif.
|
Le chemin de composition du desktop peut être remplacé par :
|
||||||
|
|
||||||
```rust
|
```text
|
||||||
let logging = match ks_logging::read_logging_json_file_with_environment(
|
KB_APP_DEMO_DESKTOP_CONFIG_PATH
|
||||||
std::path::Path::new("config/logging.config.json"),
|
|
||||||
std::path::Path::new("."),
|
|
||||||
) {
|
|
||||||
std::result::Result::Ok(value) => value,
|
|
||||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
||||||
};
|
|
||||||
let logging_profile = match ks_logging::active_logging_profile(&logging) {
|
|
||||||
std::result::Result::Ok(value) => value,
|
|
||||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
||||||
};
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Les deux `active_profile` sont indépendants. Il n’existe aucun fallback implicite du profil logging vers le nom du profil applicatif.
|
Le logging conserve l'override opérationnel :
|
||||||
|
|
||||||
|
```text
|
||||||
|
KS_LOGGING_CONFIG_PATH
|
||||||
|
```
|
||||||
|
|
||||||
|
Sans cet override, le desktop utilise le chemin logging déclaré par sa composition.
|
||||||
|
|
||||||
|
## Scénarios Devnet
|
||||||
|
|
||||||
|
Les scénarios opt-in utilisent :
|
||||||
|
|
||||||
|
```text
|
||||||
|
KS_DEVNET_CONFIG_PATH
|
||||||
|
KS_DEVNET_PROFILE
|
||||||
|
```
|
||||||
|
|
||||||
|
`KS_DEVNET_CONFIG_PATH` désigne désormais un fichier de composition. Sans override, les scénarios utilisent `config/ks-pipeline-demo-scenarios.default.config.json`.
|
||||||
|
|
||||||
|
## Transport
|
||||||
|
|
||||||
|
`transport.config.json` possède les endpoints HTTP et WebSocket ainsi que leurs rôles et limites. Le profil transport peut être consommé directement par `ks-onchain-transport` sans dépendre d'un profil applicatif complet.
|
||||||
|
|
||||||
|
Cela prépare les futurs workers : un worker de capture pourra sélectionner un profil transport différent du desktop tout en partageant le même document.
|
||||||
|
|
||||||
|
## Listeners
|
||||||
|
|
||||||
|
`listeners.config.json` contient les déclarations de subscriptions par logs, programme et compte. Un profil listeners peut être associé à n'importe quel profil transport compatible par le fichier de composition du consommateur.
|
||||||
|
|
||||||
|
La séparation évite de recopier les listes de `program_id` et les filtres lorsque plusieurs binaires observent la même surface Solana.
|
||||||
|
|
||||||
|
## Logging
|
||||||
|
|
||||||
|
`logging.config.json` appartient à `ks-logging`. Une composition référence son fichier et son profil, mais les types et validations logging ne reviennent pas dans `ks-config`.
|
||||||
|
|
||||||
|
## Contrat runtime résolu
|
||||||
|
|
||||||
|
Pendant la migration `0.5.1`, `ks-config` reconstruit encore un `AppConfig/ProfileConfig` contenant les sections nécessaires aux consommateurs existants. Ce contrat est une projection runtime, pas une configuration source.
|
||||||
|
|
||||||
|
Les tests de compatibilité utilisent les fixtures sous `test-fixtures/config/`. Aucun binaire ne doit charger ces fixtures en production.
|
||||||
|
|
||||||
|
## Étapes suivantes
|
||||||
|
|
||||||
|
Le prochain split doit extraire :
|
||||||
|
|
||||||
|
- database vers le document store ;
|
||||||
|
- `logs_directory` vers logging ;
|
||||||
|
- `wallets_directory`, le stockage wallet et les paramètres de wallet vers un document wallet ;
|
||||||
|
- les permissions `*_send_enabled` du wallet vers la politique execution ;
|
||||||
|
- execution ;
|
||||||
|
- configuration spécifique au desktop.
|
||||||
|
|
||||||
|
Après cette étape seulement, les DTO publics, diagnostics et règles de camouflage seront construits sur les nouvelles frontières.
|
||||||
|
|
||||||
## Invariants
|
## Invariants
|
||||||
|
|
||||||
- aucun secret réel ne doit être ajouté aux fichiers versionnés ;
|
- aucun secret réel dans les fichiers versionnés ;
|
||||||
- les placeholders non résolus doivent rester détectables ;
|
- tous les schémas actifs sous `config/schemas/` ;
|
||||||
- chaque schéma embarqué doit rester identique au fichier sous `config/schemas/` ;
|
- aucun retour au fichier monolithique `app.config.json` ;
|
||||||
- les profils applicatifs et logging sont validés indépendamment ;
|
- un fichier de composition appartient à son binaire ;
|
||||||
- `ks-config` ne possède plus de types logging ;
|
- un document spécialisé reste indépendant des binaires qui le consomment ;
|
||||||
- tant que `0.5.1-pre.006` n’a pas introduit les DTO sûrs, la configuration runtime résolue reste strictement backend et ne doit pas être exposée telle quelle.
|
- `ks-config` fournit les mécanismes partagés sans enregistrer une liste fermée de workers/applications.
|
||||||
|
|
||||||
## Diagnostic
|
|
||||||
|
|
||||||
Pour isoler une erreur :
|
|
||||||
|
|
||||||
1. vérifier le fichier d’environnement chargé ;
|
|
||||||
2. vérifier séparément les chemins app et logging ;
|
|
||||||
3. valider chaque document contre son schéma ;
|
|
||||||
4. vérifier son `active_profile` ;
|
|
||||||
5. vérifier ensuite les rôles HTTP/WebSocket, stockage ou routes logging concernés.
|
|
||||||
|
|
||||||
Ne jamais écrire dans les logs le JSON résolu complet s’il contient une valeur issue de `KS_SECRET_*` ou `KB_SECRET_*`.
|
|
||||||
|
|
||||||
## Références
|
|
||||||
|
|
||||||
- `ks-config/README.md` et `ks-config/USAGE.md` ;
|
|
||||||
- `ks-logging/README.md` et `ks-logging/USAGE.md` ;
|
|
||||||
- `config/README.md` ;
|
|
||||||
- `docs/decisions/KHADHROONY_SOLANA_NAMESPACE_POLICY.md`.
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/guides/LOGGING.md -->
|
<!-- file: docs/guides/LOGGING.md -->
|
||||||
<!-- version: 5 -->
|
<!-- version: 6 -->
|
||||||
|
|
||||||
# Guide de logging et tracing
|
# Guide de logging et tracing
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ let guard = match ks_logging::init_logging(config) {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Le profil logging est sélectionné indépendamment du profil général de `app.config.json`.
|
Le document logging reste indépendant de la composition binaire. Une composition `<binary>.default.config.json` sélectionne explicitement le profil logging qu’elle veut utiliser ; le `active_profile` propre à `logging.config.json` reste disponible pour les consommateurs autonomes.
|
||||||
|
|
||||||
## Contrat JSON
|
## Contrat JSON
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/plans/V0_5_1_KHADHROONY_SOLANA_NAMESPACE_AND_CONFIG_PLAN.md -->
|
<!-- file: docs/plans/V0_5_1_KHADHROONY_SOLANA_NAMESPACE_AND_CONFIG_PLAN.md -->
|
||||||
<!-- version: 5 -->
|
<!-- version: 6 -->
|
||||||
|
|
||||||
# Plan temporaire `0.5.1` — namespace Khadhroony Solana et configuration sûre
|
# Plan temporaire `0.5.1` — namespace Khadhroony Solana et configuration sûre
|
||||||
|
|
||||||
@@ -32,18 +32,18 @@ Les bibliothèques internes Solana utilisent `ks-*` / `ks_*` et leurs variables
|
|||||||
|
|
||||||
## 4. Inventaire des crates et ordre de migration
|
## 4. Inventaire des crates et ordre de migration
|
||||||
|
|
||||||
| Package actuel | Identifiant Rust actuel | Package cible | Identifiant Rust cible | Dépendances workspace directes actuelles | Ordre |
|
| Package actuel | Identifiant Rust actuel | Package cible | Identifiant Rust cible | Dépendances workspace directes actuelles | Ordre |
|
||||||
|---|---|---|---|---|---:|
|
|------------------------------|------------------------------|------------------------------|------------------------------|----------------------------------------------------------------------------------------------------|------:|
|
||||||
| `kb-core` | `kb_core` | `ks-core` | `ks_core` | — | 1 |
|
| `kb-core` | `kb_core` | `ks-core` | `ks_core` | — | 1 |
|
||||||
| `kb-program-ids` | `kb_program_ids` | `ks-program-ids` | `ks_program_ids` | — | 2 |
|
| `kb-program-ids` | `kb_program_ids` | `ks-program-ids` | `ks_program_ids` | — | 2 |
|
||||||
| `kb-config` | `kb_config` | `ks-config` | `ks_config` | kb-core | 3 |
|
| `kb-config` | `kb_config` | `ks-config` | `ks_config` | kb-core | 3 |
|
||||||
| `kb-logging` | `kb_logging` | `ks-logging` | `ks_logging` | kb-core | 4 |
|
| `kb-logging` | `kb_logging` | `ks-logging` | `ks_logging` | kb-core | 4 |
|
||||||
| `kb-wallet` | `kb_wallet` | `ks-wallet` | `ks_wallet` | kb-core | 5 |
|
| `kb-wallet` | `kb_wallet` | `ks-wallet` | `ks_wallet` | kb-core | 5 |
|
||||||
| `kb-lib` | `kb_lib` | `ks-lib` | `ks_lib` | kb-core, kb-program-ids | 6 |
|
| `kb-lib` | `kb_lib` | `ks-lib` | `ks_lib` | kb-core, kb-program-ids | 6 |
|
||||||
| `kb-onchain-transport` | `kb_onchain_transport` | `ks-onchain-transport` | `ks_onchain_transport` | kb-config, kb-core, kb-lib | 7 |
|
| `kb-onchain-transport` | `kb_onchain_transport` | `ks-onchain-transport` | `ks_onchain_transport` | kb-config, kb-core, kb-lib | 7 |
|
||||||
| `kb-store` | `kb_store` | `ks-store` | `ks_store` | kb-core, kb-lib | 8 |
|
| `kb-store` | `kb_store` | `ks-store` | `ks_store` | kb-core, kb-lib | 8 |
|
||||||
| `kb-pipeline` | `kb_pipeline` | `ks-pipeline` | `ks_pipeline` | kb-core, kb-config, kb-lib, kb-onchain-transport, kb-program-ids, kb-store | 9 |
|
| `kb-pipeline` | `kb_pipeline` | `ks-pipeline` | `ks_pipeline` | kb-core, kb-config, kb-lib, kb-onchain-transport, kb-program-ids, kb-store | 9 |
|
||||||
| `kb-pipeline-demo-scenarios` | `kb_pipeline_demo_scenarios` | `ks-pipeline-demo-scenarios` | `ks_pipeline_demo_scenarios` | kb-core, kb-config, kb-lib, kb-onchain-transport, kb-pipeline, kb-program-ids, kb-store, kb-wallet | 10 |
|
| `kb-pipeline-demo-scenarios` | `kb_pipeline_demo_scenarios` | `ks-pipeline-demo-scenarios` | `ks_pipeline_demo_scenarios` | kb-core, kb-config, kb-lib, kb-onchain-transport, kb-pipeline, kb-program-ids, kb-store, kb-wallet | 10 |
|
||||||
|
|
||||||
`kb-app-demo-desktop` est adapté en dernier, mais garde son package, son répertoire et ses identifiants applicatifs.
|
`kb-app-demo-desktop` est adapté en dernier, mais garde son package, son répertoire et ses identifiants applicatifs.
|
||||||
|
|
||||||
@@ -58,18 +58,18 @@ bin : kb-pipeline-demo-scenarios-cli -> ks-pipeline-demo-scenarios-cli
|
|||||||
|
|
||||||
Les valeurs suivantes sont des métriques d'orientation sur les fichiers actifs, hors archives et artefacts générés. Elles montrent qu'un renommage massif en une seule opération serait difficile à diagnostiquer.
|
Les valeurs suivantes sont des métriques d'orientation sur les fichiers actifs, hors archives et artefacts générés. Elles montrent qu'un renommage massif en une seule opération serait difficile à diagnostiquer.
|
||||||
|
|
||||||
| Crate | Références package / fichiers | Références identifiant Rust / fichiers |
|
| Crate | Références package / fichiers | Références identifiant Rust / fichiers |
|
||||||
|---|---:|---:|
|
|------------------------------|------------------------------:|---------------------------------------:|
|
||||||
| `kb-core` | 51 / 32 | 3165 / 407 |
|
| `kb-core` | 51 / 32 | 3165 / 407 |
|
||||||
| `kb-config` | 56 / 33 | 201 / 44 |
|
| `kb-config` | 56 / 33 | 201 / 44 |
|
||||||
| `kb-lib` | 3145 / 550 | 2785 / 97 |
|
| `kb-lib` | 3145 / 550 | 2785 / 97 |
|
||||||
| `kb-logging` | 72 / 27 | 22 / 3 |
|
| `kb-logging` | 72 / 27 | 22 / 3 |
|
||||||
| `kb-program-ids` | 42 / 28 | 1413 / 334 |
|
| `kb-program-ids` | 42 / 28 | 1413 / 334 |
|
||||||
| `kb-pipeline` | 287 / 112 | 436 / 38 |
|
| `kb-pipeline` | 287 / 112 | 436 / 38 |
|
||||||
| `kb-pipeline-demo-scenarios` | 145 / 75 | 173 / 18 |
|
| `kb-pipeline-demo-scenarios` | 145 / 75 | 173 / 18 |
|
||||||
| `kb-onchain-transport` | 125 / 56 | 530 / 50 |
|
| `kb-onchain-transport` | 125 / 56 | 530 / 50 |
|
||||||
| `kb-store` | 157 / 81 | 344 / 30 |
|
| `kb-store` | 157 / 81 | 344 / 30 |
|
||||||
| `kb-wallet` | 75 / 30 | 53 / 17 |
|
| `kb-wallet` | 75 / 30 | 53 / 17 |
|
||||||
|
|
||||||
Le volume `kb-lib` inclut notamment les identités techniques `kb-lib.*`; il ne doit pas être interprété comme autant d'importations Cargo.
|
Le volume `kb-lib` inclut notamment les identités techniques `kb-lib.*`; il ne doit pas être interprété comme autant d'importations Cargo.
|
||||||
|
|
||||||
@@ -145,264 +145,264 @@ Les targets de tracing de crates génériques doivent également migrer vers `ks
|
|||||||
|
|
||||||
### 6.1 Inventaire exhaustif des identités `kb-lib.*`
|
### 6.1 Inventaire exhaustif des identités `kb-lib.*`
|
||||||
|
|
||||||
| Identité actuelle | Identité cible |
|
| Identité actuelle | Identité cible |
|
||||||
|---|---|
|
|----------------------------------------------------------------|----------------------------------------------------------------|
|
||||||
| `kb-lib.decoder.adapter.saber_decimal_wrapper` | `ks-lib-decoder.adapter.saber_decimal_wrapper` |
|
| `kb-lib.decoder.adapter.saber_decimal_wrapper` | `ks-lib-decoder.adapter.saber_decimal_wrapper` |
|
||||||
| `kb-lib.decoder.adapter.spl_token_wrap` | `ks-lib-decoder.adapter.spl_token_wrap` |
|
| `kb-lib.decoder.adapter.spl_token_wrap` | `ks-lib-decoder.adapter.spl_token_wrap` |
|
||||||
| `kb-lib.decoder.admin.jupiter_lock` | `ks-lib-decoder.admin.jupiter_lock` |
|
| `kb-lib.decoder.admin.jupiter_lock` | `ks-lib-decoder.admin.jupiter_lock` |
|
||||||
| `kb-lib.decoder.admin.pump_fees` | `ks-lib-decoder.admin.pump_fees` |
|
| `kb-lib.decoder.admin.pump_fees` | `ks-lib-decoder.admin.pump_fees` |
|
||||||
| `kb-lib.decoder.amm.aldrin_v1` | `ks-lib-decoder.amm.aldrin_v1` |
|
| `kb-lib.decoder.amm.aldrin_v1` | `ks-lib-decoder.amm.aldrin_v1` |
|
||||||
| `kb-lib.decoder.amm.aldrin_v2` | `ks-lib-decoder.amm.aldrin_v2` |
|
| `kb-lib.decoder.amm.aldrin_v2` | `ks-lib-decoder.amm.aldrin_v2` |
|
||||||
| `kb-lib.decoder.amm.alphaq` | `ks-lib-decoder.amm.alphaq` |
|
| `kb-lib.decoder.amm.alphaq` | `ks-lib-decoder.amm.alphaq` |
|
||||||
| `kb-lib.decoder.amm.believe` | `ks-lib-decoder.amm.believe` |
|
| `kb-lib.decoder.amm.believe` | `ks-lib-decoder.amm.believe` |
|
||||||
| `kb-lib.decoder.amm.bonk_swap` | `ks-lib-decoder.amm.bonk_swap` |
|
| `kb-lib.decoder.amm.bonk_swap` | `ks-lib-decoder.amm.bonk_swap` |
|
||||||
| `kb-lib.decoder.amm.fluxbeam` | `ks-lib-decoder.amm.fluxbeam` |
|
| `kb-lib.decoder.amm.fluxbeam` | `ks-lib-decoder.amm.fluxbeam` |
|
||||||
| `kb-lib.decoder.amm.goon_fi` | `ks-lib-decoder.amm.goon_fi` |
|
| `kb-lib.decoder.amm.goon_fi` | `ks-lib-decoder.amm.goon_fi` |
|
||||||
| `kb-lib.decoder.amm.goosefx_gamma` | `ks-lib-decoder.amm.goosefx_gamma` |
|
| `kb-lib.decoder.amm.goosefx_gamma` | `ks-lib-decoder.amm.goosefx_gamma` |
|
||||||
| `kb-lib.decoder.amm.goosefx_v2` | `ks-lib-decoder.amm.goosefx_v2` |
|
| `kb-lib.decoder.amm.goosefx_v2` | `ks-lib-decoder.amm.goosefx_v2` |
|
||||||
| `kb-lib.decoder.amm.guac_swap` | `ks-lib-decoder.amm.guac_swap` |
|
| `kb-lib.decoder.amm.guac_swap` | `ks-lib-decoder.amm.guac_swap` |
|
||||||
| `kb-lib.decoder.amm.lifinity_swap_v2` | `ks-lib-decoder.amm.lifinity_swap_v2` |
|
| `kb-lib.decoder.amm.lifinity_swap_v2` | `ks-lib-decoder.amm.lifinity_swap_v2` |
|
||||||
| `kb-lib.decoder.amm.metadao_futarchy_amm` | `ks-lib-decoder.amm.metadao_futarchy_amm` |
|
| `kb-lib.decoder.amm.metadao_futarchy_amm` | `ks-lib-decoder.amm.metadao_futarchy_amm` |
|
||||||
| `kb-lib.decoder.amm.metadao_v0_5` | `ks-lib-decoder.amm.metadao_v0_5` |
|
| `kb-lib.decoder.amm.metadao_v0_5` | `ks-lib-decoder.amm.metadao_v0_5` |
|
||||||
| `kb-lib.decoder.amm.meteora_damm_v1` | `ks-lib-decoder.amm.meteora_damm_v1` |
|
| `kb-lib.decoder.amm.meteora_damm_v1` | `ks-lib-decoder.amm.meteora_damm_v1` |
|
||||||
| `kb-lib.decoder.amm.meteora_damm_v2` | `ks-lib-decoder.amm.meteora_damm_v2` |
|
| `kb-lib.decoder.amm.meteora_damm_v2` | `ks-lib-decoder.amm.meteora_damm_v2` |
|
||||||
| `kb-lib.decoder.amm.obric_v2` | `ks-lib-decoder.amm.obric_v2` |
|
| `kb-lib.decoder.amm.obric_v2` | `ks-lib-decoder.amm.obric_v2` |
|
||||||
| `kb-lib.decoder.amm.one_dex` | `ks-lib-decoder.amm.one_dex` |
|
| `kb-lib.decoder.amm.one_dex` | `ks-lib-decoder.amm.one_dex` |
|
||||||
| `kb-lib.decoder.amm.pump_swap` | `ks-lib-decoder.amm.pump_swap` |
|
| `kb-lib.decoder.amm.pump_swap` | `ks-lib-decoder.amm.pump_swap` |
|
||||||
| `kb-lib.decoder.amm.raydium_lp_v4` | `ks-lib-decoder.amm.raydium_lp_v4` |
|
| `kb-lib.decoder.amm.raydium_lp_v4` | `ks-lib-decoder.amm.raydium_lp_v4` |
|
||||||
| `kb-lib.decoder.amm.solfi` | `ks-lib-decoder.amm.solfi` |
|
| `kb-lib.decoder.amm.solfi` | `ks-lib-decoder.amm.solfi` |
|
||||||
| `kb-lib.decoder.amm.solfi_v2` | `ks-lib-decoder.amm.solfi_v2` |
|
| `kb-lib.decoder.amm.solfi_v2` | `ks-lib-decoder.amm.solfi_v2` |
|
||||||
| `kb-lib.decoder.amm.vertigo` | `ks-lib-decoder.amm.vertigo` |
|
| `kb-lib.decoder.amm.vertigo` | `ks-lib-decoder.amm.vertigo` |
|
||||||
| `kb-lib.decoder.amm.virtuals` | `ks-lib-decoder.amm.virtuals` |
|
| `kb-lib.decoder.amm.virtuals` | `ks-lib-decoder.amm.virtuals` |
|
||||||
| `kb-lib.decoder.amm.woofi` | `ks-lib-decoder.amm.woofi` |
|
| `kb-lib.decoder.amm.woofi` | `ks-lib-decoder.amm.woofi` |
|
||||||
| `kb-lib.decoder.amm.zero_fi` | `ks-lib-decoder.amm.zero_fi` |
|
| `kb-lib.decoder.amm.zero_fi` | `ks-lib-decoder.amm.zero_fi` |
|
||||||
| `kb-lib.decoder.amm.zora` | `ks-lib-decoder.amm.zora` |
|
| `kb-lib.decoder.amm.zora` | `ks-lib-decoder.amm.zora` |
|
||||||
| `kb-lib.decoder.anchor` | `ks-lib-decoder.anchor` |
|
| `kb-lib.decoder.anchor` | `ks-lib-decoder.anchor` |
|
||||||
| `kb-lib.decoder.api` | `ks-lib-decoder.api` |
|
| `kb-lib.decoder.api` | `ks-lib-decoder.api` |
|
||||||
| `kb-lib.decoder.bridge.circle_cctp_token_messenger_minter` | `ks-lib-decoder.bridge.circle_cctp_token_messenger_minter` |
|
| `kb-lib.decoder.bridge.circle_cctp_token_messenger_minter` | `ks-lib-decoder.bridge.circle_cctp_token_messenger_minter` |
|
||||||
| `kb-lib.decoder.bridge.circle_cctp_token_messenger_minter_v2` | `ks-lib-decoder.bridge.circle_cctp_token_messenger_minter_v2` |
|
| `kb-lib.decoder.bridge.circle_cctp_token_messenger_minter_v2` | `ks-lib-decoder.bridge.circle_cctp_token_messenger_minter_v2` |
|
||||||
| `kb-lib.decoder.bridge.layer_zero_endpoint` | `ks-lib-decoder.bridge.layer_zero_endpoint` |
|
| `kb-lib.decoder.bridge.layer_zero_endpoint` | `ks-lib-decoder.bridge.layer_zero_endpoint` |
|
||||||
| `kb-lib.decoder.bridge.layer_zero_executor` | `ks-lib-decoder.bridge.layer_zero_executor` |
|
| `kb-lib.decoder.bridge.layer_zero_executor` | `ks-lib-decoder.bridge.layer_zero_executor` |
|
||||||
| `kb-lib.decoder.clmm.byreal` | `ks-lib-decoder.clmm.byreal` |
|
| `kb-lib.decoder.clmm.byreal` | `ks-lib-decoder.clmm.byreal` |
|
||||||
| `kb-lib.decoder.clmm.fusion` | `ks-lib-decoder.clmm.fusion` |
|
| `kb-lib.decoder.clmm.fusion` | `ks-lib-decoder.clmm.fusion` |
|
||||||
| `kb-lib.decoder.clmm.orca_whirlpool` | `ks-lib-decoder.clmm.orca_whirlpool` |
|
| `kb-lib.decoder.clmm.orca_whirlpool` | `ks-lib-decoder.clmm.orca_whirlpool` |
|
||||||
| `kb-lib.decoder.clmm.pancake_swap` | `ks-lib-decoder.clmm.pancake_swap` |
|
| `kb-lib.decoder.clmm.pancake_swap` | `ks-lib-decoder.clmm.pancake_swap` |
|
||||||
| `kb-lib.decoder.clmm.raydium` | `ks-lib-decoder.clmm.raydium` |
|
| `kb-lib.decoder.clmm.raydium` | `ks-lib-decoder.clmm.raydium` |
|
||||||
| `kb-lib.decoder.clmm.stabble` | `ks-lib-decoder.clmm.stabble` |
|
| `kb-lib.decoder.clmm.stabble` | `ks-lib-decoder.clmm.stabble` |
|
||||||
| `kb-lib.decoder.cpmm.raydium` | `ks-lib-decoder.cpmm.raydium` |
|
| `kb-lib.decoder.cpmm.raydium` | `ks-lib-decoder.cpmm.raydium` |
|
||||||
| `kb-lib.decoder.dlmm.meteora` | `ks-lib-decoder.dlmm.meteora` |
|
| `kb-lib.decoder.dlmm.meteora` | `ks-lib-decoder.dlmm.meteora` |
|
||||||
| `kb-lib.decoder.fees.bags_fee_share_v1` | `ks-lib-decoder.fees.bags_fee_share_v1` |
|
| `kb-lib.decoder.fees.bags_fee_share_v1` | `ks-lib-decoder.fees.bags_fee_share_v1` |
|
||||||
| `kb-lib.decoder.fees.bags_fee_share_v2` | `ks-lib-decoder.fees.bags_fee_share_v2` |
|
| `kb-lib.decoder.fees.bags_fee_share_v2` | `ks-lib-decoder.fees.bags_fee_share_v2` |
|
||||||
| `kb-lib.decoder.fees.pump_fees` | `ks-lib-decoder.fees.pump_fees` |
|
| `kb-lib.decoder.fees.pump_fees` | `ks-lib-decoder.fees.pump_fees` |
|
||||||
| `kb-lib.decoder.governance.metadao_bid_wall` | `ks-lib-decoder.governance.metadao_bid_wall` |
|
| `kb-lib.decoder.governance.metadao_bid_wall` | `ks-lib-decoder.governance.metadao_bid_wall` |
|
||||||
| `kb-lib.decoder.governance.metadao_futarchy` | `ks-lib-decoder.governance.metadao_futarchy` |
|
| `kb-lib.decoder.governance.metadao_futarchy` | `ks-lib-decoder.governance.metadao_futarchy` |
|
||||||
| `kb-lib.decoder.governance.squads_multisig` | `ks-lib-decoder.governance.squads_multisig` |
|
| `kb-lib.decoder.governance.squads_multisig` | `ks-lib-decoder.governance.squads_multisig` |
|
||||||
| `kb-lib.decoder.launchpad.boop_fun` | `ks-lib-decoder.launchpad.boop_fun` |
|
| `kb-lib.decoder.launchpad.boop_fun` | `ks-lib-decoder.launchpad.boop_fun` |
|
||||||
| `kb-lib.decoder.launchpad.metadao_ico` | `ks-lib-decoder.launchpad.metadao_ico` |
|
| `kb-lib.decoder.launchpad.metadao_ico` | `ks-lib-decoder.launchpad.metadao_ico` |
|
||||||
| `kb-lib.decoder.launchpad.meteora_dbc` | `ks-lib-decoder.launchpad.meteora_dbc` |
|
| `kb-lib.decoder.launchpad.meteora_dbc` | `ks-lib-decoder.launchpad.meteora_dbc` |
|
||||||
| `kb-lib.decoder.launchpad.moonit` | `ks-lib-decoder.launchpad.moonit` |
|
| `kb-lib.decoder.launchpad.moonit` | `ks-lib-decoder.launchpad.moonit` |
|
||||||
| `kb-lib.decoder.launchpad.orca_wavebreak` | `ks-lib-decoder.launchpad.orca_wavebreak` |
|
| `kb-lib.decoder.launchpad.orca_wavebreak` | `ks-lib-decoder.launchpad.orca_wavebreak` |
|
||||||
| `kb-lib.decoder.launchpad.printr` | `ks-lib-decoder.launchpad.printr` |
|
| `kb-lib.decoder.launchpad.printr` | `ks-lib-decoder.launchpad.printr` |
|
||||||
| `kb-lib.decoder.launchpad.pump_fun` | `ks-lib-decoder.launchpad.pump_fun` |
|
| `kb-lib.decoder.launchpad.pump_fun` | `ks-lib-decoder.launchpad.pump_fun` |
|
||||||
| `kb-lib.decoder.launchpad.pump_pumpup_ai` | `ks-lib-decoder.launchpad.pump_pumpup_ai` |
|
| `kb-lib.decoder.launchpad.pump_pumpup_ai` | `ks-lib-decoder.launchpad.pump_pumpup_ai` |
|
||||||
| `kb-lib.decoder.launchpad.raydium_launchlab` | `ks-lib-decoder.launchpad.raydium_launchlab` |
|
| `kb-lib.decoder.launchpad.raydium_launchlab` | `ks-lib-decoder.launchpad.raydium_launchlab` |
|
||||||
| `kb-lib.decoder.launchpad.virtuals` | `ks-lib-decoder.launchpad.virtuals` |
|
| `kb-lib.decoder.launchpad.virtuals` | `ks-lib-decoder.launchpad.virtuals` |
|
||||||
| `kb-lib.decoder.lending.clone` | `ks-lib-decoder.lending.clone` |
|
| `kb-lib.decoder.lending.clone` | `ks-lib-decoder.lending.clone` |
|
||||||
| `kb-lib.decoder.lending.jupiter_lend_borrow` | `ks-lib-decoder.lending.jupiter_lend_borrow` |
|
| `kb-lib.decoder.lending.jupiter_lend_borrow` | `ks-lib-decoder.lending.jupiter_lend_borrow` |
|
||||||
| `kb-lib.decoder.lending.jupiter_lend_earn` | `ks-lib-decoder.lending.jupiter_lend_earn` |
|
| `kb-lib.decoder.lending.jupiter_lend_earn` | `ks-lib-decoder.lending.jupiter_lend_earn` |
|
||||||
| `kb-lib.decoder.lending.jupiter_lend_flash_loan` | `ks-lib-decoder.lending.jupiter_lend_flash_loan` |
|
| `kb-lib.decoder.lending.jupiter_lend_flash_loan` | `ks-lib-decoder.lending.jupiter_lend_flash_loan` |
|
||||||
| `kb-lib.decoder.lending.jupiter_lend_liquidity` | `ks-lib-decoder.lending.jupiter_lend_liquidity` |
|
| `kb-lib.decoder.lending.jupiter_lend_liquidity` | `ks-lib-decoder.lending.jupiter_lend_liquidity` |
|
||||||
| `kb-lib.decoder.lending.kamino` | `ks-lib-decoder.lending.kamino` |
|
| `kb-lib.decoder.lending.kamino` | `ks-lib-decoder.lending.kamino` |
|
||||||
| `kb-lib.decoder.lending.marginfi_v2` | `ks-lib-decoder.lending.marginfi_v2` |
|
| `kb-lib.decoder.lending.marginfi_v2` | `ks-lib-decoder.lending.marginfi_v2` |
|
||||||
| `kb-lib.decoder.lock.raydium_lp` | `ks-lib-decoder.lock.raydium_lp` |
|
| `kb-lib.decoder.lock.raydium_lp` | `ks-lib-decoder.lock.raydium_lp` |
|
||||||
| `kb-lib.decoder.metadata.metaplex_token_metadata` | `ks-lib-decoder.metadata.metaplex_token_metadata` |
|
| `kb-lib.decoder.metadata.metaplex_token_metadata` | `ks-lib-decoder.metadata.metaplex_token_metadata` |
|
||||||
| `kb-lib.decoder.metadata.solana_program_metadata` | `ks-lib-decoder.metadata.solana_program_metadata` |
|
| `kb-lib.decoder.metadata.solana_program_metadata` | `ks-lib-decoder.metadata.solana_program_metadata` |
|
||||||
| `kb-lib.decoder.metadata.spl_name_service` | `ks-lib-decoder.metadata.spl_name_service` |
|
| `kb-lib.decoder.metadata.spl_name_service` | `ks-lib-decoder.metadata.spl_name_service` |
|
||||||
| `kb-lib.decoder.nft.metaplex_bubblegum` | `ks-lib-decoder.nft.metaplex_bubblegum` |
|
| `kb-lib.decoder.nft.metaplex_bubblegum` | `ks-lib-decoder.nft.metaplex_bubblegum` |
|
||||||
| `kb-lib.decoder.nft.tensor_cnft` | `ks-lib-decoder.nft.tensor_cnft` |
|
| `kb-lib.decoder.nft.tensor_cnft` | `ks-lib-decoder.nft.tensor_cnft` |
|
||||||
| `kb-lib.decoder.orderbook.jupiter_limit_order` | `ks-lib-decoder.orderbook.jupiter_limit_order` |
|
| `kb-lib.decoder.orderbook.jupiter_limit_order` | `ks-lib-decoder.orderbook.jupiter_limit_order` |
|
||||||
| `kb-lib.decoder.orderbook.jupiter_limit_order_v2` | `ks-lib-decoder.orderbook.jupiter_limit_order_v2` |
|
| `kb-lib.decoder.orderbook.jupiter_limit_order_v2` | `ks-lib-decoder.orderbook.jupiter_limit_order_v2` |
|
||||||
| `kb-lib.decoder.orderbook.openbook_v2` | `ks-lib-decoder.orderbook.openbook_v2` |
|
| `kb-lib.decoder.orderbook.openbook_v2` | `ks-lib-decoder.orderbook.openbook_v2` |
|
||||||
| `kb-lib.decoder.perpetuals.drift_v2` | `ks-lib-decoder.perpetuals.drift_v2` |
|
| `kb-lib.decoder.perpetuals.drift_v2` | `ks-lib-decoder.perpetuals.drift_v2` |
|
||||||
| `kb-lib.decoder.perpetuals.jupiter` | `ks-lib-decoder.perpetuals.jupiter` |
|
| `kb-lib.decoder.perpetuals.jupiter` | `ks-lib-decoder.perpetuals.jupiter` |
|
||||||
| `kb-lib.decoder.perpetuals.phoenix_eternal` | `ks-lib-decoder.perpetuals.phoenix_eternal` |
|
| `kb-lib.decoder.perpetuals.phoenix_eternal` | `ks-lib-decoder.perpetuals.phoenix_eternal` |
|
||||||
| `kb-lib.decoder.perpetuals.zeta` | `ks-lib-decoder.perpetuals.zeta` |
|
| `kb-lib.decoder.perpetuals.zeta` | `ks-lib-decoder.perpetuals.zeta` |
|
||||||
| `kb-lib.decoder.router.dflow_aggregator_v4` | `ks-lib-decoder.router.dflow_aggregator_v4` |
|
| `kb-lib.decoder.router.dflow_aggregator_v4` | `ks-lib-decoder.router.dflow_aggregator_v4` |
|
||||||
| `kb-lib.decoder.router.jupiter_aggregator_v4` | `ks-lib-decoder.router.jupiter_aggregator_v4` |
|
| `kb-lib.decoder.router.jupiter_aggregator_v4` | `ks-lib-decoder.router.jupiter_aggregator_v4` |
|
||||||
| `kb-lib.decoder.router.jupiter_aggregator_v6` | `ks-lib-decoder.router.jupiter_aggregator_v6` |
|
| `kb-lib.decoder.router.jupiter_aggregator_v6` | `ks-lib-decoder.router.jupiter_aggregator_v6` |
|
||||||
| `kb-lib.decoder.router.jupiter_dca` | `ks-lib-decoder.router.jupiter_dca` |
|
| `kb-lib.decoder.router.jupiter_dca` | `ks-lib-decoder.router.jupiter_dca` |
|
||||||
| `kb-lib.decoder.router.okx_labs_v1` | `ks-lib-decoder.router.okx_labs_v1` |
|
| `kb-lib.decoder.router.okx_labs_v1` | `ks-lib-decoder.router.okx_labs_v1` |
|
||||||
| `kb-lib.decoder.router.okx_labs_v2` | `ks-lib-decoder.router.okx_labs_v2` |
|
| `kb-lib.decoder.router.okx_labs_v2` | `ks-lib-decoder.router.okx_labs_v2` |
|
||||||
| `kb-lib.decoder.rwa.ondo_global_markets` | `ks-lib-decoder.rwa.ondo_global_markets` |
|
| `kb-lib.decoder.rwa.ondo_global_markets` | `ks-lib-decoder.rwa.ondo_global_markets` |
|
||||||
| `kb-lib.decoder.solana.core` | `ks-lib-decoder.solana.core` |
|
| `kb-lib.decoder.solana.core` | `ks-lib-decoder.solana.core` |
|
||||||
| `kb-lib.decoder.spl.account_compression` | `ks-lib-decoder.spl.account_compression` |
|
| `kb-lib.decoder.spl.account_compression` | `ks-lib-decoder.spl.account_compression` |
|
||||||
| `kb-lib.decoder.spl.associated_token_account` | `ks-lib-decoder.spl.associated_token_account` |
|
| `kb-lib.decoder.spl.associated_token_account` | `ks-lib-decoder.spl.associated_token_account` |
|
||||||
| `kb-lib.decoder.spl.elgamal_registry` | `ks-lib-decoder.spl.elgamal_registry` |
|
| `kb-lib.decoder.spl.elgamal_registry` | `ks-lib-decoder.spl.elgamal_registry` |
|
||||||
| `kb-lib.decoder.spl.memo` | `ks-lib-decoder.spl.memo` |
|
| `kb-lib.decoder.spl.memo` | `ks-lib-decoder.spl.memo` |
|
||||||
| `kb-lib.decoder.spl.noop` | `ks-lib-decoder.spl.noop` |
|
| `kb-lib.decoder.spl.noop` | `ks-lib-decoder.spl.noop` |
|
||||||
| `kb-lib.decoder.spl.single_pool` | `ks-lib-decoder.spl.single_pool` |
|
| `kb-lib.decoder.spl.single_pool` | `ks-lib-decoder.spl.single_pool` |
|
||||||
| `kb-lib.decoder.spl.stake_pool` | `ks-lib-decoder.spl.stake_pool` |
|
| `kb-lib.decoder.spl.stake_pool` | `ks-lib-decoder.spl.stake_pool` |
|
||||||
| `kb-lib.decoder.spl.token` | `ks-lib-decoder.spl.token` |
|
| `kb-lib.decoder.spl.token` | `ks-lib-decoder.spl.token` |
|
||||||
| `kb-lib.decoder.spl.token_2022` | `ks-lib-decoder.spl.token_2022` |
|
| `kb-lib.decoder.spl.token_2022` | `ks-lib-decoder.spl.token_2022` |
|
||||||
| `kb-lib.decoder.stable.swap_hylo_exchange` | `ks-lib-decoder.stable.swap_hylo_exchange` |
|
| `kb-lib.decoder.stable.swap_hylo_exchange` | `ks-lib-decoder.stable.swap_hylo_exchange` |
|
||||||
| `kb-lib.decoder.stable.swap_jupiter_stable` | `ks-lib-decoder.stable.swap_jupiter_stable` |
|
| `kb-lib.decoder.stable.swap_jupiter_stable` | `ks-lib-decoder.stable.swap_jupiter_stable` |
|
||||||
| `kb-lib.decoder.stable.swap_numeraire` | `ks-lib-decoder.stable.swap_numeraire` |
|
| `kb-lib.decoder.stable.swap_numeraire` | `ks-lib-decoder.stable.swap_numeraire` |
|
||||||
| `kb-lib.decoder.stable.swap_stabble` | `ks-lib-decoder.stable.swap_stabble` |
|
| `kb-lib.decoder.stable.swap_stabble` | `ks-lib-decoder.stable.swap_stabble` |
|
||||||
| `kb-lib.decoder.staking.jito_tip_distribution` | `ks-lib-decoder.staking.jito_tip_distribution` |
|
| `kb-lib.decoder.staking.jito_tip_distribution` | `ks-lib-decoder.staking.jito_tip_distribution` |
|
||||||
| `kb-lib.decoder.staking.kamino_farm` | `ks-lib-decoder.staking.kamino_farm` |
|
| `kb-lib.decoder.staking.kamino_farm` | `ks-lib-decoder.staking.kamino_farm` |
|
||||||
| `kb-lib.decoder.staking.marinade_finance` | `ks-lib-decoder.staking.marinade_finance` |
|
| `kb-lib.decoder.staking.marinade_finance` | `ks-lib-decoder.staking.marinade_finance` |
|
||||||
| `kb-lib.decoder.staking.solayer` | `ks-lib-decoder.staking.solayer` |
|
| `kb-lib.decoder.staking.solayer` | `ks-lib-decoder.staking.solayer` |
|
||||||
| `kb-lib.decoder.storage.solana_record` | `ks-lib-decoder.storage.solana_record` |
|
| `kb-lib.decoder.storage.solana_record` | `ks-lib-decoder.storage.solana_record` |
|
||||||
| `kb-lib.decoder.strategy.jupiter_dca` | `ks-lib-decoder.strategy.jupiter_dca` |
|
| `kb-lib.decoder.strategy.jupiter_dca` | `ks-lib-decoder.strategy.jupiter_dca` |
|
||||||
| `kb-lib.decoder.treasury.helium_treasury_management` | `ks-lib-decoder.treasury.helium_treasury_management` |
|
| `kb-lib.decoder.treasury.helium_treasury_management` | `ks-lib-decoder.treasury.helium_treasury_management` |
|
||||||
| `kb-lib.decoder.vault.carrot_defi` | `ks-lib-decoder.vault.carrot_defi` |
|
| `kb-lib.decoder.vault.carrot_defi` | `ks-lib-decoder.vault.carrot_defi` |
|
||||||
| `kb-lib.decoder.vault.hylo_stability_pool` | `ks-lib-decoder.vault.hylo_stability_pool` |
|
| `kb-lib.decoder.vault.hylo_stability_pool` | `ks-lib-decoder.vault.hylo_stability_pool` |
|
||||||
| `kb-lib.decoder.vault.kamino` | `ks-lib-decoder.vault.kamino` |
|
| `kb-lib.decoder.vault.kamino` | `ks-lib-decoder.vault.kamino` |
|
||||||
| `kb-lib.decoder.vault.kamino_v2` | `ks-lib-decoder.vault.kamino_v2` |
|
| `kb-lib.decoder.vault.kamino_v2` | `ks-lib-decoder.vault.kamino_v2` |
|
||||||
| `kb-lib.decoder.vault.kamino_yvaults` | `ks-lib-decoder.vault.kamino_yvaults` |
|
| `kb-lib.decoder.vault.kamino_yvaults` | `ks-lib-decoder.vault.kamino_yvaults` |
|
||||||
| `kb-lib.decoder.vault.meteora` | `ks-lib-decoder.vault.meteora` |
|
| `kb-lib.decoder.vault.meteora` | `ks-lib-decoder.vault.meteora` |
|
||||||
| `kb-lib.decoder.vesting.jupiter_lock` | `ks-lib-decoder.vesting.jupiter_lock` |
|
| `kb-lib.decoder.vesting.jupiter_lock` | `ks-lib-decoder.vesting.jupiter_lock` |
|
||||||
| `kb-lib.decoder.vesting.streamflow` | `ks-lib-decoder.vesting.streamflow` |
|
| `kb-lib.decoder.vesting.streamflow` | `ks-lib-decoder.vesting.streamflow` |
|
||||||
| `kb-lib.decoder.wallet.jupiter_apepro_smart_wallet` | `ks-lib-decoder.wallet.jupiter_apepro_smart_wallet` |
|
| `kb-lib.decoder.wallet.jupiter_apepro_smart_wallet` | `ks-lib-decoder.wallet.jupiter_apepro_smart_wallet` |
|
||||||
| `kb-lib.decoder.weighted.swap_stabble` | `ks-lib-decoder.weighted.swap_stabble` |
|
| `kb-lib.decoder.weighted.swap_stabble` | `ks-lib-decoder.weighted.swap_stabble` |
|
||||||
| `kb-lib.executor.adapter.saber_decimal_wrapper` | `ks-lib-executor.adapter.saber_decimal_wrapper` |
|
| `kb-lib.executor.adapter.saber_decimal_wrapper` | `ks-lib-executor.adapter.saber_decimal_wrapper` |
|
||||||
| `kb-lib.executor.adapter.spl_token_wrap` | `ks-lib-executor.adapter.spl_token_wrap` |
|
| `kb-lib.executor.adapter.spl_token_wrap` | `ks-lib-executor.adapter.spl_token_wrap` |
|
||||||
| `kb-lib.executor.amm.aldrin_v1` | `ks-lib-executor.amm.aldrin_v1` |
|
| `kb-lib.executor.amm.aldrin_v1` | `ks-lib-executor.amm.aldrin_v1` |
|
||||||
| `kb-lib.executor.amm.aldrin_v2` | `ks-lib-executor.amm.aldrin_v2` |
|
| `kb-lib.executor.amm.aldrin_v2` | `ks-lib-executor.amm.aldrin_v2` |
|
||||||
| `kb-lib.executor.amm.alphaq` | `ks-lib-executor.amm.alphaq` |
|
| `kb-lib.executor.amm.alphaq` | `ks-lib-executor.amm.alphaq` |
|
||||||
| `kb-lib.executor.amm.believe` | `ks-lib-executor.amm.believe` |
|
| `kb-lib.executor.amm.believe` | `ks-lib-executor.amm.believe` |
|
||||||
| `kb-lib.executor.amm.bonk_swap` | `ks-lib-executor.amm.bonk_swap` |
|
| `kb-lib.executor.amm.bonk_swap` | `ks-lib-executor.amm.bonk_swap` |
|
||||||
| `kb-lib.executor.amm.fluxbeam` | `ks-lib-executor.amm.fluxbeam` |
|
| `kb-lib.executor.amm.fluxbeam` | `ks-lib-executor.amm.fluxbeam` |
|
||||||
| `kb-lib.executor.amm.goon_fi` | `ks-lib-executor.amm.goon_fi` |
|
| `kb-lib.executor.amm.goon_fi` | `ks-lib-executor.amm.goon_fi` |
|
||||||
| `kb-lib.executor.amm.goosefx_gamma` | `ks-lib-executor.amm.goosefx_gamma` |
|
| `kb-lib.executor.amm.goosefx_gamma` | `ks-lib-executor.amm.goosefx_gamma` |
|
||||||
| `kb-lib.executor.amm.goosefx_v2` | `ks-lib-executor.amm.goosefx_v2` |
|
| `kb-lib.executor.amm.goosefx_v2` | `ks-lib-executor.amm.goosefx_v2` |
|
||||||
| `kb-lib.executor.amm.guac_swap` | `ks-lib-executor.amm.guac_swap` |
|
| `kb-lib.executor.amm.guac_swap` | `ks-lib-executor.amm.guac_swap` |
|
||||||
| `kb-lib.executor.amm.lifinity_swap_v2` | `ks-lib-executor.amm.lifinity_swap_v2` |
|
| `kb-lib.executor.amm.lifinity_swap_v2` | `ks-lib-executor.amm.lifinity_swap_v2` |
|
||||||
| `kb-lib.executor.amm.metadao_v0_5` | `ks-lib-executor.amm.metadao_v0_5` |
|
| `kb-lib.executor.amm.metadao_v0_5` | `ks-lib-executor.amm.metadao_v0_5` |
|
||||||
| `kb-lib.executor.amm.meteora_damm_v1` | `ks-lib-executor.amm.meteora_damm_v1` |
|
| `kb-lib.executor.amm.meteora_damm_v1` | `ks-lib-executor.amm.meteora_damm_v1` |
|
||||||
| `kb-lib.executor.amm.meteora_damm_v2` | `ks-lib-executor.amm.meteora_damm_v2` |
|
| `kb-lib.executor.amm.meteora_damm_v2` | `ks-lib-executor.amm.meteora_damm_v2` |
|
||||||
| `kb-lib.executor.amm.obric_v2` | `ks-lib-executor.amm.obric_v2` |
|
| `kb-lib.executor.amm.obric_v2` | `ks-lib-executor.amm.obric_v2` |
|
||||||
| `kb-lib.executor.amm.one_dex` | `ks-lib-executor.amm.one_dex` |
|
| `kb-lib.executor.amm.one_dex` | `ks-lib-executor.amm.one_dex` |
|
||||||
| `kb-lib.executor.amm.pump_swap` | `ks-lib-executor.amm.pump_swap` |
|
| `kb-lib.executor.amm.pump_swap` | `ks-lib-executor.amm.pump_swap` |
|
||||||
| `kb-lib.executor.amm.raydium_lp_v4` | `ks-lib-executor.amm.raydium_lp_v4` |
|
| `kb-lib.executor.amm.raydium_lp_v4` | `ks-lib-executor.amm.raydium_lp_v4` |
|
||||||
| `kb-lib.executor.amm.solfi` | `ks-lib-executor.amm.solfi` |
|
| `kb-lib.executor.amm.solfi` | `ks-lib-executor.amm.solfi` |
|
||||||
| `kb-lib.executor.amm.solfi_v2` | `ks-lib-executor.amm.solfi_v2` |
|
| `kb-lib.executor.amm.solfi_v2` | `ks-lib-executor.amm.solfi_v2` |
|
||||||
| `kb-lib.executor.amm.vertigo` | `ks-lib-executor.amm.vertigo` |
|
| `kb-lib.executor.amm.vertigo` | `ks-lib-executor.amm.vertigo` |
|
||||||
| `kb-lib.executor.amm.woofi` | `ks-lib-executor.amm.woofi` |
|
| `kb-lib.executor.amm.woofi` | `ks-lib-executor.amm.woofi` |
|
||||||
| `kb-lib.executor.amm.zero_fi` | `ks-lib-executor.amm.zero_fi` |
|
| `kb-lib.executor.amm.zero_fi` | `ks-lib-executor.amm.zero_fi` |
|
||||||
| `kb-lib.executor.amm.zora` | `ks-lib-executor.amm.zora` |
|
| `kb-lib.executor.amm.zora` | `ks-lib-executor.amm.zora` |
|
||||||
| `kb-lib.executor.bridge.circle_cctp_token_messenger_minter` | `ks-lib-executor.bridge.circle_cctp_token_messenger_minter` |
|
| `kb-lib.executor.bridge.circle_cctp_token_messenger_minter` | `ks-lib-executor.bridge.circle_cctp_token_messenger_minter` |
|
||||||
| `kb-lib.executor.bridge.circle_cctp_token_messenger_minter_v2` | `ks-lib-executor.bridge.circle_cctp_token_messenger_minter_v2` |
|
| `kb-lib.executor.bridge.circle_cctp_token_messenger_minter_v2` | `ks-lib-executor.bridge.circle_cctp_token_messenger_minter_v2` |
|
||||||
| `kb-lib.executor.bridge.layer_zero_endpoint` | `ks-lib-executor.bridge.layer_zero_endpoint` |
|
| `kb-lib.executor.bridge.layer_zero_endpoint` | `ks-lib-executor.bridge.layer_zero_endpoint` |
|
||||||
| `kb-lib.executor.bridge.layer_zero_executor` | `ks-lib-executor.bridge.layer_zero_executor` |
|
| `kb-lib.executor.bridge.layer_zero_executor` | `ks-lib-executor.bridge.layer_zero_executor` |
|
||||||
| `kb-lib.executor.clmm.byreal` | `ks-lib-executor.clmm.byreal` |
|
| `kb-lib.executor.clmm.byreal` | `ks-lib-executor.clmm.byreal` |
|
||||||
| `kb-lib.executor.clmm.fusion` | `ks-lib-executor.clmm.fusion` |
|
| `kb-lib.executor.clmm.fusion` | `ks-lib-executor.clmm.fusion` |
|
||||||
| `kb-lib.executor.clmm.orca_whirlpool` | `ks-lib-executor.clmm.orca_whirlpool` |
|
| `kb-lib.executor.clmm.orca_whirlpool` | `ks-lib-executor.clmm.orca_whirlpool` |
|
||||||
| `kb-lib.executor.clmm.pancake_swap` | `ks-lib-executor.clmm.pancake_swap` |
|
| `kb-lib.executor.clmm.pancake_swap` | `ks-lib-executor.clmm.pancake_swap` |
|
||||||
| `kb-lib.executor.clmm.raydium` | `ks-lib-executor.clmm.raydium` |
|
| `kb-lib.executor.clmm.raydium` | `ks-lib-executor.clmm.raydium` |
|
||||||
| `kb-lib.executor.clmm.stabble` | `ks-lib-executor.clmm.stabble` |
|
| `kb-lib.executor.clmm.stabble` | `ks-lib-executor.clmm.stabble` |
|
||||||
| `kb-lib.executor.cpmm.raydium` | `ks-lib-executor.cpmm.raydium` |
|
| `kb-lib.executor.cpmm.raydium` | `ks-lib-executor.cpmm.raydium` |
|
||||||
| `kb-lib.executor.dlmm.meteora` | `ks-lib-executor.dlmm.meteora` |
|
| `kb-lib.executor.dlmm.meteora` | `ks-lib-executor.dlmm.meteora` |
|
||||||
| `kb-lib.executor.fees.bags_fee_share_v1` | `ks-lib-executor.fees.bags_fee_share_v1` |
|
| `kb-lib.executor.fees.bags_fee_share_v1` | `ks-lib-executor.fees.bags_fee_share_v1` |
|
||||||
| `kb-lib.executor.fees.bags_fee_share_v2` | `ks-lib-executor.fees.bags_fee_share_v2` |
|
| `kb-lib.executor.fees.bags_fee_share_v2` | `ks-lib-executor.fees.bags_fee_share_v2` |
|
||||||
| `kb-lib.executor.fees.pump_fees` | `ks-lib-executor.fees.pump_fees` |
|
| `kb-lib.executor.fees.pump_fees` | `ks-lib-executor.fees.pump_fees` |
|
||||||
| `kb-lib.executor.governance.metadao_bid_wall` | `ks-lib-executor.governance.metadao_bid_wall` |
|
| `kb-lib.executor.governance.metadao_bid_wall` | `ks-lib-executor.governance.metadao_bid_wall` |
|
||||||
| `kb-lib.executor.governance.metadao_futarchy` | `ks-lib-executor.governance.metadao_futarchy` |
|
| `kb-lib.executor.governance.metadao_futarchy` | `ks-lib-executor.governance.metadao_futarchy` |
|
||||||
| `kb-lib.executor.governance.squads_multisig` | `ks-lib-executor.governance.squads_multisig` |
|
| `kb-lib.executor.governance.squads_multisig` | `ks-lib-executor.governance.squads_multisig` |
|
||||||
| `kb-lib.executor.launchpad.boop_fun` | `ks-lib-executor.launchpad.boop_fun` |
|
| `kb-lib.executor.launchpad.boop_fun` | `ks-lib-executor.launchpad.boop_fun` |
|
||||||
| `kb-lib.executor.launchpad.metadao_ico` | `ks-lib-executor.launchpad.metadao_ico` |
|
| `kb-lib.executor.launchpad.metadao_ico` | `ks-lib-executor.launchpad.metadao_ico` |
|
||||||
| `kb-lib.executor.launchpad.meteora_dbc` | `ks-lib-executor.launchpad.meteora_dbc` |
|
| `kb-lib.executor.launchpad.meteora_dbc` | `ks-lib-executor.launchpad.meteora_dbc` |
|
||||||
| `kb-lib.executor.launchpad.moonit` | `ks-lib-executor.launchpad.moonit` |
|
| `kb-lib.executor.launchpad.moonit` | `ks-lib-executor.launchpad.moonit` |
|
||||||
| `kb-lib.executor.launchpad.orca_wavebreak` | `ks-lib-executor.launchpad.orca_wavebreak` |
|
| `kb-lib.executor.launchpad.orca_wavebreak` | `ks-lib-executor.launchpad.orca_wavebreak` |
|
||||||
| `kb-lib.executor.launchpad.printr` | `ks-lib-executor.launchpad.printr` |
|
| `kb-lib.executor.launchpad.printr` | `ks-lib-executor.launchpad.printr` |
|
||||||
| `kb-lib.executor.launchpad.pump_fun` | `ks-lib-executor.launchpad.pump_fun` |
|
| `kb-lib.executor.launchpad.pump_fun` | `ks-lib-executor.launchpad.pump_fun` |
|
||||||
| `kb-lib.executor.launchpad.pump_pumpup_ai` | `ks-lib-executor.launchpad.pump_pumpup_ai` |
|
| `kb-lib.executor.launchpad.pump_pumpup_ai` | `ks-lib-executor.launchpad.pump_pumpup_ai` |
|
||||||
| `kb-lib.executor.launchpad.raydium_launchlab` | `ks-lib-executor.launchpad.raydium_launchlab` |
|
| `kb-lib.executor.launchpad.raydium_launchlab` | `ks-lib-executor.launchpad.raydium_launchlab` |
|
||||||
| `kb-lib.executor.launchpad.virtuals` | `ks-lib-executor.launchpad.virtuals` |
|
| `kb-lib.executor.launchpad.virtuals` | `ks-lib-executor.launchpad.virtuals` |
|
||||||
| `kb-lib.executor.lending.clone` | `ks-lib-executor.lending.clone` |
|
| `kb-lib.executor.lending.clone` | `ks-lib-executor.lending.clone` |
|
||||||
| `kb-lib.executor.lending.jupiter_lend_borrow` | `ks-lib-executor.lending.jupiter_lend_borrow` |
|
| `kb-lib.executor.lending.jupiter_lend_borrow` | `ks-lib-executor.lending.jupiter_lend_borrow` |
|
||||||
| `kb-lib.executor.lending.jupiter_lend_earn` | `ks-lib-executor.lending.jupiter_lend_earn` |
|
| `kb-lib.executor.lending.jupiter_lend_earn` | `ks-lib-executor.lending.jupiter_lend_earn` |
|
||||||
| `kb-lib.executor.lending.jupiter_lend_flash_loan` | `ks-lib-executor.lending.jupiter_lend_flash_loan` |
|
| `kb-lib.executor.lending.jupiter_lend_flash_loan` | `ks-lib-executor.lending.jupiter_lend_flash_loan` |
|
||||||
| `kb-lib.executor.lending.jupiter_lend_liquidity` | `ks-lib-executor.lending.jupiter_lend_liquidity` |
|
| `kb-lib.executor.lending.jupiter_lend_liquidity` | `ks-lib-executor.lending.jupiter_lend_liquidity` |
|
||||||
| `kb-lib.executor.lending.kamino` | `ks-lib-executor.lending.kamino` |
|
| `kb-lib.executor.lending.kamino` | `ks-lib-executor.lending.kamino` |
|
||||||
| `kb-lib.executor.lending.marginfi_v2` | `ks-lib-executor.lending.marginfi_v2` |
|
| `kb-lib.executor.lending.marginfi_v2` | `ks-lib-executor.lending.marginfi_v2` |
|
||||||
| `kb-lib.executor.lock.raydium_lp` | `ks-lib-executor.lock.raydium_lp` |
|
| `kb-lib.executor.lock.raydium_lp` | `ks-lib-executor.lock.raydium_lp` |
|
||||||
| `kb-lib.executor.metadata.metaplex_token_metadata` | `ks-lib-executor.metadata.metaplex_token_metadata` |
|
| `kb-lib.executor.metadata.metaplex_token_metadata` | `ks-lib-executor.metadata.metaplex_token_metadata` |
|
||||||
| `kb-lib.executor.metadata.solana_program_metadata` | `ks-lib-executor.metadata.solana_program_metadata` |
|
| `kb-lib.executor.metadata.solana_program_metadata` | `ks-lib-executor.metadata.solana_program_metadata` |
|
||||||
| `kb-lib.executor.metadata.spl_name_service` | `ks-lib-executor.metadata.spl_name_service` |
|
| `kb-lib.executor.metadata.spl_name_service` | `ks-lib-executor.metadata.spl_name_service` |
|
||||||
| `kb-lib.executor.nft.metaplex_bubblegum` | `ks-lib-executor.nft.metaplex_bubblegum` |
|
| `kb-lib.executor.nft.metaplex_bubblegum` | `ks-lib-executor.nft.metaplex_bubblegum` |
|
||||||
| `kb-lib.executor.nft.tensor_cnft` | `ks-lib-executor.nft.tensor_cnft` |
|
| `kb-lib.executor.nft.tensor_cnft` | `ks-lib-executor.nft.tensor_cnft` |
|
||||||
| `kb-lib.executor.orderbook.jupiter_limit_order` | `ks-lib-executor.orderbook.jupiter_limit_order` |
|
| `kb-lib.executor.orderbook.jupiter_limit_order` | `ks-lib-executor.orderbook.jupiter_limit_order` |
|
||||||
| `kb-lib.executor.orderbook.jupiter_limit_order_v2` | `ks-lib-executor.orderbook.jupiter_limit_order_v2` |
|
| `kb-lib.executor.orderbook.jupiter_limit_order_v2` | `ks-lib-executor.orderbook.jupiter_limit_order_v2` |
|
||||||
| `kb-lib.executor.orderbook.openbook_v2` | `ks-lib-executor.orderbook.openbook_v2` |
|
| `kb-lib.executor.orderbook.openbook_v2` | `ks-lib-executor.orderbook.openbook_v2` |
|
||||||
| `kb-lib.executor.perpetuals.drift_v2` | `ks-lib-executor.perpetuals.drift_v2` |
|
| `kb-lib.executor.perpetuals.drift_v2` | `ks-lib-executor.perpetuals.drift_v2` |
|
||||||
| `kb-lib.executor.perpetuals.jupiter` | `ks-lib-executor.perpetuals.jupiter` |
|
| `kb-lib.executor.perpetuals.jupiter` | `ks-lib-executor.perpetuals.jupiter` |
|
||||||
| `kb-lib.executor.perpetuals.phoenix_eternal` | `ks-lib-executor.perpetuals.phoenix_eternal` |
|
| `kb-lib.executor.perpetuals.phoenix_eternal` | `ks-lib-executor.perpetuals.phoenix_eternal` |
|
||||||
| `kb-lib.executor.perpetuals.zeta` | `ks-lib-executor.perpetuals.zeta` |
|
| `kb-lib.executor.perpetuals.zeta` | `ks-lib-executor.perpetuals.zeta` |
|
||||||
| `kb-lib.executor.router.dflow_aggregator_v4` | `ks-lib-executor.router.dflow_aggregator_v4` |
|
| `kb-lib.executor.router.dflow_aggregator_v4` | `ks-lib-executor.router.dflow_aggregator_v4` |
|
||||||
| `kb-lib.executor.router.jupiter_aggregator_v4` | `ks-lib-executor.router.jupiter_aggregator_v4` |
|
| `kb-lib.executor.router.jupiter_aggregator_v4` | `ks-lib-executor.router.jupiter_aggregator_v4` |
|
||||||
| `kb-lib.executor.router.jupiter_aggregator_v6` | `ks-lib-executor.router.jupiter_aggregator_v6` |
|
| `kb-lib.executor.router.jupiter_aggregator_v6` | `ks-lib-executor.router.jupiter_aggregator_v6` |
|
||||||
| `kb-lib.executor.router.okx_labs_v1` | `ks-lib-executor.router.okx_labs_v1` |
|
| `kb-lib.executor.router.okx_labs_v1` | `ks-lib-executor.router.okx_labs_v1` |
|
||||||
| `kb-lib.executor.router.okx_labs_v2` | `ks-lib-executor.router.okx_labs_v2` |
|
| `kb-lib.executor.router.okx_labs_v2` | `ks-lib-executor.router.okx_labs_v2` |
|
||||||
| `kb-lib.executor.rwa.ondo_global_markets` | `ks-lib-executor.rwa.ondo_global_markets` |
|
| `kb-lib.executor.rwa.ondo_global_markets` | `ks-lib-executor.rwa.ondo_global_markets` |
|
||||||
| `kb-lib.executor.solana.core` | `ks-lib-executor.solana.core` |
|
| `kb-lib.executor.solana.core` | `ks-lib-executor.solana.core` |
|
||||||
| `kb-lib.executor.solana.transaction` | `ks-lib-executor.solana.transaction` |
|
| `kb-lib.executor.solana.transaction` | `ks-lib-executor.solana.transaction` |
|
||||||
| `kb-lib.executor.spl.account_compression` | `ks-lib-executor.spl.account_compression` |
|
| `kb-lib.executor.spl.account_compression` | `ks-lib-executor.spl.account_compression` |
|
||||||
| `kb-lib.executor.spl.associated_token_account` | `ks-lib-executor.spl.associated_token_account` |
|
| `kb-lib.executor.spl.associated_token_account` | `ks-lib-executor.spl.associated_token_account` |
|
||||||
| `kb-lib.executor.spl.elgamal_registry` | `ks-lib-executor.spl.elgamal_registry` |
|
| `kb-lib.executor.spl.elgamal_registry` | `ks-lib-executor.spl.elgamal_registry` |
|
||||||
| `kb-lib.executor.spl.memo` | `ks-lib-executor.spl.memo` |
|
| `kb-lib.executor.spl.memo` | `ks-lib-executor.spl.memo` |
|
||||||
| `kb-lib.executor.spl.noop` | `ks-lib-executor.spl.noop` |
|
| `kb-lib.executor.spl.noop` | `ks-lib-executor.spl.noop` |
|
||||||
| `kb-lib.executor.spl.single_pool` | `ks-lib-executor.spl.single_pool` |
|
| `kb-lib.executor.spl.single_pool` | `ks-lib-executor.spl.single_pool` |
|
||||||
| `kb-lib.executor.spl.stake_pool` | `ks-lib-executor.spl.stake_pool` |
|
| `kb-lib.executor.spl.stake_pool` | `ks-lib-executor.spl.stake_pool` |
|
||||||
| `kb-lib.executor.spl.token` | `ks-lib-executor.spl.token` |
|
| `kb-lib.executor.spl.token` | `ks-lib-executor.spl.token` |
|
||||||
| `kb-lib.executor.spl.token-2022` | `ks-lib-executor.spl.token-2022` |
|
| `kb-lib.executor.spl.token-2022` | `ks-lib-executor.spl.token-2022` |
|
||||||
| `kb-lib.executor.spl.token_2022` | `ks-lib-executor.spl.token_2022` |
|
| `kb-lib.executor.spl.token_2022` | `ks-lib-executor.spl.token_2022` |
|
||||||
| `kb-lib.executor.stable.swap_hylo_exchange` | `ks-lib-executor.stable.swap_hylo_exchange` |
|
| `kb-lib.executor.stable.swap_hylo_exchange` | `ks-lib-executor.stable.swap_hylo_exchange` |
|
||||||
| `kb-lib.executor.stable.swap_jupiter_stable` | `ks-lib-executor.stable.swap_jupiter_stable` |
|
| `kb-lib.executor.stable.swap_jupiter_stable` | `ks-lib-executor.stable.swap_jupiter_stable` |
|
||||||
| `kb-lib.executor.stable.swap_numeraire` | `ks-lib-executor.stable.swap_numeraire` |
|
| `kb-lib.executor.stable.swap_numeraire` | `ks-lib-executor.stable.swap_numeraire` |
|
||||||
| `kb-lib.executor.stable.swap_stabble` | `ks-lib-executor.stable.swap_stabble` |
|
| `kb-lib.executor.stable.swap_stabble` | `ks-lib-executor.stable.swap_stabble` |
|
||||||
| `kb-lib.executor.staking.jito_tip_distribution` | `ks-lib-executor.staking.jito_tip_distribution` |
|
| `kb-lib.executor.staking.jito_tip_distribution` | `ks-lib-executor.staking.jito_tip_distribution` |
|
||||||
| `kb-lib.executor.staking.kamino_farm` | `ks-lib-executor.staking.kamino_farm` |
|
| `kb-lib.executor.staking.kamino_farm` | `ks-lib-executor.staking.kamino_farm` |
|
||||||
| `kb-lib.executor.staking.marinade_finance` | `ks-lib-executor.staking.marinade_finance` |
|
| `kb-lib.executor.staking.marinade_finance` | `ks-lib-executor.staking.marinade_finance` |
|
||||||
| `kb-lib.executor.staking.solayer` | `ks-lib-executor.staking.solayer` |
|
| `kb-lib.executor.staking.solayer` | `ks-lib-executor.staking.solayer` |
|
||||||
| `kb-lib.executor.storage.solana_record` | `ks-lib-executor.storage.solana_record` |
|
| `kb-lib.executor.storage.solana_record` | `ks-lib-executor.storage.solana_record` |
|
||||||
| `kb-lib.executor.strategy.jupiter_dca` | `ks-lib-executor.strategy.jupiter_dca` |
|
| `kb-lib.executor.strategy.jupiter_dca` | `ks-lib-executor.strategy.jupiter_dca` |
|
||||||
| `kb-lib.executor.treasury.helium_treasury_management` | `ks-lib-executor.treasury.helium_treasury_management` |
|
| `kb-lib.executor.treasury.helium_treasury_management` | `ks-lib-executor.treasury.helium_treasury_management` |
|
||||||
| `kb-lib.executor.vault.carrot_defi` | `ks-lib-executor.vault.carrot_defi` |
|
| `kb-lib.executor.vault.carrot_defi` | `ks-lib-executor.vault.carrot_defi` |
|
||||||
| `kb-lib.executor.vault.hylo_stability_pool` | `ks-lib-executor.vault.hylo_stability_pool` |
|
| `kb-lib.executor.vault.hylo_stability_pool` | `ks-lib-executor.vault.hylo_stability_pool` |
|
||||||
| `kb-lib.executor.vault.kamino` | `ks-lib-executor.vault.kamino` |
|
| `kb-lib.executor.vault.kamino` | `ks-lib-executor.vault.kamino` |
|
||||||
| `kb-lib.executor.vault.kamino_v2` | `ks-lib-executor.vault.kamino_v2` |
|
| `kb-lib.executor.vault.kamino_v2` | `ks-lib-executor.vault.kamino_v2` |
|
||||||
| `kb-lib.executor.vault.kamino_yvaults` | `ks-lib-executor.vault.kamino_yvaults` |
|
| `kb-lib.executor.vault.kamino_yvaults` | `ks-lib-executor.vault.kamino_yvaults` |
|
||||||
| `kb-lib.executor.vault.meteora` | `ks-lib-executor.vault.meteora` |
|
| `kb-lib.executor.vault.meteora` | `ks-lib-executor.vault.meteora` |
|
||||||
| `kb-lib.executor.vesting.jupiter_lock` | `ks-lib-executor.vesting.jupiter_lock` |
|
| `kb-lib.executor.vesting.jupiter_lock` | `ks-lib-executor.vesting.jupiter_lock` |
|
||||||
| `kb-lib.executor.vesting.streamflow` | `ks-lib-executor.vesting.streamflow` |
|
| `kb-lib.executor.vesting.streamflow` | `ks-lib-executor.vesting.streamflow` |
|
||||||
| `kb-lib.executor.wallet.jupiter_apepro_smart_wallet` | `ks-lib-executor.wallet.jupiter_apepro_smart_wallet` |
|
| `kb-lib.executor.wallet.jupiter_apepro_smart_wallet` | `ks-lib-executor.wallet.jupiter_apepro_smart_wallet` |
|
||||||
| `kb-lib.executor.weighted.swap_stabble` | `ks-lib-executor.weighted.swap_stabble` |
|
| `kb-lib.executor.weighted.swap_stabble` | `ks-lib-executor.weighted.swap_stabble` |
|
||||||
| `kb-lib.materializer.admin` | `ks-lib-materializer.admin` |
|
| `kb-lib.materializer.admin` | `ks-lib-materializer.admin` |
|
||||||
| `kb-lib.materializer.bridge` | `ks-lib-materializer.bridge` |
|
| `kb-lib.materializer.bridge` | `ks-lib-materializer.bridge` |
|
||||||
| `kb-lib.materializer.compliance.audit` | `ks-lib-materializer.compliance.audit` |
|
| `kb-lib.materializer.compliance.audit` | `ks-lib-materializer.compliance.audit` |
|
||||||
| `kb-lib.materializer.fees` | `ks-lib-materializer.fees` |
|
| `kb-lib.materializer.fees` | `ks-lib-materializer.fees` |
|
||||||
| `kb-lib.materializer.governance` | `ks-lib-materializer.governance` |
|
| `kb-lib.materializer.governance` | `ks-lib-materializer.governance` |
|
||||||
| `kb-lib.materializer.lending` | `ks-lib-materializer.lending` |
|
| `kb-lib.materializer.lending` | `ks-lib-materializer.lending` |
|
||||||
| `kb-lib.materializer.lifecycle` | `ks-lib-materializer.lifecycle` |
|
| `kb-lib.materializer.lifecycle` | `ks-lib-materializer.lifecycle` |
|
||||||
| `kb-lib.materializer.liquidity` | `ks-lib-materializer.liquidity` |
|
| `kb-lib.materializer.liquidity` | `ks-lib-materializer.liquidity` |
|
||||||
| `kb-lib.materializer.metadata.metaplex_token_metadata` | `ks-lib-materializer.metadata.metaplex_token_metadata` |
|
| `kb-lib.materializer.metadata.metaplex_token_metadata` | `ks-lib-materializer.metadata.metaplex_token_metadata` |
|
||||||
| `kb-lib.materializer.metadata.solana_program_metadata` | `ks-lib-materializer.metadata.solana_program_metadata` |
|
| `kb-lib.materializer.metadata.solana_program_metadata` | `ks-lib-materializer.metadata.solana_program_metadata` |
|
||||||
| `kb-lib.materializer.metadata.token_2022` | `ks-lib-materializer.metadata.token_2022` |
|
| `kb-lib.materializer.metadata.token_2022` | `ks-lib-materializer.metadata.token_2022` |
|
||||||
| `kb-lib.materializer.nft` | `ks-lib-materializer.nft` |
|
| `kb-lib.materializer.nft` | `ks-lib-materializer.nft` |
|
||||||
| `kb-lib.materializer.oracle` | `ks-lib-materializer.oracle` |
|
| `kb-lib.materializer.oracle` | `ks-lib-materializer.oracle` |
|
||||||
| `kb-lib.materializer.orderbook` | `ks-lib-materializer.orderbook` |
|
| `kb-lib.materializer.orderbook` | `ks-lib-materializer.orderbook` |
|
||||||
| `kb-lib.materializer.perpetuals` | `ks-lib-materializer.perpetuals` |
|
| `kb-lib.materializer.perpetuals` | `ks-lib-materializer.perpetuals` |
|
||||||
| `kb-lib.materializer.pool.state` | `ks-lib-materializer.pool.state` |
|
| `kb-lib.materializer.pool.state` | `ks-lib-materializer.pool.state` |
|
||||||
| `kb-lib.materializer.rewards` | `ks-lib-materializer.rewards` |
|
| `kb-lib.materializer.rewards` | `ks-lib-materializer.rewards` |
|
||||||
| `kb-lib.materializer.risk` | `ks-lib-materializer.risk` |
|
| `kb-lib.materializer.risk` | `ks-lib-materializer.risk` |
|
||||||
| `kb-lib.materializer.routing` | `ks-lib-materializer.routing` |
|
| `kb-lib.materializer.routing` | `ks-lib-materializer.routing` |
|
||||||
| `kb-lib.materializer.staking` | `ks-lib-materializer.staking` |
|
| `kb-lib.materializer.staking` | `ks-lib-materializer.staking` |
|
||||||
| `kb-lib.materializer.token.accounts` | `ks-lib-materializer.token.accounts` |
|
| `kb-lib.materializer.token.accounts` | `ks-lib-materializer.token.accounts` |
|
||||||
| `kb-lib.materializer.token.metadata_risk` | `ks-lib-materializer.token.metadata_risk` |
|
| `kb-lib.materializer.token.metadata_risk` | `ks-lib-materializer.token.metadata_risk` |
|
||||||
| `kb-lib.materializer.trades` | `ks-lib-materializer.trades` |
|
| `kb-lib.materializer.trades` | `ks-lib-materializer.trades` |
|
||||||
| `kb-lib.materializer.transaction.annotations` | `ks-lib-materializer.transaction.annotations` |
|
| `kb-lib.materializer.transaction.annotations` | `ks-lib-materializer.transaction.annotations` |
|
||||||
| `kb-lib.materializer.vault` | `ks-lib-materializer.vault` |
|
| `kb-lib.materializer.vault` | `ks-lib-materializer.vault` |
|
||||||
|
|
||||||
## 7. Inventaire des variables d'environnement
|
## 7. Inventaire des variables d'environnement
|
||||||
|
|
||||||
@@ -446,13 +446,15 @@ Les anciennes fixtures `TOKEN_2022_*` et les alias opérateur déjà préfixés
|
|||||||
|
|
||||||
### 7.2 Mapping code/config/tests — 85 noms
|
### 7.2 Mapping code/config/tests — 85 noms
|
||||||
|
|
||||||
| Nom actuel | Nom cible | Classe |
|
| Nom actuel | Nom cible | Classe |
|
||||||
|---|---|---|
|
|------------------------------|-----------------------------------|----------------|
|
||||||
| `HELIUS_API_KEY` | `KS_SECRET_HELIUS_API_KEY` | `secret` |
|
| `HELIUS_API_KEY` | `KS_SECRET_HELIUS_API_KEY` | `secret` |
|
||||||
| `KB_CONFIG_PATH` | `KS_CONFIG_PATH` | `internal` |
|
| `KB_CONFIG_PATH` | `KB_APP_DEMO_DESKTOP_CONFIG_PATH` | `internal` Bot |
|
||||||
| `KB_CONFIG_TEST_MISSING` | `KS_CONFIG_TEST_MISSING` | `internal` |
|
| `KB_CONFIG_TEST_MISSING` | `KS_CONFIG_TEST_MISSING` | `internal` |
|
||||||
| `KB_DEVNET_AIRDROP_LAMPORTS` | `KS_DEVNET_AIRDROP_LAMPORTS` | `internal` |
|
| `KB_DEVNET_AIRDROP_LAMPORTS` | `KS_DEVNET_AIRDROP_LAMPORTS` | `internal` |
|
||||||
| `KB_DEVNET_CONFIG_PATH` | `KS_DEVNET_CONFIG_PATH` | `internal` |
|
| `KB_DEVNET_CONFIG_PATH` | `KS_DEVNET_CONFIG_PATH` | `internal` |
|
||||||
|
|
||||||
|
La cible `KB_APP_DEMO_DESKTOP_CONFIG_PATH` remplace la transition `KS_CONFIG_PATH` de `pre.004` : une composition appartient au binaire qui la charge, alors que les documents qu’elle référence restent possédés par les crates `ks-*`.
|
||||||
| `KB_DEVNET_EXECUTION_TEST` | `KS_DEVNET_EXECUTION_TEST` | `internal` |
|
| `KB_DEVNET_EXECUTION_TEST` | `KS_DEVNET_EXECUTION_TEST` | `internal` |
|
||||||
| `KB_DEVNET_MEMO_EXECUTION_TEST` | `KS_DEVNET_MEMO_EXECUTION_TEST` | `internal` |
|
| `KB_DEVNET_MEMO_EXECUTION_TEST` | `KS_DEVNET_MEMO_EXECUTION_TEST` | `internal` |
|
||||||
| `KB_DEVNET_MEMO_SUBMIT` | `KS_DEVNET_MEMO_SUBMIT` | `internal` |
|
| `KB_DEVNET_MEMO_SUBMIT` | `KS_DEVNET_MEMO_SUBMIT` | `internal` |
|
||||||
@@ -536,50 +538,58 @@ Les anciennes fixtures `TOKEN_2022_*` et les alias opérateur déjà préfixés
|
|||||||
|
|
||||||
### 7.3 Mapping guide opérateur Devnet — 17 noms
|
### 7.3 Mapping guide opérateur Devnet — 17 noms
|
||||||
|
|
||||||
| Nom actuel | Nom cible | Classe |
|
| Nom actuel | Nom cible | Classe |
|
||||||
|---|---|---|
|
|---------------------------------------|---------------------------------------|------------|
|
||||||
| `KB_CONFIRM_DEVNET_DATABASE_RESET` | `KS_CONFIRM_DEVNET_DATABASE_RESET` | `internal` |
|
| `KB_CONFIRM_DEVNET_DATABASE_RESET` | `KS_CONFIRM_DEVNET_DATABASE_RESET` | `internal` |
|
||||||
| `KB_DEVNET_CLASSIC_DESTINATION_ATA` | `KS_DEVNET_CLASSIC_DESTINATION_ATA` | `internal` |
|
| `KB_DEVNET_CLASSIC_DESTINATION_ATA` | `KS_DEVNET_CLASSIC_DESTINATION_ATA` | `internal` |
|
||||||
| `KB_DEVNET_CLASSIC_MINT` | `KS_DEVNET_CLASSIC_MINT` | `internal` |
|
| `KB_DEVNET_CLASSIC_MINT` | `KS_DEVNET_CLASSIC_MINT` | `internal` |
|
||||||
| `KB_DEVNET_CLASSIC_MINT_KEYPAIR` | `KS_DEVNET_CLASSIC_MINT_KEYPAIR` | `internal` |
|
| `KB_DEVNET_CLASSIC_MINT_KEYPAIR` | `KS_DEVNET_CLASSIC_MINT_KEYPAIR` | `internal` |
|
||||||
| `KB_DEVNET_CLASSIC_RECIPIENT` | `KS_DEVNET_CLASSIC_RECIPIENT` | `internal` |
|
| `KB_DEVNET_CLASSIC_RECIPIENT` | `KS_DEVNET_CLASSIC_RECIPIENT` | `internal` |
|
||||||
| `KB_DEVNET_CLASSIC_RECIPIENT_KEYPAIR` | `KS_DEVNET_CLASSIC_RECIPIENT_KEYPAIR` | `internal` |
|
| `KB_DEVNET_CLASSIC_RECIPIENT_KEYPAIR` | `KS_DEVNET_CLASSIC_RECIPIENT_KEYPAIR` | `internal` |
|
||||||
| `KB_DEVNET_CLASSIC_SOURCE_ATA` | `KS_DEVNET_CLASSIC_SOURCE_ATA` | `internal` |
|
| `KB_DEVNET_CLASSIC_SOURCE_ATA` | `KS_DEVNET_CLASSIC_SOURCE_ATA` | `internal` |
|
||||||
| `KB_DEVNET_RECIPIENT` | `KS_DEVNET_RECIPIENT` | `internal` |
|
| `KB_DEVNET_RECIPIENT` | `KS_DEVNET_RECIPIENT` | `internal` |
|
||||||
| `KB_DEVNET_SCENARIO` | `KS_DEVNET_SCENARIO` | `internal` |
|
| `KB_DEVNET_SCENARIO` | `KS_DEVNET_SCENARIO` | `internal` |
|
||||||
| `KB_DEVNET_SIGNATURE` | `KS_DEVNET_SIGNATURE` | `internal` |
|
| `KB_DEVNET_SIGNATURE` | `KS_DEVNET_SIGNATURE` | `internal` |
|
||||||
| `KB_DEVNET_TOKEN_2022_FIXTURE` | `KS_DEVNET_TOKEN_2022_FIXTURE` | `internal` |
|
| `KB_DEVNET_TOKEN_2022_FIXTURE` | `KS_DEVNET_TOKEN_2022_FIXTURE` | `internal` |
|
||||||
| `KB_DEVNET_TOKEN_2022_MINT` | `KS_PUBLIC_DEVNET_TOKEN_2022_MINT` | `public` |
|
| `KB_DEVNET_TOKEN_2022_MINT` | `KS_PUBLIC_DEVNET_TOKEN_2022_MINT` | `public` |
|
||||||
| `KB_DEVNET_TOKEN_2022_MINT_KEYPAIR` | `KS_DEVNET_TOKEN_2022_MINT_KEYPAIR` | `internal` |
|
| `KB_DEVNET_TOKEN_2022_MINT_KEYPAIR` | `KS_DEVNET_TOKEN_2022_MINT_KEYPAIR` | `internal` |
|
||||||
| `KB_DEVNET_VALIDATION_DIR` | `KS_DEVNET_VALIDATION_DIR` | `internal` |
|
| `KB_DEVNET_VALIDATION_DIR` | `KS_DEVNET_VALIDATION_DIR` | `internal` |
|
||||||
| `KB_DEVNET_WALLET_PUBKEY` | `KS_PUBLIC_DEVNET_WALLET_ADDRESS` | `public` |
|
| `KB_DEVNET_WALLET_PUBKEY` | `KS_PUBLIC_DEVNET_WALLET_ADDRESS` | `public` |
|
||||||
| `KB_SPL_TOKEN_2022_PROGRAM_ID` | `KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID` | `public` |
|
| `KB_SPL_TOKEN_2022_PROGRAM_ID` | `KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID` | `public` |
|
||||||
| `KB_SPL_TOKEN_PROGRAM_ID` | `KS_PUBLIC_SPL_TOKEN_PROGRAM_ID` | `public` |
|
| `KB_SPL_TOKEN_PROGRAM_ID` | `KS_PUBLIC_SPL_TOKEN_PROGRAM_ID` | `public` |
|
||||||
|
|
||||||
## 8. Split configuration / logging
|
## 8. Décomposition des documents de configuration
|
||||||
|
|
||||||
L'audit `0.5.0` a confirmé une duplication importante : chaque profil généraliste transporte un bloc logging volumineux. La cible minimale devient :
|
Le split `pre.005` a d'abord extrait le logging. L'audit suivant a confirmé que le document applicatif restant mélangeait encore des responsabilités ayant des cycles de vie et des consommateurs distincts. La cible devient donc une composition propre à chaque binaire, complétée par des documents spécialisés partageables.
|
||||||
|
|
||||||
|
La convention de composition est :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
config/app.config.json
|
config/<binary>.default.config.json
|
||||||
config/logging.config.json
|
|
||||||
config/example.app.config.json
|
|
||||||
config/example.logging.config.json
|
|
||||||
config/schemas/app.config.schema.json
|
|
||||||
config/schemas/logging.config.schema.json
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Les profils applicatifs/réseau et les profils logging sont sélectionnables indépendamment. Un profil `devnet` n'impose donc pas un profil logging `debug`, et `mainnet` n'impose pas mécaniquement un profil logging `release`.
|
Les premières compositions sont :
|
||||||
|
|
||||||
Le code duplique actuellement dans `ks-config` et `ks-logging` les concepts :
|
```text
|
||||||
|
config/kb-app-demo-desktop.default.config.json
|
||||||
|
config/ks-pipeline-demo-scenarios.default.config.json
|
||||||
|
```
|
||||||
|
|
||||||
- `LoggingConfig` ;
|
`pre.006` extrait :
|
||||||
- `LogTargetConfig` ;
|
|
||||||
- `LogTargetFilterConfig`.
|
|
||||||
|
|
||||||
La migration `pre.005` ferme cette dette : `ks-config` ne définit plus de type logging, `ks-logging` possède le document, le schéma et les types runtime, et le desktop charge les deux fichiers indépendamment. `ks-logging` réutilise uniquement les helpers génériques d’environnement de `ks-config`, sans créer de dépendance inverse.
|
```text
|
||||||
|
config/logging.config.json
|
||||||
|
config/transport.config.json
|
||||||
|
config/listeners.config.json
|
||||||
|
```
|
||||||
|
|
||||||
Aucun troisième document spécialisé n'est créé dans `0.5.1` sans bénéfice de découplage démontré.
|
avec exemples sous `config/` et schémas source sous `config/schemas/`. Chaque composition sélectionne explicitement les profils logging, transport et listeners qu'elle consomme. Les `active_profile` propres aux documents spécialisés restent des valeurs de repli pour les consommateurs autonomes, mais ne couplent pas les sélections d'un binaire.
|
||||||
|
|
||||||
|
`AppConfig/ProfileConfig` demeure provisoirement un **contrat runtime résolu**, reconstruit par `ks-config`, afin de préserver les consommateurs pendant la migration. Son schéma est `config/schemas/resolved.app.config.schema.json` et ses fixtures de test sont sous `test-fixtures/config/`; il ne correspond plus à un document source chargé au démarrage.
|
||||||
|
|
||||||
|
`pre.007` doit poursuivre la décomposition de `database/data`, wallet, execution et de la configuration réellement spécifique au desktop. À son terme, une composition doit principalement référencer des documents/profils spécialisés et une configuration dédiée au binaire, sans obliger `ks-config` à enregistrer la liste des futurs workers ou exécutables.
|
||||||
|
|
||||||
|
Cette décomposition doit être terminée avant de figer les surfaces `public`/`diagnostic` et la propagation de sensibilité en `pre.008`.
|
||||||
|
|
||||||
## 9. Source, runtime, public et diagnostic
|
## 9. Source, runtime, public et diagnostic
|
||||||
|
|
||||||
@@ -630,7 +640,8 @@ Avant chaque changement structurel correspondant, conserver ou ajouter des tests
|
|||||||
- l'interdiction des variables de configuration possédées par le workspace hors namespace d'ownership `KS_*` ou `KB_*` ;
|
- l'interdiction des variables de configuration possédées par le workspace hors namespace d'ownership `KS_*` ou `KB_*` ;
|
||||||
- la propagation de sensibilité depuis `KS_SECRET_*` vers les valeurs composées ;
|
- la propagation de sensibilité depuis `KS_SECRET_*` vers les valeurs composées ;
|
||||||
- l'impossibilité pour une sentinelle secrète d'apparaître dans `Debug`, logs, erreurs, payloads Tauri, sérialisation publique ou diagnostic ;
|
- l'impossibilité pour une sentinelle secrète d'apparaître dans `Debug`, logs, erreurs, payloads Tauri, sérialisation publique ou diagnostic ;
|
||||||
- la validation indépendante de `config/schemas/app.config.schema.json` et `config/schemas/logging.config.schema.json` ;
|
- la validation indépendante des schémas source de composition, logging, transport et listeners sous `config/schemas/` ;
|
||||||
|
- la validation du schéma `resolved.app.config.schema.json` uniquement comme contrat runtime transitoire ;
|
||||||
- l'indépendance des profils généralistes et logging ;
|
- l'indépendance des profils généralistes et logging ;
|
||||||
- l'absence de duplication structurelle des types logging entre `ks-config` et `ks-logging` ;
|
- l'absence de duplication structurelle des types logging entre `ks-config` et `ks-logging` ;
|
||||||
- le maintien des contrats publics réellement nécessaires après remplacement des types de configuration exposés.
|
- le maintien des contrats publics réellement nécessaires après remplacement des types de configuration exposés.
|
||||||
@@ -670,27 +681,52 @@ Les tests ne doivent pas figer comme comportement légitime la fuite actuelle de
|
|||||||
- reporter la propagation de sensibilité et le camouflage effectif après le split config/logging ;
|
- reporter la propagation de sensibilité et le camouflage effectif après le split config/logging ;
|
||||||
- supprimer les anciens noms une fois la migration vérifiée ;
|
- supprimer les anciens noms une fois la migration vérifiée ;
|
||||||
- étendre l’audit workspace pour refuser la réintroduction de variables applicatives hors `KS_*` / `KB_*` dans le code, `.env.example`, la configuration exemple et le guide opérateur ;
|
- étendre l’audit workspace pour refuser la réintroduction de variables applicatives hors `KS_*` / `KB_*` dans le code, `.env.example`, la configuration exemple et le guide opérateur ;
|
||||||
- ne pas encore modifier les DTO publics ni implémenter le camouflage, qui appartiennent à `pre.006`.
|
- ne pas encore modifier les DTO publics ni implémenter le camouflage, qui appartiennent désormais à `pre.008` après la fin du split des documents.
|
||||||
|
|
||||||
### `0.5.1-pre.005` — split config/logging
|
### `0.5.1-pre.005` — split config/logging
|
||||||
|
|
||||||
- **implémenté** : `config/app.config.json` et `config/logging.config.json` deviennent les deux documents chargés par défaut ;
|
- **implémenté** : extraction initiale du logging hors de l’ancien document applicatif monolithique ;
|
||||||
- **implémenté** : les schémas sont centralisés sous `config/schemas/app.config.schema.json` et `config/schemas/logging.config.schema.json` ;
|
- **implémenté** : centralisation des schémas sous `config/schemas/` ;
|
||||||
- **implémenté** : `example.app.config.json` et `example.logging.config.json` fournissent des exemples minimaux conformes ;
|
- **implémenté** : profils logging indépendants ;
|
||||||
- **implémenté** : les profils logging et généralistes possèdent chacun leur propre `active_profile` ;
|
|
||||||
- **implémenté** : `ks-logging` devient propriétaire unique du contrat logging et de sa validation ;
|
- **implémenté** : `ks-logging` devient propriétaire unique du contrat logging et de sa validation ;
|
||||||
- **implémenté** : le desktop supprime la conversion `ks_config::LoggingConfig` -> `ks_logging::LoggingConfig`.
|
- **implémenté** : suppression de la conversion `ks_config::LoggingConfig` -> `ks_logging::LoggingConfig`.
|
||||||
|
|
||||||
### `0.5.1-pre.006` — surfaces publiques sûres
|
### `0.5.1-pre.006` — composition binaire + transport + listeners
|
||||||
|
|
||||||
|
- **implémenté** : remplacement du rôle de `app.config.json` par des compositions `<binary>.default.config.json` ;
|
||||||
|
- **implémenté** : création de `kb-app-demo-desktop.default.config.json` et d’une composition propre à `ks-pipeline-demo-scenarios` ;
|
||||||
|
- **implémenté** : extraction des endpoints HTTP/WebSocket vers `transport.config.json` avec schéma et exemple dédiés ;
|
||||||
|
- **implémenté** : extraction des listeners vers `listeners.config.json` avec schéma et exemple dédiés ;
|
||||||
|
- **implémenté** : sélection explicite des profils logging/transport/listeners par chaque composition ;
|
||||||
|
- **implémenté** : maintien temporaire de `AppConfig/ProfileConfig` comme contrat runtime résolu afin de ne pas casser tous les consommateurs pendant la migration ;
|
||||||
|
- **implémenté** : consommation directe de `TransportProfileConfig` par `ks-onchain-transport` ;
|
||||||
|
- **implémenté** : suppression des anciens fichiers source `app.config.json`, `example.app.config.json` et de leur schéma source historique ;
|
||||||
|
- ne pas encore modifier les DTO publics ni la politique de camouflage.
|
||||||
|
|
||||||
|
### `0.5.1-pre.007` — store + wallet + execution + configuration dédiée des binaires
|
||||||
|
|
||||||
|
- extraire `database` vers un document store cohérent avec les frontières de `ks-store` ;
|
||||||
|
- supprimer `DataConfig` en réaffectant `logs_directory` au document logging et `wallets_directory` au document wallet selon leur ownership réel ;
|
||||||
|
- auditer la redondance entre `data.wallets_directory` et `wallet.wallet_dir`, puis définir un répertoire racine wallet global et des chemins/alias de profils sans duplication ;
|
||||||
|
- sortir les paramètres identité/stockage temporaire du wallet vers un document wallet et préparer le contrat `0.5.2` ;
|
||||||
|
- déplacer `localnet_send_enabled`, `devnet_send_enabled`, `testnet_send_enabled` et `mainnet_send_enabled` hors du wallet vers la politique d'exécution ;
|
||||||
|
- extraire les politiques d'exécution vers un document indépendant ;
|
||||||
|
- décider si `app.auto_reconnect_default`, actuellement conservé pour compatibilité, appartient au transport ou doit être supprimé avec migration explicite ;
|
||||||
|
- sortir `demo` de `ks-config` vers une configuration réellement possédée par `kb-app-demo-desktop` ;
|
||||||
|
- réduire les compositions à des références vers profils spécialisés et configuration dédiée du binaire ;
|
||||||
|
- vérifier qu'un nouveau worker peut ajouter son fichier de composition/dédié sans modifier `ks-config` pour enregistrer son existence.
|
||||||
|
|
||||||
|
### `0.5.1-pre.008` — surfaces publiques sûres et camouflage
|
||||||
|
|
||||||
- séparer types source/runtime/public/diagnostic ;
|
- séparer types source/runtime/public/diagnostic ;
|
||||||
|
- propager la classification secret/public/internal lors de la résolution des placeholders et valeurs composées ;
|
||||||
- retirer `AppConfig`/`ProfileConfig` résolus du payload Tauri public ;
|
- retirer `AppConfig`/`ProfileConfig` résolus du payload Tauri public ;
|
||||||
- borner les DTO TS-RS et diagnostics ;
|
- borner les DTO TS-RS et diagnostics ;
|
||||||
- valider qu'aucun secret ne traverse logs/UI/erreurs/sérialisation.
|
- valider qu'aucun secret ne traverse logs/UI/erreurs/sérialisation.
|
||||||
|
|
||||||
### `0.5.1-pre.007` — clôture
|
### `0.5.1-pre.009` — clôture
|
||||||
|
|
||||||
- réconciliation complète des namespaces et docs ;
|
- réconciliation complète des namespaces, compositions, schémas et docs ;
|
||||||
- audits finaux ;
|
- audits finaux ;
|
||||||
- suppression des TODO terminés ;
|
- suppression des TODO terminés ;
|
||||||
- archivage de ce plan et du prompt `030` ;
|
- archivage de ce plan et du prompt `030` ;
|
||||||
@@ -730,7 +766,8 @@ Le desktop n'est lancé avec `cargo tauri dev` que lorsqu'une frontière runtime
|
|||||||
- le workspace racine s'appelle toujours `khadhroony-bot3` ;
|
- le workspace racine s'appelle toujours `khadhroony-bot3` ;
|
||||||
- les variables Solana ont migré vers `KS_*` avec classification nominale sûre et `KB_*` reste réservé aux futurs contrats Bot ;
|
- les variables Solana ont migré vers `KS_*` avec classification nominale sûre et `KB_*` reste réservé aux futurs contrats Bot ;
|
||||||
- les identités techniques `kb-lib.*` ciblées ont disparu au profit de `ks-lib-*` ;
|
- les identités techniques `kb-lib.*` ciblées ont disparu au profit de `ks-lib-*` ;
|
||||||
- la configuration généraliste et logging sont séparées et validées indépendamment ;
|
- les binaires utilisent leurs compositions dédiées et les documents logging/transport/listeners sont séparés, partageables et validés indépendamment ;
|
||||||
|
- database, les répertoires logging/wallet, wallet, execution et les réglages propres au desktop ont quitté la composition avant la construction des surfaces publiques ;
|
||||||
- aucune configuration runtime résolue complète ne traverse Tauri ;
|
- aucune configuration runtime résolue complète ne traverse Tauri ;
|
||||||
- aucun secret canari n'apparaît dans les surfaces publiques ou diagnostiques ;
|
- aucun secret canari n'apparaît dans les surfaces publiques ou diagnostiques ;
|
||||||
- les tests d'API externe, audits et tests workspace sont propres ;
|
- les tests d'API externe, audits et tests workspace sont propres ;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/rules/RULES_SPECIFIC_KHADHROONY.md -->
|
<!-- file: docs/rules/RULES_SPECIFIC_KHADHROONY.md -->
|
||||||
<!-- version: 16 -->
|
<!-- version: 17 -->
|
||||||
|
|
||||||
# Règles spécifiques à `khadhroony-bot3`
|
# Règles spécifiques à `khadhroony-bot3`
|
||||||
|
|
||||||
@@ -237,10 +237,14 @@ Aucun renommage massif de modules n'est autorisé sans étape de contrôle dédi
|
|||||||
|
|
||||||
## Règles de configuration
|
## Règles de configuration
|
||||||
|
|
||||||
- La configuration applicative commune doit passer par `ks-config`.
|
- La configuration commune Khadhroony Solana passe par `ks-config`, mais chaque binaire possède son fichier de composition et peut ajouter sa configuration dédiée sans rendre `ks-config` dépendant de ce binaire.
|
||||||
- Les fichiers runtime chargés par défaut sont `config/app.config.json` pour la configuration générale et `config/logging.config.json` pour le logging ; leurs sélections de profils sont indépendantes.
|
- Le nom par défaut d'une composition binaire suit `<binary>.default.config.json`. Le desktop utilise `config/kb-app-demo-desktop.default.config.json` ; le CLI des scénarios utilise `config/ks-pipeline-demo-scenarios.default.config.json`.
|
||||||
- Les schémas JSON de configuration actifs sont conservés sous `config/schemas/`, notamment `app.config.schema.json` et `logging.config.schema.json`.
|
- Une composition référence les documents spécialisés et sélectionne explicitement les profils qu'elle consomme. Elle ne doit pas recopier les blocs transport, listeners ou logging.
|
||||||
- Les exemples conformes sont conservés sous `config/` avec des noms distincts des fichiers runtime, notamment `example.app.config.json` et `example.logging.config.json`.
|
- Les documents partagés actuels sont `config/logging.config.json`, `config/transport.config.json` et `config/listeners.config.json`. Ils conservent chacun des profils nommés et peuvent être consommés indépendamment d'une composition.
|
||||||
|
- Les schémas JSON actifs sont conservés exclusivement sous `config/schemas/`. `composition.config.schema.json`, `logging.config.schema.json`, `transport.config.schema.json` et `listeners.config.schema.json` décrivent les documents source ; `resolved.app.config.schema.json` décrit uniquement le contrat runtime transitoire reconstruit par `ks-config`.
|
||||||
|
- Les exemples conformes restent sous `config/` avec un nom distinct des fichiers runtime. Les fixtures d'un contrat runtime résolu appartiennent à `test-fixtures/` et ne doivent pas être chargées en production.
|
||||||
|
- Les fichiers historiques `config/app.config.json`, `config/example.app.config.json`, `config/schemas/app.config.schema.json`, `config/example.config.json` et `config/schema.config.json` sont interdits dans l'état courant.
|
||||||
|
- Le chemin de composition desktop peut être remplacé par `KB_APP_DEMO_DESKTOP_CONFIG_PATH`. `KS_DEVNET_CONFIG_PATH` sélectionne une composition pour les scénarios Devnet opt-in. `KS_LOGGING_CONFIG_PATH` reste un override explicite du document logging ; sans override, la composition fournit son chemin.
|
||||||
- Les fichiers JSON de configuration ne doivent pas contenir de commentaires.
|
- Les fichiers JSON de configuration ne doivent pas contenir de commentaires.
|
||||||
- Les secrets ne doivent pas être écrits en clair dans le dépôt.
|
- Les secrets ne doivent pas être écrits en clair dans le dépôt.
|
||||||
- Les valeurs sensibles doivent utiliser des variables d'environnement ou un stockage chiffré dédié.
|
- Les valeurs sensibles doivent utiliser des variables d'environnement ou un stockage chiffré dédié.
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
<!-- file: kb-app-demo-desktop/CHANGELOG.md -->
|
<!-- file: kb-app-demo-desktop/CHANGELOG.md -->
|
||||||
<!-- version: 45 -->
|
<!-- version: 46 -->
|
||||||
|
|
||||||
# CHANGELOG — kb-app-demo-desktop
|
# CHANGELOG — kb-app-demo-desktop
|
||||||
|
|
||||||
|
## `0.5.1-pre.006`
|
||||||
|
|
||||||
|
- remplace `config/app.config.json` par la composition dédiée `config/kb-app-demo-desktop.default.config.json`, sélectionnable via `KB_APP_DEMO_DESKTOP_CONFIG_PATH` ;
|
||||||
|
- résout les profils transport/listeners partagés via `ks-config` et sélectionne explicitement le profil logging déclaré par la composition ;
|
||||||
|
- conserve les contrats runtime et payloads Tauri actuels jusqu'au chantier public/diagnostic de `pre.008`.
|
||||||
|
|
||||||
## `0.5.1-pre.005`
|
## `0.5.1-pre.005`
|
||||||
|
|
||||||
- charge séparément `config/app.config.json` et `config/logging.config.json` ;
|
- charge séparément `config/app.config.json` et `config/logging.config.json` ;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: kb-app-demo-desktop/src/app_state.rs
|
// file: kb-app-demo-desktop/src/app_state.rs
|
||||||
// version: 13
|
// version: 14
|
||||||
|
|
||||||
//! Shared Tauri application state and startup initialization.
|
//! Shared Tauri application state and startup initialization.
|
||||||
|
|
||||||
@@ -31,15 +31,26 @@ impl crate::AppState {
|
|||||||
/// Initializes configuration, logging and shared runtime state.
|
/// Initializes configuration, logging and shared runtime state.
|
||||||
pub(crate) fn initialize() -> ks_core::Result<crate::AppState> {
|
pub(crate) fn initialize() -> ks_core::Result<crate::AppState> {
|
||||||
let config_path = resolve_config_path();
|
let config_path = resolve_config_path();
|
||||||
let logging_config_path = resolve_logging_config_path();
|
|
||||||
let workspace_root = crate::workspace_root_dir();
|
let workspace_root = crate::workspace_root_dir();
|
||||||
let app_config = match ks_config::read_config_json_file_with_environment(
|
let composed = match ks_config::read_composed_app_config_with_environment(
|
||||||
&config_path,
|
&config_path,
|
||||||
&workspace_root,
|
&workspace_root,
|
||||||
) {
|
) {
|
||||||
std::result::Result::Ok(config) => config,
|
std::result::Result::Ok(config) => config,
|
||||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
};
|
};
|
||||||
|
let composition_profile = match ks_config::active_composition_profile(&composed.composition)
|
||||||
|
{
|
||||||
|
std::result::Result::Ok(profile) => profile.clone(),
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
let logging_source_path = ks_config::resolve_composition_source_path(
|
||||||
|
&workspace_root,
|
||||||
|
composed.composition.sources.logging.as_str(),
|
||||||
|
);
|
||||||
|
let logging_config_path =
|
||||||
|
resolve_logging_config_path(&workspace_root, &logging_source_path);
|
||||||
|
let app_config = composed.app_config;
|
||||||
let active_profile = match ks_config::active_profile(&app_config) {
|
let active_profile = match ks_config::active_profile(&app_config) {
|
||||||
std::result::Result::Ok(profile) => profile.clone(),
|
std::result::Result::Ok(profile) => profile.clone(),
|
||||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
@@ -51,7 +62,16 @@ impl crate::AppState {
|
|||||||
std::result::Result::Ok(config) => config,
|
std::result::Result::Ok(config) => config,
|
||||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
};
|
};
|
||||||
let logging_config = match ks_logging::active_logging_profile(&logging_document) {
|
for profile in &composed.composition.profiles {
|
||||||
|
match ks_logging::logging_profile(&logging_document, profile.logging_profile.as_str()) {
|
||||||
|
std::result::Result::Ok(_) => (),
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let logging_config = match ks_logging::logging_profile(
|
||||||
|
&logging_document,
|
||||||
|
composition_profile.logging_profile.as_str(),
|
||||||
|
) {
|
||||||
std::result::Result::Ok(profile) => profile.clone(),
|
std::result::Result::Ok(profile) => profile.clone(),
|
||||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
};
|
};
|
||||||
@@ -217,23 +237,38 @@ impl crate::AppState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_config_path() -> std::path::PathBuf {
|
fn resolve_config_path() -> std::path::PathBuf {
|
||||||
let configured = std::env::var("KS_CONFIG_PATH").ok();
|
let configured = std::env::var("KB_APP_DEMO_DESKTOP_CONFIG_PATH").ok();
|
||||||
return resolve_config_path_from_value(configured.as_deref());
|
return resolve_config_path_from_value(configured.as_deref());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_logging_config_path() -> std::path::PathBuf {
|
fn resolve_logging_config_path(
|
||||||
|
workspace_root: &std::path::Path,
|
||||||
|
composition_default: &std::path::Path,
|
||||||
|
) -> std::path::PathBuf {
|
||||||
let configured = std::env::var("KS_LOGGING_CONFIG_PATH").ok();
|
let configured = std::env::var("KS_LOGGING_CONFIG_PATH").ok();
|
||||||
return resolve_logging_config_path_from_value(configured.as_deref());
|
return resolve_logging_config_path_from_value(
|
||||||
|
workspace_root,
|
||||||
|
configured.as_deref(),
|
||||||
|
composition_default,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_logging_config_path_from_value(value: std::option::Option<&str>) -> std::path::PathBuf {
|
fn resolve_logging_config_path_from_value(
|
||||||
|
workspace_root: &std::path::Path,
|
||||||
|
value: std::option::Option<&str>,
|
||||||
|
composition_default: &std::path::Path,
|
||||||
|
) -> std::path::PathBuf {
|
||||||
if let std::option::Option::Some(configured) = value {
|
if let std::option::Option::Some(configured) = value {
|
||||||
let trimmed = configured.trim();
|
let trimmed = configured.trim();
|
||||||
if !trimmed.is_empty() {
|
if !trimmed.is_empty() {
|
||||||
return std::path::PathBuf::from(trimmed);
|
let path = std::path::PathBuf::from(trimmed);
|
||||||
|
if path.is_absolute() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
return workspace_root.join(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return crate::workspace_root_dir().join("config/logging.config.json");
|
return composition_default.to_path_buf();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_config_path_from_value(value: std::option::Option<&str>) -> std::path::PathBuf {
|
fn resolve_config_path_from_value(value: std::option::Option<&str>) -> std::path::PathBuf {
|
||||||
@@ -243,26 +278,29 @@ fn resolve_config_path_from_value(value: std::option::Option<&str>) -> std::path
|
|||||||
return std::path::PathBuf::from(trimmed);
|
return std::path::PathBuf::from(trimmed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return crate::workspace_root_dir().join("config/app.config.json");
|
return crate::workspace_root_dir().join("config/kb-app-demo-desktop.default.config.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn resolve_config_path_uses_workspace_default_by_default() {
|
fn resolve_config_path_uses_desktop_composition_by_default() {
|
||||||
let path = super::resolve_config_path_from_value(std::option::Option::None);
|
let path = super::resolve_config_path_from_value(std::option::Option::None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
path.file_name().and_then(std::ffi::OsStr::to_str),
|
path.file_name().and_then(std::ffi::OsStr::to_str),
|
||||||
std::option::Option::Some("app.config.json")
|
std::option::Option::Some("kb-app-demo-desktop.default.config.json")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn resolve_logging_config_path_uses_workspace_default_by_default() {
|
fn logging_path_uses_composition_source_without_override() {
|
||||||
let path = super::resolve_logging_config_path_from_value(std::option::Option::None);
|
let root = std::path::Path::new("/workspace");
|
||||||
assert_eq!(
|
let fallback = root.join("config/logging.config.json");
|
||||||
path.file_name().and_then(std::ffi::OsStr::to_str),
|
let path = super::resolve_logging_config_path_from_value(
|
||||||
std::option::Option::Some("logging.config.json")
|
root,
|
||||||
|
std::option::Option::None,
|
||||||
|
&fallback,
|
||||||
);
|
);
|
||||||
|
assert_eq!(path, fallback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: kb-app-demo-desktop/src/demo_execution_solana_core.rs
|
// file: kb-app-demo-desktop/src/demo_execution_solana_core.rs
|
||||||
// version: 15
|
// version: 16
|
||||||
|
|
||||||
//! Tauri adapter for bounded Solana Core execution on Devnet.
|
//! Tauri adapter for bounded Solana Core execution on Devnet.
|
||||||
|
|
||||||
@@ -850,11 +850,12 @@ fn memo_summary_payload(
|
|||||||
mod tests {
|
mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn example_config_exposes_one_devnet_execution_profile() {
|
fn example_config_exposes_one_devnet_execution_profile() {
|
||||||
let config =
|
let config = match ks_config::parse_config_json(include_str!(
|
||||||
match ks_config::parse_config_json(include_str!("../../config/app.config.json")) {
|
"../../test-fixtures/config/resolved.app.config.json"
|
||||||
std::result::Result::Ok(value) => value,
|
)) {
|
||||||
std::result::Result::Err(error) => panic!("example config parse failed: {error}"),
|
std::result::Result::Ok(value) => value,
|
||||||
};
|
std::result::Result::Err(error) => panic!("example config parse failed: {error}"),
|
||||||
|
};
|
||||||
let profiles = super::devnet_profile_options(&config);
|
let profiles = super::devnet_profile_options(&config);
|
||||||
assert_eq!(profiles.len(), 1);
|
assert_eq!(profiles.len(), 1);
|
||||||
assert_eq!(profiles[0].name, "local_devnet");
|
assert_eq!(profiles[0].name, "local_devnet");
|
||||||
@@ -864,11 +865,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn profile_selection_rejects_mainnet_profiles() {
|
fn profile_selection_rejects_mainnet_profiles() {
|
||||||
let config =
|
let config = match ks_config::parse_config_json(include_str!(
|
||||||
match ks_config::parse_config_json(include_str!("../../config/app.config.json")) {
|
"../../test-fixtures/config/resolved.app.config.json"
|
||||||
std::result::Result::Ok(value) => value,
|
)) {
|
||||||
std::result::Result::Err(error) => panic!("example config parse failed: {error}"),
|
std::result::Result::Ok(value) => value,
|
||||||
};
|
std::result::Result::Err(error) => panic!("example config parse failed: {error}"),
|
||||||
|
};
|
||||||
assert!(crate::select_devnet_profile(&config, "local_devnet").is_ok());
|
assert!(crate::select_devnet_profile(&config, "local_devnet").is_ok());
|
||||||
assert!(crate::select_devnet_profile(&config, "mainnet").is_err());
|
assert!(crate::select_devnet_profile(&config, "mainnet").is_err());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -286,7 +286,9 @@ pub(crate) fn demo_spl_token_2022_fixture(
|
|||||||
let decimals = match decimals_text.parse::<u8>() {
|
let decimals = match decimals_text.parse::<u8>() {
|
||||||
std::result::Result::Ok(value) => value,
|
std::result::Result::Ok(value) => value,
|
||||||
std::result::Result::Err(error) => {
|
std::result::Result::Err(error) => {
|
||||||
return std::result::Result::Err(format!("invalid KS_PUBLIC_DEVNET_TOKEN_2022_DECIMALS value: {error}"));
|
return std::result::Result::Err(format!(
|
||||||
|
"invalid KS_PUBLIC_DEVNET_TOKEN_2022_DECIMALS value: {error}"
|
||||||
|
));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
return std::result::Result::Ok(crate::DemoSplToken2022FixturePayload {
|
return std::result::Result::Ok(crate::DemoSplToken2022FixturePayload {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: kb-app-demo-desktop/src/tauri.rs
|
// file: kb-app-demo-desktop/src/tauri.rs
|
||||||
// version: 36
|
// version: 37
|
||||||
|
|
||||||
//! Tauri runtime assembly and private command wrappers.
|
//! Tauri runtime assembly and private command wrappers.
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ pub fn run() -> ks_core::Result<()> {
|
|||||||
};
|
};
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
target: crate::TRACING_TARGET,
|
target: crate::TRACING_TARGET,
|
||||||
config_path = app_state.config_path(),
|
composition_config_path = app_state.config_path(),
|
||||||
logging_config_path = app_state.logging_config_path(),
|
logging_config_path = app_state.logging_config_path(),
|
||||||
active_profile = app_state.active_profile().name.as_str(),
|
active_profile = app_state.active_profile().name.as_str(),
|
||||||
logging_routes = app_state.logging_route_count(),
|
logging_routes = app_state.logging_route_count(),
|
||||||
|
|||||||
@@ -1,8 +1,17 @@
|
|||||||
<!-- file: ks-config/CHANGELOG.md -->
|
<!-- file: ks-config/CHANGELOG.md -->
|
||||||
<!-- version: 15 -->
|
<!-- version: 16 -->
|
||||||
|
|
||||||
# CHANGELOG — ks-config
|
# CHANGELOG — ks-config
|
||||||
|
|
||||||
|
## `0.5.1-pre.006`
|
||||||
|
|
||||||
|
- remplace le document source monolithique `app.config.json` par des compositions propres aux binaires, dont `config/kb-app-demo-desktop.default.config.json` et `config/ks-pipeline-demo-scenarios.default.config.json` ;
|
||||||
|
- extrait les endpoints HTTP/WebSocket vers `config/transport.config.json` et les listeners vers `config/listeners.config.json`, chacun avec schéma et exemple dédiés sous `config/schemas/` / `config/` ;
|
||||||
|
- conserve `AppConfig`/`ProfileConfig` comme contrat runtime résolu transitoire, reconstruit depuis la composition et les documents partagés ;
|
||||||
|
- ajoute les APIs typées de chargement, validation et sélection de profils de composition, transport et listeners ;
|
||||||
|
- ajoute un test d’API externe garantissant que composition, transport et listeners restent accessibles uniquement via les exports crate-root ;
|
||||||
|
- réserve le split store/data, wallet, execution et configuration spécifique des binaires à `pre.007`, avant les surfaces publiques sûres de `pre.008`.
|
||||||
|
|
||||||
## `0.5.1-pre.005`
|
## `0.5.1-pre.005`
|
||||||
|
|
||||||
- retire définitivement le bloc `logging` de `ProfileConfig` et du schéma général ;
|
- retire définitivement le bloc `logging` de `ProfileConfig` et du schéma général ;
|
||||||
|
|||||||
@@ -1,43 +1,59 @@
|
|||||||
<!-- file: ks-config/README.md -->
|
<!-- file: ks-config/README.md -->
|
||||||
<!-- version: 8 -->
|
<!-- version: 9 -->
|
||||||
|
|
||||||
# ks-config
|
# ks-config
|
||||||
|
|
||||||
`ks-config` définit le contrat de configuration générale typé du workspace, son schéma JSON embarqué et les fonctions de chargement, résolution d’environnement, validation et sérialisation.
|
`ks-config` fournit les contrats de configuration généralistes Khadhroony Solana, les chargeurs de documents spécialisés et la résolution des compositions utilisées par les binaires.
|
||||||
|
|
||||||
## Responsabilités
|
## Responsabilités
|
||||||
|
|
||||||
- exposer `AppConfig` et les sections de configuration générale ;
|
- charger l'environnement du workspace et résoudre les placeholders `${KS_*}` / `${KB_*}` ;
|
||||||
- valider le JSON général contre `config/schemas/app.config.schema.json` ;
|
- valider les documents transport, listeners et composition contre leurs schémas sous `config/schemas/` ;
|
||||||
- appliquer les invariants métier après désérialisation ;
|
- fournir les types partagés d'endpoints, listeners et profils runtime ;
|
||||||
- charger `.env`, ou le fichier sélectionné par `KS_ENV_FILE`, depuis la racine du workspace ;
|
- résoudre les références d'une composition vers des profils transport/listeners ;
|
||||||
- résoudre les placeholders namespacés `${KS_*}` / `${KB_*}` et leurs fallbacks ;
|
- reconstruire temporairement `AppConfig/ProfileConfig` pour les consommateurs existants ;
|
||||||
- sélectionner le profil applicatif actif ;
|
- rester indépendant de la liste des applications et workers futurs.
|
||||||
- exporter les types généraux nécessaires au frontend avec `ts-rs`.
|
|
||||||
|
|
||||||
## Hors périmètre
|
## Composition
|
||||||
|
|
||||||
`ks-config` ne possède plus le contrat logging. `LoggingConfig`, les routes, filtres, profils logging et `config/schemas/logging.config.schema.json` appartiennent à `ks-logging`.
|
Le desktop possède `config/kb-app-demo-desktop.default.config.json`. Le CLI des scénarios possède `config/ks-pipeline-demo-scenarios.default.config.json`.
|
||||||
|
|
||||||
La crate n’initialise ni PostgreSQL, ni les transports et ne manipule aucun secret de wallet. Elle fournit uniquement la configuration générale validée à ces consommateurs.
|
Une composition choisit :
|
||||||
|
|
||||||
## Surface publique
|
- les documents partagés à charger ;
|
||||||
|
- le profil logging ;
|
||||||
|
- le profil transport ;
|
||||||
|
- le profil listeners ;
|
||||||
|
- temporairement les sections encore non séparées.
|
||||||
|
|
||||||
Les principales fonctions sont `read_config_json_file_with_environment`, `parse_config_json`, `validate_config`, `validate_config_json_schema`, `active_profile` et les sérialiseurs JSON.
|
Un futur worker pourra donc ajouter son propre `<binary>.default.config.json` sans créer une branche spécifique dans `ks-config`.
|
||||||
|
|
||||||
Les types publics couvrent les profils applicatifs, endpoints, listeners, base de données, wallet, exécution et démonstration.
|
## Documents spécialisés actuels
|
||||||
|
|
||||||
## Relations
|
- `config/transport.config.json` / `config/schemas/transport.config.schema.json` ;
|
||||||
|
- `config/listeners.config.json` / `config/schemas/listeners.config.schema.json` ;
|
||||||
|
- `config/logging.config.json` reste possédé par `ks-logging` ;
|
||||||
|
- `config/schemas/resolved.app.config.schema.json` décrit uniquement le contrat runtime transitoire.
|
||||||
|
|
||||||
- dépend de `ks-core` pour les erreurs structurées ;
|
Les anciens `config/app.config.json` et `config/example.app.config.json` ne sont plus des fichiers runtime.
|
||||||
- fournit les profils généraux à `ks-store`, `ks-onchain-transport`, `ks-pipeline`, `ks-wallet` et aux applications ;
|
|
||||||
- fournit à `ks-logging` les helpers génériques de chargement `.env` et de résolution des placeholders ;
|
|
||||||
- embarque [`../config/schemas/app.config.schema.json`](../config/schemas/app.config.schema.json) ;
|
|
||||||
- utilise [`../config/app.config.json`](../config/app.config.json) comme configuration générale chargée par défaut et [`../config/example.app.config.json`](../config/example.app.config.json) comme exemple minimal conforme.
|
|
||||||
|
|
||||||
## Statut
|
## API publique principale
|
||||||
|
|
||||||
Le split config/logging est effectif : un profil applicatif ne transporte plus de bloc logging et la sélection logging est indépendante. La prerelease suivante sépare les représentations source/runtime/public/diagnostic et ferme l’exposition des secrets résolus.
|
- `read_composed_app_config_with_environment` ;
|
||||||
|
- `parse_composition_json`, `composition_profile`, `active_composition_profile` ;
|
||||||
|
- `read_transport_json_file_with_environment`, `transport_profile` ;
|
||||||
|
- `read_listeners_json_file_with_environment`, `listeners_profile` ;
|
||||||
|
- `compose_app_config` ;
|
||||||
|
- `load_workspace_environment`, `resolve_environment_placeholders` ;
|
||||||
|
- `AppConfig`, `ProfileConfig` pendant la phase de compatibilité.
|
||||||
|
|
||||||
|
## Frontières
|
||||||
|
|
||||||
|
`ks-logging` dépend de `ks-config` pour les helpers d'environnement, mais `ks-config` ne possède aucun type logging runtime.
|
||||||
|
|
||||||
|
`ks-onchain-transport` peut consommer directement `TransportProfileConfig`. Un worker n'a donc pas besoin d'un profil applicatif complet pour construire ses pools réseau.
|
||||||
|
|
||||||
|
Les sections database/data, wallet, execution et demo restent transitoires dans la composition jusqu'au split suivant.
|
||||||
|
|
||||||
## Documents
|
## Documents
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
<!-- file: ks-config/TODO.md -->
|
<!-- file: ks-config/TODO.md -->
|
||||||
<!-- version: 7 -->
|
<!-- version: 8 -->
|
||||||
|
|
||||||
# TODO — ks-config
|
# TODO — ks-config
|
||||||
|
|
||||||
## Série `0.5.x`
|
## Série `0.5.x`
|
||||||
|
|
||||||
|
- [ ] `0.5.1` - sortir `database`, wallet, execution et la configuration spécifique au desktop vers leurs documents/propriétaires dédiés ; réaffecter `logs_directory` à logging et `wallets_directory` à wallet, puis réduire la composition aux références nécessaires.
|
||||||
- [ ] `0.5.1` - appliquer à l’exécution les classes `KS_SECRET_*` / `KB_SECRET_*`, `KS_PUBLIC_*` / `KB_PUBLIC_*` et internes, avec propagation de sensibilité aux valeurs composées.
|
- [ ] `0.5.1` - appliquer à l’exécution les classes `KS_SECRET_*` / `KB_SECRET_*`, `KS_PUBLIC_*` / `KB_PUBLIC_*` et internes, avec propagation de sensibilité aux valeurs composées.
|
||||||
- [ ] `0.5.1` - séparer les représentations source, runtime résolue, publique et diagnostic.
|
- [ ] `0.5.1` - séparer les représentations source, runtime résolue, publique et diagnostic.
|
||||||
- [ ] `0.5.1` - interdire qu’un secret résolu soit sérialisé, loggé, inclus dans une erreur ou transmis via Tauri.
|
- [ ] `0.5.1` - interdire qu’un secret résolu soit sérialisé, loggé, inclus dans une erreur ou transmis via Tauri.
|
||||||
|
|||||||
@@ -1,143 +1,118 @@
|
|||||||
<!-- file: ks-config/USAGE.md -->
|
<!-- file: ks-config/USAGE.md -->
|
||||||
<!-- version: 7 -->
|
<!-- version: 8 -->
|
||||||
|
|
||||||
# Utilisation de ks-config
|
# Utilisation de ks-config
|
||||||
|
|
||||||
## Chargement recommandé
|
## Rôle de la crate
|
||||||
|
|
||||||
|
`ks-config` fournit les types, validations et chargeurs des configurations Khadhroony Solana partagées. Un binaire choisit son propre fichier de composition et combine les profils spécialisés dont il a besoin.
|
||||||
|
|
||||||
|
`ks-config` ne doit pas connaître la liste des futurs workers ou applications.
|
||||||
|
|
||||||
|
## Chargement d'une composition
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let config_result = ks_config::read_config_json_file_with_environment(
|
let composed = match ks_config::read_composed_app_config_with_environment(
|
||||||
std::path::Path::new("config/app.config.json"),
|
std::path::Path::new("config/kb-app-demo-desktop.default.config.json"),
|
||||||
std::path::Path::new("."),
|
std::path::Path::new("."),
|
||||||
);
|
) {
|
||||||
let config = match config_result {
|
|
||||||
Ok(value) => value,
|
Ok(value) => value,
|
||||||
Err(error) => return Err(error),
|
Err(error) => return Err(error),
|
||||||
};
|
};
|
||||||
|
let config = composed.app_config;
|
||||||
let profile = match ks_config::active_profile(&config) {
|
let profile = match ks_config::active_profile(&config) {
|
||||||
Ok(value) => value,
|
Ok(value) => value,
|
||||||
Err(error) => return Err(error),
|
Err(error) => return Err(error),
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Cette API charge l’environnement du workspace, résout les placeholders puis applique successivement le schéma JSON général, la désérialisation typée et les invariants métier.
|
Le chargeur :
|
||||||
|
|
||||||
Le fichier chargé par défaut par le desktop est `config/app.config.json`. `KS_CONFIG_PATH` permet de remplacer explicitement ce chemin.
|
1. charge l'environnement du workspace ;
|
||||||
|
2. valide la composition ;
|
||||||
|
3. résout les chemins `transport` et `listeners` déclarés par la composition ;
|
||||||
|
4. charge et valide les deux documents spécialisés ;
|
||||||
|
5. sélectionne les profils référencés ;
|
||||||
|
6. reconstruit le contrat runtime `AppConfig/ProfileConfig` ;
|
||||||
|
7. applique les invariants métier existants.
|
||||||
|
|
||||||
## Chargement de l’environnement
|
Le logging reste chargé par `ks-logging`, car son type runtime appartient à cette crate. La composition fournit néanmoins le chemin et le nom de profil à sélectionner.
|
||||||
|
|
||||||
|
## Configuration transport indépendante
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let transport = match ks_config::read_transport_json_file_with_environment(
|
||||||
|
std::path::Path::new("config/transport.config.json"),
|
||||||
|
std::path::Path::new("."),
|
||||||
|
) {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(error) => return Err(error),
|
||||||
|
};
|
||||||
|
let profile = match ks_config::transport_profile(&transport, "mainnet_research") {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(error) => return Err(error),
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Le document expose `TransportConfigDocument` et `TransportProfileConfig` avec les endpoints HTTP/WebSocket et leurs rôles.
|
||||||
|
|
||||||
|
## Configuration listeners indépendante
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let listeners = match ks_config::read_listeners_json_file_with_environment(
|
||||||
|
std::path::Path::new("config/listeners.config.json"),
|
||||||
|
std::path::Path::new("."),
|
||||||
|
) {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(error) => return Err(error),
|
||||||
|
};
|
||||||
|
let profile = match ks_config::listeners_profile(&listeners, "mainnet_research") {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(error) => return Err(error),
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
`resolved_listener_config` convertit ce profil spécialisé vers le contrat runtime `ListenerConfig` utilisé pendant la phase de transition.
|
||||||
|
|
||||||
|
## Chargement de l'environnement
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let report = match ks_config::load_workspace_environment(std::path::Path::new(".")) {
|
let report = match ks_config::load_workspace_environment(std::path::Path::new(".")) {
|
||||||
Ok(value) => value,
|
Ok(value) => value,
|
||||||
Err(error) => return Err(error),
|
Err(error) => return Err(error),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(path) = report.loaded_path {
|
|
||||||
println!("environment file: {}", path.display());
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`EnvironmentLoadReport` indique le fichier chargé. Par défaut, `ks-config` sélectionne `.env`; `KS_ENV_FILE` permet d’en choisir un autre sans écraser les variables déjà présentes dans le processus.
|
Par défaut, `ks-config` sélectionne `.env`; `KS_ENV_FILE` permet d'en choisir un autre sans écraser les variables déjà présentes dans le processus.
|
||||||
|
|
||||||
Les contrats d’environnement utilisent `KS_*` pour Khadhroony Solana et `KB_*` pour les besoins réellement propres au Bot.
|
## Résolution des placeholders
|
||||||
|
|
||||||
## Résolution explicite des placeholders
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let raw = r#"{"databaseUrl":"${KS_SECRET_POSTGRES_DEVNET_URL:-postgres://localhost/ks}"}"#;
|
let raw = r#"{"databaseUrl":"${KS_SECRET_POSTGRES_DEVNET_URL:-postgres://localhost/ks}"}"#;
|
||||||
let resolved = ks_config::resolve_environment_placeholders(raw);
|
let resolved = ks_config::resolve_environment_placeholders(raw);
|
||||||
|
|
||||||
assert!(resolved.contains("databaseUrl"));
|
assert!(resolved.contains("databaseUrl"));
|
||||||
```
|
```
|
||||||
|
|
||||||
Cette API retourne encore une chaîne ordinaire pouvant contenir des secrets résolus. Elle reste strictement backend jusqu’à l’introduction de la représentation sensible de `0.5.1-pre.006`.
|
La chaîne résolue peut encore contenir des secrets. Elle reste strictement backend jusqu'à l'introduction de la représentation sensible dédiée.
|
||||||
|
|
||||||
## Validation et parsing
|
## Contrat runtime résolu
|
||||||
|
|
||||||
```rust
|
`AppConfig` et `ProfileConfig` restent provisoirement le contrat runtime commun afin de ne pas casser tous les consommateurs pendant les splits successifs. Ils ne correspondent plus à un fichier `config/app.config.json` chargé directement.
|
||||||
if let Err(error) = ks_config::validate_config_json_schema(raw_json) {
|
|
||||||
return Err(error);
|
|
||||||
}
|
|
||||||
let config = match ks_config::parse_config_json(raw_json) {
|
|
||||||
Ok(value) => value,
|
|
||||||
Err(error) => return Err(error),
|
|
||||||
};
|
|
||||||
if let Err(error) = ks_config::validate_config(&config) {
|
|
||||||
return Err(error);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
`parse_config_json` effectue déjà les deux validations ; les appels séparés servent aux outils de diagnostic.
|
Le schéma de ce contrat résolu est `config/schemas/resolved.app.config.schema.json`. Les fixtures correspondantes sont sous `test-fixtures/config/` et ne sont pas des configurations runtime.
|
||||||
|
|
||||||
## Schéma embarqué
|
|
||||||
|
|
||||||
```rust
|
|
||||||
let schema_text = ks_config::config_json_schema_text();
|
|
||||||
let schema_value = match ks_config::config_json_schema_value() {
|
|
||||||
Ok(value) => value,
|
|
||||||
Err(error) => return Err(error),
|
|
||||||
};
|
|
||||||
|
|
||||||
println!("embedded app schema bytes={}", schema_text.len());
|
|
||||||
assert!(schema_value.is_object());
|
|
||||||
```
|
|
||||||
|
|
||||||
Le schéma actif est [`../config/schemas/app.config.schema.json`](../config/schemas/app.config.schema.json). Les fichiers [`../config/app.config.json`](../config/app.config.json) et [`../config/example.app.config.json`](../config/example.app.config.json) doivent tous deux être conformes.
|
|
||||||
|
|
||||||
## Sélection du profil actif
|
|
||||||
|
|
||||||
```rust
|
|
||||||
let profile = match ks_config::active_profile(&config) {
|
|
||||||
Ok(value) => value,
|
|
||||||
Err(error) => return Err(error),
|
|
||||||
};
|
|
||||||
|
|
||||||
println!("active profile: {}", profile.name);
|
|
||||||
println!("http endpoints: {}", profile.solana.http_endpoints.len());
|
|
||||||
println!("websocket endpoints: {}", profile.solana.ws_endpoints.len());
|
|
||||||
```
|
|
||||||
|
|
||||||
Le profil applicatif ne contient plus de configuration logging. Le document logging et son `active_profile` sont chargés par `ks-logging`.
|
|
||||||
|
|
||||||
## Sérialisation
|
|
||||||
|
|
||||||
```rust
|
|
||||||
let pretty = match ks_config::serialize_config_json_pretty(&config) {
|
|
||||||
Ok(value) => value,
|
|
||||||
Err(error) => return Err(error),
|
|
||||||
};
|
|
||||||
|
|
||||||
let write_result = std::fs::write("config/generated.app.config.json", pretty);
|
|
||||||
if let Err(error) = write_result {
|
|
||||||
return Err(ks_core::Error::new(
|
|
||||||
"config_write_failed",
|
|
||||||
format!("cannot write generated configuration: {error}"),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
La configuration est validée avant sérialisation.
|
|
||||||
|
|
||||||
## Types publics importants
|
## Types publics importants
|
||||||
|
|
||||||
- `AppConfig`, `ProfileConfig`, `AppSectionConfig` ;
|
- `CompositionConfigDocument`, `CompositionProfileConfig`, `CompositionConfigSources` ;
|
||||||
- `DatabaseConfig`, `PostgresConfig`, `SqliteConfig`, `DataConfig` ;
|
- `TransportConfigDocument`, `TransportProfileConfig` ;
|
||||||
- `SolanaConfig`, `HttpEndpointConfig`, `WsEndpointConfig`, `EndpointRoleConfig` ;
|
- `ListenersConfigDocument`, `ListenersProfileConfig` ;
|
||||||
|
- `AppConfig`, `ProfileConfig` comme contrat runtime de transition ;
|
||||||
|
- `HttpEndpointConfig`, `WsEndpointConfig`, `EndpointRoleConfig` ;
|
||||||
- `ListenerConfig` et ses variantes ;
|
- `ListenerConfig` et ses variantes ;
|
||||||
- `WalletConfig`, `ExecutionConfig`, `DemoConfig`.
|
- `DatabaseConfig`, `WalletConfig`, `ExecutionConfig` jusqu'à leur split dédié.
|
||||||
|
|
||||||
Les types logging ne font plus partie de `ks-config`.
|
Les types logging appartiennent à `ks-logging`.
|
||||||
|
|
||||||
## Erreurs et invariants
|
## Prochaine frontière
|
||||||
|
|
||||||
Les erreurs utilisent `ks_core::Error` avec un code stable. Les validations couvrent notamment l’unicité des profils, l’existence du profil actif, les URLs, les rôles d’endpoints, les limites d’exécution et les contraintes wallet.
|
Les sections store/data, wallet, execution et desktop seront sorties de la composition dans la prerelease suivante. Une fois cette décomposition terminée, les surfaces source/runtime/public/diagnostic et le camouflage des secrets pourront être définis sur des responsabilités stables.
|
||||||
|
|
||||||
## Tests instructifs
|
|
||||||
|
|
||||||
Les tests vérifient séparément `app.config.json` et `example.app.config.json`, le roundtrip du document général et les invariants `parser_rejects_*` / `schema_rejects_*`.
|
|
||||||
|
|
||||||
## Limites
|
|
||||||
|
|
||||||
- format JSON uniquement ;
|
|
||||||
- aucune connexion externe n’est ouverte par la crate ;
|
|
||||||
- la politique de camouflage des valeurs résolues appartient à `0.5.1-pre.006`.
|
|
||||||
|
|||||||
373
ks-config/src/composition.rs
Normal file
373
ks-config/src/composition.rs
Normal file
@@ -0,0 +1,373 @@
|
|||||||
|
// file: ks-config/src/composition.rs
|
||||||
|
// version: 1
|
||||||
|
|
||||||
|
//! Binary composition configuration and resolution into the shared runtime profile contract.
|
||||||
|
|
||||||
|
const COMPOSITION_JSON_SCHEMA: &str =
|
||||||
|
include_str!("../../config/schemas/composition.config.schema.json");
|
||||||
|
|
||||||
|
/// Root composition document used by a binary to select shared configuration profiles.
|
||||||
|
#[derive(Clone, Debug, serde::Deserialize, Eq, PartialEq, serde::Serialize)]
|
||||||
|
pub struct CompositionConfigDocument {
|
||||||
|
/// Active binary composition profile name.
|
||||||
|
pub active_profile: std::string::String,
|
||||||
|
/// Shared configuration documents referenced by this composition.
|
||||||
|
pub sources: CompositionConfigSources,
|
||||||
|
/// Named binary composition profiles.
|
||||||
|
pub profiles: std::vec::Vec<CompositionProfileConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Paths of shared configuration documents consumed by one binary composition.
|
||||||
|
#[derive(Clone, Debug, serde::Deserialize, Eq, PartialEq, serde::Serialize)]
|
||||||
|
pub struct CompositionConfigSources {
|
||||||
|
/// Logging configuration document path relative to the workspace root unless absolute.
|
||||||
|
pub logging: std::string::String,
|
||||||
|
/// Transport configuration document path relative to the workspace root unless absolute.
|
||||||
|
pub transport: std::string::String,
|
||||||
|
/// Listener configuration document path relative to the workspace root unless absolute.
|
||||||
|
pub listeners: std::string::String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Named composition profile referencing shared configuration profiles.
|
||||||
|
#[derive(Clone, Debug, serde::Deserialize, Eq, PartialEq, serde::Serialize)]
|
||||||
|
pub struct CompositionProfileConfig {
|
||||||
|
/// Composition profile code.
|
||||||
|
pub name: std::string::String,
|
||||||
|
/// Application metadata retained until the remaining configuration split is completed.
|
||||||
|
pub app: crate::AppSectionConfig,
|
||||||
|
/// Logging profile selected from the referenced logging document.
|
||||||
|
pub logging_profile: std::string::String,
|
||||||
|
/// Transport profile selected from the referenced transport document.
|
||||||
|
pub transport_profile: std::string::String,
|
||||||
|
/// Listener profile selected from the referenced listener document.
|
||||||
|
pub listeners_profile: std::string::String,
|
||||||
|
/// Database configuration retained until the store split prerelease.
|
||||||
|
pub database: crate::DatabaseConfig,
|
||||||
|
/// Local data directories retained until their owning configuration files are split.
|
||||||
|
pub data: crate::DataConfig,
|
||||||
|
/// Wallet configuration retained until the wallet split prerelease.
|
||||||
|
pub wallet: crate::WalletConfig,
|
||||||
|
/// Execution policy retained until the execution split prerelease.
|
||||||
|
pub execution: crate::ExecutionConfig,
|
||||||
|
/// Desktop demo flags retained until the binary-specific split prerelease.
|
||||||
|
pub demo: crate::DemoConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the embedded binary composition JSON Schema text.
|
||||||
|
pub fn composition_json_schema_text() -> &'static str {
|
||||||
|
return COMPOSITION_JSON_SCHEMA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses the embedded binary composition JSON Schema into a JSON value.
|
||||||
|
pub fn composition_json_schema_value() -> ks_core::Result<serde_json::Value> {
|
||||||
|
let schema_result = serde_json::from_str::<serde_json::Value>(COMPOSITION_JSON_SCHEMA);
|
||||||
|
return match schema_result {
|
||||||
|
std::result::Result::Ok(schema) => std::result::Result::Ok(schema),
|
||||||
|
std::result::Result::Err(error) => std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"composition_config_schema_parse_failed",
|
||||||
|
error.to_string(),
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validates raw binary composition JSON against its embedded schema.
|
||||||
|
pub fn validate_composition_json_schema(raw_json: &str) -> ks_core::Result<()> {
|
||||||
|
let schema = match composition_json_schema_value() {
|
||||||
|
std::result::Result::Ok(schema) => schema,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
let instance = match serde_json::from_str::<serde_json::Value>(raw_json) {
|
||||||
|
std::result::Result::Ok(instance) => instance,
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"composition_config_json_parse_failed",
|
||||||
|
error.to_string(),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let validator = match jsonschema::validator_for(&schema) {
|
||||||
|
std::result::Result::Ok(validator) => validator,
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"composition_config_schema_compile_failed",
|
||||||
|
error.to_string(),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return match validator.validate(&instance) {
|
||||||
|
std::result::Result::Ok(()) => std::result::Result::Ok(()),
|
||||||
|
std::result::Result::Err(error) => std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"composition_config_schema_validation_failed",
|
||||||
|
error.to_string(),
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses and validates one binary composition document.
|
||||||
|
pub fn parse_composition_json(raw_json: &str) -> ks_core::Result<CompositionConfigDocument> {
|
||||||
|
match validate_composition_json_schema(raw_json) {
|
||||||
|
std::result::Result::Ok(()) => (),
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
}
|
||||||
|
let document = match serde_json::from_str::<CompositionConfigDocument>(raw_json) {
|
||||||
|
std::result::Result::Ok(document) => document,
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"composition_config_json_decode_failed",
|
||||||
|
error.to_string(),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return match validate_composition_document(&document) {
|
||||||
|
std::result::Result::Ok(()) => std::result::Result::Ok(document),
|
||||||
|
std::result::Result::Err(error) => std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads and parses one binary composition document from a filesystem path.
|
||||||
|
pub fn read_composition_json_file(
|
||||||
|
path: &std::path::Path,
|
||||||
|
) -> ks_core::Result<CompositionConfigDocument> {
|
||||||
|
let raw_json = match std::fs::read_to_string(path) {
|
||||||
|
std::result::Result::Ok(content) => content,
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"composition_config_file_read_failed",
|
||||||
|
error.to_string(),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return parse_composition_json(&raw_json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Loads workspace environment values, resolves placeholders and parses one binary composition document.
|
||||||
|
pub fn read_composition_json_file_with_environment(
|
||||||
|
path: &std::path::Path,
|
||||||
|
workspace_root: &std::path::Path,
|
||||||
|
) -> ks_core::Result<CompositionConfigDocument> {
|
||||||
|
match crate::load_workspace_environment(workspace_root) {
|
||||||
|
std::result::Result::Ok(_) => (),
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
}
|
||||||
|
let raw_json = match std::fs::read_to_string(path) {
|
||||||
|
std::result::Result::Ok(content) => content,
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"composition_config_file_read_failed",
|
||||||
|
error.to_string(),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let resolved = crate::resolve_environment_placeholders(&raw_json);
|
||||||
|
return parse_composition_json(&resolved);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns one named binary composition profile.
|
||||||
|
pub fn composition_profile<'a>(
|
||||||
|
document: &'a CompositionConfigDocument,
|
||||||
|
profile_name: &str,
|
||||||
|
) -> ks_core::Result<&'a CompositionProfileConfig> {
|
||||||
|
for profile in &document.profiles {
|
||||||
|
if profile.name == profile_name {
|
||||||
|
return std::result::Result::Ok(profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"composition_profile_not_found",
|
||||||
|
profile_name.to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the active binary composition profile.
|
||||||
|
pub fn active_composition_profile(
|
||||||
|
document: &CompositionConfigDocument,
|
||||||
|
) -> ks_core::Result<&CompositionProfileConfig> {
|
||||||
|
return composition_profile(document, document.active_profile.as_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolves a source path relative to the workspace root unless already absolute.
|
||||||
|
pub fn resolve_composition_source_path(
|
||||||
|
workspace_root: &std::path::Path,
|
||||||
|
configured_path: &str,
|
||||||
|
) -> std::path::PathBuf {
|
||||||
|
let path = std::path::PathBuf::from(configured_path);
|
||||||
|
if path.is_absolute() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
return workspace_root.join(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolves all shared transport/listener selections into the existing runtime application contract.
|
||||||
|
pub fn compose_app_config(
|
||||||
|
document: &CompositionConfigDocument,
|
||||||
|
transport: &crate::TransportConfigDocument,
|
||||||
|
listeners: &crate::ListenersConfigDocument,
|
||||||
|
) -> ks_core::Result<crate::AppConfig> {
|
||||||
|
let mut profiles = std::vec::Vec::<crate::ProfileConfig>::new();
|
||||||
|
for profile in &document.profiles {
|
||||||
|
let transport_profile =
|
||||||
|
match crate::transport_profile(transport, profile.transport_profile.as_str()) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
let listeners_profile =
|
||||||
|
match crate::listeners_profile(listeners, profile.listeners_profile.as_str()) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
profiles.push(crate::ProfileConfig {
|
||||||
|
name: profile.name.clone(),
|
||||||
|
app: profile.app.clone(),
|
||||||
|
database: profile.database.clone(),
|
||||||
|
data: profile.data.clone(),
|
||||||
|
solana: crate::SolanaConfig {
|
||||||
|
http_endpoints: transport_profile.http_endpoints.clone(),
|
||||||
|
ws_endpoints: transport_profile.ws_endpoints.clone(),
|
||||||
|
listeners: crate::resolved_listener_config(listeners_profile),
|
||||||
|
},
|
||||||
|
wallet: profile.wallet.clone(),
|
||||||
|
execution: profile.execution.clone(),
|
||||||
|
demo: profile.demo.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let config = crate::AppConfig {
|
||||||
|
active_profile: document.active_profile.clone(),
|
||||||
|
profiles,
|
||||||
|
};
|
||||||
|
return match crate::validate_config(&config) {
|
||||||
|
std::result::Result::Ok(()) => std::result::Result::Ok(config),
|
||||||
|
std::result::Result::Err(error) => std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads a binary composition and its referenced transport/listener documents into the resolved runtime contract.
|
||||||
|
pub fn read_composed_app_config_with_environment(
|
||||||
|
composition_path: &std::path::Path,
|
||||||
|
workspace_root: &std::path::Path,
|
||||||
|
) -> ks_core::Result<crate::ComposedAppConfig> {
|
||||||
|
let composition =
|
||||||
|
match read_composition_json_file_with_environment(composition_path, workspace_root) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
let transport_path =
|
||||||
|
resolve_composition_source_path(workspace_root, composition.sources.transport.as_str());
|
||||||
|
let listeners_path =
|
||||||
|
resolve_composition_source_path(workspace_root, composition.sources.listeners.as_str());
|
||||||
|
let transport =
|
||||||
|
match crate::read_transport_json_file_with_environment(&transport_path, workspace_root) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
let listeners =
|
||||||
|
match crate::read_listeners_json_file_with_environment(&listeners_path, workspace_root) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
let app_config = match compose_app_config(&composition, &transport, &listeners) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
return std::result::Result::Ok(crate::ComposedAppConfig {
|
||||||
|
composition,
|
||||||
|
app_config,
|
||||||
|
transport_path,
|
||||||
|
listeners_path,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolved application configuration and the source documents needed by a binary.
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub struct ComposedAppConfig {
|
||||||
|
/// Parsed binary composition document.
|
||||||
|
pub composition: CompositionConfigDocument,
|
||||||
|
/// Resolved runtime application configuration.
|
||||||
|
pub app_config: crate::AppConfig,
|
||||||
|
/// Resolved transport source path.
|
||||||
|
pub transport_path: std::path::PathBuf,
|
||||||
|
/// Resolved listener source path.
|
||||||
|
pub listeners_path: std::path::PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validates a typed binary composition document before referenced documents are loaded.
|
||||||
|
pub fn validate_composition_document(document: &CompositionConfigDocument) -> ks_core::Result<()> {
|
||||||
|
match crate::require_non_empty(&document.active_profile, "active_profile") {
|
||||||
|
std::result::Result::Ok(()) => (),
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
}
|
||||||
|
for source in [
|
||||||
|
&document.sources.logging,
|
||||||
|
&document.sources.transport,
|
||||||
|
&document.sources.listeners,
|
||||||
|
] {
|
||||||
|
match crate::require_non_empty(source, "composition.sources") {
|
||||||
|
std::result::Result::Ok(()) => (),
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if document.profiles.is_empty() {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"composition_profiles_empty",
|
||||||
|
"at least one composition profile is required",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let mut names = std::collections::BTreeSet::<std::string::String>::new();
|
||||||
|
for profile in &document.profiles {
|
||||||
|
match crate::require_non_empty(&profile.name, "composition.profile.name") {
|
||||||
|
std::result::Result::Ok(()) => (),
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
}
|
||||||
|
for reference in
|
||||||
|
[&profile.logging_profile, &profile.transport_profile, &profile.listeners_profile]
|
||||||
|
{
|
||||||
|
match crate::require_non_empty(reference, "composition.profile.reference") {
|
||||||
|
std::result::Result::Ok(()) => (),
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !names.insert(profile.name.clone()) {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"composition_profile_name_duplicate",
|
||||||
|
profile.name.clone(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return match active_composition_profile(document) {
|
||||||
|
std::result::Result::Ok(_) => std::result::Result::Ok(()),
|
||||||
|
std::result::Result::Err(error) => std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
const DEFAULT_COMPOSITION: &str =
|
||||||
|
include_str!("../../config/kb-app-demo-desktop.default.config.json");
|
||||||
|
const EXAMPLE_COMPOSITION: &str =
|
||||||
|
include_str!("../../config/example.kb-app-demo-desktop.default.config.json");
|
||||||
|
const DEFAULT_TRANSPORT: &str = include_str!("../../config/transport.config.json");
|
||||||
|
const DEFAULT_LISTENERS: &str = include_str!("../../config/listeners.config.json");
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_and_example_compositions_validate() {
|
||||||
|
assert!(super::parse_composition_json(DEFAULT_COMPOSITION).is_ok());
|
||||||
|
assert!(super::parse_composition_json(EXAMPLE_COMPOSITION).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_composition_resolves_shared_transport_and_listener_profiles() {
|
||||||
|
let composition = match super::parse_composition_json(DEFAULT_COMPOSITION) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => panic!("default composition must parse: {error}"),
|
||||||
|
};
|
||||||
|
let transport = match crate::parse_transport_json(DEFAULT_TRANSPORT) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => panic!("default transport must parse: {error}"),
|
||||||
|
};
|
||||||
|
let listeners = match crate::parse_listeners_json(DEFAULT_LISTENERS) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => panic!("default listeners must parse: {error}"),
|
||||||
|
};
|
||||||
|
let resolved = super::compose_app_config(&composition, &transport, &listeners);
|
||||||
|
assert!(resolved.is_ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,79 @@
|
|||||||
// file: ks-config/src/lib.rs
|
// file: ks-config/src/lib.rs
|
||||||
// version: 6
|
// version: 7
|
||||||
|
|
||||||
//! Khadhroony Solana application configuration contract and loading helpers.
|
//! Khadhroony Solana application configuration contract and loading helpers.
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
#![deny(unreachable_pub)]
|
#![deny(unreachable_pub)]
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
|
mod composition;
|
||||||
mod environment;
|
mod environment;
|
||||||
|
mod listeners;
|
||||||
mod settings;
|
mod settings;
|
||||||
|
mod transport;
|
||||||
|
|
||||||
|
/// Exposes the resolved application configuration plus its composition source.
|
||||||
|
pub use self::composition::ComposedAppConfig;
|
||||||
|
/// Exposes the binary composition document type.
|
||||||
|
pub use self::composition::CompositionConfigDocument;
|
||||||
|
/// Exposes binary composition source paths.
|
||||||
|
pub use self::composition::CompositionConfigSources;
|
||||||
|
/// Exposes one named binary composition profile.
|
||||||
|
pub use self::composition::CompositionProfileConfig;
|
||||||
|
/// Exposes the active binary composition profile resolver.
|
||||||
|
pub use self::composition::active_composition_profile;
|
||||||
|
/// Exposes the resolved runtime composition builder.
|
||||||
|
pub use self::composition::compose_app_config;
|
||||||
|
/// Exposes the binary composition JSON Schema text.
|
||||||
|
pub use self::composition::composition_json_schema_text;
|
||||||
|
/// Exposes the binary composition JSON Schema value parser.
|
||||||
|
pub use self::composition::composition_json_schema_value;
|
||||||
|
/// Exposes one named binary composition profile resolver.
|
||||||
|
pub use self::composition::composition_profile;
|
||||||
|
/// Exposes binary composition parsing from JSON.
|
||||||
|
pub use self::composition::parse_composition_json;
|
||||||
|
/// Exposes composed application loading with referenced shared documents.
|
||||||
|
pub use self::composition::read_composed_app_config_with_environment;
|
||||||
|
/// Exposes binary composition loading from a filesystem path.
|
||||||
|
pub use self::composition::read_composition_json_file;
|
||||||
|
/// Exposes binary composition loading with workspace environment resolution.
|
||||||
|
pub use self::composition::read_composition_json_file_with_environment;
|
||||||
|
/// Exposes composition source path resolution.
|
||||||
|
pub use self::composition::resolve_composition_source_path;
|
||||||
|
/// Exposes typed binary composition validation.
|
||||||
|
pub use self::composition::validate_composition_document;
|
||||||
|
/// Exposes binary composition JSON Schema validation.
|
||||||
|
pub use self::composition::validate_composition_json_schema;
|
||||||
/// Exposes the environment loading report.
|
/// Exposes the environment loading report.
|
||||||
pub use self::environment::EnvironmentLoadReport;
|
pub use self::environment::EnvironmentLoadReport;
|
||||||
/// Exposes workspace environment-file loading.
|
/// Exposes workspace environment-file loading.
|
||||||
pub use self::environment::load_workspace_environment;
|
pub use self::environment::load_workspace_environment;
|
||||||
/// Exposes environment placeholder resolution.
|
/// Exposes environment placeholder resolution.
|
||||||
pub use self::environment::resolve_environment_placeholders;
|
pub use self::environment::resolve_environment_placeholders;
|
||||||
|
/// Exposes the independent listener configuration document.
|
||||||
|
pub use self::listeners::ListenersConfigDocument;
|
||||||
|
/// Exposes one named listener profile.
|
||||||
|
pub use self::listeners::ListenersProfileConfig;
|
||||||
|
/// Exposes the active listener profile resolver.
|
||||||
|
pub use self::listeners::active_listeners_profile;
|
||||||
|
/// Exposes the listener JSON Schema text.
|
||||||
|
pub use self::listeners::listeners_json_schema_text;
|
||||||
|
/// Exposes the listener JSON Schema value parser.
|
||||||
|
pub use self::listeners::listeners_json_schema_value;
|
||||||
|
/// Exposes one named listener profile resolver.
|
||||||
|
pub use self::listeners::listeners_profile;
|
||||||
|
/// Exposes listener configuration parsing from JSON.
|
||||||
|
pub use self::listeners::parse_listeners_json;
|
||||||
|
/// Exposes listener configuration loading from a filesystem path.
|
||||||
|
pub use self::listeners::read_listeners_json_file;
|
||||||
|
/// Exposes listener configuration loading with workspace environment resolution.
|
||||||
|
pub use self::listeners::read_listeners_json_file_with_environment;
|
||||||
|
/// Exposes conversion from a listener profile to the resolved runtime contract.
|
||||||
|
pub use self::listeners::resolved_listener_config;
|
||||||
|
/// Exposes typed listener document validation.
|
||||||
|
pub use self::listeners::validate_listeners_document;
|
||||||
|
/// Exposes listener JSON Schema validation.
|
||||||
|
pub use self::listeners::validate_listeners_json_schema;
|
||||||
/// Exposes the account listener configuration type.
|
/// Exposes the account listener configuration type.
|
||||||
pub use self::settings::AccountListenerConfig;
|
pub use self::settings::AccountListenerConfig;
|
||||||
/// Exposes the root application configuration type.
|
/// Exposes the root application configuration type.
|
||||||
@@ -53,21 +112,52 @@ pub use self::settings::WalletConfig;
|
|||||||
pub use self::settings::WsEndpointConfig;
|
pub use self::settings::WsEndpointConfig;
|
||||||
/// Exposes the active profile resolver.
|
/// Exposes the active profile resolver.
|
||||||
pub use self::settings::active_profile;
|
pub use self::settings::active_profile;
|
||||||
/// Exposes the embedded JSON Schema text.
|
/// Exposes the embedded JSON Schema text for the resolved runtime contract.
|
||||||
pub use self::settings::config_json_schema_text;
|
pub use self::settings::config_json_schema_text;
|
||||||
/// Exposes the embedded JSON Schema value parser.
|
/// Exposes the embedded JSON Schema value parser for the resolved runtime contract.
|
||||||
pub use self::settings::config_json_schema_value;
|
pub use self::settings::config_json_schema_value;
|
||||||
/// Exposes the configuration parser from a JSON string.
|
/// Exposes resolved runtime configuration parsing from a JSON string.
|
||||||
pub use self::settings::parse_config_json;
|
pub use self::settings::parse_config_json;
|
||||||
/// Exposes the configuration loader from a filesystem path.
|
/// Exposes resolved runtime configuration loading from a filesystem path.
|
||||||
pub use self::settings::read_config_json_file;
|
pub use self::settings::read_config_json_file;
|
||||||
/// Exposes configuration loading with workspace environment resolution.
|
/// Exposes resolved runtime configuration loading with workspace environment resolution.
|
||||||
pub use self::settings::read_config_json_file_with_environment;
|
pub use self::settings::read_config_json_file_with_environment;
|
||||||
/// Exposes the compact JSON serializer for configuration values.
|
/// Exposes the compact JSON serializer for resolved runtime configuration values.
|
||||||
pub use self::settings::serialize_config_json;
|
pub use self::settings::serialize_config_json;
|
||||||
/// Exposes the pretty JSON serializer for configuration values.
|
/// Exposes the pretty JSON serializer for resolved runtime configuration values.
|
||||||
pub use self::settings::serialize_config_json_pretty;
|
pub use self::settings::serialize_config_json_pretty;
|
||||||
/// Exposes the typed configuration validator.
|
/// Exposes the typed resolved runtime configuration validator.
|
||||||
pub use self::settings::validate_config;
|
pub use self::settings::validate_config;
|
||||||
/// Exposes the JSON Schema validator for raw JSON configuration.
|
/// Exposes the JSON Schema validator for raw resolved runtime configuration JSON.
|
||||||
pub use self::settings::validate_config_json_schema;
|
pub use self::settings::validate_config_json_schema;
|
||||||
|
/// Exposes the independent transport configuration document.
|
||||||
|
pub use self::transport::TransportConfigDocument;
|
||||||
|
/// Exposes one named transport profile.
|
||||||
|
pub use self::transport::TransportProfileConfig;
|
||||||
|
/// Exposes the active transport profile resolver.
|
||||||
|
pub use self::transport::active_transport_profile;
|
||||||
|
/// Exposes transport configuration parsing from JSON.
|
||||||
|
pub use self::transport::parse_transport_json;
|
||||||
|
/// Exposes transport configuration loading from a filesystem path.
|
||||||
|
pub use self::transport::read_transport_json_file;
|
||||||
|
/// Exposes transport configuration loading with workspace environment resolution.
|
||||||
|
pub use self::transport::read_transport_json_file_with_environment;
|
||||||
|
/// Exposes the transport JSON Schema text.
|
||||||
|
pub use self::transport::transport_json_schema_text;
|
||||||
|
/// Exposes the transport JSON Schema value parser.
|
||||||
|
pub use self::transport::transport_json_schema_value;
|
||||||
|
/// Exposes one named transport profile resolver.
|
||||||
|
pub use self::transport::transport_profile;
|
||||||
|
/// Exposes typed transport document validation.
|
||||||
|
pub use self::transport::validate_transport_document;
|
||||||
|
/// Exposes transport JSON Schema validation.
|
||||||
|
pub use self::transport::validate_transport_json_schema;
|
||||||
|
|
||||||
|
/// Internal non-empty string validation shared by configuration documents.
|
||||||
|
pub(crate) use self::settings::require_non_empty;
|
||||||
|
/// Internal typed HTTP endpoint validation shared by resolved and transport documents.
|
||||||
|
pub(crate) use self::settings::validate_http_endpoint;
|
||||||
|
/// Internal typed listener validation shared by resolved and listener documents.
|
||||||
|
pub(crate) use self::settings::validate_listeners;
|
||||||
|
/// Internal typed WebSocket endpoint validation shared by resolved and transport documents.
|
||||||
|
pub(crate) use self::settings::validate_ws_endpoint;
|
||||||
|
|||||||
224
ks-config/src/listeners.rs
Normal file
224
ks-config/src/listeners.rs
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
// file: ks-config/src/listeners.rs
|
||||||
|
// version: 1
|
||||||
|
|
||||||
|
//! Independent Solana listener configuration document loading and validation.
|
||||||
|
|
||||||
|
const LISTENERS_JSON_SCHEMA: &str =
|
||||||
|
include_str!("../../config/schemas/listeners.config.schema.json");
|
||||||
|
|
||||||
|
/// Root listener document containing independently selectable named profiles.
|
||||||
|
#[derive(Clone, Debug, serde::Deserialize, Eq, PartialEq, serde::Serialize)]
|
||||||
|
pub struct ListenersConfigDocument {
|
||||||
|
/// Active listener profile used by consumers that do not provide an explicit selection.
|
||||||
|
pub active_profile: std::string::String,
|
||||||
|
/// Named listener profiles available in this document.
|
||||||
|
pub profiles: std::vec::Vec<ListenersProfileConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Named listener profile.
|
||||||
|
#[derive(Clone, Debug, serde::Deserialize, Eq, PartialEq, serde::Serialize)]
|
||||||
|
pub struct ListenersProfileConfig {
|
||||||
|
/// Profile code.
|
||||||
|
pub name: std::string::String,
|
||||||
|
/// Enables listener creation.
|
||||||
|
pub enabled: bool,
|
||||||
|
/// Default commitment used by listener subscriptions.
|
||||||
|
pub default_commitment: std::string::String,
|
||||||
|
/// Log listeners filtered by program mentions.
|
||||||
|
pub log_listeners: std::vec::Vec<crate::LogListenerConfig>,
|
||||||
|
/// Program account listeners.
|
||||||
|
pub program_listeners: std::vec::Vec<crate::ProgramListenerConfig>,
|
||||||
|
/// Account listeners.
|
||||||
|
pub account_listeners: std::vec::Vec<crate::AccountListenerConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the embedded listener JSON Schema text.
|
||||||
|
pub fn listeners_json_schema_text() -> &'static str {
|
||||||
|
return LISTENERS_JSON_SCHEMA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses the embedded listener JSON Schema into a JSON value.
|
||||||
|
pub fn listeners_json_schema_value() -> ks_core::Result<serde_json::Value> {
|
||||||
|
let schema_result = serde_json::from_str::<serde_json::Value>(LISTENERS_JSON_SCHEMA);
|
||||||
|
return match schema_result {
|
||||||
|
std::result::Result::Ok(schema) => std::result::Result::Ok(schema),
|
||||||
|
std::result::Result::Err(error) => std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"listeners_config_schema_parse_failed",
|
||||||
|
error.to_string(),
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validates raw listener JSON against the embedded listener schema.
|
||||||
|
pub fn validate_listeners_json_schema(raw_json: &str) -> ks_core::Result<()> {
|
||||||
|
let schema = match listeners_json_schema_value() {
|
||||||
|
std::result::Result::Ok(schema) => schema,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
let instance = match serde_json::from_str::<serde_json::Value>(raw_json) {
|
||||||
|
std::result::Result::Ok(instance) => instance,
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"listeners_config_json_parse_failed",
|
||||||
|
error.to_string(),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let validator = match jsonschema::validator_for(&schema) {
|
||||||
|
std::result::Result::Ok(validator) => validator,
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"listeners_config_schema_compile_failed",
|
||||||
|
error.to_string(),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return match validator.validate(&instance) {
|
||||||
|
std::result::Result::Ok(()) => std::result::Result::Ok(()),
|
||||||
|
std::result::Result::Err(error) => std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"listeners_config_schema_validation_failed",
|
||||||
|
error.to_string(),
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses and validates one independent listener configuration document.
|
||||||
|
pub fn parse_listeners_json(raw_json: &str) -> ks_core::Result<ListenersConfigDocument> {
|
||||||
|
match validate_listeners_json_schema(raw_json) {
|
||||||
|
std::result::Result::Ok(()) => (),
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
}
|
||||||
|
let document = match serde_json::from_str::<ListenersConfigDocument>(raw_json) {
|
||||||
|
std::result::Result::Ok(document) => document,
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"listeners_config_json_decode_failed",
|
||||||
|
error.to_string(),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return match validate_listeners_document(&document) {
|
||||||
|
std::result::Result::Ok(()) => std::result::Result::Ok(document),
|
||||||
|
std::result::Result::Err(error) => std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads and parses one listener configuration document from a filesystem path.
|
||||||
|
pub fn read_listeners_json_file(
|
||||||
|
path: &std::path::Path,
|
||||||
|
) -> ks_core::Result<ListenersConfigDocument> {
|
||||||
|
let raw_json = match std::fs::read_to_string(path) {
|
||||||
|
std::result::Result::Ok(content) => content,
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"listeners_config_file_read_failed",
|
||||||
|
error.to_string(),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return parse_listeners_json(&raw_json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Loads workspace environment values, resolves placeholders and parses listener configuration.
|
||||||
|
pub fn read_listeners_json_file_with_environment(
|
||||||
|
path: &std::path::Path,
|
||||||
|
workspace_root: &std::path::Path,
|
||||||
|
) -> ks_core::Result<ListenersConfigDocument> {
|
||||||
|
match crate::load_workspace_environment(workspace_root) {
|
||||||
|
std::result::Result::Ok(_) => (),
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
}
|
||||||
|
let raw_json = match std::fs::read_to_string(path) {
|
||||||
|
std::result::Result::Ok(content) => content,
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"listeners_config_file_read_failed",
|
||||||
|
error.to_string(),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let resolved = crate::resolve_environment_placeholders(&raw_json);
|
||||||
|
return parse_listeners_json(&resolved);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns one named listener profile.
|
||||||
|
pub fn listeners_profile<'a>(
|
||||||
|
document: &'a ListenersConfigDocument,
|
||||||
|
profile_name: &str,
|
||||||
|
) -> ks_core::Result<&'a ListenersProfileConfig> {
|
||||||
|
for profile in &document.profiles {
|
||||||
|
if profile.name == profile_name {
|
||||||
|
return std::result::Result::Ok(profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"listeners_profile_not_found",
|
||||||
|
profile_name.to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the active listener profile declared by the document.
|
||||||
|
pub fn active_listeners_profile(
|
||||||
|
document: &ListenersConfigDocument,
|
||||||
|
) -> ks_core::Result<&ListenersProfileConfig> {
|
||||||
|
return listeners_profile(document, document.active_profile.as_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts one named listener profile into the resolved runtime listener contract.
|
||||||
|
pub fn resolved_listener_config(profile: &ListenersProfileConfig) -> crate::ListenerConfig {
|
||||||
|
return crate::ListenerConfig {
|
||||||
|
enabled: profile.enabled,
|
||||||
|
default_commitment: profile.default_commitment.clone(),
|
||||||
|
log_listeners: profile.log_listeners.clone(),
|
||||||
|
program_listeners: profile.program_listeners.clone(),
|
||||||
|
account_listeners: profile.account_listeners.clone(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validates a typed listener configuration document.
|
||||||
|
pub fn validate_listeners_document(document: &ListenersConfigDocument) -> ks_core::Result<()> {
|
||||||
|
match crate::require_non_empty(&document.active_profile, "active_profile") {
|
||||||
|
std::result::Result::Ok(()) => (),
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
}
|
||||||
|
if document.profiles.is_empty() {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"listeners_config_profiles_empty",
|
||||||
|
"at least one listener profile is required",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let mut names = std::collections::BTreeSet::<std::string::String>::new();
|
||||||
|
for profile in &document.profiles {
|
||||||
|
match crate::require_non_empty(&profile.name, "listeners.profile.name") {
|
||||||
|
std::result::Result::Ok(()) => (),
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
}
|
||||||
|
if !names.insert(profile.name.clone()) {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"listeners_profile_name_duplicate",
|
||||||
|
profile.name.clone(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let resolved = resolved_listener_config(profile);
|
||||||
|
match crate::validate_listeners(&resolved) {
|
||||||
|
std::result::Result::Ok(()) => (),
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return match active_listeners_profile(document) {
|
||||||
|
std::result::Result::Ok(_) => std::result::Result::Ok(()),
|
||||||
|
std::result::Result::Err(error) => std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
const DEFAULT_LISTENERS: &str = include_str!("../../config/listeners.config.json");
|
||||||
|
const EXAMPLE_LISTENERS: &str = include_str!("../../config/example.listeners.config.json");
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_and_example_listener_configs_validate() {
|
||||||
|
assert!(super::parse_listeners_json(DEFAULT_LISTENERS).is_ok());
|
||||||
|
assert!(super::parse_listeners_json(EXAMPLE_LISTENERS).is_ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,23 +1,24 @@
|
|||||||
// file: ks-config/src/settings.rs
|
// file: ks-config/src/settings.rs
|
||||||
// version: 20
|
// version: 21
|
||||||
|
|
||||||
//! Typed configuration models shared by applications and workers.
|
//! Resolved runtime configuration models retained during the `0.5.1` source-document split.
|
||||||
|
|
||||||
use ts_rs::TS; // rust-rules: derive-import
|
use ts_rs::TS; // rust-rules: derive-import
|
||||||
|
|
||||||
const CONFIG_JSON_SCHEMA: &str = include_str!("../../config/schemas/app.config.schema.json");
|
const CONFIG_JSON_SCHEMA: &str =
|
||||||
|
include_str!("../../config/schemas/resolved.app.config.schema.json");
|
||||||
|
|
||||||
/// Root configuration containing every named profile.
|
/// Resolved runtime configuration containing every composed named profile.
|
||||||
#[derive(Clone, Debug, serde::Deserialize, Eq, PartialEq, serde::Serialize, TS)]
|
#[derive(Clone, Debug, serde::Deserialize, Eq, PartialEq, serde::Serialize, TS)]
|
||||||
#[ts(export, export_to = "../frontend/ts/bindings/ks_config/settings/AppConfig.ts")]
|
#[ts(export, export_to = "../frontend/ts/bindings/ks_config/settings/AppConfig.ts")]
|
||||||
pub struct AppConfig {
|
pub struct AppConfig {
|
||||||
/// Active profile name.
|
/// Active profile name.
|
||||||
pub active_profile: std::string::String,
|
pub active_profile: std::string::String,
|
||||||
/// Named profiles available in this configuration file.
|
/// Named profiles reconstructed from the active binary composition and shared documents.
|
||||||
pub profiles: std::vec::Vec<ProfileConfig>,
|
pub profiles: std::vec::Vec<ProfileConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration profile selected by the root active profile name.
|
/// Resolved runtime profile selected by the root active profile name.
|
||||||
#[derive(Clone, Debug, serde::Deserialize, Eq, PartialEq, serde::Serialize, TS)]
|
#[derive(Clone, Debug, serde::Deserialize, Eq, PartialEq, serde::Serialize, TS)]
|
||||||
#[ts(
|
#[ts(
|
||||||
export,
|
export,
|
||||||
@@ -382,12 +383,12 @@ pub struct DemoConfig {
|
|||||||
pub trading_demo_enabled: bool,
|
pub trading_demo_enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the embedded JSON Schema text used for configuration validation.
|
/// Returns the embedded JSON Schema text used for resolved runtime contract validation.
|
||||||
pub fn config_json_schema_text() -> &'static str {
|
pub fn config_json_schema_text() -> &'static str {
|
||||||
return CONFIG_JSON_SCHEMA;
|
return CONFIG_JSON_SCHEMA;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses the embedded JSON Schema into a JSON value.
|
/// Parses the embedded resolved runtime JSON Schema into a JSON value.
|
||||||
pub fn config_json_schema_value() -> ks_core::Result<serde_json::Value> {
|
pub fn config_json_schema_value() -> ks_core::Result<serde_json::Value> {
|
||||||
let schema_result = serde_json::from_str::<serde_json::Value>(CONFIG_JSON_SCHEMA);
|
let schema_result = serde_json::from_str::<serde_json::Value>(CONFIG_JSON_SCHEMA);
|
||||||
return match schema_result {
|
return match schema_result {
|
||||||
@@ -399,7 +400,7 @@ pub fn config_json_schema_value() -> ks_core::Result<serde_json::Value> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validates a raw JSON configuration string against the embedded JSON Schema.
|
/// Validates a raw resolved runtime JSON string against the embedded compatibility schema.
|
||||||
pub fn validate_config_json_schema(raw_json: &str) -> ks_core::Result<()> {
|
pub fn validate_config_json_schema(raw_json: &str) -> ks_core::Result<()> {
|
||||||
let schema = match config_json_schema_value() {
|
let schema = match config_json_schema_value() {
|
||||||
std::result::Result::Ok(schema) => schema,
|
std::result::Result::Ok(schema) => schema,
|
||||||
@@ -433,7 +434,7 @@ pub fn validate_config_json_schema(raw_json: &str) -> ks_core::Result<()> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses the application configuration from a JSON string and validates it.
|
/// Parses the resolved runtime application contract from a JSON string and validates it.
|
||||||
pub fn parse_config_json(raw_json: &str) -> ks_core::Result<AppConfig> {
|
pub fn parse_config_json(raw_json: &str) -> ks_core::Result<AppConfig> {
|
||||||
match validate_config_json_schema(raw_json) {
|
match validate_config_json_schema(raw_json) {
|
||||||
std::result::Result::Ok(()) => (),
|
std::result::Result::Ok(()) => (),
|
||||||
@@ -454,7 +455,7 @@ pub fn parse_config_json(raw_json: &str) -> ks_core::Result<AppConfig> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads and parses the application configuration from a filesystem path.
|
/// Reads and parses a resolved runtime application snapshot from a filesystem path.
|
||||||
pub fn read_config_json_file(path: &std::path::Path) -> ks_core::Result<AppConfig> {
|
pub fn read_config_json_file(path: &std::path::Path) -> ks_core::Result<AppConfig> {
|
||||||
let raw_json = match std::fs::read_to_string(path) {
|
let raw_json = match std::fs::read_to_string(path) {
|
||||||
std::result::Result::Ok(content) => content,
|
std::result::Result::Ok(content) => content,
|
||||||
@@ -468,7 +469,7 @@ pub fn read_config_json_file(path: &std::path::Path) -> ks_core::Result<AppConfi
|
|||||||
return parse_config_json(&raw_json);
|
return parse_config_json(&raw_json);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads the workspace environment, resolves placeholders and parses one configuration file.
|
/// Loads the workspace environment, resolves placeholders and parses one resolved runtime snapshot.
|
||||||
pub fn read_config_json_file_with_environment(
|
pub fn read_config_json_file_with_environment(
|
||||||
path: &std::path::Path,
|
path: &std::path::Path,
|
||||||
workspace_root: &std::path::Path,
|
workspace_root: &std::path::Path,
|
||||||
@@ -700,7 +701,7 @@ fn validate_solana(config: &SolanaConfig) -> ks_core::Result<()> {
|
|||||||
return validate_listeners(&config.listeners);
|
return validate_listeners(&config.listeners);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_http_endpoint(config: &HttpEndpointConfig) -> ks_core::Result<()> {
|
pub(crate) fn validate_http_endpoint(config: &HttpEndpointConfig) -> ks_core::Result<()> {
|
||||||
match validate_endpoint_common(&config.name, &config.provider, &config.cluster, &config.roles) {
|
match validate_endpoint_common(&config.name, &config.provider, &config.cluster, &config.roles) {
|
||||||
std::result::Result::Ok(()) => (),
|
std::result::Result::Ok(()) => (),
|
||||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
@@ -731,7 +732,7 @@ fn validate_http_endpoint(config: &HttpEndpointConfig) -> ks_core::Result<()> {
|
|||||||
return std::result::Result::Ok(());
|
return std::result::Result::Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_ws_endpoint(config: &WsEndpointConfig) -> ks_core::Result<()> {
|
pub(crate) fn validate_ws_endpoint(config: &WsEndpointConfig) -> ks_core::Result<()> {
|
||||||
match validate_endpoint_common(&config.name, &config.provider, &config.cluster, &config.roles) {
|
match validate_endpoint_common(&config.name, &config.provider, &config.cluster, &config.roles) {
|
||||||
std::result::Result::Ok(()) => (),
|
std::result::Result::Ok(()) => (),
|
||||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
@@ -826,7 +827,7 @@ fn validate_endpoint_role(config: &EndpointRoleConfig) -> ks_core::Result<()> {
|
|||||||
return std::result::Result::Ok(());
|
return std::result::Result::Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_listeners(config: &ListenerConfig) -> ks_core::Result<()> {
|
pub(crate) fn validate_listeners(config: &ListenerConfig) -> ks_core::Result<()> {
|
||||||
match require_non_empty(&config.default_commitment, "solana.listeners.default_commitment") {
|
match require_non_empty(&config.default_commitment, "solana.listeners.default_commitment") {
|
||||||
std::result::Result::Ok(()) => (),
|
std::result::Result::Ok(()) => (),
|
||||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
@@ -1015,7 +1016,7 @@ fn validate_wallet_execution_pair(
|
|||||||
return std::result::Result::Ok(());
|
return std::result::Result::Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn require_non_empty(value: &str, field_name: &str) -> ks_core::Result<()> {
|
pub(crate) fn require_non_empty(value: &str, field_name: &str) -> ks_core::Result<()> {
|
||||||
if value.trim().is_empty() {
|
if value.trim().is_empty() {
|
||||||
return std::result::Result::Err(ks_core::Error::new(
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
"config_field_empty",
|
"config_field_empty",
|
||||||
@@ -1045,14 +1046,18 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_CONFIG: &str = include_str!("../../config/app.config.json");
|
const DEFAULT_CONFIG: &str =
|
||||||
const EXAMPLE_CONFIG: &str = include_str!("../../config/example.app.config.json");
|
include_str!("../../test-fixtures/config/resolved.app.config.json");
|
||||||
|
const EXAMPLE_CONFIG: &str =
|
||||||
|
include_str!("../../test-fixtures/config/example.resolved.app.config.json");
|
||||||
|
|
||||||
fn parse_default_value() -> serde_json::Value {
|
fn parse_default_value() -> serde_json::Value {
|
||||||
let result = serde_json::from_str::<serde_json::Value>(DEFAULT_CONFIG);
|
let result = serde_json::from_str::<serde_json::Value>(DEFAULT_CONFIG);
|
||||||
match result {
|
match result {
|
||||||
std::result::Result::Ok(value) => return value,
|
std::result::Result::Ok(value) => return value,
|
||||||
std::result::Result::Err(error) => panic!("default app config must be valid JSON: {error}"),
|
std::result::Result::Err(error) => {
|
||||||
|
panic!("default app config must be valid JSON: {error}")
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
240
ks-config/src/transport.rs
Normal file
240
ks-config/src/transport.rs
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
// file: ks-config/src/transport.rs
|
||||||
|
// version: 1
|
||||||
|
|
||||||
|
//! Independent Solana transport configuration document loading and validation.
|
||||||
|
|
||||||
|
const TRANSPORT_JSON_SCHEMA: &str =
|
||||||
|
include_str!("../../config/schemas/transport.config.schema.json");
|
||||||
|
|
||||||
|
/// Root transport document containing independently selectable named profiles.
|
||||||
|
#[derive(Clone, Debug, serde::Deserialize, Eq, PartialEq, serde::Serialize)]
|
||||||
|
pub struct TransportConfigDocument {
|
||||||
|
/// Active transport profile used by consumers that do not provide an explicit selection.
|
||||||
|
pub active_profile: std::string::String,
|
||||||
|
/// Named transport profiles available in this document.
|
||||||
|
pub profiles: std::vec::Vec<TransportProfileConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Named Solana HTTP and WebSocket endpoint profile.
|
||||||
|
#[derive(Clone, Debug, serde::Deserialize, Eq, PartialEq, serde::Serialize)]
|
||||||
|
pub struct TransportProfileConfig {
|
||||||
|
/// Profile code.
|
||||||
|
pub name: std::string::String,
|
||||||
|
/// HTTP JSON-RPC endpoints.
|
||||||
|
pub http_endpoints: std::vec::Vec<crate::HttpEndpointConfig>,
|
||||||
|
/// Standard Solana WebSocket endpoints.
|
||||||
|
pub ws_endpoints: std::vec::Vec<crate::WsEndpointConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the embedded transport JSON Schema text.
|
||||||
|
pub fn transport_json_schema_text() -> &'static str {
|
||||||
|
return TRANSPORT_JSON_SCHEMA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses the embedded transport JSON Schema into a JSON value.
|
||||||
|
pub fn transport_json_schema_value() -> ks_core::Result<serde_json::Value> {
|
||||||
|
let schema_result = serde_json::from_str::<serde_json::Value>(TRANSPORT_JSON_SCHEMA);
|
||||||
|
return match schema_result {
|
||||||
|
std::result::Result::Ok(schema) => std::result::Result::Ok(schema),
|
||||||
|
std::result::Result::Err(error) => std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"transport_config_schema_parse_failed",
|
||||||
|
error.to_string(),
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validates raw transport JSON against the embedded transport schema.
|
||||||
|
pub fn validate_transport_json_schema(raw_json: &str) -> ks_core::Result<()> {
|
||||||
|
let schema = match transport_json_schema_value() {
|
||||||
|
std::result::Result::Ok(schema) => schema,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
let instance = match serde_json::from_str::<serde_json::Value>(raw_json) {
|
||||||
|
std::result::Result::Ok(instance) => instance,
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"transport_config_json_parse_failed",
|
||||||
|
error.to_string(),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let validator = match jsonschema::validator_for(&schema) {
|
||||||
|
std::result::Result::Ok(validator) => validator,
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"transport_config_schema_compile_failed",
|
||||||
|
error.to_string(),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return match validator.validate(&instance) {
|
||||||
|
std::result::Result::Ok(()) => std::result::Result::Ok(()),
|
||||||
|
std::result::Result::Err(error) => std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"transport_config_schema_validation_failed",
|
||||||
|
error.to_string(),
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses and validates one independent transport configuration document.
|
||||||
|
pub fn parse_transport_json(raw_json: &str) -> ks_core::Result<TransportConfigDocument> {
|
||||||
|
match validate_transport_json_schema(raw_json) {
|
||||||
|
std::result::Result::Ok(()) => (),
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
}
|
||||||
|
let document = match serde_json::from_str::<TransportConfigDocument>(raw_json) {
|
||||||
|
std::result::Result::Ok(document) => document,
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"transport_config_json_decode_failed",
|
||||||
|
error.to_string(),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return match validate_transport_document(&document) {
|
||||||
|
std::result::Result::Ok(()) => std::result::Result::Ok(document),
|
||||||
|
std::result::Result::Err(error) => std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads and parses one transport configuration document from a filesystem path.
|
||||||
|
pub fn read_transport_json_file(
|
||||||
|
path: &std::path::Path,
|
||||||
|
) -> ks_core::Result<TransportConfigDocument> {
|
||||||
|
let raw_json = match std::fs::read_to_string(path) {
|
||||||
|
std::result::Result::Ok(content) => content,
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"transport_config_file_read_failed",
|
||||||
|
error.to_string(),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return parse_transport_json(&raw_json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Loads workspace environment values, resolves placeholders and parses transport configuration.
|
||||||
|
pub fn read_transport_json_file_with_environment(
|
||||||
|
path: &std::path::Path,
|
||||||
|
workspace_root: &std::path::Path,
|
||||||
|
) -> ks_core::Result<TransportConfigDocument> {
|
||||||
|
match crate::load_workspace_environment(workspace_root) {
|
||||||
|
std::result::Result::Ok(_) => (),
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
}
|
||||||
|
let raw_json = match std::fs::read_to_string(path) {
|
||||||
|
std::result::Result::Ok(content) => content,
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"transport_config_file_read_failed",
|
||||||
|
error.to_string(),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let resolved = crate::resolve_environment_placeholders(&raw_json);
|
||||||
|
return parse_transport_json(&resolved);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns one named transport profile.
|
||||||
|
pub fn transport_profile<'a>(
|
||||||
|
document: &'a TransportConfigDocument,
|
||||||
|
profile_name: &str,
|
||||||
|
) -> ks_core::Result<&'a TransportProfileConfig> {
|
||||||
|
for profile in &document.profiles {
|
||||||
|
if profile.name == profile_name {
|
||||||
|
return std::result::Result::Ok(profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"transport_profile_not_found",
|
||||||
|
profile_name.to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the active transport profile declared by the document.
|
||||||
|
pub fn active_transport_profile(
|
||||||
|
document: &TransportConfigDocument,
|
||||||
|
) -> ks_core::Result<&TransportProfileConfig> {
|
||||||
|
return transport_profile(document, document.active_profile.as_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validates a typed transport configuration document.
|
||||||
|
pub fn validate_transport_document(document: &TransportConfigDocument) -> ks_core::Result<()> {
|
||||||
|
match crate::require_non_empty(&document.active_profile, "active_profile") {
|
||||||
|
std::result::Result::Ok(()) => (),
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
}
|
||||||
|
if document.profiles.is_empty() {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"transport_config_profiles_empty",
|
||||||
|
"at least one transport profile is required",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let mut names = std::collections::BTreeSet::<std::string::String>::new();
|
||||||
|
for profile in &document.profiles {
|
||||||
|
match crate::require_non_empty(&profile.name, "transport.profile.name") {
|
||||||
|
std::result::Result::Ok(()) => (),
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
}
|
||||||
|
if !names.insert(profile.name.clone()) {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"transport_profile_name_duplicate",
|
||||||
|
profile.name.clone(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if profile.http_endpoints.is_empty() || profile.ws_endpoints.is_empty() {
|
||||||
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
|
"transport_profile_endpoints_empty",
|
||||||
|
profile.name.clone(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
for endpoint in &profile.http_endpoints {
|
||||||
|
match crate::validate_http_endpoint(endpoint) {
|
||||||
|
std::result::Result::Ok(()) => (),
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for endpoint in &profile.ws_endpoints {
|
||||||
|
match crate::validate_ws_endpoint(endpoint) {
|
||||||
|
std::result::Result::Ok(()) => (),
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return match active_transport_profile(document) {
|
||||||
|
std::result::Result::Ok(_) => std::result::Result::Ok(()),
|
||||||
|
std::result::Result::Err(error) => std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
const DEFAULT_TRANSPORT: &str = include_str!("../../config/transport.config.json");
|
||||||
|
const EXAMPLE_TRANSPORT: &str = include_str!("../../config/example.transport.config.json");
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_and_example_transport_configs_validate() {
|
||||||
|
assert!(super::parse_transport_json(DEFAULT_TRANSPORT).is_ok());
|
||||||
|
assert!(super::parse_transport_json(EXAMPLE_TRANSPORT).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn schema_rejects_unsupported_transport_surface() {
|
||||||
|
let value_result = serde_json::from_str::<serde_json::Value>(DEFAULT_TRANSPORT);
|
||||||
|
let mut value = match value_result {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
panic!("default transport config must parse: {error}")
|
||||||
|
},
|
||||||
|
};
|
||||||
|
value["profiles"][0]["advanced_streams"] = serde_json::json!([]);
|
||||||
|
let raw_result = serde_json::to_string(&value);
|
||||||
|
let raw = match raw_result {
|
||||||
|
std::result::Result::Ok(raw) => raw,
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
panic!("transport test value must serialize: {error}")
|
||||||
|
},
|
||||||
|
};
|
||||||
|
assert!(super::validate_transport_json_schema(&raw).is_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
32
ks-config/tests/external_composition_api.rs
Normal file
32
ks-config/tests/external_composition_api.rs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// file: ks-config/tests/external_composition_api.rs
|
||||||
|
// version: 1
|
||||||
|
|
||||||
|
//! External API coverage for binary composition and shared configuration documents.
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn external_consumer_resolves_composition_through_crate_root_exports() {
|
||||||
|
let composition = match ks_config::parse_composition_json(include_str!(
|
||||||
|
"../../config/example.kb-app-demo-desktop.default.config.json"
|
||||||
|
)) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => panic!("composition must parse: {error}"),
|
||||||
|
};
|
||||||
|
let transport = match ks_config::parse_transport_json(include_str!(
|
||||||
|
"../../config/example.transport.config.json"
|
||||||
|
)) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => panic!("transport must parse: {error}"),
|
||||||
|
};
|
||||||
|
let listeners = match ks_config::parse_listeners_json(include_str!(
|
||||||
|
"../../config/example.listeners.config.json"
|
||||||
|
)) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => panic!("listeners must parse: {error}"),
|
||||||
|
};
|
||||||
|
let resolved = match ks_config::compose_app_config(&composition, &transport, &listeners) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => panic!("composition must resolve: {error}"),
|
||||||
|
};
|
||||||
|
assert_eq!(resolved.active_profile, composition.active_profile);
|
||||||
|
assert_eq!(resolved.profiles.len(), composition.profiles.len());
|
||||||
|
}
|
||||||
@@ -1,8 +1,13 @@
|
|||||||
<!-- file: ks-logging/CHANGELOG.md -->
|
<!-- file: ks-logging/CHANGELOG.md -->
|
||||||
<!-- version: 14 -->
|
<!-- version: 15 -->
|
||||||
|
|
||||||
# CHANGELOG — ks-logging
|
# CHANGELOG — ks-logging
|
||||||
|
|
||||||
|
## `0.5.1-pre.006`
|
||||||
|
|
||||||
|
- ajoute la sélection explicite d'un profil logging nommé afin qu'une composition binaire puisse choisir un profil indépendamment du `active_profile` propre au document logging ;
|
||||||
|
- conserve `config/logging.config.json` comme document partagé autonome, référencé par les compositions plutôt qu'imposé par un fichier applicatif monolithique.
|
||||||
|
|
||||||
## `0.5.1-pre.005`
|
## `0.5.1-pre.005`
|
||||||
|
|
||||||
- devient propriétaire unique des types `LoggingConfig`, `LogTargetConfig` et `LogTargetFilterConfig` ;
|
- devient propriétaire unique des types `LoggingConfig`, `LogTargetConfig` et `LogTargetFilterConfig` ;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: ks-logging/README.md -->
|
<!-- file: ks-logging/README.md -->
|
||||||
<!-- version: 6 -->
|
<!-- version: 7 -->
|
||||||
|
|
||||||
# ks-logging
|
# ks-logging
|
||||||
|
|
||||||
@@ -20,13 +20,13 @@
|
|||||||
|
|
||||||
`ks-logging` dépend de `ks-config` uniquement pour le chargement du fichier `.env` et la résolution générique `${KS_*}` / `${KB_*}`. `ks-config` ne dépend pas de `ks-logging` et ne duplique aucun type logging.
|
`ks-logging` dépend de `ks-config` uniquement pour le chargement du fichier `.env` et la résolution générique `${KS_*}` / `${KB_*}`. `ks-config` ne dépend pas de `ks-logging` et ne duplique aucun type logging.
|
||||||
|
|
||||||
Le desktop charge `config/app.config.json` et `config/logging.config.json` séparément puis transmet directement le profil logging actif à `init_logging`.
|
Le desktop lit le chemin `logging` et le `logging_profile` depuis `config/kb-app-demo-desktop.default.config.json`, charge le document logging puis transmet le profil explicitement sélectionné à `init_logging`.
|
||||||
|
|
||||||
## API publique
|
## API publique
|
||||||
|
|
||||||
- `read_logging_json_file_with_environment` charge le document logging ;
|
- `read_logging_json_file_with_environment` charge le document logging ;
|
||||||
- `parse_logging_json` et `validate_logging_json_schema` valident le format ;
|
- `parse_logging_json` et `validate_logging_json_schema` valident le format ;
|
||||||
- `active_logging_profile` sélectionne le profil actif ;
|
- `active_logging_profile` sélectionne le profil autonome actif et `logging_profile` résout un profil explicitement nommé par une composition ;
|
||||||
- `LoggingConfigDocument` et `LoggingProfileConfig` décrivent le document ;
|
- `LoggingConfigDocument` et `LoggingProfileConfig` décrivent le document ;
|
||||||
- `LoggingConfig`, `LogTargetConfig` et `LogTargetFilterConfig` décrivent le runtime ;
|
- `LoggingConfig`, `LogTargetConfig` et `LogTargetFilterConfig` décrivent le runtime ;
|
||||||
- `init_logging` initialise le subscriber global ;
|
- `init_logging` initialise le subscriber global ;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: ks-logging/USAGE.md -->
|
<!-- file: ks-logging/USAGE.md -->
|
||||||
<!-- version: 5 -->
|
<!-- version: 6 -->
|
||||||
|
|
||||||
# Utilisation de ks-logging
|
# Utilisation de ks-logging
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ let guard = match ks_logging::init_logging(config) {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Le desktop utilise `config/logging.config.json` par défaut. `KS_LOGGING_CONFIG_PATH` peut sélectionner un autre document sans modifier `KS_CONFIG_PATH` ni le profil applicatif.
|
Le desktop utilise normalement le chemin déclaré dans sa composition `config/kb-app-demo-desktop.default.config.json`. `KS_LOGGING_CONFIG_PATH` peut encore remplacer explicitement ce chemin sans modifier le fichier de composition.
|
||||||
|
|
||||||
## Format du document
|
## Format du document
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ Le schéma formel est `config/schemas/logging.config.schema.json`. `config/examp
|
|||||||
|
|
||||||
## Sélection indépendante
|
## Sélection indépendante
|
||||||
|
|
||||||
Le `active_profile` logging n’est jamais déduit de `app.config.json`. Un opérateur peut donc utiliser, par exemple, un profil applicatif `mainnet_research` avec un profil logging `local_devnet` ou tout autre profil logging explicitement défini.
|
Le `active_profile` logging reste le défaut autonome du document. Lorsqu’un binaire utilise une composition, il sélectionne explicitement son `logging_profile` avec `ks_logging::logging_profile`; cette sélection prime pour ce binaire sans modifier le document partagé.
|
||||||
|
|
||||||
## Construction directe
|
## Construction directe
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: ks-logging/src/document.rs
|
// file: ks-logging/src/document.rs
|
||||||
// version: 1
|
// version: 2
|
||||||
|
|
||||||
//! Independent logging configuration document loading and validation.
|
//! Independent logging configuration document loading and validation.
|
||||||
|
|
||||||
@@ -132,21 +132,29 @@ pub fn read_logging_json_file_with_environment(
|
|||||||
return parse_logging_json(&resolved);
|
return parse_logging_json(&resolved);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the active runtime logging profile selected by the logging document.
|
/// Returns one named runtime logging profile.
|
||||||
pub fn active_logging_profile(
|
pub fn logging_profile<'a>(
|
||||||
document: &LoggingConfigDocument,
|
document: &'a LoggingConfigDocument,
|
||||||
) -> ks_core::Result<&crate::LoggingConfig> {
|
profile_name: &str,
|
||||||
|
) -> ks_core::Result<&'a crate::LoggingConfig> {
|
||||||
for profile in &document.profiles {
|
for profile in &document.profiles {
|
||||||
if profile.name == document.active_profile {
|
if profile.name == profile_name {
|
||||||
return std::result::Result::Ok(&profile.config);
|
return std::result::Result::Ok(&profile.config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return std::result::Result::Err(ks_core::Error::new(
|
return std::result::Result::Err(ks_core::Error::new(
|
||||||
"active_logging_profile_not_found",
|
"logging_profile_not_found",
|
||||||
document.active_profile.clone(),
|
profile_name.to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the active runtime logging profile selected by the logging document.
|
||||||
|
pub fn active_logging_profile(
|
||||||
|
document: &LoggingConfigDocument,
|
||||||
|
) -> ks_core::Result<&crate::LoggingConfig> {
|
||||||
|
return logging_profile(document, document.active_profile.as_str());
|
||||||
|
}
|
||||||
|
|
||||||
/// Validates a typed logging configuration document.
|
/// Validates a typed logging configuration document.
|
||||||
pub fn validate_logging_document(document: &LoggingConfigDocument) -> ks_core::Result<()> {
|
pub fn validate_logging_document(document: &LoggingConfigDocument) -> ks_core::Result<()> {
|
||||||
match require_non_empty(&document.active_profile, "active_profile") {
|
match require_non_empty(&document.active_profile, "active_profile") {
|
||||||
@@ -330,7 +338,9 @@ mod tests {
|
|||||||
let result = serde_json::from_str::<serde_json::Value>(DEFAULT_LOGGING_CONFIG);
|
let result = serde_json::from_str::<serde_json::Value>(DEFAULT_LOGGING_CONFIG);
|
||||||
return match result {
|
return match result {
|
||||||
std::result::Result::Ok(value) => value,
|
std::result::Result::Ok(value) => value,
|
||||||
std::result::Result::Err(error) => panic!("default logging config must be JSON: {error}"),
|
std::result::Result::Err(error) => {
|
||||||
|
panic!("default logging config must be JSON: {error}")
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,7 +367,9 @@ mod tests {
|
|||||||
for entry_result in entries {
|
for entry_result in entries {
|
||||||
let entry = match entry_result {
|
let entry = match entry_result {
|
||||||
std::result::Result::Ok(entry) => entry,
|
std::result::Result::Ok(entry) => entry,
|
||||||
std::result::Result::Err(error) => panic!("workspace entry must be readable: {error}"),
|
std::result::Result::Err(error) => {
|
||||||
|
panic!("workspace entry must be readable: {error}")
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let cargo_path = entry.path().join("Cargo.toml");
|
let cargo_path = entry.path().join("Cargo.toml");
|
||||||
if !cargo_path.is_file() {
|
if !cargo_path.is_file() {
|
||||||
@@ -413,6 +425,7 @@ mod tests {
|
|||||||
assert_eq!(document.active_profile, "mainnet_research");
|
assert_eq!(document.active_profile, "mainnet_research");
|
||||||
assert_eq!(document.profiles.len(), 3);
|
assert_eq!(document.profiles.len(), 3);
|
||||||
assert!(super::active_logging_profile(&document).is_ok());
|
assert!(super::active_logging_profile(&document).is_ok());
|
||||||
|
assert!(super::logging_profile(&document, "local_devnet").is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: ks-logging/src/lib.rs
|
// file: ks-logging/src/lib.rs
|
||||||
// version: 8
|
// version: 9
|
||||||
|
|
||||||
//! Logging and tracing initialization for applications and workers.
|
//! Logging and tracing initialization for applications and workers.
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
@@ -32,6 +32,8 @@ pub use self::document::active_logging_profile;
|
|||||||
pub use self::document::logging_json_schema_text;
|
pub use self::document::logging_json_schema_text;
|
||||||
/// Exposes the embedded logging JSON Schema parser.
|
/// Exposes the embedded logging JSON Schema parser.
|
||||||
pub use self::document::logging_json_schema_value;
|
pub use self::document::logging_json_schema_value;
|
||||||
|
/// Exposes one named logging profile resolver.
|
||||||
|
pub use self::document::logging_profile;
|
||||||
/// Exposes logging configuration parsing from JSON.
|
/// Exposes logging configuration parsing from JSON.
|
||||||
pub use self::document::parse_logging_json;
|
pub use self::document::parse_logging_json;
|
||||||
/// Exposes logging configuration loading from a filesystem path.
|
/// Exposes logging configuration loading from a filesystem path.
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
<!-- file: ks-onchain-transport/CHANGELOG.md -->
|
<!-- file: ks-onchain-transport/CHANGELOG.md -->
|
||||||
<!-- version: 13 -->
|
<!-- version: 14 -->
|
||||||
|
|
||||||
# CHANGELOG — ks-onchain-transport
|
# CHANGELOG — ks-onchain-transport
|
||||||
|
|
||||||
|
## `0.5.1-pre.006`
|
||||||
|
|
||||||
|
- permet de construire directement les pools HTTP et WebSocket depuis `ks_config::TransportProfileConfig` ;
|
||||||
|
- conserve temporairement les constructeurs `from_profile` sur le contrat runtime résolu pour compatibilité pendant la décomposition de configuration.
|
||||||
|
|
||||||
## `0.5.1-pre.002`
|
## `0.5.1-pre.002`
|
||||||
|
|
||||||
- renomme `kb-onchain-transport` en `ks-onchain-transport` et `kb_onchain_transport` en `ks_onchain_transport` ;
|
- renomme `kb-onchain-transport` en `ks-onchain-transport` et `kb_onchain_transport` en `ks_onchain_transport` ;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: ks-onchain-transport/README.md -->
|
<!-- file: ks-onchain-transport/README.md -->
|
||||||
<!-- version: 2 -->
|
<!-- version: 3 -->
|
||||||
|
|
||||||
# ks-onchain-transport
|
# ks-onchain-transport
|
||||||
|
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
- requêtes JSON-RPC HTTP standard ;
|
- requêtes JSON-RPC HTTP standard ;
|
||||||
- sessions et pools WebSocket ;
|
- sessions et pools WebSocket ;
|
||||||
- routage par rôle d’endpoint ;
|
- routage par rôle d’endpoint ;
|
||||||
|
- consommation directe des profils partagés définis par `config/transport.config.json` via `ks-config` ;
|
||||||
- adaptation des réponses RPC vers les contrats canoniques ;
|
- adaptation des réponses RPC vers les contrats canoniques ;
|
||||||
- simulation, soumission et confirmation de transactions ;
|
- simulation, soumission et confirmation de transactions ;
|
||||||
- acquisition de signatures et transactions pour le backfill ;
|
- acquisition de signatures et transactions pour le backfill ;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: ks-onchain-transport/USAGE.md -->
|
<!-- file: ks-onchain-transport/USAGE.md -->
|
||||||
<!-- version: 6 -->
|
<!-- version: 7 -->
|
||||||
|
|
||||||
# Utilisation de ks-onchain-transport
|
# Utilisation de ks-onchain-transport
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ La crate expose les contrats publics nécessaires aux communications RPC HTTP et
|
|||||||
|
|
||||||
## Prérequis
|
## Prérequis
|
||||||
|
|
||||||
- une configuration `ks-config` contenant au moins un endpoint compatible ;
|
- un profil de transport `ks-config::TransportProfileConfig` contenant au moins un endpoint compatible ;
|
||||||
- un runtime Tokio pour les opérations asynchrones ;
|
- un runtime Tokio pour les opérations asynchrones ;
|
||||||
- des limites et engagements adaptés à l’opération demandée.
|
- des limites et engagements adaptés à l’opération demandée.
|
||||||
|
|
||||||
@@ -32,9 +32,9 @@ fn build_http_client(
|
|||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn select_query_client(
|
fn select_query_client(
|
||||||
profile: &ks_config::ProfileConfig,
|
profile: &ks_config::TransportProfileConfig,
|
||||||
) -> ks_core::Result<ks_onchain_transport::HttpClient> {
|
) -> ks_core::Result<ks_onchain_transport::HttpClient> {
|
||||||
let pool_result = ks_onchain_transport::HttpEndpointPool::from_profile(profile);
|
let pool_result = ks_onchain_transport::HttpEndpointPool::from_transport_profile(profile);
|
||||||
let pool = match pool_result {
|
let pool = match pool_result {
|
||||||
Ok(pool) => pool,
|
Ok(pool) => pool,
|
||||||
Err(error) => return Err(error),
|
Err(error) => return Err(error),
|
||||||
@@ -44,7 +44,7 @@ fn select_query_client(
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`HttpEndpointPool::snapshot` fournit un état sérialisable des endpoints actifs et de leurs rôles.
|
`HttpEndpointPool::snapshot` fournit un état sérialisable des endpoints actifs et de leurs rôles. Les constructeurs `from_profile` restent temporairement disponibles pour le contrat runtime `ProfileConfig` résolu pendant la migration `0.5.1`.
|
||||||
|
|
||||||
## Classer une méthode RPC
|
## Classer une méthode RPC
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: ks-onchain-transport/src/http_pool.rs
|
// file: ks-onchain-transport/src/http_pool.rs
|
||||||
// version: 9
|
// version: 10
|
||||||
|
|
||||||
//! HTTP endpoint pool and role-based routing.
|
//! HTTP endpoint pool and role-based routing.
|
||||||
|
|
||||||
@@ -11,10 +11,21 @@ pub struct HttpEndpointPool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl crate::HttpEndpointPool {
|
impl crate::HttpEndpointPool {
|
||||||
/// Builds a pool from the active profile HTTP endpoint list.
|
/// Builds a pool from an independently selected transport profile.
|
||||||
|
pub fn from_transport_profile(
|
||||||
|
profile: &ks_config::TransportProfileConfig,
|
||||||
|
) -> ks_core::Result<Self> {
|
||||||
|
return crate::HttpEndpointPool::from_http_endpoints(&profile.http_endpoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds a pool from the resolved application profile HTTP endpoint list.
|
||||||
pub fn from_profile(profile: &ks_config::ProfileConfig) -> ks_core::Result<Self> {
|
pub fn from_profile(profile: &ks_config::ProfileConfig) -> ks_core::Result<Self> {
|
||||||
|
return crate::HttpEndpointPool::from_http_endpoints(&profile.solana.http_endpoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_http_endpoints(endpoints: &[ks_config::HttpEndpointConfig]) -> ks_core::Result<Self> {
|
||||||
let mut clients = std::vec::Vec::new();
|
let mut clients = std::vec::Vec::new();
|
||||||
for endpoint in &profile.solana.http_endpoints {
|
for endpoint in endpoints {
|
||||||
if !endpoint.enabled {
|
if !endpoint.enabled {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -184,6 +195,26 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transport_profile_builds_http_pool_without_resolved_app_profile() {
|
||||||
|
let profile = ks_config::TransportProfileConfig {
|
||||||
|
name: "direct".to_string(),
|
||||||
|
http_endpoints: std::vec![endpoint(
|
||||||
|
"direct",
|
||||||
|
"http_queries",
|
||||||
|
std::vec!["get_version".to_string()],
|
||||||
|
)],
|
||||||
|
ws_endpoints: std::vec::Vec::new(),
|
||||||
|
};
|
||||||
|
let pool = match crate::HttpEndpointPool::from_transport_profile(&profile) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
panic!("transport profile pool creation failed: {error}")
|
||||||
|
},
|
||||||
|
};
|
||||||
|
assert_eq!(pool.snapshot().len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn new_rejects_empty_pool() {
|
fn new_rejects_empty_pool() {
|
||||||
let result = crate::HttpEndpointPool::new(std::vec::Vec::new());
|
let result = crate::HttpEndpointPool::new(std::vec::Vec::new());
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: ks-onchain-transport/src/ws_pool.rs
|
// file: ks-onchain-transport/src/ws_pool.rs
|
||||||
// version: 7
|
// version: 8
|
||||||
|
|
||||||
//! WebSocket endpoint pool and role-based routing.
|
//! WebSocket endpoint pool and role-based routing.
|
||||||
|
|
||||||
@@ -11,10 +11,21 @@ pub struct WsEndpointPool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl crate::WsEndpointPool {
|
impl crate::WsEndpointPool {
|
||||||
/// Builds a pool from the active profile WebSocket endpoint list.
|
/// Builds a pool from an independently selected transport profile.
|
||||||
|
pub fn from_transport_profile(
|
||||||
|
profile: &ks_config::TransportProfileConfig,
|
||||||
|
) -> ks_core::Result<Self> {
|
||||||
|
return crate::WsEndpointPool::from_ws_endpoints(&profile.ws_endpoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds a pool from the resolved application profile WebSocket endpoint list.
|
||||||
pub fn from_profile(profile: &ks_config::ProfileConfig) -> ks_core::Result<Self> {
|
pub fn from_profile(profile: &ks_config::ProfileConfig) -> ks_core::Result<Self> {
|
||||||
|
return crate::WsEndpointPool::from_ws_endpoints(&profile.solana.ws_endpoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_ws_endpoints(endpoints: &[ks_config::WsEndpointConfig]) -> ks_core::Result<Self> {
|
||||||
let mut clients = std::vec::Vec::new();
|
let mut clients = std::vec::Vec::new();
|
||||||
for endpoint in &profile.solana.ws_endpoints {
|
for endpoint in endpoints {
|
||||||
if !endpoint.enabled {
|
if !endpoint.enabled {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -164,6 +175,26 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transport_profile_builds_ws_pool_without_resolved_app_profile() {
|
||||||
|
let profile = ks_config::TransportProfileConfig {
|
||||||
|
name: "direct".to_string(),
|
||||||
|
http_endpoints: std::vec::Vec::new(),
|
||||||
|
ws_endpoints: std::vec![endpoint(
|
||||||
|
"direct",
|
||||||
|
"slot_notifications",
|
||||||
|
std::vec!["slot_subscribe".to_string()],
|
||||||
|
)],
|
||||||
|
};
|
||||||
|
let pool = match crate::WsEndpointPool::from_transport_profile(&profile) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
panic!("transport profile pool creation failed: {error}")
|
||||||
|
},
|
||||||
|
};
|
||||||
|
assert_eq!(pool.snapshot().len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn new_rejects_empty_pool() {
|
fn new_rejects_empty_pool() {
|
||||||
let result = crate::WsEndpointPool::new(std::vec::Vec::new());
|
let result = crate::WsEndpointPool::new(std::vec::Vec::new());
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
<!-- file: ks-pipeline-demo-scenarios/CHANGELOG.md -->
|
<!-- file: ks-pipeline-demo-scenarios/CHANGELOG.md -->
|
||||||
<!-- version: 76 -->
|
<!-- version: 77 -->
|
||||||
|
|
||||||
# CHANGELOG — ks-pipeline-demo-scenarios
|
# CHANGELOG — ks-pipeline-demo-scenarios
|
||||||
|
|
||||||
|
## `0.5.1-pre.006`
|
||||||
|
|
||||||
|
- remplace la dépendance runtime au document applicatif monolithique par `config/ks-pipeline-demo-scenarios.default.config.json` pour les scénarios Devnet opt-in ;
|
||||||
|
- résout la composition par `ks-config`, puis conserve le contrat `AppConfig/ProfileConfig` runtime existant afin de ne pas requalifier les scénarios réseau ;
|
||||||
|
- aligne les fixtures unitaires sur les snapshots runtime sous `test-fixtures/config/` plutôt que sur une configuration source de binaire.
|
||||||
|
|
||||||
## `0.5.1-pre.005`
|
## `0.5.1-pre.005`
|
||||||
|
|
||||||
- aligne les scénarios et fixtures sur `config/app.config.json` comme document général par défaut ;
|
- aligne les scénarios et fixtures sur `config/app.config.json` comme document général par défaut ;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: ks-pipeline-demo-scenarios/USAGE.md -->
|
<!-- file: ks-pipeline-demo-scenarios/USAGE.md -->
|
||||||
<!-- version: 29 -->
|
<!-- version: 30 -->
|
||||||
|
|
||||||
# Utilisation de ks-pipeline-demo-scenarios
|
# Utilisation de ks-pipeline-demo-scenarios
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ KS_SECRET_POSTGRES_TEST_URL='postgresql://…' \
|
|||||||
cargo test -p ks-pipeline-demo-scenarios optional_devnet_token_2022_metadata_campaign_from_env -- --nocapture
|
cargo test -p ks-pipeline-demo-scenarios optional_devnet_token_2022_metadata_campaign_from_env -- --nocapture
|
||||||
```
|
```
|
||||||
|
|
||||||
`KS_DEVNET_PROFILE` peut sélectionner explicitement le profil Devnet et `KS_DEVNET_CONFIG_PATH` peut remplacer `config/app.config.json`. Le profil doit utiliser un wallet persistant, autoriser les soumissions Devnet et respecter les plafonds de dépense et de frais.
|
`KS_DEVNET_PROFILE` peut sélectionner explicitement le profil Devnet et `KS_DEVNET_CONFIG_PATH` peut remplacer la composition `config/ks-pipeline-demo-scenarios.default.config.json`. La composition résout ensuite les profils transport/listeners et le profil runtime doit utiliser un wallet persistant, autoriser les soumissions Devnet et respecter les plafonds de dépense et de frais.
|
||||||
|
|
||||||
La sortie `TOKEN_2022_METADATA_FIXTURE` conserve le mint et la signature de préparation. Chaque ligne `TOKEN_2022_METADATA_STEP` conserve l’opération, la signature, le slot, la postcondition, le nombre de matérialisations et, pour `Emit`, la taille du `returnData`. La campagne de référence de `pre.012` a été exécutée avec succès et ses preuves sont conservées dans `SPL_TOKEN_2022_METADATA_DEVNET_VALIDATION_MATRIX.json` et dans le rapport `docs/validation/V0_4_8_METADATA_VALIDATION_REPORT.md` ; le rapport détaillé `pre.012` est archivé sous `olddocs/archivekbot3/docs/validation/`. Une nouvelle exécution produit de nouvelles transactions et ne remplace ces preuves qu’après validation explicite.
|
La sortie `TOKEN_2022_METADATA_FIXTURE` conserve le mint et la signature de préparation. Chaque ligne `TOKEN_2022_METADATA_STEP` conserve l’opération, la signature, le slot, la postcondition, le nombre de matérialisations et, pour `Emit`, la taille du `returnData`. La campagne de référence de `pre.012` a été exécutée avec succès et ses preuves sont conservées dans `SPL_TOKEN_2022_METADATA_DEVNET_VALIDATION_MATRIX.json` et dans le rapport `docs/validation/V0_4_8_METADATA_VALIDATION_REPORT.md` ; le rapport détaillé `pre.012` est archivé sous `olddocs/archivekbot3/docs/validation/`. Une nouvelle exécution produit de nouvelles transactions et ne remplace ces preuves qu’après validation explicite.
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: ks-pipeline-demo-scenarios/src/environment.rs
|
// file: ks-pipeline-demo-scenarios/src/environment.rs
|
||||||
// version: 5
|
// version: 6
|
||||||
|
|
||||||
//! Environment initialization for opt-in demonstration scenarios.
|
//! Environment initialization for opt-in demonstration scenarios.
|
||||||
|
|
||||||
@@ -151,8 +151,9 @@ pub async fn prepare_demo_devnet_profile_store(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
fn example_config() -> ks_config::AppConfig {
|
fn example_config() -> ks_config::AppConfig {
|
||||||
return match ks_config::parse_config_json(include_str!("../../config/app.config.json"))
|
return match ks_config::parse_config_json(include_str!(
|
||||||
{
|
"../../test-fixtures/config/resolved.app.config.json"
|
||||||
|
)) {
|
||||||
std::result::Result::Ok(value) => value,
|
std::result::Result::Ok(value) => value,
|
||||||
std::result::Result::Err(error) => panic!("example config parse failed: {error}"),
|
std::result::Result::Err(error) => panic!("example config parse failed: {error}"),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/collection_verify_campaign.rs
|
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/collection_verify_campaign.rs
|
||||||
// version: 4
|
// version: 5
|
||||||
|
|
||||||
//! Confirmed Devnet collection parent/member `Verify -> Unverify` campaign.
|
//! Confirmed Devnet collection parent/member `Verify -> Unverify` campaign.
|
||||||
|
|
||||||
@@ -648,13 +648,16 @@ mod tests {
|
|||||||
let path = std::path::PathBuf::from(value);
|
let path = std::path::PathBuf::from(value);
|
||||||
if path.is_absolute() { path } else { workspace_root.join(path) }
|
if path.is_absolute() { path } else { workspace_root.join(path) }
|
||||||
},
|
},
|
||||||
std::result::Result::Err(_) => workspace_root.join("config/app.config.json"),
|
std::result::Result::Err(_) => {
|
||||||
|
workspace_root.join("config/ks-pipeline-demo-scenarios.default.config.json")
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let config = ks_config::read_config_json_file_with_environment(
|
let composed = ks_config::read_composed_app_config_with_environment(
|
||||||
config_path.as_path(),
|
config_path.as_path(),
|
||||||
workspace_root,
|
workspace_root,
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
|
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
|
||||||
|
let config = composed.app_config;
|
||||||
let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
|
let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
|
||||||
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
|
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
|
||||||
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
|
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/create_mint_campaign.rs
|
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/create_mint_campaign.rs
|
||||||
// version: 12
|
// version: 13
|
||||||
|
|
||||||
//! Confirmed Devnet `Create -> Mint` campaign for one Metaplex asset family.
|
//! Confirmed Devnet `Create -> Mint` campaign for one Metaplex asset family.
|
||||||
|
|
||||||
@@ -813,13 +813,16 @@ mod tests {
|
|||||||
let path = std::path::PathBuf::from(value);
|
let path = std::path::PathBuf::from(value);
|
||||||
if path.is_absolute() { path } else { workspace_root.join(path) }
|
if path.is_absolute() { path } else { workspace_root.join(path) }
|
||||||
},
|
},
|
||||||
std::result::Result::Err(_) => workspace_root.join("config/app.config.json"),
|
std::result::Result::Err(_) => {
|
||||||
|
workspace_root.join("config/ks-pipeline-demo-scenarios.default.config.json")
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let config = ks_config::read_config_json_file_with_environment(
|
let composed = ks_config::read_composed_app_config_with_environment(
|
||||||
config_path.as_path(),
|
config_path.as_path(),
|
||||||
workspace_root,
|
workspace_root,
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
|
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
|
||||||
|
let config = composed.app_config;
|
||||||
let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
|
let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
|
||||||
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
|
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
|
||||||
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
|
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/devnet_execution.rs
|
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/devnet_execution.rs
|
||||||
// version: 20
|
// version: 21
|
||||||
|
|
||||||
//! Real Devnet simulation and submission for current Metaplex Token Metadata operations.
|
//! Real Devnet simulation and submission for current Metaplex Token Metadata operations.
|
||||||
|
|
||||||
@@ -1267,7 +1267,7 @@ fn validate_available_signers(
|
|||||||
mod tests {
|
mod tests {
|
||||||
fn example_devnet_profile() -> ks_config::ProfileConfig {
|
fn example_devnet_profile() -> ks_config::ProfileConfig {
|
||||||
let config = match ks_config::parse_config_json(include_str!(
|
let config = match ks_config::parse_config_json(include_str!(
|
||||||
"../../../../config/app.config.json"
|
"../../../../test-fixtures/config/resolved.app.config.json"
|
||||||
)) {
|
)) {
|
||||||
std::result::Result::Ok(value) => value,
|
std::result::Result::Ok(value) => value,
|
||||||
std::result::Result::Err(error) => panic!("example config parse failed: {error}"),
|
std::result::Result::Err(error) => panic!("example config parse failed: {error}"),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/escrow_campaign.rs
|
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/escrow_campaign.rs
|
||||||
// version: 4
|
// version: 5
|
||||||
|
|
||||||
//! Confirmed Devnet Token Owned Escrow campaign for current Metaplex escrow operations.
|
//! Confirmed Devnet Token Owned Escrow campaign for current Metaplex escrow operations.
|
||||||
|
|
||||||
@@ -973,13 +973,16 @@ mod tests {
|
|||||||
let path = std::path::PathBuf::from(value);
|
let path = std::path::PathBuf::from(value);
|
||||||
if path.is_absolute() { path } else { workspace_root.join(path) }
|
if path.is_absolute() { path } else { workspace_root.join(path) }
|
||||||
},
|
},
|
||||||
std::result::Result::Err(_) => workspace_root.join("config/app.config.json"),
|
std::result::Result::Err(_) => {
|
||||||
|
workspace_root.join("config/ks-pipeline-demo-scenarios.default.config.json")
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let config = ks_config::read_config_json_file_with_environment(
|
let composed = ks_config::read_composed_app_config_with_environment(
|
||||||
config_path.as_path(),
|
config_path.as_path(),
|
||||||
workspace_root,
|
workspace_root,
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
|
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
|
||||||
|
let config = composed.app_config;
|
||||||
let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
|
let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
|
||||||
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
|
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
|
||||||
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
|
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/maintenance_campaign.rs
|
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/maintenance_campaign.rs
|
||||||
// version: 6
|
// version: 7
|
||||||
|
|
||||||
//! Final bounded Devnet qualification campaign for current Metaplex maintenance operations.
|
//! Final bounded Devnet qualification campaign for current Metaplex maintenance operations.
|
||||||
|
|
||||||
@@ -577,13 +577,16 @@ mod tests {
|
|||||||
let path = std::path::PathBuf::from(value);
|
let path = std::path::PathBuf::from(value);
|
||||||
if path.is_absolute() { path } else { workspace_root.join(path) }
|
if path.is_absolute() { path } else { workspace_root.join(path) }
|
||||||
},
|
},
|
||||||
std::result::Result::Err(_) => workspace_root.join("config/app.config.json"),
|
std::result::Result::Err(_) => {
|
||||||
|
workspace_root.join("config/ks-pipeline-demo-scenarios.default.config.json")
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let config = ks_config::read_config_json_file_with_environment(
|
let composed = ks_config::read_composed_app_config_with_environment(
|
||||||
config_path.as_path(),
|
config_path.as_path(),
|
||||||
workspace_root,
|
workspace_root,
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
|
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
|
||||||
|
let config = composed.app_config;
|
||||||
let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
|
let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
|
||||||
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
|
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
|
||||||
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
|
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/pnft_lifecycle_campaign.rs
|
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/pnft_lifecycle_campaign.rs
|
||||||
// version: 6
|
// version: 7
|
||||||
|
|
||||||
//! Confirmed Devnet pNFT delegate, lock, unlock, revoke and transfer campaign.
|
//! Confirmed Devnet pNFT delegate, lock, unlock, revoke and transfer campaign.
|
||||||
|
|
||||||
@@ -1071,13 +1071,16 @@ mod tests {
|
|||||||
let path = std::path::PathBuf::from(value);
|
let path = std::path::PathBuf::from(value);
|
||||||
if path.is_absolute() { path } else { workspace_root.join(path) }
|
if path.is_absolute() { path } else { workspace_root.join(path) }
|
||||||
},
|
},
|
||||||
std::result::Result::Err(_) => workspace_root.join("config/app.config.json"),
|
std::result::Result::Err(_) => {
|
||||||
|
workspace_root.join("config/ks-pipeline-demo-scenarios.default.config.json")
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let config = ks_config::read_config_json_file_with_environment(
|
let composed = ks_config::read_composed_app_config_with_environment(
|
||||||
config_path.as_path(),
|
config_path.as_path(),
|
||||||
workspace_root,
|
workspace_root,
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
|
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
|
||||||
|
let config = composed.app_config;
|
||||||
let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
|
let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
|
||||||
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
|
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
|
||||||
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
|
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/print_burn_campaign.rs
|
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/print_burn_campaign.rs
|
||||||
// version: 7
|
// version: 8
|
||||||
|
|
||||||
//! Devnet printable master NFT `Print -> Burn` campaign.
|
//! Devnet printable master NFT `Print -> Burn` campaign.
|
||||||
|
|
||||||
@@ -1180,13 +1180,16 @@ mod tests {
|
|||||||
let path = std::path::PathBuf::from(value);
|
let path = std::path::PathBuf::from(value);
|
||||||
if path.is_absolute() { path } else { workspace_root.join(path) }
|
if path.is_absolute() { path } else { workspace_root.join(path) }
|
||||||
},
|
},
|
||||||
std::result::Result::Err(_) => workspace_root.join("config/app.config.json"),
|
std::result::Result::Err(_) => {
|
||||||
|
workspace_root.join("config/ks-pipeline-demo-scenarios.default.config.json")
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let config = ks_config::read_config_json_file_with_environment(
|
let composed = ks_config::read_composed_app_config_with_environment(
|
||||||
config_path.as_path(),
|
config_path.as_path(),
|
||||||
workspace_root,
|
workspace_root,
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
|
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
|
||||||
|
let config = composed.app_config;
|
||||||
let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
|
let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
|
||||||
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
|
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
|
||||||
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
|
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/use_campaign.rs
|
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/use_campaign.rs
|
||||||
// version: 4
|
// version: 5
|
||||||
|
|
||||||
//! Bounded Devnet availability probe for the current Metaplex `Use` surface.
|
//! Bounded Devnet availability probe for the current Metaplex `Use` surface.
|
||||||
|
|
||||||
@@ -425,13 +425,16 @@ mod tests {
|
|||||||
let path = std::path::PathBuf::from(value);
|
let path = std::path::PathBuf::from(value);
|
||||||
if path.is_absolute() { path } else { workspace_root.join(path) }
|
if path.is_absolute() { path } else { workspace_root.join(path) }
|
||||||
},
|
},
|
||||||
std::result::Result::Err(_) => workspace_root.join("config/app.config.json"),
|
std::result::Result::Err(_) => {
|
||||||
|
workspace_root.join("config/ks-pipeline-demo-scenarios.default.config.json")
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let config = ks_config::read_config_json_file_with_environment(
|
let composed = ks_config::read_composed_app_config_with_environment(
|
||||||
config_path.as_path(),
|
config_path.as_path(),
|
||||||
workspace_root,
|
workspace_root,
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
|
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
|
||||||
|
let config = composed.app_config;
|
||||||
let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
|
let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
|
||||||
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
|
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
|
||||||
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
|
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: ks-pipeline-demo-scenarios/src/solana.rs
|
// file: ks-pipeline-demo-scenarios/src/solana.rs
|
||||||
// version: 14
|
// version: 15
|
||||||
|
|
||||||
//! Devnet Solana execution orchestration with canonical post-validation.
|
//! Devnet Solana execution orchestration with canonical post-validation.
|
||||||
|
|
||||||
@@ -1224,11 +1224,12 @@ pub(crate) fn emit<O>(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
fn example_devnet_profile() -> ks_config::ProfileConfig {
|
fn example_devnet_profile() -> ks_config::ProfileConfig {
|
||||||
let config =
|
let config = match ks_config::parse_config_json(include_str!(
|
||||||
match ks_config::parse_config_json(include_str!("../../config/app.config.json")) {
|
"../../test-fixtures/config/resolved.app.config.json"
|
||||||
std::result::Result::Ok(value) => value,
|
)) {
|
||||||
std::result::Result::Err(error) => panic!("example config parse failed: {error}"),
|
std::result::Result::Ok(value) => value,
|
||||||
};
|
std::result::Result::Err(error) => panic!("example config parse failed: {error}"),
|
||||||
|
};
|
||||||
return match crate::resolve_demo_devnet_profile(&config, std::option::Option::None) {
|
return match crate::resolve_demo_devnet_profile(&config, std::option::Option::None) {
|
||||||
std::result::Result::Ok(profile) => profile,
|
std::result::Result::Ok(profile) => profile,
|
||||||
std::result::Result::Err(error) => panic!("Devnet profile resolution failed: {error}"),
|
std::result::Result::Err(error) => panic!("Devnet profile resolution failed: {error}"),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: ks-pipeline-demo-scenarios/src/spl/associated_token_account.rs
|
// file: ks-pipeline-demo-scenarios/src/spl/associated_token_account.rs
|
||||||
// version: 13
|
// version: 14
|
||||||
|
|
||||||
//! Devnet ATA execution with stateful and canonical post-validation.
|
//! Devnet ATA execution with stateful and canonical post-validation.
|
||||||
|
|
||||||
@@ -993,12 +993,12 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn example_devnet_profile() -> ks_config::ProfileConfig {
|
fn example_devnet_profile() -> ks_config::ProfileConfig {
|
||||||
let config =
|
let config = match ks_config::parse_config_json(include_str!(
|
||||||
match ks_config::parse_config_json(include_str!("../../../config/app.config.json"))
|
"../../../test-fixtures/config/resolved.app.config.json"
|
||||||
{
|
)) {
|
||||||
std::result::Result::Ok(value) => value,
|
std::result::Result::Ok(value) => value,
|
||||||
std::result::Result::Err(error) => panic!("example config parse failed: {error}"),
|
std::result::Result::Err(error) => panic!("example config parse failed: {error}"),
|
||||||
};
|
};
|
||||||
return match crate::resolve_demo_devnet_profile(&config, std::option::Option::None) {
|
return match crate::resolve_demo_devnet_profile(&config, std::option::Option::None) {
|
||||||
std::result::Result::Ok(profile) => profile,
|
std::result::Result::Ok(profile) => profile,
|
||||||
std::result::Result::Err(error) => panic!("Devnet profile resolution failed: {error}"),
|
std::result::Result::Err(error) => panic!("Devnet profile resolution failed: {error}"),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: ks-pipeline-demo-scenarios/src/spl/memo.rs
|
// file: ks-pipeline-demo-scenarios/src/spl/memo.rs
|
||||||
// version: 9
|
// version: 10
|
||||||
|
|
||||||
//! Devnet SPL Memo v4 execution with canonical post-validation.
|
//! Devnet SPL Memo v4 execution with canonical post-validation.
|
||||||
|
|
||||||
@@ -754,12 +754,12 @@ fn decode_completed(summary: &ks_pipeline::DecodeReplaySummary) -> bool {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
fn example_devnet_profile() -> ks_config::ProfileConfig {
|
fn example_devnet_profile() -> ks_config::ProfileConfig {
|
||||||
let config =
|
let config = match ks_config::parse_config_json(include_str!(
|
||||||
match ks_config::parse_config_json(include_str!("../../../config/app.config.json"))
|
"../../../test-fixtures/config/resolved.app.config.json"
|
||||||
{
|
)) {
|
||||||
std::result::Result::Ok(value) => value,
|
std::result::Result::Ok(value) => value,
|
||||||
std::result::Result::Err(error) => panic!("example config parse failed: {error}"),
|
std::result::Result::Err(error) => panic!("example config parse failed: {error}"),
|
||||||
};
|
};
|
||||||
return match crate::resolve_demo_devnet_profile(&config, std::option::Option::None) {
|
return match crate::resolve_demo_devnet_profile(&config, std::option::Option::None) {
|
||||||
std::result::Result::Ok(profile) => profile,
|
std::result::Result::Ok(profile) => profile,
|
||||||
std::result::Result::Err(error) => panic!("Devnet profile resolution failed: {error}"),
|
std::result::Result::Err(error) => panic!("Devnet profile resolution failed: {error}"),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: ks-pipeline-demo-scenarios/src/spl/token/execution.rs
|
// file: ks-pipeline-demo-scenarios/src/spl/token/execution.rs
|
||||||
// version: 13
|
// version: 14
|
||||||
|
|
||||||
//! Devnet classic SPL Token execution with stateful and canonical post-validation.
|
//! Devnet classic SPL Token execution with stateful and canonical post-validation.
|
||||||
|
|
||||||
@@ -975,7 +975,7 @@ pub(crate) fn decode_completed(summary: &ks_pipeline::DecodeReplaySummary) -> bo
|
|||||||
mod tests {
|
mod tests {
|
||||||
fn example_devnet_profile() -> ks_config::ProfileConfig {
|
fn example_devnet_profile() -> ks_config::ProfileConfig {
|
||||||
let config = match ks_config::parse_config_json(include_str!(
|
let config = match ks_config::parse_config_json(include_str!(
|
||||||
"../../../../config/app.config.json"
|
"../../../../test-fixtures/config/resolved.app.config.json"
|
||||||
)) {
|
)) {
|
||||||
std::result::Result::Ok(value) => value,
|
std::result::Result::Ok(value) => value,
|
||||||
std::result::Result::Err(error) => panic!("example config parse failed: {error}"),
|
std::result::Result::Err(error) => panic!("example config parse failed: {error}"),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: ks-pipeline-demo-scenarios/src/spl/token/lifecycle.rs
|
// file: ks-pipeline-demo-scenarios/src/spl/token/lifecycle.rs
|
||||||
// version: 12
|
// version: 13
|
||||||
|
|
||||||
//! Controlled Devnet lifecycle for freshly prepared classic SPL Token accounts.
|
//! Controlled Devnet lifecycle for freshly prepared classic SPL Token accounts.
|
||||||
|
|
||||||
@@ -1688,7 +1688,7 @@ mod tests {
|
|||||||
|
|
||||||
fn example_devnet_profile() -> ks_config::ProfileConfig {
|
fn example_devnet_profile() -> ks_config::ProfileConfig {
|
||||||
let config = match ks_config::parse_config_json(include_str!(
|
let config = match ks_config::parse_config_json(include_str!(
|
||||||
"../../../../config/app.config.json"
|
"../../../../test-fixtures/config/resolved.app.config.json"
|
||||||
)) {
|
)) {
|
||||||
std::result::Result::Ok(value) => value,
|
std::result::Result::Ok(value) => value,
|
||||||
std::result::Result::Err(error) => panic!("example config parse failed: {error}"),
|
std::result::Result::Err(error) => panic!("example config parse failed: {error}"),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: ks-pipeline-demo-scenarios/src/spl/token_2022/metadata/campaign.rs
|
// file: ks-pipeline-demo-scenarios/src/spl/token_2022/metadata/campaign.rs
|
||||||
// version: 7
|
// version: 8
|
||||||
|
|
||||||
//! Ordered confirmed Devnet campaign for the five Token-2022 Token Metadata instructions.
|
//! Ordered confirmed Devnet campaign for the five Token-2022 Token Metadata instructions.
|
||||||
|
|
||||||
@@ -502,13 +502,16 @@ mod tests {
|
|||||||
let path = std::path::PathBuf::from(value);
|
let path = std::path::PathBuf::from(value);
|
||||||
if path.is_absolute() { path } else { workspace_root.join(path) }
|
if path.is_absolute() { path } else { workspace_root.join(path) }
|
||||||
},
|
},
|
||||||
std::result::Result::Err(_) => workspace_root.join("config/app.config.json"),
|
std::result::Result::Err(_) => {
|
||||||
|
workspace_root.join("config/ks-pipeline-demo-scenarios.default.config.json")
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let config = ks_config::read_config_json_file_with_environment(
|
let composed = ks_config::read_composed_app_config_with_environment(
|
||||||
config_path.as_path(),
|
config_path.as_path(),
|
||||||
workspace_root,
|
workspace_root,
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
|
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
|
||||||
|
let config = composed.app_config;
|
||||||
let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
|
let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
|
||||||
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
|
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
|
||||||
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
|
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
<!-- file: ks-pipeline/CHANGELOG.md -->
|
<!-- file: ks-pipeline/CHANGELOG.md -->
|
||||||
<!-- version: 34 -->
|
<!-- version: 35 -->
|
||||||
|
|
||||||
# CHANGELOG — ks-pipeline
|
# CHANGELOG — ks-pipeline
|
||||||
|
|
||||||
|
## `0.5.1-pre.006`
|
||||||
|
|
||||||
|
- déplace ses fixtures de configuration vers le contrat runtime résolu sous `test-fixtures/config/` ;
|
||||||
|
- ne modifie aucune orchestration ou qualification réseau.
|
||||||
|
|
||||||
## `0.5.1-pre.005`
|
## `0.5.1-pre.005`
|
||||||
|
|
||||||
- aligne les tests de configuration sur le nouveau document général `config/app.config.json` après extraction du logging ;
|
- aligne les tests de configuration sur le nouveau document général `config/app.config.json` après extraction du logging ;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: ks-pipeline/src/spl_token_stateful.rs
|
// file: ks-pipeline/src/spl_token_stateful.rs
|
||||||
// version: 5
|
// version: 6
|
||||||
|
|
||||||
//! Stateful Localnet and Devnet readiness checks for classic SPL Token operations.
|
//! Stateful Localnet and Devnet readiness checks for classic SPL Token operations.
|
||||||
|
|
||||||
@@ -1439,11 +1439,12 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn local_devnet_profile() -> ks_config::ProfileConfig {
|
fn local_devnet_profile() -> ks_config::ProfileConfig {
|
||||||
let config =
|
let config = match ks_config::parse_config_json(include_str!(
|
||||||
match ks_config::parse_config_json(include_str!("../../config/app.config.json")) {
|
"../../test-fixtures/config/resolved.app.config.json"
|
||||||
std::result::Result::Ok(value) => value,
|
)) {
|
||||||
std::result::Result::Err(error) => panic!("example config parse failed: {error}"),
|
std::result::Result::Ok(value) => value,
|
||||||
};
|
std::result::Result::Err(error) => panic!("example config parse failed: {error}"),
|
||||||
|
};
|
||||||
for profile in config.profiles {
|
for profile in config.profiles {
|
||||||
if profile.name == "local_devnet" {
|
if profile.name == "local_devnet" {
|
||||||
return profile;
|
return profile;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: prompts/030_v0_5_1_khadhroony_solana_namespace_and_config.md -->
|
<!-- file: prompts/030_v0_5_1_khadhroony_solana_namespace_and_config.md -->
|
||||||
<!-- version: 4 -->
|
<!-- version: 5 -->
|
||||||
|
|
||||||
# Khadhroony Bot3 — `0.5.1` — migration Khadhroony Solana et configuration sûre
|
# Khadhroony Bot3 — `0.5.1` — migration Khadhroony Solana et configuration sûre
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ Le workspace, le dépôt et le répertoire racine restent nommés `khadhroony-bo
|
|||||||
- `VERSION_DEVELOPMENT_LIFECYCLE.md` ;
|
- `VERSION_DEVELOPMENT_LIFECYCLE.md` ;
|
||||||
4. `docs/architecture/PROJECT_OBJECTIVES.md`, `CRATE_MAP.md`, `ARCHITECTURE.md`, `PIPELINE_ARCHITECTURE.md`, `STORAGE_ARCHITECTURE.md` et `SURFACE_CRATE_MATRIX.md` ;
|
4. `docs/architecture/PROJECT_OBJECTIVES.md`, `CRATE_MAP.md`, `ARCHITECTURE.md`, `PIPELINE_ARCHITECTURE.md`, `STORAGE_ARCHITECTURE.md` et `SURFACE_CRATE_MATRIX.md` ;
|
||||||
5. `README.md`, `USAGE.md`, `TODO.md` et `CHANGELOG.md` des dix crates à renommer et de `kb-app-demo-desktop` ;
|
5. `README.md`, `USAGE.md`, `TODO.md` et `CHANGELOG.md` des dix crates à renommer et de `kb-app-demo-desktop` ;
|
||||||
6. `config/app.config.json`, `config/logging.config.json`, leurs schémas sous `config/schemas/`, `.env.example` et tous les exemples/configurations de test ;
|
6. les compositions `config/<binary>.default.config.json`, les documents partagés `logging.config.json`, `transport.config.json`, `listeners.config.json`, leurs schémas sous `config/schemas/`, `.env.example` et les fixtures runtime sous `test-fixtures/config/` ;
|
||||||
7. les tests d'API externe, tests TS-RS, scripts d'audit et références de noms de crates/targets/identités ;
|
7. les tests d'API externe, tests TS-RS, scripts d'audit et références de noms de crates/targets/identités ;
|
||||||
8. les documents archivés `0.5.0` uniquement comme historique, jamais comme source prioritaire face à la politique active et au code courant.
|
8. les documents archivés `0.5.0` uniquement comme historique, jamais comme source prioritaire face à la politique active et au code courant.
|
||||||
|
|
||||||
@@ -329,12 +329,27 @@ Le détail doit être confirmé par `0.5.1-pre.001`, mais la trajectoire cible e
|
|||||||
|
|
||||||
### `0.5.1-pre.005` — split configuration/logging
|
### `0.5.1-pre.005` — split configuration/logging
|
||||||
|
|
||||||
- documents et schémas indépendants ;
|
- extraire le logging dans son document et son schéma indépendants ;
|
||||||
- profils logging indépendants ;
|
- rendre les profils logging indépendants ;
|
||||||
- propriété unique des contrats logging ;
|
- transférer la propriété des contrats logging à `ks-logging`.
|
||||||
- migration/compatibilité explicite du document monolithique précédent.
|
|
||||||
|
|
||||||
### `0.5.1-pre.006` — runtime/public, camouflage et Tauri sûr
|
### `0.5.1-pre.006` — composition binaire + transport + listeners
|
||||||
|
|
||||||
|
- remplacer le rôle du document monolithique par des compositions `<binary>.default.config.json` ;
|
||||||
|
- fournir une composition dédiée au desktop et une composition dédiée aux scénarios ;
|
||||||
|
- extraire transport et listeners dans des documents/schémas indépendants ;
|
||||||
|
- conserver `AppConfig/ProfileConfig` comme contrat runtime résolu transitoire ;
|
||||||
|
- permettre aux transports de consommer directement `TransportProfileConfig`.
|
||||||
|
|
||||||
|
### `0.5.1-pre.007` — store + wallet + execution + configuration dédiée des binaires
|
||||||
|
|
||||||
|
- extraire database vers store, `logs_directory` vers logging et les chemins de wallets vers wallet selon leur ownership réel ;
|
||||||
|
- déplacer les permissions `*_send_enabled` du wallet vers execution ;
|
||||||
|
- sortir la configuration spécifique au desktop du domaine `ks-config` ;
|
||||||
|
- réduire les compositions à des références vers profils spécialisés et configuration dédiée ;
|
||||||
|
- vérifier qu'un futur worker peut ajouter sa propre composition sans enregistrer son identité dans `ks-config`.
|
||||||
|
|
||||||
|
### `0.5.1-pre.008` — runtime/public, camouflage et Tauri sûr
|
||||||
|
|
||||||
- séparer source/runtime/public/diagnostic ;
|
- séparer source/runtime/public/diagnostic ;
|
||||||
- propager la sensibilité des valeurs composées ;
|
- propager la sensibilité des valeurs composées ;
|
||||||
@@ -342,9 +357,9 @@ Le détail doit être confirmé par `0.5.1-pre.001`, mais la trajectoire cible e
|
|||||||
- diagnostics sûrs et camouflage systématique ;
|
- diagnostics sûrs et camouflage systématique ;
|
||||||
- tests de non-divulgation et TS-RS aligné.
|
- tests de non-divulgation et TS-RS aligné.
|
||||||
|
|
||||||
### `0.5.1-pre.007` — réconciliation et clôture
|
### `0.5.1-pre.009` — réconciliation et clôture
|
||||||
|
|
||||||
- audit exhaustif des anciens préfixes ;
|
- audit exhaustif des anciens préfixes et anciens documents ;
|
||||||
- documentation finale ;
|
- documentation finale ;
|
||||||
- TODO/changelogs ;
|
- TODO/changelogs ;
|
||||||
- validations workspace ;
|
- validations workspace ;
|
||||||
|
|||||||
125
scripts/audit_khadhroony_workspace_rules.py
Executable file → Normal file
125
scripts/audit_khadhroony_workspace_rules.py
Executable file → Normal file
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# file: scripts/audit_khadhroony_workspace_rules.py
|
# file: scripts/audit_khadhroony_workspace_rules.py
|
||||||
# version: 21
|
# version: 22
|
||||||
|
|
||||||
"""Audit mechanically verifiable rules specific to khadhroony-bot3."""
|
"""Audit mechanically verifiable rules specific to khadhroony-bot3."""
|
||||||
|
|
||||||
@@ -908,10 +908,15 @@ def audit_environment_namespaces(root: pathlib.Path) -> list[Violation]:
|
|||||||
)
|
)
|
||||||
placeholder = re.compile(r"\$\{([A-Z][A-Z0-9_]*)")
|
placeholder = re.compile(r"\$\{([A-Z][A-Z0-9_]*)")
|
||||||
for relative in [
|
for relative in [
|
||||||
"config/app.config.json",
|
"config/kb-app-demo-desktop.default.config.json",
|
||||||
|
"config/ks-pipeline-demo-scenarios.default.config.json",
|
||||||
"config/logging.config.json",
|
"config/logging.config.json",
|
||||||
"config/example.app.config.json",
|
"config/transport.config.json",
|
||||||
|
"config/listeners.config.json",
|
||||||
|
"config/example.kb-app-demo-desktop.default.config.json",
|
||||||
"config/example.logging.config.json",
|
"config/example.logging.config.json",
|
||||||
|
"config/example.transport.config.json",
|
||||||
|
"config/example.listeners.config.json",
|
||||||
]:
|
]:
|
||||||
config = root / relative
|
config = root / relative
|
||||||
if not config.is_file():
|
if not config.is_file():
|
||||||
@@ -949,16 +954,24 @@ def audit_environment_namespaces(root: pathlib.Path) -> list[Violation]:
|
|||||||
|
|
||||||
|
|
||||||
def audit_configuration_split(root: pathlib.Path) -> list[Violation]:
|
def audit_configuration_split(root: pathlib.Path) -> list[Violation]:
|
||||||
"""Require the independent application and logging configuration contract."""
|
"""Require binary composition plus independent shared configuration documents."""
|
||||||
|
|
||||||
violations: list[Violation] = []
|
violations: list[Violation] = []
|
||||||
required_files = [
|
required_files = [
|
||||||
"config/app.config.json",
|
"config/kb-app-demo-desktop.default.config.json",
|
||||||
|
"config/ks-pipeline-demo-scenarios.default.config.json",
|
||||||
"config/logging.config.json",
|
"config/logging.config.json",
|
||||||
"config/example.app.config.json",
|
"config/transport.config.json",
|
||||||
|
"config/listeners.config.json",
|
||||||
|
"config/example.kb-app-demo-desktop.default.config.json",
|
||||||
"config/example.logging.config.json",
|
"config/example.logging.config.json",
|
||||||
"config/schemas/app.config.schema.json",
|
"config/example.transport.config.json",
|
||||||
|
"config/example.listeners.config.json",
|
||||||
|
"config/schemas/composition.config.schema.json",
|
||||||
"config/schemas/logging.config.schema.json",
|
"config/schemas/logging.config.schema.json",
|
||||||
|
"config/schemas/transport.config.schema.json",
|
||||||
|
"config/schemas/listeners.config.schema.json",
|
||||||
|
"config/schemas/resolved.app.config.schema.json",
|
||||||
]
|
]
|
||||||
for relative in required_files:
|
for relative in required_files:
|
||||||
if (root / relative).is_file():
|
if (root / relative).is_file():
|
||||||
@@ -971,58 +984,82 @@ def audit_configuration_split(root: pathlib.Path) -> list[Violation]:
|
|||||||
"required split configuration file is missing",
|
"required split configuration file is missing",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
app_path = root / "config/app.config.json"
|
composition_paths = [
|
||||||
if app_path.is_file():
|
"config/kb-app-demo-desktop.default.config.json",
|
||||||
|
"config/ks-pipeline-demo-scenarios.default.config.json",
|
||||||
|
]
|
||||||
|
for relative in composition_paths:
|
||||||
|
path = root / relative
|
||||||
|
if not path.is_file():
|
||||||
|
continue
|
||||||
try:
|
try:
|
||||||
app = json.loads(app_path.read_text(encoding="utf-8"))
|
composition = json.loads(path.read_text(encoding="utf-8"))
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
app = None
|
composition = None
|
||||||
if isinstance(app, dict):
|
if not isinstance(composition, dict):
|
||||||
for index, profile in enumerate(app.get("profiles", []), 1):
|
continue
|
||||||
if isinstance(profile, dict) and "logging" in profile:
|
sources = composition.get("sources")
|
||||||
violations.append(
|
if not isinstance(sources, dict) or set(sources) != {"logging", "transport", "listeners"}:
|
||||||
Violation(
|
violations.append(
|
||||||
"KH_CFG002",
|
Violation(
|
||||||
"config/app.config.json",
|
"KH_CFG002",
|
||||||
index,
|
relative,
|
||||||
"application profiles must not embed logging configuration",
|
1,
|
||||||
)
|
"binary composition must reference logging, transport and listeners sources",
|
||||||
)
|
)
|
||||||
logging_path = root / "config/logging.config.json"
|
)
|
||||||
if logging_path.is_file():
|
for index, profile in enumerate(composition.get("profiles", []), 1):
|
||||||
try:
|
if not isinstance(profile, dict):
|
||||||
logging = json.loads(logging_path.read_text(encoding="utf-8"))
|
continue
|
||||||
except json.JSONDecodeError:
|
if "solana" in profile or "logging" in profile:
|
||||||
logging = None
|
|
||||||
if isinstance(logging, dict):
|
|
||||||
if not isinstance(logging.get("active_profile"), str):
|
|
||||||
violations.append(
|
violations.append(
|
||||||
Violation(
|
Violation(
|
||||||
"KH_CFG003",
|
"KH_CFG003",
|
||||||
"config/logging.config.json",
|
relative,
|
||||||
1,
|
index,
|
||||||
"logging configuration must define its own active_profile",
|
"composition profiles must reference transport/listener/logging profiles instead of embedding them",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if not isinstance(logging.get("profiles"), list) or not logging.get("profiles"):
|
for key in ["logging_profile", "transport_profile", "listeners_profile"]:
|
||||||
violations.append(
|
if not isinstance(profile.get(key), str) or not profile.get(key, "").strip():
|
||||||
Violation(
|
violations.append(
|
||||||
"KH_CFG004",
|
Violation(
|
||||||
"config/logging.config.json",
|
"KH_CFG004",
|
||||||
1,
|
relative,
|
||||||
"logging configuration must define independent named profiles",
|
index,
|
||||||
|
f"composition profile must define non-empty `{key}`",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
for relative in ["config/logging.config.json", "config/transport.config.json", "config/listeners.config.json"]:
|
||||||
legacy = ["config/example.config.json", "config/schema.config.json"]
|
path = root / relative
|
||||||
|
if not path.is_file():
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
document = json.loads(path.read_text(encoding="utf-8"))
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
document = None
|
||||||
|
if not isinstance(document, dict):
|
||||||
|
continue
|
||||||
|
if not isinstance(document.get("active_profile"), str):
|
||||||
|
violations.append(Violation("KH_CFG005", relative, 1, "shared configuration document must define active_profile"))
|
||||||
|
if not isinstance(document.get("profiles"), list) or not document.get("profiles"):
|
||||||
|
violations.append(Violation("KH_CFG006", relative, 1, "shared configuration document must define named profiles"))
|
||||||
|
legacy = [
|
||||||
|
"config/app.config.json",
|
||||||
|
"config/example.app.config.json",
|
||||||
|
"config/schemas/app.config.schema.json",
|
||||||
|
"config/example.config.json",
|
||||||
|
"config/schema.config.json",
|
||||||
|
]
|
||||||
for relative in legacy:
|
for relative in legacy:
|
||||||
if not (root / relative).exists():
|
if not (root / relative).exists():
|
||||||
continue
|
continue
|
||||||
violations.append(
|
violations.append(
|
||||||
Violation(
|
Violation(
|
||||||
"KH_CFG005",
|
"KH_CFG007",
|
||||||
relative,
|
relative,
|
||||||
1,
|
1,
|
||||||
"legacy combined configuration file must be removed after the split",
|
"legacy monolithic application configuration file must be removed",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return violations
|
return violations
|
||||||
|
|||||||
1110
test-fixtures/config/resolved.app.config.json
Normal file
1110
test-fixtures/config/resolved.app.config.json
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user