/** * Thin bridge over the Tauri JS API. Everything is dynamically imported so the * web bundle never pulls in `@tauri-apps/*` and `pnpm build` (web) keeps * working even if the native packages are absent. */ import { isTauriRuntime } from "@/lib/platform" type InvokeFn = (cmd: string, args?: Record) => Promise type ListenFn = ( event: string, handler: (e: { payload: unknown }) => void ) => Promise<() => void> let invokeImpl: InvokeFn | null = null let listenImpl: ListenFn | null = null async function loadCore(): Promise { if (!isTauriRuntime()) return null if (invokeImpl) return invokeImpl try { const mod = (await import("@tauri-apps/api/core")) as { invoke: InvokeFn } invokeImpl = mod.invoke return invokeImpl } catch { return null } } async function loadEvent(): Promise { if (!isTauriRuntime()) return null if (listenImpl) return listenImpl try { const mod = (await import("@tauri-apps/api/event")) as { listen: ListenFn } listenImpl = mod.listen return listenImpl } catch { return null } } /** Invoke a Tauri command. Returns null (no-op) outside a Tauri webview or on timeout. */ export async function invoke( cmd: string, args?: Record ): Promise { const fn = await loadCore() if (!fn) return null try { return await Promise.race([ fn(cmd, args), new Promise((_, reject) => { setTimeout(() => reject(new Error("invoke_timeout")), 5_000) }), ]) } catch { return null } } /** Subscribe to a Tauri event. Returns an unsubscribe fn (no-op on web). */ export async function listen( event: string, handler: (payload: unknown) => void ): Promise<() => void> { const fn = await loadEvent() if (!fn) return () => {} return fn(event, (e) => handler(e.payload)) }