/** * Safe Tauri API Wrappers * * All Tauri APIs (invoke, listen, etc.) depend on `window.__TAURI_INTERNALS__` * which only exists inside the Tauri WebView. When the frontend is accessed * from a regular browser (e.g. http://localhost:1420/ for debugging), these * APIs throw cryptic errors like: * * TypeError: Cannot read properties of undefined (reading 'transformCallback') * * This module provides drop-in replacements that gracefully degrade when * the Tauri runtime is not available. */ import { isTauriRuntime } from './tauri-gateway'; import { createLogger } from './logger'; const log = createLogger('safe-tauri'); // --------------------------------------------------------------------------- // Types // --------------------------------------------------------------------------- export type { UnlistenFn } from '@tauri-apps/api/event'; // --------------------------------------------------------------------------- // Safe invoke // --------------------------------------------------------------------------- /** * Type-safe wrapper around Tauri `invoke`. * Returns `null` (with a debug log) when not in Tauri runtime. */ export async function safeInvoke( cmd: string, args?: Record, ): Promise { if (!isTauriRuntime()) { log.debug(`invoke("${cmd}") skipped — not in Tauri runtime`); return null; } const { invoke } = await import('@tauri-apps/api/core'); return invoke(cmd, args); } /** * Like `safeInvoke` but throws when not in Tauri runtime. * Use for operations that MUST have a Tauri backend. */ export async function requireInvoke( cmd: string, args?: Record, ): Promise { if (!isTauriRuntime()) { throw new Error(`invoke("${cmd}") failed — not running in Tauri WebView`); } const { invoke } = await import('@tauri-apps/api/core'); return invoke(cmd, args); } // --------------------------------------------------------------------------- // Safe listen // --------------------------------------------------------------------------- /** * Wrapper around Tauri `listen`. * Returns a no-op `UnlistenFn` when not in Tauri runtime. * * Usage — replace: * import { listen } from '@tauri-apps/api/event'; * With: * import { safeListen } from '../lib/safe-tauri'; */ export async function safeListen( event: string, handler: (payload: T) => void, ): Promise<() => void> { if (!isTauriRuntime()) { log.debug(`listen("${event}") skipped — not in Tauri runtime`); return () => {}; } const { listen } = await import('@tauri-apps/api/event'); return listen(event, (e) => handler(e.payload)); } /** * Wrapper around Tauri `listen` that provides the full Event object. * Returns a no-op `UnlistenFn` when not in Tauri runtime. */ export async function safeListenEvent( event: string, handler: (event: { event: string; payload: T }) => void, ): Promise<() => void> { if (!isTauriRuntime()) { log.debug(`listen("${event}") skipped — not in Tauri runtime`); return () => {}; } const { listen } = await import('@tauri-apps/api/event'); return listen(event, (e) => handler(e)); }