/** * Admin 后台管理系统 - 统一 API 客户端(门面) * * 鉴权:通过 POST /api/v1/auth/login 用密码换取 HttpOnly Cookie 会话, * 同源请求自动携带 Cookie,无需手动管理密钥。 * 收到 401 时广播 `profeto:unauthorized` 事件,由 AdminLayout 切回登录页。 * * 实现已收敛到共享层 lib/http.ts(超时/错误解析/401 广播只此一份), * 本文件仅保留 Admin 侧的门面签名与认证接口,供既有页面按原路径导入。 */ import { http, ApiError, UNAUTHORIZED_EVENT } from '../lib/http' /** Admin 侧兼容导出:错误类型与会话失效事件名的规范来源在 lib/http */ export { ApiError, UNAUTHORIZED_EVENT } const API_BASE = '/api/v1' /** Admin 请求可覆盖项(与 lib/http RequestOptions 对齐的子集) */ type ApiOpts = { timeoutMs?: number /** 改密接口的 401 表示「当前密码错误」,非会话过期,置 true 跳过登出广播 */ skipAuthHandling?: boolean } export const api = { get: (path: string) => http.get(path), post: (path: string, body?: unknown, opts?: ApiOpts) => http.post(path, body, opts), put: (path: string, body?: unknown, opts?: ApiOpts) => http.put(path, body, opts), delete: (path: string) => http.delete(path), } // ── 认证 ──────────────────────────────────────────────────────── /** 密码登录,成功后服务端写入 HttpOnly 会话 Cookie */ export function login(password: string): Promise<{ ok: boolean }> { return api.post(`${API_BASE}/auth/login`, { password }) } /** 退出登录,清除会话 Cookie */ export function logout(): Promise<{ ok: boolean }> { return api.post(`${API_BASE}/auth/logout`) } /** 探测当前登录状态 */ export function fetchAuthState(): Promise<{ authenticated: boolean enabled: boolean password_origin?: 'db' | 'env' | 'none' }> { return api.get(`${API_BASE}/auth/me`) } /** 修改管理员密码(成功后所有会话失效,需重新登录) */ export function changePassword(currentPassword: string, newPassword: string): Promise<{ ok: boolean; message: string }> { // skipAuthHandling: 改密接口的 401 表示「当前密码错误」,非会话过期,不要触发登出 return api.post( `${API_BASE}/auth/change-password`, { current_password: currentPassword, new_password: newPassword }, { skipAuthHandling: true }, ) } export { API_BASE }