final
This commit is contained in:
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user