const API_BASE = process.env.NEXT_PUBLIC_API_URL || ''; export interface User { id: string; email: string; name: string; avatar?: string; role: 'user' | 'admin'; tier: 'free' | 'pro' | 'business'; balance: number; emailVerified: boolean; provider: string; createdAt: string; updatedAt: string; } export interface AuthTokens { accessToken: string; refreshToken: string; expiresIn: number; tokenType: string; user: User; } export interface RegisterRequest { email: string; password: string; name: string; } export interface LoginRequest { email: string; password: string; } export interface ChangePasswordRequest { currentPassword: string; newPassword: string; } export interface ResetPasswordRequest { email: string; } export interface ResetPasswordConfirm { token: string; newPassword: string; } export interface UpdateProfileRequest { name: string; avatar?: string; } const TOKEN_KEY = 'token'; const REFRESH_TOKEN_KEY = 'refreshToken'; const USER_KEY = 'user'; export function getStoredToken(): string | null { if (typeof window === 'undefined') return null; return localStorage.getItem(TOKEN_KEY); } export function getStoredRefreshToken(): string | null { if (typeof window === 'undefined') return null; return localStorage.getItem(REFRESH_TOKEN_KEY); } export function getStoredUser(): User | null { if (typeof window === 'undefined') return null; const data = localStorage.getItem(USER_KEY); if (!data) return null; try { return JSON.parse(data); } catch { return null; } } export function storeAuth(tokens: AuthTokens): void { localStorage.setItem(TOKEN_KEY, tokens.accessToken); localStorage.setItem(REFRESH_TOKEN_KEY, tokens.refreshToken); localStorage.setItem(USER_KEY, JSON.stringify(tokens.user)); } export function clearAuth(): void { localStorage.removeItem(TOKEN_KEY); localStorage.removeItem(REFRESH_TOKEN_KEY); localStorage.removeItem(USER_KEY); } async function handleResponse(response: Response): Promise { if (!response.ok) { const data = await response.json().catch(() => ({})); throw new Error(data.error || `Request failed: ${response.status}`); } return response.json(); } export async function register(data: RegisterRequest): Promise { const response = await fetch(`${API_BASE}/api/v1/auth/register`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }); const tokens = await handleResponse(response); storeAuth(tokens); return tokens; } export async function login(data: LoginRequest): Promise { const response = await fetch(`${API_BASE}/api/v1/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }); const tokens = await handleResponse(response); storeAuth(tokens); return tokens; } export async function refreshTokens(): Promise { const refreshToken = getStoredRefreshToken(); if (!refreshToken) return null; try { const response = await fetch(`${API_BASE}/api/v1/auth/refresh`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ refreshToken }), }); if (!response.ok) { clearAuth(); return null; } const tokens = await response.json(); storeAuth(tokens); return tokens; } catch { clearAuth(); return null; } } export async function logout(): Promise { const token = getStoredToken(); const refreshToken = getStoredRefreshToken(); if (token) { try { await fetch(`${API_BASE}/api/v1/auth/logout`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, }, body: JSON.stringify({ refreshToken }), }); } catch { // Ignore errors during logout } } clearAuth(); } export async function logoutAll(): Promise { const token = getStoredToken(); if (token) { try { await fetch(`${API_BASE}/api/v1/auth/logout-all`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, }, }); } catch { // Ignore errors } } clearAuth(); } export async function getMe(): Promise { const token = getStoredToken(); if (!token) return null; try { const response = await fetch(`${API_BASE}/api/v1/auth/me`, { headers: { 'Authorization': `Bearer ${token}`, }, }); if (!response.ok) { if (response.status === 401) { const refreshed = await refreshTokens(); if (refreshed) { return getMe(); } return null; } return null; } return response.json(); } catch { return null; } } export async function updateProfile(data: UpdateProfileRequest): Promise { const token = getStoredToken(); if (!token) throw new Error('Not authenticated'); const response = await fetch(`${API_BASE}/api/v1/auth/me`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, }, body: JSON.stringify(data), }); const user = await handleResponse(response); const storedUser = getStoredUser(); if (storedUser) { localStorage.setItem(USER_KEY, JSON.stringify({ ...storedUser, ...user })); } return user; } export async function changePassword(data: ChangePasswordRequest): Promise { const token = getStoredToken(); if (!token) throw new Error('Not authenticated'); const response = await fetch(`${API_BASE}/api/v1/auth/change-password`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, }, body: JSON.stringify(data), }); await handleResponse<{ message: string }>(response); } export async function forgotPassword(email: string): Promise { const response = await fetch(`${API_BASE}/api/v1/auth/forgot-password`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email }), }); await handleResponse<{ message: string }>(response); } export async function resetPassword(data: ResetPasswordConfirm): Promise { const response = await fetch(`${API_BASE}/api/v1/auth/reset-password`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }); await handleResponse<{ message: string }>(response); } export function isAuthenticated(): boolean { return !!getStoredToken(); }