import { create } from 'zustand' import { persist } from 'zustand/middleware' import type { AuthSession, Tenant, User } from '@/types' import type { RoleKey } from '@/config/roles' import { setTokenGetter, setUnauthorizedHandler } from '@/services/api/client' interface AuthState { token: string | null user: User | null tenant: Tenant | null onboarded: boolean setSession: (session: AuthSession) => void logout: () => void setOnboarded: (v: boolean) => void } export const useAuthStore = create()( persist( (set) => ({ token: null, user: null, tenant: null, onboarded: true, setSession: (session) => set({ token: session.token, user: session.user, tenant: session.tenant, onboarded: session.onboarded }), logout: () => set({ token: null, user: null, tenant: null }), setOnboarded: (v) => set({ onboarded: v }), }), { name: 'lx-auth' }, ), ) // 让 API client 能读取 token(真实后端模式使用) setTokenGetter(() => useAuthStore.getState().token) setUnauthorizedHandler(() => { useAuthStore.getState().logout() if (!window.location.pathname.startsWith('/login')) { window.location.replace('/login?reason=session-expired') } }) export function isSessionTokenExpired(token: string | null): boolean { if (!token) return true try { const encoded = token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/') const padded = encoded.padEnd(Math.ceil(encoded.length / 4) * 4, '=') const payload = JSON.parse(window.atob(padded)) as { exp?: number } return !payload.exp || payload.exp * 1_000 <= Date.now() } catch { return true } } export function useCurrentRole(): RoleKey { return useAuthStore((s) => s.user?.role ?? 'viewer') }