import { store, updateSettings } from "@store/state.svelte"; export type AuthMode = "NONE" | "BASIC_AUTH" | "SIMPLE_LOGIN" | "UI_LOGIN"; export const authSession = { clearTokens() {}, hasSession(): boolean { return true; }, }; function getServerBase(): string { const url = store.settings.serverUrl; return typeof url === "string" && url.trim() ? url.replace(/\/$/, "") : "http://127.0.0.1:4567"; } function basicHeader(user: string, pass: string): Record { return { Authorization: `Basic ${btoa(`${user}:${pass}`)}` }; } export function fetchAuthenticated(url: string, init: RequestInit, signal?: AbortSignal): Promise { const mode = store.settings.serverAuthMode ?? "NONE"; if (mode === "BASIC_AUTH") { const user = store.settings.serverAuthUser?.trim() ?? ""; const pass = store.settings.serverAuthPass?.trim() ?? ""; return fetch(url, { ...init, signal, credentials: "omit", headers: { ...(init.headers as Record ?? {}), ...(user && pass ? basicHeader(user, pass) : {}) }, }); } return fetch(url, { ...init, signal, credentials: "omit" }); } export async function loginBasic(user: string, pass: string): Promise { const res = await fetch(`${getServerBase()}/api/graphql`, { method: "POST", credentials: "omit", headers: { "Content-Type": "application/json", ...basicHeader(user, pass) }, body: JSON.stringify({ query: "{ __typename }" }), signal: AbortSignal.timeout(5000), }); if (!res.ok) throw new Error(`Authentication failed (${res.status})`); updateSettings({ serverAuthMode: "BASIC_AUTH", serverAuthUser: user, serverAuthPass: pass }); } export async function logout(): Promise { updateSettings({ serverAuthPass: "" }); } export async function probeServer(): Promise<"ok" | "auth_required" | "unsupported_mode" | "unreachable"> { const base = getServerBase(); const mode = store.settings.serverAuthMode ?? "NONE"; const s = store.settings; try { const headers: Record = { "Content-Type": "application/json" }; if (mode === "BASIC_AUTH") { const user = s.serverAuthUser?.trim() ?? ""; const pass = s.serverAuthPass?.trim() ?? ""; if (user && pass) Object.assign(headers, basicHeader(user, pass)); } const res = await fetch(`${base}/api/graphql`, { method: "POST", credentials: "omit", headers, body: JSON.stringify({ query: "{ __typename }" }), signal: AbortSignal.timeout(5000), }); if (res.ok) return "ok"; if (res.status === 401) { const wwwAuth = res.headers.get("WWW-Authenticate") ?? ""; if (/basic/i.test(wwwAuth)) { if (mode !== "BASIC_AUTH") updateSettings({ serverAuthMode: "BASIC_AUTH" }); return "auth_required"; } if (/bearer/i.test(wwwAuth)) { if (mode !== "UI_LOGIN") updateSettings({ serverAuthMode: "UI_LOGIN" }); } else if (mode === "NONE") { updateSettings({ serverAuthMode: "SIMPLE_LOGIN" }); } return "unsupported_mode"; } return "unreachable"; } catch { return "unreachable"; } }