@replyke/core
Version:
Replyke: Build interactive apps with social features like comments, votes, feeds, user lists, notifications, and more.
44 lines • 2.07 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const react_1 = require("react");
const axios_1 = require("./axios");
const auth_1 = require("../hooks/auth");
// Module-level mutex: prevents concurrent token rotations from racing
let refreshPromise = null;
const useAxiosPrivate = () => {
const { accessToken, requestNewAccessToken } = (0, auth_1.useAuth)();
(0, react_1.useEffect)(() => {
const requestIntercept = axios_1.axiosPrivate.interceptors.request.use((config) => {
if (config.headers["Authorization"])
return config;
config.headers["Authorization"] = `Bearer ${accessToken}`;
return config;
}, (error) => Promise.reject(error));
const responseIntercept = axios_1.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 (0, axios_1.axiosPrivate)(prevRequest);
}
return Promise.reject(error);
});
return () => {
axios_1.axiosPrivate.interceptors.request.eject(requestIntercept);
axios_1.axiosPrivate.interceptors.response.eject(responseIntercept);
};
}, [accessToken, requestNewAccessToken]);
return axios_1.axiosPrivate;
};
exports.default = useAxiosPrivate;
//# sourceMappingURL=useAxiosPrivate.js.map