import { ofetch } from "ofetch"; export interface RequestOptions extends RequestInit { onErrorOccured?: (error: Error, statusCode: number) => void; onSuccess?: (data: T, statusCode: number) => void; onStart?: () => void; } /** * @function useMyFetch * * @description * Makes a request to a given url, handles cookies and errors. * * @param {string} url - The url to make a request to. * @param {RequestOptions} [options] - The options to use for the request. * * @returns {Promise} - A promise resolving to the response data * or undefined if an error occurred. * * @example * const { data } = useMyFetch<{ name: string }>('/api/user') */ export const useMyFetch = async (url: string, options?: RequestOptions): Promise => { if (options?.onStart) options.onStart(); let response = null; try { const event = useRequestEvent(); if (options == null) options = {}; options.credentials = "include"; if (import.meta.server) { const api_uri = event?.node.req.headers["api-uri"] || "http://localhost:4000"; url = api_uri + url; options.headers = event?.headers; } response = await ofetch.raw(url, options); if (import.meta.server && !event?.handled) { for (const cookie of response.headers.getSetCookie()) { event?.headers.set("Cookie", cookie); event?.node.res.setHeader("set-cookie", cookie); } } // handle errors if any if (!response.ok && typeof options.onErrorOccured == "function") { options.onErrorOccured(new Error(response.statusText), response.status); } // handle success to be able clearly marked that request has finished if (response.ok && typeof options.onSuccess == "function") { options.onSuccess( response._data, response.status); } return response._data as T; } catch (e) { // handle errors if any if (typeof options?.onErrorOccured == "function") { options.onErrorOccured(e as Error, response?.status || 500); } else { console.error(e); } return {} as T; } };