Los argumentos inyectados
Hay argumentos que el frontend no envía: los pone el framework. Cuáles son, cómo los reconoce —por su tipo y no por su nombre—, y por qué esa distinción es una frontera de confianza y no una comodidad.
Las dos clases
#[tauri::command]async fn guardar_proyecto( app: tauri::AppHandle, // inyectado window: tauri::WebviewWindow, // inyectado estado: tauri::State<'_, Sesion>, // inyectado id: ProyectoId, // del frontend contenido: String, // del frontend) -> Result<(), ErrorPayload> { … }Y la llamada correspondiente solo manda los dos últimos:
await invoke('guardar_proyecto', { id, contenido });La regla que lo gobierna: el framework mira los tipos. Si un argumento es de uno de los tipos que sabe inyectar, lo pone él; todo lo demás lo busca en el mensaje. No depende del nombre del parámetro, ni del orden, ni de ninguna anotación.
De ahí una consecuencia práctica: puedes ponerlos en el orden que quieras y llamarlos como quieras. La convención habitual es ponerlos primero y usar los nombres del tipo, para que se lea de un vistazo qué parte de la firma es contrato con el frontend y qué parte es contexto.
Qué se puede inyectar
El caso del canal es el más curioso: se declara como argumento inyectado y en realidad lo crea el frontend. Lo verás en el nivel 21; hasta entonces basta con saber que existe.
Por qué inyectar la ventana es una frontera
Es el punto del nivel y merece detenerse. Compara estas dos firmas:
// A · el frontend dice qué ventana es#[tauri::command]async fn cerrar_esta(app: tauri::AppHandle, etiqueta: String) -> Result<(), ErrorPayload> { if let Some(w) = app.get_webview_window(&etiqueta) { w.close()?; } Ok(())}// B · el framework dice qué ventana es#[tauri::command]async fn cerrar_esta(window: tauri::WebviewWindow) -> Result<(), ErrorPayload> { Ok(window.close()?)}Las dos hacen lo mismo cuando todo va bien. La diferencia aparece cuando algo va mal: en la primera, cualquier código que se ejecute en cualquier ventana puede cerrar cualquier otra, porque la etiqueta es un dato que el frontend elige. En la segunda no puede: el framework sabe de dónde vino el mensaje y no acepta discusión.
Es exactamente el criterio del nivel 14.4 —operaciones, no mecanismos— aplicado a la identidad: si el frontend puede decir quién es, no es identidad, es una sugerencia.
Lo que cuesta usarlos
Poco, y hay dos detalles que aparecen enseguida:
El estado lleva un tiempo de vida en la firma. Se escribe con un guion bajo y el compilador lo resuelve; en un comando asíncrono es obligatorio y su ausencia produce un error que no menciona comandos. Es el nivel 16.2.
El manejador de la aplicación se puede clonar y llevar a otro hilo. Esa es su gracia y la razón de que sea el argumento más útil de los tres: una tarea de fondo que necesite emitir un evento o leer una ruta se lleva una copia. Nivel 16.3.