new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Tauri · Develop · all subjects

ipc/commands

98 notes in this subject, read out of this brain and free to use. This is page 2 of 2.

Migrate HTTP plugin: Rust setup

Add `tauri-plugin-http = "2"` to Cargo.toml. Initialize with `.plugin(tauri_plugin_http::init())`. The plugin reexports reqwest, so use `tauri_plugin_http::reqwest` in async context via `tauri::async_runtime::block_on`.

Migrate HTTP plugin: JavaScript setup

Add `@tauri-apps/plugin-http` to package.json. Initialize in Rust with `tauri_plugin_http::init()`. Use JavaScript: `import { fetch } from '@tauri-apps/plugin-http'` and call `const response = await fetch('https://...')`.

Migrate Notification plugin: Rust setup

Add `tauri-plugin-notification = "2"` to Cargo.toml. Initialize with `.plugin(tauri_plugin_notification::init())`. In setup, check permission state with `app.notification().permission_state()` and send notifications with `app.notification().builder().body().show()` using the `NotificationExt` trait.

Migrate Notification plugin: JavaScript setup

Add `@tauri-apps/plugin-notification` to package.json. Initialize in Rust with `tauri_plugin_notification::init()`. Use JavaScript: `import { sendNotification } from '@tauri-apps/plugin-notification'` and call `sendNotification('message')`.

Migrate OS plugin: Rust setup

Add `tauri-plugin-os = "2"` to Cargo.toml. Initialize with `.plugin(tauri_plugin_os::init())`. In setup, call functions directly like `tauri_plugin_os::arch()`.

Migrate OS plugin: JavaScript setup

Add `@tauri-apps/plugin-os` to package.json. Initialize in Rust with `tauri_plugin_os::init()`. Use JavaScript: `import { arch } from '@tauri-apps/plugin-os'` and call `const architecture = await arch()`.

Migrate Process plugin: Rust setup

Add `tauri-plugin-process = "2"` to Cargo.toml. Initialize with `.plugin(tauri_plugin_process::init())`. In setup, use `app.handle().exit(code)` to exit the app or `app.handle().restart()` to restart.

Migrate Process plugin: JavaScript setup

Add `@tauri-apps/plugin-process` to package.json. Initialize in Rust with `tauri_plugin_process::init()`. Use JavaScript: `import { exit, relaunch } from '@tauri-apps/plugin-process'` and call `await exit(0)` or `await relaunch()`.

Tauri command definition with #[tauri::command] attribute

Commands are Rust functions that can be invoked from JavaScript. To define a command, add a function and annotate it with the #[tauri::command] attribute. Commands can accept arguments, return values, return errors, and be asynchronous.

Command names must be unique across entire application

Command names must be unique. They are not scoped to modules, so command names must be unique across all modules in the application.

Commands in lib.rs cannot be public (pub) functions

Commands defined in the lib.rs file cannot be specified as pub (public) due to glue code generation constraints. Attempting to make them public results in error E0255 indicating that __cmd__command_name is defined multiple times. Commands must be defined without the pub keyword in lib.rs.

Register commands with tauri::generate_handler! macro

Commands must be provided to the builder function's invoke_handler using tauri::generate_handler![command_name]. Multiple commands are passed as a comma-separated list to a single generate_handler call.

Invoke command from JavaScript using invoke function

Commands are called from JavaScript using the invoke() function from '@tauri-apps/api/core'. For example: invoke('my_custom_command'). Alternatively, use const invoke = window.__TAURI__.core.invoke when not using npm packages, but require app.withGlobalTauri to be true in tauri.conf.json.

Define commands in separate modules

Commands can be defined in separate modules like src-tauri/src/commands.rs to avoid cluttering lib.rs. Commands defined in separate modules must be marked as pub (public). In lib.rs, declare the module with mod commands; and register commands using .invoke_handler(tauri::generate_handler![commands::my_custom_command]). The module prefix commands:: specifies the full path but is not included in the command name invoked from frontend.

WASM frontend calling commands without arguments

