mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-21 14:11:12 -05:00
feat: Implement auth logging and session verification optimizations
This commit is contained in:
@@ -3,6 +3,7 @@ import type { User, Session } from '@supabase/supabase-js';
|
|||||||
import { supabase } from '@/integrations/supabase/client';
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
import type { Profile } from '@/types/database';
|
import type { Profile } from '@/types/database';
|
||||||
import { toast } from '@/hooks/use-toast';
|
import { toast } from '@/hooks/use-toast';
|
||||||
|
import { authLog, authWarn, authError } from '@/lib/authLogger';
|
||||||
|
|
||||||
interface AuthContextType {
|
interface AuthContextType {
|
||||||
user: User | null;
|
user: User | null;
|
||||||
@@ -36,6 +37,7 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
|||||||
const previousEmailRef = useRef<string | null>(null);
|
const previousEmailRef = useRef<string | null>(null);
|
||||||
const loadingTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
const loadingTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
const loadingStateRef = useRef(loading);
|
const loadingStateRef = useRef(loading);
|
||||||
|
const lastVisibilityVerificationRef = useRef<number>(Date.now());
|
||||||
|
|
||||||
const fetchProfile = async (userId: string, retryCount = 0, onComplete?: () => void) => {
|
const fetchProfile = async (userId: string, retryCount = 0, onComplete?: () => void) => {
|
||||||
try {
|
try {
|
||||||
@@ -46,12 +48,12 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
|||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
|
|
||||||
if (error && error.code !== 'PGRST116') {
|
if (error && error.code !== 'PGRST116') {
|
||||||
console.error('[Auth] Error fetching profile:', error);
|
authError('[Auth] Error fetching profile:', error);
|
||||||
|
|
||||||
// Retry up to 3 times with exponential backoff
|
// Retry up to 3 times with exponential backoff
|
||||||
if (retryCount < 3 && isMountedRef.current) {
|
if (retryCount < 3 && isMountedRef.current) {
|
||||||
const delay = Math.pow(2, retryCount) * 1000; // 1s, 2s, 4s
|
const delay = Math.pow(2, retryCount) * 1000; // 1s, 2s, 4s
|
||||||
console.log(`[Auth] Retrying profile fetch in ${delay}ms (attempt ${retryCount + 1}/3)`);
|
authLog(`[Auth] Retrying profile fetch in ${delay}ms (attempt ${retryCount + 1}/3)`);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (isMountedRef.current) {
|
if (isMountedRef.current) {
|
||||||
fetchProfile(userId, retryCount + 1, onComplete);
|
fetchProfile(userId, retryCount + 1, onComplete);
|
||||||
@@ -62,7 +64,7 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
|||||||
|
|
||||||
// All retries exhausted - complete anyway
|
// All retries exhausted - complete anyway
|
||||||
if (isMountedRef.current) {
|
if (isMountedRef.current) {
|
||||||
console.warn('[Auth] Profile fetch failed after 3 retries');
|
authWarn('[Auth] Profile fetch failed after 3 retries');
|
||||||
setProfile(null);
|
setProfile(null);
|
||||||
onComplete?.();
|
onComplete?.();
|
||||||
}
|
}
|
||||||
@@ -76,7 +78,7 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
|||||||
onComplete?.();
|
onComplete?.();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[Auth] Error fetching profile:', error);
|
authError('[Auth] Error fetching profile:', error);
|
||||||
|
|
||||||
// Retry logic for network errors
|
// Retry logic for network errors
|
||||||
if (retryCount < 3 && isMountedRef.current) {
|
if (retryCount < 3 && isMountedRef.current) {
|
||||||
@@ -112,7 +114,7 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
|||||||
const { data: { session }, error } = await supabase.auth.getSession();
|
const { data: { session }, error } = await supabase.auth.getSession();
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error('[Auth] Session verification failed:', error);
|
authError('[Auth] Session verification failed:', error);
|
||||||
setSessionError(error.message);
|
setSessionError(error.message);
|
||||||
if (updateLoadingState && isMountedRef.current) {
|
if (updateLoadingState && isMountedRef.current) {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -121,14 +123,14 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!session) {
|
if (!session) {
|
||||||
console.log('[Auth] No active session found');
|
authLog('[Auth] No active session found');
|
||||||
if (updateLoadingState && isMountedRef.current) {
|
if (updateLoadingState && isMountedRef.current) {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[Auth] Session verified:', session.user.email);
|
authLog('[Auth] Session verified:', session.user.email);
|
||||||
sessionVerifiedRef.current = true;
|
sessionVerifiedRef.current = true;
|
||||||
|
|
||||||
// Update state if session was found but not set
|
// Update state if session was found but not set
|
||||||
@@ -142,7 +144,7 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[Auth] Session verification error:', error);
|
authError('[Auth] Session verification error:', error);
|
||||||
if (updateLoadingState && isMountedRef.current) {
|
if (updateLoadingState && isMountedRef.current) {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -153,17 +155,17 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
|||||||
// Keep loading state ref in sync
|
// Keep loading state ref in sync
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadingStateRef.current = loading;
|
loadingStateRef.current = loading;
|
||||||
console.log('[Auth] Loading state changed:', loading);
|
authLog('[Auth] Loading state changed:', loading);
|
||||||
}, [loading]);
|
}, [loading]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('[Auth] Initializing auth provider');
|
authLog('[Auth] Initializing auth provider');
|
||||||
|
|
||||||
// CRITICAL: Set up listener FIRST to catch all events
|
// CRITICAL: Set up listener FIRST to catch all events
|
||||||
const {
|
const {
|
||||||
data: { subscription },
|
data: { subscription },
|
||||||
} = supabase.auth.onAuthStateChange((event, session) => {
|
} = supabase.auth.onAuthStateChange((event, session) => {
|
||||||
console.log('[Auth] State change:', event, 'User:', session?.user?.email || 'none', 'Has session:', !!session);
|
authLog('[Auth] State change:', event, 'User:', session?.user?.email || 'none', 'Has session:', !!session);
|
||||||
|
|
||||||
// Extract email info early for cleanup
|
// Extract email info early for cleanup
|
||||||
const currentEmail = session?.user?.email;
|
const currentEmail = session?.user?.email;
|
||||||
@@ -177,18 +179,18 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
|||||||
|
|
||||||
// Update session and user state based on event
|
// Update session and user state based on event
|
||||||
if (event === 'SIGNED_IN' && session) {
|
if (event === 'SIGNED_IN' && session) {
|
||||||
console.log('[Auth] SIGNED_IN detected, setting session and user');
|
authLog('[Auth] SIGNED_IN detected, setting session and user');
|
||||||
setSession(session);
|
setSession(session);
|
||||||
setUser(session.user);
|
setUser(session.user);
|
||||||
sessionVerifiedRef.current = true;
|
sessionVerifiedRef.current = true;
|
||||||
} else if (event === 'INITIAL_SESSION') {
|
} else if (event === 'INITIAL_SESSION') {
|
||||||
if (session?.user) {
|
if (session?.user) {
|
||||||
console.log('[Auth] INITIAL_SESSION with user, setting session');
|
authLog('[Auth] INITIAL_SESSION with user, setting session');
|
||||||
setSession(session);
|
setSession(session);
|
||||||
setUser(session.user);
|
setUser(session.user);
|
||||||
sessionVerifiedRef.current = true;
|
sessionVerifiedRef.current = true;
|
||||||
} else {
|
} else {
|
||||||
console.log('[Auth] INITIAL_SESSION with no user - setting loading to false');
|
authLog('[Auth] INITIAL_SESSION with no user - setting loading to false');
|
||||||
setSession(null);
|
setSession(null);
|
||||||
setUser(null);
|
setUser(null);
|
||||||
setProfile(null);
|
setProfile(null);
|
||||||
@@ -198,7 +200,7 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
|||||||
return; // Exit early, no need to fetch profile
|
return; // Exit early, no need to fetch profile
|
||||||
}
|
}
|
||||||
} else if (event === 'SIGNED_OUT') {
|
} else if (event === 'SIGNED_OUT') {
|
||||||
console.log('[Auth] SIGNED_OUT detected, clearing all state');
|
authLog('[Auth] SIGNED_OUT detected, clearing all state');
|
||||||
setSession(null);
|
setSession(null);
|
||||||
setUser(null);
|
setUser(null);
|
||||||
setProfile(null);
|
setProfile(null);
|
||||||
@@ -261,7 +263,7 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error updating Novu after email confirmation:', error);
|
authError('Error updating Novu after email confirmation:', error);
|
||||||
} finally {
|
} finally {
|
||||||
novuUpdateTimeoutRef.current = null;
|
novuUpdateTimeoutRef.current = null;
|
||||||
}
|
}
|
||||||
@@ -282,12 +284,12 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
|||||||
|
|
||||||
// Only wait for profile on initial auth events
|
// Only wait for profile on initial auth events
|
||||||
const shouldWaitForProfile = (event === 'SIGNED_IN' || event === 'INITIAL_SESSION');
|
const shouldWaitForProfile = (event === 'SIGNED_IN' || event === 'INITIAL_SESSION');
|
||||||
console.log('[Auth] Fetching profile, shouldWaitForProfile:', shouldWaitForProfile);
|
authLog('[Auth] Fetching profile, shouldWaitForProfile:', shouldWaitForProfile);
|
||||||
|
|
||||||
profileFetchTimeoutRef.current = setTimeout(() => {
|
profileFetchTimeoutRef.current = setTimeout(() => {
|
||||||
fetchProfile(session.user.id, 0, () => {
|
fetchProfile(session.user.id, 0, () => {
|
||||||
if (shouldWaitForProfile) {
|
if (shouldWaitForProfile) {
|
||||||
console.log('[Auth] Profile fetch complete, setting loading to false');
|
authLog('[Auth] Profile fetch complete, setting loading to false');
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -296,7 +298,7 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
|||||||
} else {
|
} else {
|
||||||
// No session/user - clear profile and resolve loading
|
// No session/user - clear profile and resolve loading
|
||||||
setProfile(null);
|
setProfile(null);
|
||||||
console.log('[Auth] No user, setting loading to false');
|
authLog('[Auth] No user, setting loading to false');
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -304,7 +306,7 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
|||||||
// THEN get initial session (this may trigger INITIAL_SESSION event)
|
// THEN get initial session (this may trigger INITIAL_SESSION event)
|
||||||
supabase.auth.getSession().then(({ data: { session }, error }) => {
|
supabase.auth.getSession().then(({ data: { session }, error }) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error('[Auth] Initial session fetch error:', error);
|
authError('[Auth] Initial session fetch error:', error);
|
||||||
setSessionError(error.message);
|
setSessionError(error.message);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
return;
|
return;
|
||||||
@@ -312,13 +314,13 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
|||||||
|
|
||||||
// Note: onAuthStateChange will handle the INITIAL_SESSION event
|
// Note: onAuthStateChange will handle the INITIAL_SESSION event
|
||||||
// This is just a backup in case the event doesn't fire
|
// This is just a backup in case the event doesn't fire
|
||||||
console.log('[Auth] getSession completed, session exists:', !!session);
|
authLog('[Auth] getSession completed, session exists:', !!session);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add a STRONG safety timeout to force loading to resolve
|
// Add a STRONG safety timeout to force loading to resolve
|
||||||
loadingTimeoutRef.current = setTimeout(() => {
|
loadingTimeoutRef.current = setTimeout(() => {
|
||||||
if (loadingStateRef.current) {
|
if (loadingStateRef.current) {
|
||||||
console.warn('[Auth] ⚠️ SAFETY TIMEOUT: Forcing loading to false after 3 seconds');
|
authWarn('[Auth] ⚠️ SAFETY TIMEOUT: Forcing loading to false after 3 seconds');
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, 3000);
|
}, 3000);
|
||||||
@@ -326,23 +328,31 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
|||||||
// Session verification fallback
|
// Session verification fallback
|
||||||
const verificationTimeout = setTimeout(() => {
|
const verificationTimeout = setTimeout(() => {
|
||||||
if (!sessionVerifiedRef.current) {
|
if (!sessionVerifiedRef.current) {
|
||||||
console.log('[Auth] Session not verified after 2s, attempting manual verification');
|
authLog('[Auth] Session not verified after 2s, attempting manual verification');
|
||||||
verifySession();
|
verifySession();
|
||||||
}
|
}
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
|
||||||
// Handle page visibility changes
|
// Handle page visibility changes - only verify if inactive for >5 minutes
|
||||||
const handleVisibilityChange = () => {
|
const handleVisibilityChange = () => {
|
||||||
if (document.visibilityState === 'visible') {
|
if (document.visibilityState === 'visible') {
|
||||||
console.log('[Auth] Tab became visible, verifying session');
|
const timeSinceLastCheck = Date.now() - lastVisibilityVerificationRef.current;
|
||||||
verifySession();
|
const FIVE_MINUTES = 5 * 60 * 1000;
|
||||||
|
|
||||||
|
if (timeSinceLastCheck > FIVE_MINUTES) {
|
||||||
|
authLog('[Auth] Tab visible after 5+ minutes, verifying session');
|
||||||
|
lastVisibilityVerificationRef.current = Date.now();
|
||||||
|
verifySession();
|
||||||
|
} else {
|
||||||
|
authLog('[Auth] Tab visible, session recently verified, skipping');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
document.addEventListener('visibilitychange', handleVisibilityChange);
|
document.addEventListener('visibilitychange', handleVisibilityChange);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
console.log('[Auth] Cleaning up auth provider');
|
authLog('[Auth] Cleaning up auth provider');
|
||||||
isMountedRef.current = false;
|
isMountedRef.current = false;
|
||||||
subscription.unsubscribe();
|
subscription.unsubscribe();
|
||||||
clearTimeout(verificationTimeout);
|
clearTimeout(verificationTimeout);
|
||||||
@@ -366,7 +376,7 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
|||||||
const signOut = async () => {
|
const signOut = async () => {
|
||||||
const { error } = await supabase.auth.signOut();
|
const { error } = await supabase.auth.signOut();
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error('Error signing out:', error);
|
authError('Error signing out:', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
23
src/lib/authLogger.ts
Normal file
23
src/lib/authLogger.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Conditional authentication logging utility
|
||||||
|
* Logs are only shown in development mode
|
||||||
|
*/
|
||||||
|
|
||||||
|
const isDevelopment = import.meta.env.DEV;
|
||||||
|
|
||||||
|
export const authLog = (...args: any[]) => {
|
||||||
|
if (isDevelopment) {
|
||||||
|
console.log(...args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const authWarn = (...args: any[]) => {
|
||||||
|
if (isDevelopment) {
|
||||||
|
console.warn(...args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const authError = (...args: any[]) => {
|
||||||
|
// Always log errors
|
||||||
|
console.error(...args);
|
||||||
|
};
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { authLog, authWarn, authError } from './authLogger';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom storage adapter for Supabase authentication that handles iframe localStorage restrictions.
|
* Custom storage adapter for Supabase authentication that handles iframe localStorage restrictions.
|
||||||
* Falls back to sessionStorage or in-memory storage if localStorage is blocked.
|
* Falls back to sessionStorage or in-memory storage if localStorage is blocked.
|
||||||
@@ -15,7 +17,7 @@ class AuthStorage {
|
|||||||
localStorage.removeItem('__supabase_test__');
|
localStorage.removeItem('__supabase_test__');
|
||||||
this.storage = localStorage;
|
this.storage = localStorage;
|
||||||
this.storageType = 'localStorage';
|
this.storageType = 'localStorage';
|
||||||
console.log('[AuthStorage] Using localStorage ✓');
|
authLog('[AuthStorage] Using localStorage ✓');
|
||||||
} catch {
|
} catch {
|
||||||
// Try sessionStorage as fallback
|
// Try sessionStorage as fallback
|
||||||
try {
|
try {
|
||||||
@@ -23,12 +25,12 @@ class AuthStorage {
|
|||||||
sessionStorage.removeItem('__supabase_test__');
|
sessionStorage.removeItem('__supabase_test__');
|
||||||
this.storage = sessionStorage;
|
this.storage = sessionStorage;
|
||||||
this.storageType = 'sessionStorage';
|
this.storageType = 'sessionStorage';
|
||||||
console.warn('[AuthStorage] localStorage blocked, using sessionStorage ⚠️');
|
authWarn('[AuthStorage] localStorage blocked, using sessionStorage ⚠️');
|
||||||
} catch {
|
} catch {
|
||||||
// Use in-memory storage as last resort
|
// Use in-memory storage as last resort
|
||||||
this.storageType = 'memory';
|
this.storageType = 'memory';
|
||||||
console.error('[AuthStorage] Both localStorage and sessionStorage blocked, using in-memory storage ⛔');
|
authError('[AuthStorage] Both localStorage and sessionStorage blocked, using in-memory storage ⛔');
|
||||||
console.error('[AuthStorage] Sessions will NOT persist across page reloads!');
|
authError('[AuthStorage] Sessions will NOT persist across page reloads!');
|
||||||
|
|
||||||
// Attempt to recover session from URL
|
// Attempt to recover session from URL
|
||||||
this.attemptSessionRecoveryFromURL();
|
this.attemptSessionRecoveryFromURL();
|
||||||
@@ -51,7 +53,7 @@ class AuthStorage {
|
|||||||
const refreshToken = urlParams.get('refresh_token');
|
const refreshToken = urlParams.get('refresh_token');
|
||||||
|
|
||||||
if (accessToken && refreshToken) {
|
if (accessToken && refreshToken) {
|
||||||
console.log('[AuthStorage] Recovering session from URL parameters');
|
authLog('[AuthStorage] Recovering session from URL parameters');
|
||||||
// Store in memory
|
// Store in memory
|
||||||
this.memoryStorage.set('sb-auth-token', JSON.stringify({
|
this.memoryStorage.set('sb-auth-token', JSON.stringify({
|
||||||
access_token: accessToken,
|
access_token: accessToken,
|
||||||
@@ -63,23 +65,23 @@ class AuthStorage {
|
|||||||
window.history.replaceState({}, document.title, window.location.pathname);
|
window.history.replaceState({}, document.title, window.location.pathname);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[AuthStorage] Failed to recover session from URL:', error);
|
authError('[AuthStorage] Failed to recover session from URL:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleStorageChange(event: StorageEvent) {
|
private handleStorageChange(event: StorageEvent) {
|
||||||
// Sync auth state across tabs
|
// Sync auth state across tabs
|
||||||
if (event.key?.startsWith('sb-') && event.newValue) {
|
if (event.key?.startsWith('sb-') && event.newValue) {
|
||||||
console.log('[AuthStorage] Syncing auth state across tabs');
|
authLog('[AuthStorage] Syncing auth state across tabs');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getItem(key: string): string | null {
|
getItem(key: string): string | null {
|
||||||
console.log('[AuthStorage] Getting key:', key);
|
authLog('[AuthStorage] Getting key:', key);
|
||||||
try {
|
try {
|
||||||
if (this.storage) {
|
if (this.storage) {
|
||||||
const value = this.storage.getItem(key);
|
const value = this.storage.getItem(key);
|
||||||
console.log('[AuthStorage] Retrieved from storage:', !!value);
|
authLog('[AuthStorage] Retrieved from storage:', !!value);
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
// Verify it's not expired
|
// Verify it's not expired
|
||||||
@@ -94,7 +96,7 @@ class AuthStorage {
|
|||||||
: parsed.expires_at * 1000; // Convert from seconds to milliseconds
|
: parsed.expires_at * 1000; // Convert from seconds to milliseconds
|
||||||
|
|
||||||
if (parsed.expires_at && expiryTime < Date.now()) {
|
if (parsed.expires_at && expiryTime < Date.now()) {
|
||||||
console.warn('[AuthStorage] Token expired, removing', {
|
authWarn('[AuthStorage] Token expired, removing', {
|
||||||
expires_at: parsed.expires_at,
|
expires_at: parsed.expires_at,
|
||||||
expiryTime: new Date(expiryTime),
|
expiryTime: new Date(expiryTime),
|
||||||
now: new Date()
|
now: new Date()
|
||||||
@@ -103,24 +105,24 @@ class AuthStorage {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[AuthStorage] Token valid, expires:', new Date(expiryTime));
|
authLog('[AuthStorage] Token valid, expires:', new Date(expiryTime));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('[AuthStorage] Could not parse token for expiry check:', e);
|
authWarn('[AuthStorage] Could not parse token for expiry check:', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
console.log('[AuthStorage] Using memory storage');
|
authLog('[AuthStorage] Using memory storage');
|
||||||
return this.memoryStorage.get(key) || null;
|
return this.memoryStorage.get(key) || null;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[AuthStorage] Error reading from storage:', error);
|
authError('[AuthStorage] Error reading from storage:', error);
|
||||||
return this.memoryStorage.get(key) || null;
|
return this.memoryStorage.get(key) || null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setItem(key: string, value: string): void {
|
setItem(key: string, value: string): void {
|
||||||
console.log('[AuthStorage] Setting key:', key);
|
authLog('[AuthStorage] Setting key:', key);
|
||||||
try {
|
try {
|
||||||
if (this.storage) {
|
if (this.storage) {
|
||||||
this.storage.setItem(key, value);
|
this.storage.setItem(key, value);
|
||||||
@@ -128,7 +130,7 @@ class AuthStorage {
|
|||||||
// Always keep in memory as backup
|
// Always keep in memory as backup
|
||||||
this.memoryStorage.set(key, value);
|
this.memoryStorage.set(key, value);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[AuthStorage] Error writing to storage:', error);
|
authError('[AuthStorage] Error writing to storage:', error);
|
||||||
// Fallback to memory only
|
// Fallback to memory only
|
||||||
this.memoryStorage.set(key, value);
|
this.memoryStorage.set(key, value);
|
||||||
}
|
}
|
||||||
@@ -141,7 +143,7 @@ class AuthStorage {
|
|||||||
}
|
}
|
||||||
this.memoryStorage.delete(key);
|
this.memoryStorage.delete(key);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[AuthStorage] Error removing from storage:', error);
|
authError('[AuthStorage] Error removing from storage:', error);
|
||||||
this.memoryStorage.delete(key);
|
this.memoryStorage.delete(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,7 +161,7 @@ class AuthStorage {
|
|||||||
|
|
||||||
// Clear all auth-related storage (for force logout)
|
// Clear all auth-related storage (for force logout)
|
||||||
clearAll(): void {
|
clearAll(): void {
|
||||||
console.log('[AuthStorage] Clearing all auth storage');
|
authLog('[AuthStorage] Clearing all auth storage');
|
||||||
try {
|
try {
|
||||||
if (this.storage) {
|
if (this.storage) {
|
||||||
// Get all keys from storage
|
// Get all keys from storage
|
||||||
@@ -173,16 +175,16 @@ class AuthStorage {
|
|||||||
|
|
||||||
// Remove all Supabase auth keys
|
// Remove all Supabase auth keys
|
||||||
keys.forEach(key => {
|
keys.forEach(key => {
|
||||||
console.log('[AuthStorage] Removing key:', key);
|
authLog('[AuthStorage] Removing key:', key);
|
||||||
this.storage!.removeItem(key);
|
this.storage!.removeItem(key);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear memory storage
|
// Clear memory storage
|
||||||
this.memoryStorage.clear();
|
this.memoryStorage.clear();
|
||||||
console.log('[AuthStorage] ✓ All auth storage cleared');
|
authLog('[AuthStorage] ✓ All auth storage cleared');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[AuthStorage] Error clearing storage:', error);
|
authError('[AuthStorage] Error clearing storage:', error);
|
||||||
// Still clear memory storage as fallback
|
// Still clear memory storage as fallback
|
||||||
this.memoryStorage.clear();
|
this.memoryStorage.clear();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user