Download admin/src/api/client.ts from Abhisingh-18/Labour-Connect: direct link, hf CLI and curl.
- Browser
- Download file 2.7 kB
-
https://huggingface.co/Abhisingh-18/Labour-Connect/resolve/main/admin/src/api/client.ts
- Command line
-
hf download hf://Abhisingh-18/Labour-Connect/admin/src/api/client.ts
-
curl -L -o client.ts https://huggingface.co/Abhisingh-18/Labour-Connect/resolve/main/admin/src/api/client.ts
2.7 kB
| import axios, { AxiosError, type InternalAxiosRequestConfig } from "axios"; | |
| const TOKEN_KEY = "lc_admin_token"; | |
| const REFRESH_KEY = "lc_admin_refresh"; | |
| export const tokenStore = { | |
| get: () => localStorage.getItem(TOKEN_KEY), | |
| getRefresh: () => localStorage.getItem(REFRESH_KEY), | |
| set: (access: string, refresh?: string) => { | |
| localStorage.setItem(TOKEN_KEY, access); | |
| if (refresh) localStorage.setItem(REFRESH_KEY, refresh); | |
| }, | |
| clear: () => { | |
| localStorage.removeItem(TOKEN_KEY); | |
| localStorage.removeItem(REFRESH_KEY); | |
| }, | |
| }; | |
| const baseURL = | |
| import.meta.env.VITE_API_BASE_URL ?? "http://localhost:8000/api/v1"; | |
| const api = axios.create({ baseURL, timeout: 20000 }); | |
| api.interceptors.request.use((config) => { | |
| const token = tokenStore.get(); | |
| if (token) config.headers.Authorization = `Bearer ${token}`; | |
| return config; | |
| }); | |
| let onUnauthorized: (() => void) | null = null; | |
| export const setUnauthorizedHandler = (fn: () => void) => { | |
| onUnauthorized = fn; | |
| }; | |
| // Single-flight refresh: queue concurrent 401s behind one refresh call. | |
| let refreshing: Promise<string | null> | null = null; | |
| async function doRefresh(): Promise<string | null> { | |
| const refresh = tokenStore.getRefresh(); | |
| if (!refresh) return null; | |
| try { | |
| const res = await axios.post(`${baseURL}/auth/refresh`, { | |
| refresh_token: refresh, | |
| }); | |
| tokenStore.set(res.data.access_token, res.data.refresh_token); | |
| return res.data.access_token as string; | |
| } catch { | |
| return null; | |
| } | |
| } | |
| api.interceptors.response.use( | |
| (res) => res, | |
| async (error: AxiosError) => { | |
| const original = error.config as InternalAxiosRequestConfig & { | |
| _retry?: boolean; | |
| }; | |
| const isAuthCall = original?.url?.includes("/auth/"); | |
| if (error.response?.status === 401 && original && !original._retry && !isAuthCall) { | |
| original._retry = true; | |
| refreshing = refreshing ?? doRefresh(); | |
| const newToken = await refreshing; | |
| refreshing = null; | |
| if (newToken) { | |
| original.headers.Authorization = `Bearer ${newToken}`; | |
| return api(original); | |
| } | |
| tokenStore.clear(); | |
| onUnauthorized?.(); | |
| } | |
| return Promise.reject(error); | |
| }, | |
| ); | |
| export function apiErrorMessage(error: unknown): string { | |
| if (axios.isAxiosError(error)) { | |
| const detail = error.response?.data?.detail; | |
| if (typeof detail === "string") return detail; | |
| if (Array.isArray(detail) && detail[0]?.msg) return detail[0].msg as string; | |
| if (error.code === "ERR_NETWORK") return "Cannot reach the server."; | |
| } | |
| return "Something went wrong. Please try again."; | |
| } | |
| export default api; | |