When using a Rust frontend with WebAssembly and calling invoke() without arguments, declare two separate functions using wasm_bindgen: one for calling without arguments (#[wasm_bindgen(js_namespace = ["window", "__TAURI__", "core"], js_name = invoke)] async fn invoke_without_args(cmd: &str)) and one for calling with arguments. The two functions must have different names because Rust does not support optional arguments.

Pass command arguments as camelCase JSON object

Command arguments must be passed as a JSON object with camelCase keys. For example: invoke('my_custom_command', { invokeMessage: 'Hello!' }). Arguments can be any type implementing serde::Deserialize.

Use rename_all attribute for snake_case arguments

The #[tauri::command(rename_all = "snake_case")] attribute allows command arguments to use snake_case instead of camelCase. When applied, frontend must call with snake_case keys: invoke('my_custom_command', { invoke_message: 'Hello!' }).

Return data from commands

Commands can return data by specifying a return type. The returned data must implement serde::Serialize. The invoke function returns a promise that resolves with the return value. Example: invoke('my_custom_command').then((message) => console.log(message)).

Return array buffers from Tauri commands using tauri::ipc::Response

To return large data like files or downloads efficiently without JSON serialization overhead, use tauri::ipc::Response. Example: use tauri::ipc::Response; #[tauri::command] fn read_file() -> Response { let data = std::fs::read("/path/to/file").unwrap(); tauri::ipc::Response::new(data) }

Error handling in commands using Result type

Commands can return errors by using Result<SuccessType, ErrorType>. When a command returns an error, the JavaScript promise rejects. When successful, it resolves. Example: fn login(user: String, password: String) -> Result<String, String> { if user == "tauri" && password == "tauri" { Ok("logged_in".to_string()) } else { Err("invalid credentials".to_string()) } }

All returned error types must implement serde::Serialize

Error types returned from commands must implement serde::Serialize. Standard library and external crate error types often do not implement this trait. Use map_err to convert errors to String, or create a custom error type implementing both thiserror::Error and serde::Serialize.

Create custom error types with thiserror and serde

Use the thiserror crate to create error types by deriving thiserror::Error, then manually implement serde::Serialize to control serialization. This allows explicit error types showing all possible errors and mapping errors to specific codes or messages.

Async commands avoid UI freezing

Async commands are recommended for heavy workloads to prevent UI freezing or slowdowns. Declare a command as async simply by adding the async keyword to the function signature. Async commands run on a separate async task using async_runtime::spawn, while non-async commands run on the main thread.

Async command constraint: borrowed arguments not supported

Async commands cannot include borrowed arguments directly in their signature. Examples of borrowed types that cause issues: &str, State<'_, Data>. This constraint is discussed at https://github.com/tauri-apps/tauri/issues/2533. Use workarounds: convert borrowed types to owned types (e.g., String instead of &str), or wrap return type in Result.

Async command workaround: convert borrowed types to owned types

For async commands with borrowed arguments, convert them to owned types. For example, use String instead of &str. This works for types that have owned equivalents. Example: #[tauri::command] async fn my_custom_command(value: String) -> String { some_async_function().await; value }

Async command workaround: wrap return type in Result

For async commands with borrowed arguments, wrap the return type in Result to avoid the borrowing issue. Format is Result<ReturnType, ErrorType>. Use () for null return or no error. Examples: Result<String, ()> returns String with no error; Result<(), ()> returns null; Result<bool, Error> returns bool or error. Example: #[tauri::command] async fn my_custom_command(value: &str) -> Result<String, ()> { some_async_function().await; Ok(format!(value)) }

Async commands return promises to JavaScript

JavaScript invocation of async commands returns a promise that works the same as non-async commands. Example: invoke('my_custom_command', { value: 'Hello, Async!' }).then(() => console.log('Completed!'))

Tauri channels for streaming data

Tauri channels are the recommended mechanism for streaming data to the frontend, similar to streaming HTTP responses. Pass a tauri::ipc::Channel<T> parameter to command. Use reader.send(data) to send chunks. Example: async fn load_image(path: std::path::PathBuf, reader: tauri::ipc::Channel<&[u8]>) reads file and sends 4096-byte chunks.

Access WebviewWindow in command handler

Commands can access the WebviewWindow instance that invoked them by adding a tauri::WebviewWindow parameter. Example: #[tauri::command] async fn my_custom_command(webview_window: tauri::WebviewWindow) { println!("WebviewWindow: {}", webview_window.label()); }

Access AppHandle in command handler

Commands can access the AppHandle instance by adding a tauri::AppHandle parameter. Example: #[tauri::command] async fn my_custom_command(app_handle: tauri::AppHandle) { let app_dir = app_handle.path_resolver().app_dir(); }

Access raw request body and headers in commands

Commands can access the full tauri::ipc::Request object containing raw body payload and headers. Pattern match on request.body() to get tauri::ipc::InvokeBody::Raw(data). Access headers with request.headers().get(header_name). Example shows upload handler checking Authorization header and raw body.

Send raw request body from frontend with ArrayBuffer or Uint8Array

Frontend can send raw request bodies by passing ArrayBuffer or Uint8Array as second argument to invoke(), with optional headers as third argument. Example: const data = new Uint8Array([1, 2, 3]); await __TAURI__.core.invoke('upload', data, { headers: { Authorization: 'apikey' } });

Register multiple commands

When registering multiple commands, pass all commands to a single tauri::generate_handler! macro call as comma-separated list. invoke_handler cannot be called multiple times; only the last call will be used. Example: .invoke_handler(tauri::generate_handler![cmd_a, cmd_b])

Combined Tauri command example with multiple features

Commands can combine multiple features: async, WebviewWindow parameter, State parameter, and Result return type. Example: #[tauri::command] async fn my_custom_command(window: tauri::WebviewWindow, number: usize, database: tauri::State<'_, Database>) -> Result<CustomResponse, String> { ... }

Tauri v2: Rust crate api module removal

The api module has been removed from Tauri v2 Rust crate. Each API module is referenced in Tauri plugins: api::dialog removed (use tauri-plugin-dialog); api::file removed (use Rust std::fs); api::http removed (use tauri-plugin-http); api::ip rewritten and moved to tauri::ipc with new Channel API; api::path functionality moved to tauri::Manager::path.

Tauri v2: Rust command and shell API removal

The Command, shell, and shell_scope APIs have been removed: api::process::Command removed (use tauri-plugin-shell); tauri::api::shell removed (use tauri-plugin-shell); tauri::Manager::shell_scope removed (use tauri-plugin-shell). The process-command-api feature flag no longer exists in v2.

Tauri v2: JavaScript API changes

@tauri-apps/api package no longer exports non-core modules. Only tauri (now core), path, event, and window modules are exported. All other functionality moved to plugins. @tauri-apps/api/tauri module renamed to @tauri-apps/api/core. @tauri-apps/api/window module renamed to @tauri-apps/api/webviewWindow. WebviewWindow JS API exported from @tauri-apps/api/webviewWindow instead of @tauri-apps/api/window.

Tauri v2: core module import change

JavaScript imports changed: @tauri-apps/api/tauri renamed to @tauri-apps/api/core. Update import statement: change `import { invoke } from '@tauri-apps/api/tauri'` to `import { invoke } from '@tauri-apps/api/core'`

Give your agent this brain