import axios, { AxiosResponse } from "axios"; import { create } from "zustand"; import { persist } from "zustand/middleware"; type Token = string; interface AuthStore { token: Token; makeRequest: (props: FirstRequest) => Promise; clearToken: () => void; } interface FirstRequest { method?: string; url: string; body?: T; /** Send access token */ useToken?: boolean; contentType?: boolean; signal?: AbortSignal; /** Send refresh token */ withCredentials?: boolean; } export const authStore = create()( persist( (set, get) => ({ token: "", makeRequest: (props: FirstRequest): Promise => { const newProps = { ...props, HC: (newToken: Token) => set({ token: newToken }), token: get().token }; return makeRequest(newProps); }, clearToken: () => set({ token: "" }), }), { name: "token", } ) ); interface MakeRequest extends FirstRequest { HC: (newToken: Token) => void; token: Token; } async function makeRequest({ method = "post", url, body, useToken = true, contentType = false, HC, token, signal, withCredentials, }: MakeRequest) { //В случае 401 рефреш должен попробовать вызваться 1 раз let headers: Record = {}; if (useToken) headers["Authorization"] = `Bearer ${token}`; if (contentType) headers["Content-Type"] = "application/json"; try { const response = await axios>({ url, method, headers, data: body, signal, withCredentials, }); if (response.data?.accessToken) { HC(response.data.accessToken); } return response.data; } catch (error) { if (axios.isAxiosError(error) && error.response?.status === 401 && !withCredentials) { const refreshResponse = await refresh(token); if (refreshResponse.data?.accessToken) HC(refreshResponse.data.accessToken); headers["Authorization"] = refreshResponse.data.accessToken; const response = await axios.request>({ url, method, headers, data: body, signal, }); return response.data; } throw error; } } function refresh(token: Token) { return axios>("https://admin.pena.digital/auth/refresh", { headers: { Authorization: token, "Content-Type": "application/json", }, }); }