import { AUTH_USER_ID, CLAIM_NAME } from "@/shared/config"; import { getCookie, setCookie, removeCookie } from "@/shared/lib"; export class TokenManager { private static instance: TokenManager; private refreshTimer: NodeJS.Timeout | null = null; private constructor() {} public static getInstance(): TokenManager { if (!TokenManager.instance) { TokenManager.instance = new TokenManager(); } return TokenManager.instance; } public getToken(key: string): string | undefined { return getCookie(key); } public setToken(key: string, value: string): void { // 환경에 따른 도메인 설정 const domain = this.getCookieDomain(); setCookie(key, value, { secure: window.location.protocol === "https:", sameSite: "lax", domain: domain, path: "/", // 모든 경로에서 접근 가능 }); } private getCookieDomain(): string | undefined { const hostname = window.location.hostname; // 개발 환경에서는 localhost 도메인 사용 if (hostname === "localhost" || hostname === "127.0.0.1") { return undefined; // localhost에서는 도메인 설정하지 않음 } // 운영 환경에서는 서브도메인을 포함한 최상위 도메인 사용 if (hostname.includes("hasuon.or.kr")) { return ".hasuon.or.kr"; } // 기타 환경에서는 현재 호스트명 사용 return hostname; } public removeToken(key: string): void { const domain = this.getCookieDomain(); removeCookie(key, { domain, path: "/" }); } public setupRefreshTimer( callback: () => Promise, expirationTime: number, ): void { if (this.refreshTimer) { clearTimeout(this.refreshTimer); } this.refreshTimer = setTimeout(() => { callback().catch((error) => { console.error("Silent refresh failed:", error); this.clearAuthToken(); }); }, expirationTime - 60000); } public clearAuthToken(): void { if (this.refreshTimer) { clearTimeout(this.refreshTimer); this.refreshTimer = null; } this.removeToken(CLAIM_NAME); this.removeToken(AUTH_USER_ID); } } export const tokenManager = TokenManager.getInstance();