55 lines
1.8 KiB
TypeScript
55 lines
1.8 KiB
TypeScript
import { createClient, createConfig } from "../client";
|
|
import type { ClientOptions as ClientOptions2 } from '../types.gen';
|
|
import type { Client, RequestOptions, RequestResult } from "../client";
|
|
import { refreshTokens } from "../../auth";
|
|
import type { ResponseStyle } from "../client";
|
|
|
|
let refreshPromise: Promise<boolean> | null = null;
|
|
|
|
async function getRefreshed(): Promise<boolean> {
|
|
if (!refreshPromise) {
|
|
refreshPromise = (async () => {
|
|
try {
|
|
const res = await refreshTokens();
|
|
// consider refresh successful if res.data exists
|
|
return !!res.data;
|
|
} catch (err) {
|
|
return false; // failed to refresh
|
|
}
|
|
})();
|
|
}
|
|
|
|
return refreshPromise;
|
|
}
|
|
|
|
const baseClient = createClient(createConfig<ClientOptions2>({ baseUrl: '/api/v1' }));
|
|
|
|
export const authClient: Client = {
|
|
...baseClient,
|
|
|
|
request: function <
|
|
TData = unknown,
|
|
TError = unknown,
|
|
ThrowOnError extends boolean = false,
|
|
TResponseStyle extends ResponseStyle = 'fields',
|
|
>(
|
|
options: Omit<RequestOptions<TData, TResponseStyle, ThrowOnError>, 'method'> &
|
|
Pick<Required<RequestOptions<TData, TResponseStyle, ThrowOnError>>, 'method'>
|
|
): RequestResult<TData, TError, ThrowOnError, TResponseStyle> {
|
|
|
|
// Wrap logic inside a Promise to satisfy RequestResult type
|
|
return baseClient.request<TData, TError, ThrowOnError, TResponseStyle>(options).catch(async (err: any) => {
|
|
if (err?.status === 401) {
|
|
const refreshed = await getRefreshed();
|
|
if (!refreshed) {
|
|
localStorage.clear();
|
|
window.location.href = "/login";
|
|
throw err;
|
|
}
|
|
// Retry original request
|
|
return baseClient.request<TData, TError, ThrowOnError, TResponseStyle>(options);
|
|
}
|
|
throw err;
|
|
}) as RequestResult<TData, TError, ThrowOnError, TResponseStyle>;
|
|
},
|
|
};
|