import { storageGet, storageSet, storageRemove } from './storage'; /* ===================== 双 Token 存储(access + refresh) ===================== * 规范 §4:Access Token 用于业务请求;Refresh Token 只提交给 /auth/refresh。 * * 鉴权请求头在 fetch 构造时是「同步」的,但 AsyncStorage 是异步的, * 因此这里保留一份内存单例,供请求层同步读取 accessToken; * 持久化仍走 storage(qingsongpin: 前缀),由 hydrateTokens 在启动时回填。 */ const KEY_ACCESS = 'auth:accessToken'; const KEY_REFRESH = 'auth:refreshToken'; const KEY_EXP = 'auth:expiresAt'; export interface TokenPair { accessToken: string; refreshToken: string; /** accessToken 过期时间戳(毫秒);后端可能不返回,故可选 */ expiresAt?: number; } let memory: TokenPair | null = null; /** 应用启动时调用一次:从持久化回填内存态;失败静默降级为未登录 */ export async function hydrateTokens(): Promise { try { const [access, refresh, exp] = await Promise.all([ storageGet(KEY_ACCESS), storageGet(KEY_REFRESH), storageGet(KEY_EXP), ]); if (access && refresh) { memory = { accessToken: access, refreshToken: refresh, expiresAt: exp ? Number(exp) : undefined, }; } } catch { /* 降级为未登录 */ } } /** 同步读取 accessToken(供请求层构造 Authorization 头) */ export function getAccessToken(): string | null { return memory?.accessToken ?? null; } /** 同步读取完整 Token 对(供刷新判断是否有 refreshToken) */ export function getTokens(): TokenPair | null { return memory; } /** 写入并持久化;expiresAt 缺省时不覆盖已存值 */ export async function setTokens( accessToken: string, refreshToken: string, expiresAt?: number, ): Promise { memory = { accessToken, refreshToken, expiresAt }; const writes: Promise[] = [ storageSet(KEY_ACCESS, accessToken), storageSet(KEY_REFRESH, refreshToken), ]; if (expiresAt !== undefined) { writes.push(storageSet(KEY_EXP, String(expiresAt))); } await Promise.all(writes); } /** 清空(登出 / 刷新失败 / 401 清会话):内存与持久化一并清 */ export async function clearTokens(): Promise { memory = null; await Promise.all([ storageRemove(KEY_ACCESS), storageRemove(KEY_REFRESH), storageRemove(KEY_EXP), ]); } /** 仅供测试:复位内存态,避免用例间污染 */ export function __resetTokenMemory(): void { memory = null; }