import axios, { type AxiosRequestConfig, type InternalAxiosRequestConfig } from 'axios' import { parseApiJsonResponse } from '@chongchong/shared' import { ApiError, isApiEnvelope, isApiFailure } from '@/api/types' import { getOverseasAccessToken } from '@/api/session' import { refreshAuthenticatedSession } from '@/api/http' interface RetryableRequest extends InternalAxiosRequestConfig { _retriedOverseasAuth?: boolean } const transport = axios.create({ baseURL: import.meta.env.VITE_OVERSEAS_API_BASE_URL || '/overseas-api', timeout: 15_000, transformResponse: [(data: unknown) => parseApiJsonResponse(data)], }) async function requireToken() { const current = getOverseasAccessToken() if (current) return current await refreshAuthenticatedSession() const refreshed = getOverseasAccessToken() if (!refreshed) throw new ApiError('当前环境未签发海外访问令牌', 'OVERSEAS_TOKEN_UNAVAILABLE') return refreshed } transport.interceptors.request.use(async (config) => { config.headers.Authorization = `Bearer ${await requireToken()}` return config }) transport.interceptors.response.use((response) => response, async (error) => { const request = error.config as RetryableRequest | undefined if (error.response?.status !== 401 || !request || request._retriedOverseasAuth) throw error request._retriedOverseasAuth = true await refreshAuthenticatedSession() request.headers.Authorization = `Bearer ${await requireToken()}` return transport.request(request) }) export async function overseasApiRequest(config: AxiosRequestConfig) { try { const response = await transport.request(config) if (isApiFailure(response.data)) { throw new ApiError(response.data.message, response.data.code, response.status, undefined, response.data.traceId, response.data.requestId) } if (!isApiEnvelope(response.data) || response.data.code !== '200') { throw new ApiError( isApiEnvelope(response.data) ? response.data.message : '海外接口响应格式错误', isApiEnvelope(response.data) ? response.data.code : 'INVALID_RESPONSE', undefined, undefined, isApiEnvelope(response.data) ? response.data.traceId : null, isApiEnvelope(response.data) ? response.data.requestId : null, ) } return response.data.data as T } catch (error) { if (error instanceof ApiError) throw error if (axios.isAxiosError(error)) { const body = error.response?.data if (isApiEnvelope(body) || isApiFailure(body)) { throw new ApiError(body.message, body.code, error.response?.status, undefined, body.traceId, body.requestId) } throw new ApiError(error.code === 'ERR_NETWORK' ? '无法连接海外服务' : error.message, error.code || 'OVERSEAS_HTTP_ERROR', error.response?.status) } throw new ApiError(error instanceof Error ? error.message : '海外接口请求失败') } }