Spaces:
Running
Running
File size: 4,452 Bytes
1e2158c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | /**
* User ID Utility - Ensures proper user isolation
*
* CRITICAL: Each user (authenticated or guest) gets a unique ID.
* This ID is used to isolate all user data (files, models, chats, etc.)
*/
import { auth } from '../lib/auth-client';
const GUEST_ID_KEY = 'guestUserId';
const USER_ID_KEY = 'userId';
/**
* Generate a unique guest ID
*/
function generateGuestId(): string {
const timestamp = Date.now().toString(36);
const randomPart = Math.random().toString(36).substring(2, 10);
return `guest_${timestamp}_${randomPart}`;
}
/**
* Get or create a guest user ID
* This ensures guests have persistent, unique IDs
*/
function getOrCreateGuestId(): string {
let guestId = localStorage.getItem(GUEST_ID_KEY);
if (!guestId) {
guestId = generateGuestId();
localStorage.setItem(GUEST_ID_KEY, guestId);
console.log('๐ Created new guest ID:', guestId);
}
return guestId;
}
/**
* Get the current user ID (authenticated or guest)
* ALWAYS use this function to get user ID for API calls
*/
export async function getUserId(): Promise<string> {
try {
// First check auth session
const { data: { session } } = await auth.getSession();
if (session?.user?.id) {
// Authenticated user - use their user ID
localStorage.setItem(USER_ID_KEY, session.user.id);
return session.user.id;
}
} catch (error) {
console.warn('Could not check auth session:', error);
}
// Check for stored authenticated user ID
const storedUserId = localStorage.getItem(USER_ID_KEY);
if (storedUserId && !storedUserId.startsWith('guest_')) {
return storedUserId;
}
// Fallback to guest ID
return getOrCreateGuestId();
}
/**
* Synchronous version - uses cached value
* Prefer getUserId() when possible
*/
export function getUserIdSync(): string {
// Check for authenticated user ID first
const storedUserId = localStorage.getItem(USER_ID_KEY);
if (storedUserId && !storedUserId.startsWith('guest_')) {
return storedUserId;
}
// Fallback to guest ID
return getOrCreateGuestId();
}
/**
* Clear user data on logout
*/
export function clearUserData(): void {
const userId = getUserIdSync();
// Clear user-specific localStorage items
const keysToRemove = [
`mlResults_${userId}`,
`hasMLResults_${userId}`,
`userPreferences_${userId}`,
`userProfile_${userId}`,
];
keysToRemove.forEach(key => localStorage.removeItem(key));
// Clear user-specific sessionStorage
sessionStorage.removeItem(`mlCharts_${userId}`);
// Remove authenticated user ID but keep guest ID
localStorage.removeItem(USER_ID_KEY);
console.log('๐งน Cleared user data for:', userId);
}
/**
* Check if current user is authenticated
*/
export async function isAuthenticated(): Promise<boolean> {
try {
const { data: { session } } = await auth.getSession();
return !!session?.user;
} catch {
return false;
}
}
/**
* ๐ Get authorization headers for fetch calls
* Use this for all direct fetch() calls to ensure proper auth
*/
export async function getAuthHeaders(): Promise<Record<string, string>> {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
};
try {
const { data: { session } } = await auth.getSession();
if (session?.access_token) {
headers['Authorization'] = `Bearer ${session.access_token}`;
headers['X-User-ID'] = session.user.id;
} else {
const guestId = getOrCreateGuestId();
headers['X-User-ID'] = guestId;
}
} catch (error) {
console.warn('Failed to get auth headers:', error);
const guestId = getOrCreateGuestId();
headers['X-User-ID'] = guestId;
}
return headers;
}
/**
* Sync version - uses cached token if available
*/
export function getAuthHeadersSync(): Record<string, string> {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
};
const userId = localStorage.getItem(USER_ID_KEY);
if (userId && !userId.startsWith('guest_')) {
headers['X-User-ID'] = userId;
// Note: For sync, we can't get the JWT token without async call
// The interceptor in api.ts handles adding the token
} else {
const guestId = getOrCreateGuestId();
headers['X-User-ID'] = guestId;
}
return headers;
}
export default {
getUserId,
getUserIdSync,
clearUserData,
isAuthenticated,
getAuthHeaders,
getAuthHeadersSync,
};
|