| 1 | import type { AxiosInstance, AxiosRequestHeaders } from "axios" |
| 2 | import axios from "axios" |
| 3 | import { useAuthStore } from "@/stores/auth" |
| 4 | import { isDebounceTimeOver, isJwtExpiring } from "@/utils/auth" |
| 5 | // import { useGlobalActions } from "@/composables/common/useGlobalActions" |
| 6 | |
| 7 | type HttpClientBase = "api" | "ws" |
| 8 | |
| 9 | const DEFAULT_API_ROOT = "/api" |
| 10 | const API_ROOT = import.meta.env.VITE_API_ROOT || DEFAULT_API_ROOT |
| 11 | const WS_ROOT = import.meta.env.VITE_WS_ROOT || API_ROOT |
| 12 | |
| 13 | let __TOKEN_REFRESHING = false |
| 14 | let __TOKEN_LAST_CHECK: Date | null = null |
| 15 | |
| 16 | function applyInterceptors(client: AxiosInstance) { |
| 17 | client.interceptors.request.use( |
| 18 | config => { |
| 19 | const store = useAuthStore() |
| 20 | |
| 21 | if (!config.headers) config.headers = {} as AxiosRequestHeaders |
| 22 | if (store.userToken) { |
| 23 | config.headers.Authorization = `Bearer ${store.userToken}` |
| 24 | } |
| 25 | |
| 26 | if ( |
| 27 | store.userToken && |
| 28 | isJwtExpiring(store.userToken, 60 * 15 /** 15 minutes */) && |
| 29 | !__TOKEN_REFRESHING && |
| 30 | isDebounceTimeOver(__TOKEN_LAST_CHECK) |
| 31 | ) { |
| 32 | __TOKEN_REFRESHING = true |
| 33 | __TOKEN_LAST_CHECK = new Date() |
| 34 | |
| 35 | store.refreshToken().then(() => { |
| 36 | __TOKEN_REFRESHING = false |
| 37 | }) |
| 38 | } |
| 39 | |
| 40 | return config |
| 41 | }, |
| 42 | error => Promise.reject(error) |
| 43 | ) |
| 44 | |
| 45 | client.interceptors.response.use( |
| 46 | response => response, |
| 47 | error => { |
| 48 | if (error.response && error.response.status === 401) { |
| 49 | if (!window.location.pathname.includes("login")) { |
| 50 | window.location.href = "/logout" |
| 51 | } |
| 52 | /* |
| 53 | useGlobalActions().message("You are not authorized to access the resource", { type: "error" }) |
| 54 | */ |
| 55 | } |
| 56 | |
| 57 | return Promise.reject(error) |
| 58 | } |
| 59 | ) |
| 60 | } |
| 61 | |
| 62 | function createHttpClient(baseURL: string) { |
| 63 | const client = axios.create({ baseURL }) |
| 64 | applyInterceptors(client) |
| 65 | return client |
| 66 | } |
| 67 | |
| 68 | const HttpClient = createHttpClient(API_ROOT) |
| 69 | const WsHttpClient = createHttpClient(WS_ROOT) |
| 70 | |
| 71 | const CLIENTS: Record<HttpClientBase, AxiosInstance> = { |
| 72 | api: HttpClient, |
| 73 | ws: WsHttpClient |
| 74 | } |
| 75 | |
| 76 | function getHttpClient(base: HttpClientBase = "api") { |
| 77 | return CLIENTS[base] |
| 78 | } |
| 79 | |
| 80 | export { createHttpClient, getHttpClient, HttpClient, WsHttpClient } |