import type { Api } from 'nocodb-sdk' const DbNotFoundMsg = 'Database config not found' const TIMEOUT_RETRY_COUNT = 1 export function addAxiosInterceptors(api: Api) { const state = useGlobal() const router = useRouter() const route = router.currentRoute const optimisedQuery = useState('optimisedQuery', () => true) const axiosInstance = api.instance axiosInstance.interceptors.request.use((config) => { config.headers['xc-gui'] = 'true' if (state.token.value && !config.headers['xc-short-token']) { config.headers['xc-auth'] = state.token.value } if (!config.url?.endsWith('/user/me') && !config.url?.endsWith('/admin/roles') && state.previewAs?.value) { config.headers['xc-preview'] = state.previewAs.value } if (!config.url?.endsWith('/user/me') && !config.url?.endsWith('/admin/roles')) { if (route.value && route.value.params && route.value.params.typeOrId === 'base') { config.headers['xc-shared-base-id'] = route.value.params.baseId delete config.headers['xc-auth'] } else if (route.value && route.value.params && route.value.params.typeOrId === 'ERD') { config.headers['xc-shared-erd-id'] = route.value.params.erdUuid delete config.headers['xc-auth'] } } if (!optimisedQuery.value) { config.params = { ...(config.params ?? {}), opt: 'false' } } return config }) axiosInstance.interceptors.response.use( (response) => response, async (error) => { const isSharedPage = route.value?.params?.typeOrId === 'base' || route.value?.params?.typeOrId === 'ERD' || route.value.meta.public if (error.code === 'ERR_CANCELED') return Promise.reject(error) if (error.response?.data?.msg === DbNotFoundMsg) { return router.replace('/base/0') } if (!error.response || error.response.status !== 401) { return Promise.reject(error) } if (error.config.url === '/auth/token/refresh') { await state.signOut({ redirectToSignin: !route.value.meta.public, skipApiCall: true, }) return Promise.reject(error) } let retry = 0 do { try { const token = await state.refreshToken({ axiosInstance, skipLogout: true, }) if (!token) { await state.signOut({ redirectToSignin: !isSharedPage, skipApiCall: true, }) return Promise.reject(error) } const config = error.config config.headers['xc-auth'] = token const response = await axiosInstance.request(config) return response } catch (refreshTokenError) { if ((refreshTokenError as any)?.code === 'ERR_CANCELED') { return Promise.reject(refreshTokenError) } // if shared execution error, don't sign out if (!(refreshTokenError instanceof SharedExecutionError)) { await state.signOut({ redirectToSignin: !isSharedPage, skipApiCall: true, }) return Promise.reject(error) } if (retry >= TIMEOUT_RETRY_COUNT) return Promise.reject(error) } } while (retry++ < TIMEOUT_RETRY_COUNT) }, ) return api }