Expand description
Trait-based, type-safe Tauri IPC, built on specta v2. Sync by default.
Define your IPC surface once as a Rust trait. procedures
flattens it into a dispatch core and a descriptor the TypeScript client
is rendered from; handler mounts that on tauri’s invoke pipeline.
The wire is identical to a raw #[tauri::command] – same command name,
same named-argument JSON, no envelope – so generated calls,
hand-written invokes, and raw commands are interchangeable, and a
trait can be adopted one command at a time through
handler_with_fallback.
A procedure is a plain fn by default, dispatched inline on the main
thread; mark one async fn and only that one is spawned on tauri’s
runtime. Sync-first is the founding choice: a sync handler carries no
Send bound on its own logic and skips the executor hop, where TauRPC
makes every procedure async. (A sync handler still runs on the UI
thread, so long-running work opts into async.)
§Quickstart
Define the surface and implement it:
use tauri_typed_ipc::procedures;
#[procedures]
trait Greeter {
fn greet(&self, name: String) -> String;
}
struct Backend;
impl Greeter for Backend {
fn greet(&self, name: String) -> String {
format!("Hello, {name}!")
}
}
// `#[procedures]` adds `into_procedures`, which type-erases the trait
// for the handler:
let procedures = Backend.into_procedures();
assert_eq!(procedures.names(), &["greet"]);Mount every procedure on one handler. handler adapts the type-erased
procedures into a tauri invoke handler; drop it into your Builder,
then run as usual with .run(tauri::generate_context!()):
fn mount<R: tauri::Runtime>(builder: tauri::Builder<R>) -> tauri::Builder<R> {
builder.invoke_handler(tauri_typed_ipc::handler(Backend.into_procedures()))
}With the export feature, render the matching client and guard it
against drift:
tauri_typed_ipc::Bindings::new()
.register::<GreeterProcedures>()
.export_to("../src/bindings.ts")?;import { greeter } from "./bindings";
const hello = await greeter.greet("world"); // Promise<string>§What’s here
- Procedures –
procedureson a trait: a syncfndispatches inline, anasync fnis spawned on tauri’s runtime. - Typed client – with the
exportfeature,Bindingsrenders a TypeScript client from the generatedProcedureSetdescriptor, and itscheckfails CI when the committed client drifts. - Events, both directions –
Eventon an enum emits typed payloads and generates the matching listeners. - Typed errors –
Error: aResult<_, E>procedure rejectsEon the wire, and the client types itscatchagainst it. - Injection by type – an
AppHandleortauri::Stateparameter is resolved from the [Context] by its type, never by its name. - Streaming – a
Channel<T>parameter streams values back to the caller, on top of the value the procedure returns. - Composition –
Procedures::mergemounts several traits on one handler.
Structs§
- Bindings
- Renders a TypeScript client for one or more procedure sets: a
constobject per set whose methods are wire-parityinvokecalls, plus the specta type definitions they reference. One file by default;Layout::Filessplits them into a directory. - Channel
- A typed, one-way channel a procedure streams values through.
- Procedures
- A type-erased procedure set: the
(names, dispatch)pair that#[procedures]flattens a trait into, so routing needs no knowledge of the trait itself.mergecombines several sets into one, so a whole app mounts on a singlehandler. - Validation
Error - A payload that failed its command’s contract. Carried into
DispatchError::Invalidby a validating handler and rejected at the boundary, before dispatch. - Validator
- Compiled per-command argument validators, built from one or more procedure
sets. Reuses the binding descriptor a
#[procedures]trait already generates, so validation needs no separate schema definition and cannot drift from the client’s types.
Enums§
- Bindings
Error - Failure rendering or checking the TypeScript client.
- Dispatch
Error - Error returned by a generated
dispatchwhen a call cannot reach or leave the procedure. Wire-level failures only – a procedure’s own failures belong in its return type. - Layout
- Allows configuring the format of the final types file
- Method
Case - How a generated client casts its TypeScript method names. The wire command name and argument keys are always the Rust identifiers verbatim (wire parity); argument names in the TypeScript signature are always camelCase. Only the method name varies.
- Validator
Error - Failure assembling a
Validatorfrom a procedure set: the contract’s JSON Schema could not be built or compiled. Structural, so it is raised once atregister, never per call.
Traits§
- Error
Set - A wire error’s binding descriptor, generated by
#[derive(tauri_typed_ipc::Error)]and implemented on the enum itself, so a procedure’sResult<_, E>return can name the error it rejects with. - Event
Set - An event enum’s binding descriptor, generated by
#[derive(Event)]and implemented on the enum itself. - Procedure
Set - A trait’s binding descriptor, generated by
#[procedures]as the zero-sized{Trait}Procedures. Implemented on a type, not built from an instance, so a client can be rendered without standing up the procedure set.
Functions§
- handler
- Builds a tauri invoke handler from a procedure set.
- handler_
validated - Like
handler, but validates each call’s arguments against aValidatorbefore routing (thevalidatefeature). A covered command whose payload fails its schema is rejected at the boundary – before the procedure runs – withDispatchError::Invalid; everything else routes exactly ashandlerdoes. - handler_
validated_ with_ fallback - Like
handler_with_fallback, but validates covered commands first (thevalidatefeature). Seehandler_validated. - handler_
with_ fallback - Like
handler, but commands outside the set fall through tofallback– typicallytauri::generate_handler![...]– so raw commands and procedures coexist while an app migrates.
Attribute Macros§
- procedures
- Marks a trait as a tauri-typed-ipc procedure set.
Derive Macros§
- Error
- Derives a wire-serializable error for an enum: each variant serializes
to
{ type: "<variant>", message: "<Display>" }, a discriminated union the client can branch on. Display-based, so it works with non-Serialize sources likestd::io::Error. - Event
- Derives a typed event channel for an enum: each variant is an event,
emitted with
Variant { .. }.emit(&app)under the wire name"{group}:{variant}"with the variant’s fields as the payload. The derive owns the name on the Rust side; the bindings generator owns the matching listener on the TS side (a later slice).