import type { BackendCommand } from "$lib/backend/types"; type InvokeArgs = Record | undefined; type WindowWithTauri = Window & { __TAURI_INTERNALS__?: unknown; }; type UiSettingsPayload = { tags?: string[]; fragmentTypes?: string[]; }; type FetchJsonOptions = { keepalive?: boolean; }; const UI_SETTINGS_KEY = "journal.ui.settings"; function normalizedApiBase(): string { const configured = import.meta.env.VITE_JOURNAL_API_BASE?.trim(); if (!configured) { return "/api"; } return configured.endsWith("/") ? configured.slice(0, -1) : configured; } export function isTauriRuntime(): boolean { if (typeof window === "undefined") { return false; } return Object.prototype.hasOwnProperty.call(window as WindowWithTauri, "__TAURI_INTERNALS__"); } function readUiSettingsFromLocalStorage(): UiSettingsPayload { if (typeof window === "undefined") { return {}; } const raw = window.localStorage.getItem(UI_SETTINGS_KEY); if (!raw) { return {}; } try { const parsed = JSON.parse(raw) as UiSettingsPayload; return { tags: Array.isArray(parsed.tags) ? parsed.tags : undefined, fragmentTypes: Array.isArray(parsed.fragmentTypes) ? parsed.fragmentTypes : undefined }; } catch { return {}; } } function writeUiSettingsToLocalStorage(payload: UiSettingsPayload): void { if (typeof window === "undefined") { return; } const safePayload: UiSettingsPayload = { tags: Array.isArray(payload.tags) ? payload.tags : undefined, fragmentTypes: Array.isArray(payload.fragmentTypes) ? payload.fragmentTypes : undefined }; window.localStorage.setItem(UI_SETTINGS_KEY, JSON.stringify(safePayload)); } async function fetchJson(path: string, init: RequestInit = {}, options: FetchJsonOptions = {}): Promise { const response = await fetch(`${normalizedApiBase()}${path}`, { ...init, keepalive: options.keepalive === true, headers: { "Content-Type": "application/json", ...(init.headers ?? {}) } }); if (!response.ok) { const text = await response.text(); throw new Error(text || `Request failed (${response.status})`); } if (response.status === 204) { return undefined as T; } return (await response.json()) as T; } export async function invoke(command: string, args?: InvokeArgs): Promise { if (isTauriRuntime()) { const tauriCore = await import("@tauri-apps/api/core"); return tauriCore.invoke(command, args); } switch (command) { case "sidecar_command": { const envelope = args?.command; if (!envelope || typeof envelope !== "object") { throw new Error("Missing command payload."); } const keepalive = args?.keepalive === true; return fetchJson( "/command", { method: "POST", body: JSON.stringify(envelope as BackendCommand) }, { keepalive } ); } case "get_sidecar_root": return fetchJson("/sidecar/root"); case "set_sidecar_root": { const path = typeof args?.path === "string" ? args.path : ""; return fetchJson("/sidecar/root", { method: "POST", body: JSON.stringify({ path }) }); } case "get_ui_settings": return readUiSettingsFromLocalStorage() as T; case "set_ui_settings": { const tags = Array.isArray(args?.tags) ? (args?.tags as string[]) : undefined; const fragmentTypes = Array.isArray(args?.fragmentTypes) ? (args?.fragmentTypes as string[]) : Array.isArray(args?.fragment_types) ? (args?.fragment_types as string[]) : undefined; writeUiSettingsToLocalStorage({ tags, fragmentTypes }); return undefined as T; } case "shutdown": return undefined as T; default: throw new Error(`Unsupported command in web runtime: ${command}`); } }