import { getStoredToken, getStoredUser } from "@/app/lib/pocketbase"; export const API_BASE = (process.env.NEXT_PUBLIC_API_BASE_URL || "").replace(/\/$/, ""); export function apiUrl(path: string): string { if (/^https?:\/\//i.test(path)) return path; const normalizedPath = path.startsWith("/") ? path : `/${path}`; if (API_BASE.endsWith("/api") && normalizedPath.startsWith("/api/")) { return `${API_BASE}${normalizedPath.slice(4)}`; } return `${API_BASE}${normalizedPath}`; } export async function apiFetch( path: string, init?: RequestInit ): Promise { const res = await fetch(apiUrl(path), { credentials: "include", ...init, headers: init?.body instanceof FormData ? init.headers : { "Content-Type": "application/json", ...(init?.headers || {}), }, }); const data = await res.json().catch(() => ({})); if (!res.ok) { throw new Error(data?.detail || data?.error || `HTTP ${res.status}`); } return data as T; } export type AuthUser = { id: string; email: string; vip?: boolean; role?: string; [key: string]: unknown; }; export type AuthMeResponse = { user?: AuthUser | null; token?: string; }; /** 读取当前登录用户;失败时返回 null,不抛错 */ export async function fetchAuthMe(): Promise { try { return await apiFetch("/api/auth/me", { cache: "no-store" }); } catch { return null; } } /** 将本地 PocketBase token 同步到 httpOnly cookie */ export async function syncAuthSession( token: string, record: Record ): Promise { try { await apiFetch("/api/auth/sync-session", { method: "POST", body: JSON.stringify({ token, record }), }); return true; } catch { return false; } } /** * 解析当前用户:优先 cookie 会话,其次本地 token 同步后再读。 * 返回 user + token(若有),未登录返回 null。 */ export async function resolveAuthUser(): Promise<{ user: AuthUser; token: string; } | null> { let data = await fetchAuthMe(); if (data?.user?.id && data?.token) { return { user: data.user, token: data.token }; } const token = getStoredToken(); const record = getStoredUser(); if (token && record?.id && record?.email) { const synced = await syncAuthSession(token, record as Record); if (synced) { data = await fetchAuthMe(); if (data?.user?.id && data?.token) { return { user: data.user, token: data.token }; } } } return null; }