async function readJsonResponse(response) { const text = await response.text(); if (!text) { return {}; } try { return JSON.parse(text); } catch (error) { throw new Error(text); } } function nextLocation() { const params = new URLSearchParams(window.location.search); const candidate = (params.get("next") || "").trim(); if (candidate.startsWith("/") && !candidate.startsWith("//")) { return candidate; } return "/select"; } window.addEventListener("DOMContentLoaded", async () => { const bootIndicator = document.getElementById("boot-indicator"); const root = document.getElementById("login-root"); const form = document.getElementById("login-form"); const usernameInput = document.getElementById("username"); const passwordInput = document.getElementById("password"); const submitButton = document.getElementById("login-submit"); const errorNode = document.getElementById("login-error"); const showForm = () => { if (bootIndicator) { bootIndicator.hidden = true; } if (root) { root.hidden = false; } }; const setError = (message) => { if (!errorNode) { return; } errorNode.textContent = message || ""; errorNode.hidden = !message; }; try { const response = await fetch("/api/auth/session", { cache: "no-store", credentials: "same-origin", }); if (response.ok) { window.location.replace(nextLocation()); return; } if (response.status !== 401) { const payload = await readJsonResponse(response); setError(payload.error || `HTTP ${response.status}`); } } catch (error) { setError(error instanceof Error ? error.message : String(error)); } finally { showForm(); } if (!form || !(usernameInput instanceof HTMLInputElement) || !(passwordInput instanceof HTMLInputElement)) { return; } usernameInput.focus(); form.addEventListener("submit", async (event) => { event.preventDefault(); setError(""); submitButton.disabled = true; try { const response = await fetch("/api/auth/login", { method: "POST", credentials: "same-origin", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ username: usernameInput.value.trim(), password: passwordInput.value, }), }); const payload = await readJsonResponse(response); if (!response.ok) { throw new Error(payload.error || `HTTP ${response.status}`); } window.location.replace(nextLocation()); } catch (error) { setError(error instanceof Error ? error.message : String(error)); } finally { submitButton.disabled = false; } }); });