// Cross-platform OS info for the Svelte frontend. Single async fetch, // cached in memory, exposes synchronous helpers after first await. // // Backed by the `get_os_info` Tauri command (commands/diagnostics.rs). // In browser-preview mode (no Tauri runtime), falls back to a sensible // default based on navigator.platform. // // Usage: // import { loadOsInfo, osInfo, modKeyLabel, isMac } from '$lib/utils/osInfo.js'; // await loadOsInfo(); // call once at app startup // modKeyLabel(); // "Cmd" on macOS, "Ctrl" elsewhere // if (isMac()) { ... } // // The store version (osInfo) is reactive — Svelte components can read it // directly with `$osInfo` once Svelte 5 runes are everywhere, or via // destructuring on a non-reactive read. import { invoke } from '@tauri-apps/api/core'; import { hasTauriRuntime } from './runtime.js'; interface OsInfo { os: string; arch: string; family: string; usesCmd: boolean; isWayland: boolean; customHotkeyBackend: boolean; primaryModifierLabel: string; } let cached: OsInfo | null = null; const FALLBACK_BROWSER_INFO = { os: detectBrowserOs(), arch: 'unknown', family: detectBrowserFamily(), usesCmd: detectBrowserOs() === 'macos', isWayland: false, customHotkeyBackend: false, primaryModifierLabel: detectBrowserOs() === 'macos' ? 'Cmd' : 'Ctrl', }; function detectBrowserOs() { if (typeof navigator === 'undefined') return 'unknown'; const ua = (navigator.userAgent || '').toLowerCase(); const platform = (navigator.platform || '').toLowerCase(); if (platform.includes('mac') || ua.includes('mac os')) return 'macos'; if (platform.includes('win') || ua.includes('windows')) return 'windows'; if (platform.includes('linux') || ua.includes('linux')) return 'linux'; return 'unknown'; } function detectBrowserFamily() { switch (detectBrowserOs()) { case 'macos': return 'macOS'; case 'windows': return 'Windows'; case 'linux': return 'Linux'; default: return 'Unknown'; } } /** Fetch OS info from the Tauri backend. Idempotent — call multiple times, * only the first does the round-trip. Browser-preview mode returns the * navigator-detected fallback. */ export async function loadOsInfo(): Promise { if (cached) return cached; if (!hasTauriRuntime()) { cached = FALLBACK_BROWSER_INFO; return cached; } try { cached = await invoke("get_os_info"); } catch (err) { console.warn('loadOsInfo: get_os_info failed, using browser fallback', err); cached = FALLBACK_BROWSER_INFO; } return cached; } /** Synchronous accessor. Returns null if loadOsInfo has not been awaited * yet. Components that need the value at first render should await * loadOsInfo() in onMount before reading. */ export function osInfo(): OsInfo | null { return cached; } export function isMac(): boolean { return cached?.os === 'macos'; } export function isWindows(): boolean { return cached?.os === 'windows'; } export function isLinux(): boolean { return cached?.os === 'linux'; } /** Localised label for the primary keyboard modifier. "Cmd" on macOS, * "Ctrl" everywhere else. Use in hotkey display strings: * `${modKeyLabel()}+Shift+R` */ export function modKeyLabel(): string { return cached?.primaryModifierLabel ?? 'Ctrl'; } /** True if the current Linux session is Wayland. False on Windows/macOS. * Useful for Settings → Audio "PipeWire detected" status display. */ export function isWayland(): boolean { return !!cached?.isWayland; }