UNPKG

@replyke/core

Version:

Replyke: Build interactive apps with social features like comments, votes, feeds, user lists, notifications, and more.

42 lines 1.92 kB
import { useEffect } from "react"; import { axiosPrivate } from "./axios"; import { useAuth } from "../hooks/auth"; // Module-level mutex: prevents concurrent token rotations from racing let refreshPromise = null; const useAxiosPrivate = () => { const { accessToken, requestNewAccessToken } = useAuth(); useEffect(() => { const requestIntercept = axiosPrivate.interceptors.request.use((config) => { if (config.headers["Authorization"]) return config; config.headers["Authorization"] = `Bearer ${accessToken}`; return config; }, (error) => Promise.reject(error)); const responseIntercept = axiosPrivate.interceptors.response.use((response) => response, async (error) => { const prevRequest = error?.config; if (error?.response?.status === 403 && !prevRequest?.sent) { prevRequest.sent = true; // Use mutex to prevent concurrent rotation races if (!refreshPromise) { refreshPromise = requestNewAccessToken?.()?.finally(() => { refreshPromise = null; }) ?? Promise.resolve(undefined); } const newAccessToken = await refreshPromise; if (!newAccessToken) { return Promise.reject(error); } prevRequest.headers["Authorization"] = `Bearer ${newAccessToken}`; return axiosPrivate(prevRequest); } return Promise.reject(error); }); return () => { axiosPrivate.interceptors.request.eject(requestIntercept); axiosPrivate.interceptors.response.eject(responseIntercept); }; }, [accessToken, requestNewAccessToken]); return axiosPrivate; }; export default useAxiosPrivate; //# sourceMappingURL=useAxiosPrivate.js.map