ultisuite-client/lib/auth/handle-unauthorized.ts
R3D347HR4Y ad1370ea7e
Some checks are pending
E2E / Playwright e2e (push) Waiting to run
feat: enhance configuration and add new demo layouts
- Introduced turbopack alias for canvas in next.config.mjs.
- Updated package.json scripts for development and branding tasks.
- Added new dependencies for Tiptap extensions.
- Implemented new demo layouts for agenda, contacts, drive, and mail applications.
- Enhanced globals.css for improved theming and splash screen animations.
- Added OAuth callback handling for drive mounts.
- Updated layout components to integrate new demo shells and improve structure.
2026-06-12 19:10:24 +02:00

95 lines
2.1 KiB
TypeScript

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<UnauthorizedResolution> | 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<UnauthorizedResolution> {
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<UnauthorizedResolution> {
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
}