const AUTH_STORAGE_KEY = 'ten-minute-planner-auth' import { buildApiUrl, toUserFacingApiError } from './apiBase' function buildHeaders(token, hasBody, extraHeaders = {}) { return { ...(hasBody ? { 'Content-Type': 'application/json' } : {}), ...(token ? { Authorization: `Bearer ${token}` } : {}), ...extraHeaders, } } async function request(path, { method = 'GET', token, body } = {}) { const hasBody = body !== undefined const response = await fetch(buildApiUrl(path), { method, headers: buildHeaders(token, hasBody), body: hasBody ? JSON.stringify(body) : undefined, }) const data = await response.json().catch(() => ({})) if (!response.ok) { throw new Error(toUserFacingApiError(data, '요청 처리 중 문제가 발생했습니다.')) } return data } export function readAuthState() { if (typeof window === 'undefined') { return { token: '', user: null, persist: false } } try { const localState = JSON.parse(window.localStorage.getItem(AUTH_STORAGE_KEY) ?? 'null') if (localState?.token) { return { ...localState, persist: true } } const sessionState = JSON.parse(window.sessionStorage.getItem(AUTH_STORAGE_KEY) ?? 'null') if (sessionState?.token) { return { ...sessionState, persist: false } } return { token: '', user: null, persist: false } } catch (error) { console.warn('저장된 인증 상태를 불러오지 못했습니다.', error) return { token: '', user: null, persist: false } } } export function persistAuthState({ token, user, persist = false }) { if (typeof window === 'undefined') { return } const targetStorage = persist ? window.localStorage : window.sessionStorage const unusedStorage = persist ? window.sessionStorage : window.localStorage unusedStorage.removeItem(AUTH_STORAGE_KEY) targetStorage.setItem(AUTH_STORAGE_KEY, JSON.stringify({ token, user })) } export function clearAuthState() { if (typeof window === 'undefined') { return } window.localStorage.removeItem(AUTH_STORAGE_KEY) window.sessionStorage.removeItem(AUTH_STORAGE_KEY) } export async function signup({ email, password, nickname }) { return request('/api/auth/signup', { method: 'POST', body: { email, password, nickname }, }) } export async function login({ email, password }) { return request('/api/auth/login', { method: 'POST', body: { email, password }, }) } export async function fetchCurrentUser(token) { return request('/api/auth/me', { token, }) } export async function logout(token) { return request('/api/auth/logout', { method: 'POST', token, }) } export async function updateProfile(token, { email, nickname }) { return request('/api/auth/profile', { method: 'PUT', token, body: { email, nickname }, }) } export async function updatePassword(token, { currentPassword, newPassword }) { return request('/api/auth/password', { method: 'PUT', token, body: { currentPassword, newPassword }, }) } export async function deleteAccount(token, { currentPassword }) { return request('/api/auth/account', { method: 'DELETE', token, body: { currentPassword }, }) } export async function requestPasswordReset({ email }) { return request('/api/auth/password-reset/request', { method: 'POST', body: { email }, }) } export async function confirmPasswordReset({ token, newPassword }) { return request('/api/auth/password-reset/confirm', { method: 'POST', body: { token, newPassword }, }) } export async function confirmVerification({ token }) { return request('/api/auth/verification/confirm', { method: 'POST', body: { token }, }) } export async function requestVerification({ email }, token) { return request('/api/auth/verification/request', { method: 'POST', token, body: email ? { email } : {}, }) }