Tutti i playbookNative Utility

Aggiungere un comando nativo

Esporre alla UI un'operazione Rust rapida tramite app-api, un comando Tauri con il suo permesso e il client nativo, con tipi generati e test da entrambe le parti.

Quando usarlo

La UI ha bisogno di una risposta immediata dal core Rust, per esempio la dimensione del database locale o i dettagli di un file scelto. I passi usano come esempio un comando storage_info. Il lavoro che può durare più di un istante (leggere un albero di cartelle, rete, dispositivi) è un job: vedi il playbook "Aggiungere un job handler".

Regole da rispettare

  • Il percorso è sempre UI → packages/native-client → comando Tauri → crates/app-api → crate del core. Il comando chiama un solo metodo di AppApi; nessuna logica in apps/desktop/src-tauri.
  • Ogni comando ha bisogno del proprio permesso in apps/desktop/src-tauri/capabilities/main-window.json. Niente permessi globali o wildcard.
  • I tipi attraversano il confine come DTO di crates/app-api/src/dto.rs; le versioni TypeScript sono generate, mai scritte a mano.
  • Gli errori sono valori ApiError con un codice RW_* stabile, mai frasi. È la UI a tradurre il codice.
  • Un percorso che arriva dalla UI passa da validate_path prima di essere usato.

Passi

  1. Aggiungi il DTO in crates/app-api/src/dto.rs con gli stessi derive e attributi degli altri (Serialize, Deserialize, il cfg_attr di ts-export e rename_all = "camelCase"). Marca i campi u64 con ts(type = "number") come fa JobDto:

    #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
    #[cfg_attr(feature = "ts-export", derive(TS), ts(export))]
    #[serde(rename_all = "camelCase")]
    pub struct StorageInfoDto {
        pub data_dir: String,
        #[cfg_attr(feature = "ts-export", ts(type = "number"))]
        pub database_bytes: u64,
    }
    
  2. Aggiungi il metodo ad AppApi in crates/app-api/src/api.rs, che restituisce Result<StorageInfoDto, ApiError>. Costruisci gli errori con ApiError::new("RW_...", category, recoverable) e controlla i moduli disattivati come fanno i metodi esistenti. Testalo in crates/app-api/tests/api.rs con l'helper api(config()), compreso il caso di errore.

  3. Esegui pnpm types:generate, esporta il nuovo tipo da packages/shared-types/src/index.ts e fai commit dei file in packages/shared-types/src/generated. pnpm types:check fallisce se non sono aggiornati.

  4. Aggiungi il comando nel file corrispondente di apps/desktop/src-tauri/src/commands/ (qui filesystem.rs), sul modello di validate_path: riceve State<'_> e gli argomenti e restituisce state.api.storage_info(). Registralo in generate_handler! in src-tauri/src/main.rs, dichiara "storage_info" in build.rs e concedi "allow-storage-info" in capabilities/main-window.json.

  5. Aggiungi il metodo all'interfaccia NativeClient in packages/native-client/src/client.ts, a TauriNativeClient in tauri.ts (call<StorageInfoDto>("storage_info"); gli argomenti JavaScript sono in camelCase e Tauri li converte in snake_case) e a MockNativeClient in mock.ts con dati realistici e gli scenari di errore. Testa il mock in mock.test.ts.

  6. Leggilo nella UI con un hook in apps/desktop/src/features/<feature>/hooks/, come useFeatures: useQuery con una chiave stabile e useNativeClient(). Mostra gli errori con i18n.error.

  7. Aggiungi ogni nuovo codice RW_* in packages/i18n/locales/*/errors.json e ogni testo della UI in common.json, in de-DE, en e it-IT. Controlla il layout in tedesco.

  8. Elenca il comando in docs/tauri-bridge.md.

Completato quando

  • i comandi di verifica superano e pnpm types:check non segnala differenze;
  • il comando ha esattamente una voce allow-<nome> nella capability ed è registrato in main.rs e build.rs;
  • il mock implementa il metodo, così pnpm dev funziona senza il core Rust;
  • ogni nuovo codice e testo esiste nelle tre lingue.