Spaces:
Sleeping
Sleeping
File size: 7,127 Bytes
d97b8f9 | 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 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | import axios, { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import { API_BASE_URL } from '../../config';
import { getSystemHealth } from './health';
// Mobile platform detection (simpler approach without Capacitor dependency)
const isMobileApp = () => {
return typeof window !== 'undefined' &&
(window.location.href.includes('capacitor://') ||
window.location.href.includes('ionic://') ||
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent));
};
const isNative = isMobileApp();
// Create a custom axios instance
const apiClient = axios.create({
baseURL: API_BASE_URL,
headers: {
'Content-Type': 'application/json',
// Add additional headers for mobile apps
...(isNative && {
'X-Requested-With': 'XMLHttpRequest',
'X-Mobile-App': 'true'
})
},
timeout: 30000, // 30 seconds timeout
withCredentials: false // Disable withCredentials which can cause CORS issues
});
// Request interceptor to handle authentication for all requests
apiClient.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
// Get token from user_session in localStorage
const userSession = localStorage.getItem('user_session');
// Add detailed debugging
console.log(`API Request to: ${config.url}`);
console.log(`Method: ${config.method?.toUpperCase()}`);
console.log(`Running on platform: ${isNative ? 'Mobile' : 'Web'}`);
// If session exists, parse it and add token to headers
if (userSession) {
try {
const userData = JSON.parse(userSession);
console.log(`User session found: ${userData.firstName} ${userData.lastName} (${userData.email})`);
if (userData && userData.token) {
// Set Authorization header for all requests
config.headers.Authorization = `Bearer ${userData.token}`;
console.log(`Token applied: ${userData.token.substring(0, 15)}...`);
} else {
console.warn('Token missing in user session! Session data:', JSON.stringify(userData, null, 2));
}
} catch (error) {
console.error('Error parsing user session:', error);
}
} else {
console.warn('No user_session found in localStorage - request will be unauthorized');
}
// Log final headers for debugging
// console.log('Request headers:', JSON.stringify(config.headers, null, 2));
// console.log('Request URL (full):', `${config.baseURL}${config.url}`);
return config;
},
(error: AxiosError) => {
// Handle request errors
console.error('Request error:', error);
return Promise.reject(error);
}
);
// Special interceptor for the health endpoint
apiClient.interceptors.response.use(
(response: AxiosResponse) => {
const url = response.config.url;
// Check if this is a health endpoint request
if (url && (url === '/health' || url.endsWith('/health') || url === '/api/health' || url.endsWith('/api/health'))) {
console.log('Health endpoint detected, returning custom health response');
// Use the shared health implementation from health.ts
response.data = getSystemHealth();
}
return response;
},
(error) => Promise.reject(error)
);
// Response interceptor to handle authentication-related responses
apiClient.interceptors.response.use(
(response: AxiosResponse) => {
// Any status code within the range of 2xx causes this function to trigger
return response;
},
async (error: AxiosError) => {
const originalRequest = error.config as InternalAxiosRequestConfig & { _retry?: boolean };
// Handle 401 Unauthorized errors
if (error.response?.status === 401 && !originalRequest._retry) {
// Since we're using user_session, update refresh token logic accordingly
const userSession = localStorage.getItem('user_session');
if (userSession) {
originalRequest._retry = true;
try {
// Here you could implement token refresh logic
// Example (commented out):
/*
const userData = JSON.parse(userSession);
// Call your refresh token API
const response = await apiClient.post(
`${API_BASE_URL}/auth/refresh-token`,
{
userId: userData.userId,
// Include any other required fields
},
{
headers: {
'Content-Type': 'application/json'
}
}
);
if (response.data && response.data.token) {
// Update the token in localStorage
userData.token = response.data.token;
localStorage.setItem('user_session', JSON.stringify(userData));
// Retry the original request with new token
originalRequest.headers.Authorization = `Bearer ${response.data.token}`;
return apiClient(originalRequest);
}
*/
// For now, just clear the session and redirect to login
localStorage.removeItem('user_session');
// Redirect to login page
window.location.href = '/login';
return Promise.reject(error);
} catch (refreshError) {
// If any error during this process, clear session and redirect
localStorage.removeItem('user_session');
// Redirect to login page
window.location.href = '/login';
return Promise.reject(refreshError);
}
} else {
// No session available, redirect to login
window.location.href = '/login';
}
}
// Handle 403 Forbidden errors (permissions issue)
if (error.response?.status === 403) {
console.error('Forbidden resource:', error.config?.url);
// You can implement specific handling for forbidden resources
// For example, show an access denied notification or redirect
// window.location.href = '/access-denied';
}
// Handle 404 Not Found errors
if (error.response?.status === 404) {
console.error('Resource not found:', error.config?.url);
}
// Handle 500 and other server errors
if (error.response?.status && error.response.status >= 500) {
console.error('Server error:', error.response.status, error.config?.url);
// Optionally show a server error notification
}
// Network errors
if (error.message === 'Network Error') {
console.error('Network error - check internet connection');
// Optionally show a network error notification
}
// Timeout errors
if (error.code === 'ECONNABORTED') {
console.error('Request timeout');
// Optionally show a timeout error notification
}
return Promise.reject(error);
}
);
export default apiClient;
|