feat: sync api changes and fix auth-related bugs

Signed-off-by: Noa Virellia <noa@requiem.garden>
This commit is contained in:
2026-01-20 19:37:33 +08:00
parent a60a796345
commit 27ac4d9b4a
6 changed files with 109 additions and 35 deletions

View File

@@ -1,10 +1,17 @@
import type { AxiosRequestConfig } from 'axios';
import axios, { AxiosError } from 'axios';
import type { AxiosError, AxiosRequestConfig } from 'axios';
import type { JsonValue } from 'type-fest';
import axios from 'axios';
import { isNil } from 'lodash-es';
import { router } from '@/lib/router';
import { doRefreshToken, getRefreshToken, getToken, setRefreshToken, setToken } from './token';
import { clearTokens, doRefreshToken, getRefreshToken, getToken, setRefreshToken, setToken } from './token';
export const HEADER_API_VERSION = {
'X-Api-Version': 'latest',
};
export const axiosClient = axios.create({
baseURL: '/api/v1/',
headers: HEADER_API_VERSION,
});
axiosClient.interceptors.request.use((config) => {
@@ -18,27 +25,43 @@ axiosClient.interceptors.request.use((config) => {
type RetryConfig = AxiosRequestConfig & { _retry?: boolean };
axiosClient.interceptors.response.use(undefined, async (error: AxiosError) => {
interface ResponseData {
code: number;
error_id: string;
status: string;
data: JsonValue;
}
axiosClient.interceptors.response.use(async (response) => {
const data = response.data as ResponseData;
if (data.code !== 200) {
return Promise.reject(data);
}
response.data = data.data;
return response;
}, async (error: AxiosError) => {
const originalRequest = error.config as RetryConfig | undefined;
if (!error.response || error.response.status !== 401 || !originalRequest) {
return Promise.reject(error);
}
if (error.response.status === 401 && getRefreshToken() !== null) {
if (error.response.status === 401 && originalRequest.url !== '/auth/refresh' && !isNil(getRefreshToken())) {
try {
const maybeRefreshTokenValue = await doRefreshToken();
const { access_token, refresh_token } = maybeRefreshTokenValue.data;
const maybeRefreshTokenResponse = await doRefreshToken();
if (maybeRefreshTokenResponse.status !== 200) {
throw new Error('Failed to refresh token');
}
const { access_token, refresh_token } = maybeRefreshTokenResponse.data;
originalRequest.headers = originalRequest.headers ?? {};
originalRequest.headers.Authorization = `Bearer ${access_token}`;
setToken(access_token);
setRefreshToken(refresh_token);
return await axiosClient(originalRequest);
}
// eslint-disable-next-line unused-imports/no-unused-vars
catch (e) {
if (e instanceof AxiosError && e.status === 401) {
await router.navigate({ to: '/authorize' });
return Promise.reject(error);
}
// Should remove token (tokens are out of date)
clearTokens();
await router.navigate({ to: '/authorize' });
}
}
});