ultisuite-client/lib/native/bridge.ts
R3D347HR4Y d6d18f911b
Some checks failed
E2E / Playwright e2e (push) Has been cancelled
Lots of stuff and mobile app
2026-06-17 00:13:28 +02:00

69 lines
1.8 KiB
TypeScript

/**
* 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 = <T>(cmd: string, args?: Record<string, unknown>) => Promise<T>
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<InvokeFn | null> {
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<ListenFn | null> {
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<T>(
cmd: string,
args?: Record<string, unknown>
): Promise<T | null> {
const fn = await loadCore()
if (!fn) return null
try {
return await Promise.race([
fn<T>(cmd, args),
new Promise<never>((_, 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))
}