richtext's picture
Upload folder using huggingface_hub
3674b4b verified
import axios, { AxiosError, InternalAxiosRequestConfig } from 'axios'
const api = axios.create({
baseURL: '',
headers: {
'Content-Type': 'application/json',
},
})
// Flag to prevent multiple refresh attempts
let isRefreshing = false
let failedQueue: Array<{
resolve: (value?: unknown) => void
reject: (reason?: unknown) => void
}> = []
const processQueue = (error: Error | null, token: string | null = null) => {
failedQueue.forEach((prom) => {
if (error) {
prom.reject(error)
} else {
prom.resolve(token)
}
})
failedQueue = []
}
// Helper to get tokens from storage
const getStoredTokens = () => {
const stored = localStorage.getItem('auth-storage')
if (stored) {
try {
const { state } = JSON.parse(stored)
return {
accessToken: state?.token,
refreshToken: state?.refreshToken,
}
} catch {
return { accessToken: null, refreshToken: null }
}
}
return { accessToken: null, refreshToken: null }
}
// Helper to update stored tokens
const updateStoredTokens = (accessToken: string, refreshToken: string) => {
const stored = localStorage.getItem('auth-storage')
if (stored) {
try {
const data = JSON.parse(stored)
data.state.token = accessToken
data.state.refreshToken = refreshToken
localStorage.setItem('auth-storage', JSON.stringify(data))
} catch {
// Ignore parse errors
}
}
}
// Add auth token to requests
api.interceptors.request.use((config) => {
const { accessToken } = getStoredTokens()
if (accessToken) {
config.headers.Authorization = `Bearer ${accessToken}`
}
return config
})
// Handle auth errors with automatic refresh
api.interceptors.response.use(
(response) => response,
async (error: AxiosError) => {
const originalRequest = error.config as InternalAxiosRequestConfig & { _retry?: boolean }
// If 401 and we haven't retried yet
if (error.response?.status === 401 && !originalRequest._retry) {
// Don't try to refresh if this was the refresh endpoint itself
if (originalRequest.url === '/api/auth/refresh') {
localStorage.removeItem('auth-storage')
window.location.href = '/login'
return Promise.reject(error)
}
if (isRefreshing) {
// If already refreshing, queue this request
return new Promise((resolve, reject) => {
failedQueue.push({ resolve, reject })
})
.then((token) => {
originalRequest.headers.Authorization = `Bearer ${token}`
return api(originalRequest)
})
.catch((err) => Promise.reject(err))
}
originalRequest._retry = true
isRefreshing = true
const { refreshToken } = getStoredTokens()
if (!refreshToken) {
localStorage.removeItem('auth-storage')
window.location.href = '/login'
return Promise.reject(error)
}
try {
// Call refresh endpoint
const response = await axios.post('/api/auth/refresh', {
refresh_token: refreshToken,
})
const { access_token, refresh_token: newRefreshToken } = response.data
// Update stored tokens
updateStoredTokens(access_token, newRefreshToken)
// Update auth header for retry
originalRequest.headers.Authorization = `Bearer ${access_token}`
// Process queued requests
processQueue(null, access_token)
// Retry original request
return api(originalRequest)
} catch (refreshError) {
// Refresh failed - logout
processQueue(refreshError as Error, null)
localStorage.removeItem('auth-storage')
window.location.href = '/login'
return Promise.reject(refreshError)
} finally {
isRefreshing = false
}
}
return Promise.reject(error)
}
)
export default api