interface JwtPayload { exp?: number; [key: string]: unknown; } /** * JWT 토큰의 exp 클레임(Unix timestamp, 초 단위)을 반환합니다. * 파싱 실패 시 null을 반환합니다. */ export function getJwtExpiry(token: string): number | null { try { const base64Payload = token.split(".")[1]; if (!base64Payload) return null; const payload = JSON.parse(atob(base64Payload)) as JwtPayload; return typeof payload.exp === "number" ? payload.exp : null; } catch { return null; } } /** * 토큰 만료 1분 전까지 남은 시간(ms)을 반환합니다. * 이미 만료됐거나 파싱 실패 시 0을 반환합니다. */ export function getRemainingMs(token: string): number { const exp = getJwtExpiry(token); if (!exp) return 0; const remainingMs = exp * 1000 - Date.now() - 60_000; return Math.max(0, remainingMs); }