/** * 登录/会话的接口封装。 * * 会话是 HttpOnly Cookie,前端拿不到 token,只能问 `/api/auth/session`。 */ export type SessionState = { authenticated: boolean has_admin: boolean username?: string | null } type Result = { ok: true } | { ok: false; status: number; error: string } async function request( method: 'POST' | 'PATCH', url: string, body: unknown, ): Promise { try { const response = await fetch(url, { method, credentials: 'same-origin', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body), }) if (response.ok) return { ok: true } const payload = (await response.json().catch(() => null)) as { error?: string } | null return { ok: false, status: response.status, error: payload?.error ?? `请求失败(${response.status})`, } } catch (error) { return { ok: false, status: 0, error: error instanceof Error ? error.message : '网络错误' } } } export async function fetchSession(): Promise { try { const response = await fetch('/api/auth/session', { credentials: 'same-origin' }) if (!response.ok) return { authenticated: false, has_admin: false } return (await response.json()) as SessionState } catch { return { authenticated: false, has_admin: false } } } export function login(password: string): Promise { return request('POST', '/api/auth/login', { password }) } export function setup(password: string, username = 'admin'): Promise { return request('POST', '/api/auth/setup', { password, username }) } export function logout(): Promise { return request('POST', '/api/auth/logout', {}) } export function changePassword(current: string, next: string): Promise { return request('PATCH', '/api/auth/password', { current, next }) }