import { computed, ref } from 'vue' import { defineStore } from 'pinia' import { z } from 'zod' import { API_BASE } from '@/utils/apiBase' export const authUserSchema = z.object({ id: z.number().int().positive(), email: z.string().email(), }) const meResponseSchema = z.object({ user: authUserSchema, }) const loginErrorResponseSchema = z.object({ error: z.string(), }) export type AuthUser = z.infer export type LoginFieldErrors = Partial> export const useAuthStore = defineStore('auth', () => { const user = ref(null) const loading = ref(false) const error = ref(null) const isAuthenticated = computed(() => user.value !== null) async function fetchMe(): Promise { loading.value = true error.value = null try { const response = await fetch(`${API_BASE}/api/me`, { method: 'GET', credentials: 'include', headers: { Accept: 'application/json', }, }) if (response.status === 200) { const responseBody: unknown = await response.json() user.value = meResponseSchema.parse(responseBody).user return true } user.value = null if (response.status !== 401) { error.value = 'Unable to restore session' } return false } catch { user.value = null error.value = 'Unable to restore session' return false } finally { loading.value = false } } async function login(email: string, password: string): Promise { loading.value = true error.value = null try { const response = await fetch(`${API_BASE}/api/login`, { method: 'POST', credentials: 'include', headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify({ email, password }), }) const responseBody: unknown = await response.json() if (response.status === 200) { user.value = meResponseSchema.parse(responseBody).user return true } user.value = null const errorResponse = loginErrorResponseSchema.safeParse(responseBody) error.value = errorResponse.success ? errorResponse.data.error : 'Unable to log in. Please try again.' return false } catch { user.value = null error.value = 'Unable to log in. Please try again.' return false } finally { loading.value = false } } async function logout(): Promise { try { await fetch(`${API_BASE}/api/logout`, { method: 'POST', credentials: 'include', headers: { Accept: 'application/json', }, }) } finally { user.value = null } } return { user, loading, error, isAuthenticated, fetchMe, login, logout, } })