Advanced Native

Use OpenRTC directly from Rust or project it into a Tauri WebView

Native Rust does not depend on TypeScript. The openrtc crate can own the complete native endpoint and peer lifecycle by itself. Tauri adds an optional IPC adapter so a WebView can use that same Rust owner through the familiar TypeScript API.

pure Rust app ────────────────┐
                             ├─> one native openrtc::Client ─> Iroh
Tauri WebView ─> plugin IPC ──┘

There is no WASM runtime in the Tauri path and no second frontend connection manager.

Tauri WebView

Use the native-only npm entrypoint so the bundler can omit the WASM loader and binary:

import { OpenRTC } from 'openrtc/native';
import { createBridge } from 'openrtc-tauri/ipc';

const rtc = OpenRTC({ apiKey, auth }, createBridge());
const devices = await rtc.devices.start({ auth, autoConnect: 'online' });

The openrtc-tauri-plugin crate owns the native client and exposes bounded IPC commands for capabilities, connection projections, protected messages, streams, and media. Private key material stays in host secure storage and never enters the WebView.

use openrtc_tauri_plugin::{
    OpenRtcTauriConfig,
    OpenRtcTauriState,
};
use std::sync::Arc;

let state = OpenRtcTauriState::new(OpenRtcTauriConfig {
    api_key,
    data_dir: None,
    transport_config: Some(transport_config),
})
.with_native_device_key_signer(Arc::new(AppDeviceSigner));

// Product-native Rust features may use this exact same client.
let openrtc_client = state.client();

tauri::Builder::default()
    .manage(openrtc_client)
    .plugin(openrtc_tauri_plugin::init_with_state(state))
    .run(tauri::generate_context!())?;

Add openrtc-tauri-plugin:default to the Tauri capability that owns the OpenRTC WebView. Without the plugin or permission, the native frontend fails closed instead of silently starting a browser runtime.

Pure Rust

Pure-Rust consumers use ControlPlane::anonymous(apiKey, signer) for backend-free spaces, ephemeral rooms, and tickets, or ControlPlane::new with their assertion, secure signer, protected certificate store, and optional enrollment-attestation providers for authenticated devices. These high-level methods issue and renew bounded capabilities and grants; the returned handle owns exactly one avenue and exposes signaling() plus idempotent close().

use openrtc::{
    Client,
    native::{CapabilityOptions, ControlPlane, DeviceSigner},
};
use std::sync::Arc;

let signer: Arc<dyn DeviceSigner> = app_secure_signer();
let control = ControlPlane::anonymous(API_KEY, signer)?;

let room = control.join_room(
    "call-123",
    "desktop",
    CapabilityOptions::default(),
).await?;

let client = Arc::new(
    Client::builder(API_KEY.to_owned(), Box::new(|| None))?
        .signaling_backend(room.signaling())
        .build(),
);

client.send_peer(peer_id, b"hello").await?;
room.close().await;

Authenticated device meshes additionally supply the provider-neutral AssertionProvider, DeviceSigner, and CertificateStore traits. The app keeps its identity-provider SDK and private key storage outside OpenRTC.

Native media uses encoded MediaSource and MediaSink implementations supplied by the host. Native streams use Client::open_peer_bi(), open_peer_uni(), and the datagram methods. No DOM, JavaScript promise, browser WebRTC session, or MoQ session type crosses the Rust API.

See Avenues for devices, spaces, rooms, and ticket examples.

Lower-level composition

Client::new(apiKey) and new WasmClient(apiKey) are side-effect-free compiled-runtime constructors. The TypeScript capability layer owns browser assertion exchange and IndexedDB/WebCrypto install keys, while the Rust control plane owns the equivalent native exchange. Client::new_provider_neutral is an internal composition surface for hosts that already own a reviewed grant provider; it is not the normal consumer quickstart.

Advanced browser hosts using the generated binding directly may call WasmClient.setRelay(enabled) before initIroh(). Calling it after endpoint initialization fails because relay discovery cannot be changed truthfully on a running endpoint. Normal applications should configure OpenRTC({ transports: { relay: false } }); the TypeScript bridge applies the WASM setting before initialization.

Do not relay consumer Firebase credentials into Rust as the OpenRTC identity contract. The application supplies a provider-neutral assertion; optional platform attestation is enrollment evidence rather than a recurring connection token.

Host-reported compiled capabilities determine native Iroh, WebRTC, MoQ, LAN, and BLE availability.

Offline edge enrollment

client.offline() uses the same Rust endpoint and host-owned signer. It does not require TypeScript, the coordination gateway, or a public relay. Configure the client with NetworkPolicy::LocalOnly before endpoint startup and compile the transport-lan feature. See Offline edge devices for the enrollment request and trust model.