import { useEffect, useRef } from 'react'; // Tauri v2 injects `__TAURI_INTERNALS__` into the webview at runtime; we use it // directly so cinny doesn't need `@tauri-apps/api` as a dependency. Native Rust // modules push data back to the web by dispatching DOM CustomEvents (see // `emit_to_web` in cinny-desktop's `native` module), which `useTauriEvent` // subscribes to. This module is the single source for the desktop bridge that // every `useTauri*` feature hook builds on. type Invoke = (cmd: string, args?: Record) => Promise; export const tauriInvoke = (): Invoke | undefined => (window as unknown as { __TAURI_INTERNALS__?: { invoke: Invoke } }).__TAURI_INTERNALS__?.invoke; export const isTauri = (): boolean => tauriInvoke() !== undefined; /** Fire-and-forget invoke that no-ops (and never throws) outside Tauri. */ export const invokeTauri = (cmd: string, args?: Record): void => { tauriInvoke()?.(cmd, args).catch(() => undefined); }; /** * Subscribe to a CustomEvent dispatched from the Rust side via `emit_to_web`. * The handler is kept in a ref so callers don't need to memoize it to avoid * re-subscribing. No-op outside Tauri. */ export function useTauriEvent(name: string, handler: (detail: T) => void): void { const handlerRef = useRef(handler); handlerRef.current = handler; useEffect(() => { if (!isTauri()) return undefined; const listener = (e: Event): void => handlerRef.current((e as CustomEvent).detail); window.addEventListener(name, listener); return () => window.removeEventListener(name, listener); }, [name]); }