type AuthUser = { id: string email: string name: string role?: string type?: string } const getApiBase = () => { if (typeof window !== 'undefined') { return '' } const viteEnv = (import.meta as ImportMeta & { env?: Record }).env return viteEnv?.VITE_API_BASE_URL || process.env.VITE_API_BASE_URL || process.env.API_URL || '' } const getErrorMessage = async (response: Response) => { const text = await response.text() if (!text) { return `Request failed with status ${response.status}` } try { const data = JSON.parse(text) as { message?: string; error?: string } return data.message || data.error || text } catch { return text } } const authFetch = async (path: string, init?: RequestInit): Promise => { const headers = new Headers(init?.headers) const hasBody = init?.body !== undefined && init?.body !== null if (hasBody && !headers.has('content-type')) { headers.set('content-type', 'application/json') } const response = await fetch(`${getApiBase()}${path}`, { ...init, credentials: 'include', headers, }) if (!response.ok) { throw new Error(await getErrorMessage(response)) } if (response.status === 204) { return undefined as T } return await response.json() as T } export const signInWithPassword = async (email: string, password: string) => { return await authFetch<{ redirect: boolean token: string url?: string user: AuthUser }>('/api/auth/sign-in/email', { method: 'POST', body: JSON.stringify({ email, password, }), }) } export const requestMagicLink = async (email: string) => { return await authFetch<{ status: boolean }>('/api/auth/sign-in/magic-link', { method: 'POST', body: JSON.stringify({ email }), }) } export const verifyMagicLink = async (token: string) => { return await authFetch<{ token: string user: AuthUser session: { id: string userId: string expiresAt: string } }>(`/api/auth/magic-link/verify?token=${encodeURIComponent(token)}`, { method: 'GET', }) } export const signOut = async () => { return await authFetch('/api/auth/sign-out', { method: 'POST', body: JSON.stringify({}), }) }