import { useAuthStore } from "@/lib/api/auth-store" import { ensureAccessToken } from "@/lib/auth/ensure-access-token" import { fetchSession, tryRefreshSession } from "@/lib/auth/session-sync" import { isSessionExpired, useSessionGuardStore, } from "@/lib/auth/session-guard-store" import { isDemoPublicPath } from "@/lib/auth/public-paths" export type UnauthorizedResolution = "refreshed" | "offline" | "expired" type HandleUnauthorizedOptions = { /** API still returns 401 after a session refresh attempt. */ forceExpired?: boolean } let pending: Promise | null = null function isBrowserOffline() { return typeof navigator !== "undefined" && !navigator.onLine } function isDemoRoute() { if (typeof window === "undefined") return false return isDemoPublicPath(window.location.pathname) } function markSessionExpired() { if (isDemoRoute()) return useAuthStore.getState().logout() useSessionGuardStore.getState().setExpired() } async function resolveUnauthorized( opts?: HandleUnauthorizedOptions ): Promise { if (isDemoRoute()) { return "refreshed" } if (isSessionExpired()) { return "expired" } if (opts?.forceExpired) { markSessionExpired() return "expired" } if (isBrowserOffline()) { useSessionGuardStore.getState().setOffline() return "offline" } if (await tryRefreshSession()) { return "refreshed" } const session = await fetchSession() if (session?.authenticated) { return "refreshed" } if (await ensureAccessToken()) { return "refreshed" } markSessionExpired() return "expired" } /** Verify session after a 401; deduped across concurrent API calls. */ export function handleUnauthorized( opts?: HandleUnauthorizedOptions ): Promise { if (isDemoRoute()) { return Promise.resolve("refreshed") } if (isSessionExpired()) { return Promise.resolve("expired") } if (opts?.forceExpired) { return resolveUnauthorized(opts) } if (!pending) { pending = resolveUnauthorized().finally(() => { pending = null }) } return pending }