This commit is contained in:
IGNY8 VPS (Salman)
2025-12-08 14:57:36 +00:00
parent 144e955b92
commit c09c6cf7eb
5 changed files with 201 additions and 86 deletions

View File

@@ -154,8 +154,56 @@ export async function fetchAPI(endpoint: string, options?: RequestInit & { timeo
// Read response body once (can only be consumed once)
const text = await response.text();
// Handle 402/403 for plan/limits gracefully by tagging error
if (response.status === 402 || response.status === 403) {
// Handle 403 Forbidden - check for authentication errors FIRST before throwing
if (response.status === 403) {
try {
const errorData = text ? JSON.parse(text) : null;
const errorMessage = errorData?.detail || errorData?.message || errorData?.error || response.statusText;
// Check if it's an authentication credentials error
if (errorMessage?.includes?.('Authentication credentials') ||
errorMessage?.includes?.('not authenticated') ||
errorMessage?.includes?.('Invalid token') ||
errorMessage?.includes?.('Token has expired')) {
// CRITICAL: Authentication token is invalid/missing - force logout
const authState = useAuthStore.getState();
if (authState?.isAuthenticated || authState?.token) {
console.warn('Authentication token invalid - forcing logout');
const { logout } = useAuthStore.getState();
logout();
// Redirect to login page
if (typeof window !== 'undefined') {
window.location.href = '/signin';
}
}
// Throw authentication error
let err: any = new Error(errorMessage);
err.status = 403;
err.data = errorData;
throw err;
}
// Not an auth error - could be permissions/plan issue
let err: any = new Error(errorMessage);
err.status = 403;
err.data = errorData;
throw err;
} catch (e: any) {
// If it's the error we just threw, re-throw it
if (e.status === 403) throw e;
// Parsing failed - throw generic 403 error
let err: any = new Error(text || response.statusText);
err.status = 403;
throw err;
}
}
// Handle 402 Payment Required - plan/limits issue
if (response.status === 402) {
let err: any = new Error(response.statusText);
err.status = response.status;
try {
@@ -168,29 +216,6 @@ export async function fetchAPI(endpoint: string, options?: RequestInit & { timeo
throw err;
}
// Handle 403 Forbidden with authentication error - clear invalid tokens
if (response.status === 403) {
try {
const errorData = text ? JSON.parse(text) : null;
// Check if it's an authentication credentials error
if (errorData?.detail?.includes('Authentication credentials') ||
errorData?.message?.includes('Authentication credentials') ||
errorData?.error?.includes('Authentication credentials')) {
// Only logout if we actually have a token stored (means it's invalid)
// If no token, it might be a race condition after login - don't logout
const authState = useAuthStore.getState();
if (authState?.token || authState?.isAuthenticated) {
// Token exists but is invalid - clear auth state and force re-login
const { logout } = useAuthStore.getState();
logout();
}
// Don't throw here - let the error handling below show the error
}
} catch (e) {
// If parsing fails, continue with normal error handling
}
}
// Handle 401 Unauthorized - try to refresh token
if (response.status === 401) {
const refreshToken = getRefreshToken();