Desktop IPC Transport
When to use this mode
Section titled “When to use this mode”Desktop IPC transport is for Electron/Tauri-style architectures where host and remote runtimes live in different processes/webviews.
Typical fit:
- desktop extension platforms;
- plugin runtimes isolated from main UI process;
- native shell orchestration with explicit IPC policies.
Core model
Section titled “Core model”@omnicajs/vue-remote still needs the same channel contract.
IPC is just the delivery mechanism.
Host Renderer (Desktop UI) -> createReceiver() -> createEndpoint(fromDesktopIpc(...)) -> call.run(receiver.receive, hostBridge)
Desktop Main Process / IPC Layer -> routes messages between host and remote peers -> applies policy, auth/capability checks, and lifecycle rules
Remote Runtime (isolated renderer/webview/process) -> createEndpoint(fromDesktopIpc(...)) -> expose run/releaseMinimal endpoint wrapper pattern
Section titled “Minimal endpoint wrapper pattern”Build a MessageEndpoint adapter over your desktop IPC bridge:
import type { MessageEndpoint } from '@remote-ui/rpc'
type DesktopBridge = { send(channel: string, payload: unknown): void; on(channel: string, listener: (payload: unknown) => void): void; off(channel: string, listener: (payload: unknown) => void): void; close?(): void;}
export function fromDesktopIpc( bridge: DesktopBridge, channel = 'vue-remote:rpc'): MessageEndpoint { const listeners = new Set<(event: MessageEvent) => void>()
const onPayload = (payload: unknown) => { const event = { data: payload } as MessageEvent for (const listener of listeners) { listener(event) } }
bridge.on(channel, onPayload)
return { postMessage(message: any) { bridge.send(channel, message) }, addEventListener(event, listener) { if (event === 'message') listeners.add(listener) }, removeEventListener(event, listener) { if (event === 'message') listeners.delete(listener) }, terminate() { bridge.off(channel, onPayload) bridge.close?.() }, }}Then use standard endpoint flow:
const endpoint = createEndpoint<RemoteApi>(fromDesktopIpc(window.desktopBridge))await endpoint.call.run(receiver.receive, hostBridge)Electron and Tauri notes
Section titled “Electron and Tauri notes”Electron:
- expose a narrow IPC API from preload (
contextBridge); - keep
contextIsolation: true; - avoid passing unrestricted objects from main process.
Tauri:
- use command/event channels as a constrained bridge;
- keep allowlists explicit in capabilities;
- avoid broad wildcard event pipes for untrusted plugins.
Production notes
Section titled “Production notes”- Treat IPC channels as privileged boundaries.
- Version protocol and enforce compatibility checks.
- Add capability-based routing per extension session.
- Ensure teardown closes channels and releases retained references.