stan44 069b38071c Added Web WebGateway
Added connector so gateway works.
scripts are much more polished and functional.
2026-02-27 11:03:53 -06:00

144 lines
3.8 KiB
TypeScript

import type { BackendCommand } from "$lib/backend/types";
type InvokeArgs = Record<string, unknown> | 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<T>(path: string, init: RequestInit = {}, options: FetchJsonOptions = {}): Promise<T> {
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<T>(command: string, args?: InvokeArgs): Promise<T> {
if (isTauriRuntime()) {
const tauriCore = await import("@tauri-apps/api/core");
return tauriCore.invoke<T>(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<T>(
"/command",
{
method: "POST",
body: JSON.stringify(envelope as BackendCommand)
},
{ keepalive }
);
}
case "get_sidecar_root":
return fetchJson<T>("/sidecar/root");
case "set_sidecar_root": {
const path = typeof args?.path === "string" ? args.path : "";
return fetchJson<T>("/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}`);
}
}