export function getCurrentRelativeUrl() { return `${window.location.pathname}${window.location.search}${window.location.hash}`; } export function buildLoginUrl(nextPath = getCurrentRelativeUrl()) { const loginUrl = new URL('/login.html', window.location.origin); if (nextPath) { loginUrl.searchParams.set('next', nextPath); } return `${loginUrl.pathname}${loginUrl.search}`; } export function buildSetupUrl(nextPath = getCurrentRelativeUrl()) { const setupUrl = new URL('/setup.html', window.location.origin); if (nextPath) { setupUrl.searchParams.set('next', nextPath); } return `${setupUrl.pathname}${setupUrl.search}`; } export function redirectToLogin(nextPath = getCurrentRelativeUrl()) { window.location.assign(buildLoginUrl(nextPath)); } export function redirectToSetup(nextPath = getCurrentRelativeUrl()) { window.location.assign(buildSetupUrl(nextPath)); } export function readNextPath(fallback = '/') { const nextPath = new URLSearchParams(window.location.search).get('next'); if (!nextPath || !nextPath.startsWith('/') || nextPath.startsWith('//')) { return fallback; } return nextPath; } export function redirectToNextPath(fallback = '/') { window.location.assign(readNextPath(fallback)); } export async function loadAuthState() { const response = await fetch('/api/auth/state'); const payload = await response.json().catch(() => ({})); if (!response.ok) { throw new Error(`${payload.error?.code ?? 'AUTH_STATE_FAILED'}: ${payload.error?.message ?? 'Failed to load auth state.'}`); } return payload.auth; } export async function logoutCurrentSession() { const response = await fetch('/api/auth/logout', { method: 'POST' }); const payload = await response.json().catch(() => ({ ok: false })); if (!response.ok) { throw new Error(`${payload.error?.code ?? 'LOGOUT_FAILED'}: ${payload.error?.message ?? 'Logout failed.'}`); } return payload; } export function bindLogoutButton(button, labelElement, fallbackLabel = '已登录') { if (!button) { return; } button.addEventListener('click', async () => { button.disabled = true; if (labelElement) { labelElement.textContent = 'Signing out...'; } try { await logoutCurrentSession(); } finally { redirectToLogin('/'); } }); if (labelElement && !labelElement.textContent.trim()) { labelElement.textContent = fallbackLabel; } }