const API_BASE_URL = import.meta.env.VITE_API_BASE_URL ?? ''; const ADMIN_LOGIN_URL = '/uat/uia/actionSecurityLogin.do'; const ADMIN_ID = 'admin'; const ADMIN_PASSWORD = '1'; type ApiEnvelope = { success?: boolean; message?: string; data?: T; }; let loginPromise: Promise | null = null; function toApiUrl(path: string) { if (/^https?:\/\//i.test(path)) { return path; } return `${API_BASE_URL}${path}`; } function createHeaders(headers?: HeadersInit) { return new Headers(headers); } async function adminLogin() { if (!loginPromise) { loginPromise = fetch(toApiUrl(ADMIN_LOGIN_URL), { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest', }, body: new URLSearchParams({ id: ADMIN_ID, password: ADMIN_PASSWORD, }), }) .then(async (response) => { if (!response.ok) { throw new Error(`Admin login failed: ${response.status}`); } const contentType = response.headers.get('content-type') ?? ''; if (contentType.includes('application/json')) { const result = (await response.json()) as ApiEnvelope; if (result.success === false) { throw new Error(result.message ?? 'Admin login failed'); } } }) .finally(() => { loginPromise = null; }); } return loginPromise; } async function needsAdminLogin(response: Response) { if (response.type === 'opaqueredirect' || response.status === 0) { return true; } if (response.status >= 300 && response.status < 400) { return true; } if (response.status === 401 || response.status === 403) { return true; } const contentType = response.headers.get('content-type') ?? ''; if (contentType.includes('text/html')) { const html = await response.clone().text(); return html.includes('/uat/uia/actionMain.do') || html.includes('actionSecurityLogin.do'); } if (contentType.includes('application/json')) { try { const result = (await response.clone().json()) as ApiEnvelope; const message = result.message ?? ''; return result.success === false && /login|로그인|/.test(message); } catch { return false; } } return false; } export async function adminAuthFetch(path: string, init: RequestInit = {}, retry = true): Promise { const response = await fetch(toApiUrl(path), { ...init, credentials: 'include', headers: createHeaders(init.headers), redirect: 'manual', }); if (retry && (await needsAdminLogin(response))) { await adminLogin(); return adminAuthFetch(path, init, false); } return response; } export async function adminAuthJson(path: string, init?: RequestInit): Promise { const response = await adminAuthFetch(path, init); if (!response.ok) { throw new Error(`API request failed: ${response.status}`); } const result = (await response.json()) as ApiEnvelope; if (result.success === false) { throw new Error(result.message ?? 'API request failed'); } return result.data as T; }