diff --git a/script.js b/script.js index e414310..8dcd18d 100644 --- a/script.js +++ b/script.js @@ -446,10 +446,12 @@ function getAuthConfig() { const cfg = globalThis.AUTH_CONFIG && typeof globalThis.AUTH_CONFIG === "object" ? globalThis.AUTH_CONFIG : {}; const allowEndUserConfig = Boolean(cfg.allowEndUserConfig); + const apiBase = String(cfg.apiBase || "").trim(); // optional, e.g. https://api.ncue.net const auth0 = cfg.auth0 && typeof cfg.auth0 === "object" ? cfg.auth0 : {}; const allowedEmails = Array.isArray(cfg.allowedEmails) ? cfg.allowedEmails : []; const base = { allowEndUserConfig, + apiBase, auth0: { domain: String(auth0.domain || "").trim(), clientId: String(auth0.clientId || "").trim(), @@ -466,6 +468,7 @@ // override가 있으면 우선 적용 (서버 재배포 없이 테스트 가능) return { allowEndUserConfig, + apiBase, auth0: { domain: override.auth0.domain || base.auth0.domain, clientId: override.auth0.clientId || base.auth0.clientId, @@ -479,6 +482,17 @@ }; } + function apiUrl(pathname) { + const cfg = getAuthConfig(); + const base = cfg.apiBase; + if (!base) return pathname; // same-origin + try { + return new URL(pathname, base).toString(); + } catch { + return pathname; + } + } + function currentUrlNoQuery() { // Auth0 callback 후 URL 정리용 const u = new URL(location.href); @@ -649,7 +663,7 @@ async function syncUserToServerWithIdToken(idToken) { try { const cfg = getAuthConfig(); - const r = await fetch("/api/auth/sync", { + const r = await fetch(apiUrl("/api/auth/sync"), { method: "POST", headers: { Authorization: `Bearer ${idToken}`, @@ -657,11 +671,18 @@ "X-Auth0-ClientId": cfg.auth0.clientId, }, }); - if (!r.ok) return null; + if (!r.ok) { + toastOnce( + "syncfail", + `사용자 저장(API)이 실패했습니다. (${r.status}) 정적 호스팅이면 /api 를 서버로 프록시하거나 apiBase를 설정해야 합니다.` + ); + return null; + } const data = await r.json(); if (data && data.ok) return Boolean(data.canManage); return null; } catch { + toastOnce("syncerr", "사용자 저장(API)에 연결하지 못했습니다. /api 서버 연결을 확인하세요."); return null; } } @@ -673,14 +694,14 @@ // Prefer sendBeacon to survive navigation try { const blob = new Blob([payload], { type: "application/json" }); - const ok = navigator.sendBeacon("/api/auth/logout", blob); + const ok = navigator.sendBeacon(apiUrl("/api/auth/logout"), blob); if (ok) return; } catch { // ignore } // Fallback fetch keepalive (best-effort) try { - fetch("/api/auth/logout", { + fetch(apiUrl("/api/auth/logout"), { method: "POST", headers: { Authorization: `Bearer ${idToken}`,