import { queryClient } from '../lib/queryClient'; export const LOCAL_STORAGE_TOKEN_KEY = 'pfm_access_token'; export const LOCAL_STORAGE_USER_KEY = 'pfm_auth_user'; export const LOCAL_STORAGE_SUB_KEY = 'pfm_user_sub'; export const LOCAL_STORAGE_CLAIMS_KEY = 'pfm_user_claims'; export const LOCAL_STORAGE_USER_SYNC_KEY = 'pfm_user_sync_record'; export const LOCAL_STORAGE_ACTIVATION_PENDING_KEY = 'pfm_user_pending_activation'; export const LOCAL_STORAGE_ACTIVATION_REASON_KEY = 'pfm_user_pending_activation_reason'; export function isUserSyncEndpoint(url?: string): boolean { if (!url) return false; const clean = url.toLowerCase().split('?')[0]; return ( clean.includes('/users/sync') || clean.includes('/integration/sync') || clean.includes('/user/sync') || clean.endsWith('/sync') || clean === '/sync' ); } export function isTenantEndpoint(url?: string): boolean { if (!url) return false; const clean = url.toLowerCase().split('?')[0]; return clean.includes('/governance/tenants'); } type SessionExpiredListener = (reason?: string) => void; const listeners = new Set(); let hasTriggeredSessionExpired = false; export function dismissSubordinateModals(): void { if (typeof window !== 'undefined') { window.dispatchEvent(new CustomEvent('pfm:dismiss-subordinates')); } } export function cancelSessionExpiration(): void { hasTriggeredSessionExpired = false; if (typeof window !== 'undefined') { window.dispatchEvent(new CustomEvent('pfm:session-expired-cancelled')); } } export function isSessionExpiredState(): boolean { return hasTriggeredSessionExpired; } export function triggerSessionExpired(reason?: string, requestUrl?: string): void { if (requestUrl && isUserSyncEndpoint(requestUrl)) { return; } if (typeof window !== 'undefined' && localStorage.getItem(LOCAL_STORAGE_ACTIVATION_PENDING_KEY)) { return; } if (hasTriggeredSessionExpired) { return; } const hasExistingToken = typeof window !== 'undefined' && !!localStorage.getItem(LOCAL_STORAGE_TOKEN_KEY); if (!hasExistingToken) { return; } hasTriggeredSessionExpired = true; dismissSubordinateModals(); if (typeof window !== 'undefined') { window.dispatchEvent( new CustomEvent('pfm:session-expired', { detail: { reason: reason || 'HTTP 401 Unauthorized' }, }) ); } listeners.forEach((callback) => { try { callback(reason); } catch (err) { console.warn('[SessionExpiration] Callback execution error:', err); } }); } export function onSessionExpired(listener: SessionExpiredListener): () => void { listeners.add(listener); return () => { listeners.delete(listener); }; } export function resetSessionExpiredState(): void { hasTriggeredSessionExpired = false; } export function clearSessionAndRedirectToLanding(): void { if (typeof window === 'undefined') return; try { localStorage.removeItem(LOCAL_STORAGE_TOKEN_KEY); localStorage.removeItem(LOCAL_STORAGE_USER_KEY); localStorage.removeItem(LOCAL_STORAGE_SUB_KEY); localStorage.removeItem(LOCAL_STORAGE_CLAIMS_KEY); localStorage.removeItem(LOCAL_STORAGE_USER_SYNC_KEY); localStorage.removeItem(LOCAL_STORAGE_ACTIVATION_PENDING_KEY); localStorage.removeItem(LOCAL_STORAGE_ACTIVATION_REASON_KEY); } catch (err) { console.warn('[SessionExpiration] Storage cleanup warning:', err); } try { queryClient.clear(); } catch (err) { console.warn('[SessionExpiration] QueryClient clear warning:', err); } resetSessionExpiredState(); window.location.replace('/'); }