import { type DefaultError, type UseMutationOptions, type queryOptions, useQuery } from "@tanstack/react-query" import { useNavigate } from "@tanstack/react-router" import { useEffect } from "react" class BadRequestError extends Error {} class InternalError extends Error {} class UnauthenticatedError extends Error {} type QueryKey = ["bookmarks", ...ReadonlyArray] async function fetchApi(route: string, init?: RequestInit): Promise<[TData | void, Response]> { const response = await fetch(`${import.meta.env.VITE_API_URL}/api${route}`, { ...init, credentials: "include", }) switch (response.status) { case 200: return [await response.json(), response] case 204: return [undefined, response] case 400: throw new BadRequestError() case 401: throw new UnauthenticatedError() default: throw new InternalError() } } function useAuthenticatedQuery(queryKey: QueryKey, fn: () => Promise) { const query = useQuery({ queryKey, queryFn: () => fn(), retry: (_, error) => !(error instanceof UnauthenticatedError), }) const navigate = useNavigate() useEffect(() => { if (query.error && query.error instanceof UnauthenticatedError) { navigate({ to: "/login", replace: true }) } }, [query.error, navigate]) return query } function mutationOptions( options: UseMutationOptions, ): UseMutationOptions { return options } export { BadRequestError, InternalError, UnauthenticatedError, fetchApi, useAuthenticatedQuery, mutationOptions } export type { QueryKey }