import {data} from "react-router-dom"; const ongoingRequests = new Map(); function _default_hash_function(url, method, body){ const url_obj = new URL(url, window.location.origin); const query_params = [...url_obj.searchParams.entries()] .sort(([a], [b]) => a.localeCompare(b)) .map(([key, value]) => `${key}=${value}`) .join("&"); const normalized_url = `${url_obj.origin}${url_obj.pathname}${query_params ? "?" + query_params : ""}`; const normalized_body = body ? JSON.stringify( Object.keys(body) .sort() .reduce((acc, key) => { acc[key] = body[key]; return acc; }, {}) ) : ""; return `${method.toUpperCase()}:${normalized_url}:${normalized_body}`; } export async function fetch_(url, init = {}, init_options = {}){ const default_options = { use_cache: true, cache_key: _default_hash_function(url, init.method || "GET", init.body || null), cache_expires: 60, use_token: true, }; const options = { ...default_options, ...init_options }; const token = options.use_token ? localStorage.getItem("accessToken") : null; const request_options = { ...init, headers: { ...(init.headers || {}), ...(token ? {Authorization: `Bearer ${token}`} : {}), ...(init.method && ['PUT', 'POST'].includes(init.method.toUpperCase()) ? {'Content-Type': 'application/json'} : {}), } }; if(options.use_cache && ongoingRequests.has(options.cache_key)){ return ongoingRequests.get(options.cache_key); } const now = Date.now(); const cached_data = localStorage.getItem(options.cache_key); if(options.use_cache && cached_data){ const {data, timestamp} = JSON.parse(cached_data); if(now - timestamp < options.cache_expires * 1000) return data; } try { const fetchPromise = fetch(url, request_options) .then((response) => { if(!response.ok) { throw new Error(`RESPONSE_ERROR: ${response.status}`); } return response.json(); }) .then((data) => { if (options.use_cache) { localStorage.setItem( options.cache_key, JSON.stringify({ data, timestamp: now }) ); ongoingRequests.delete(options.cache_key); } return data; }); if(options.use_cache){ ongoingRequests.set(options.cache_key, fetchPromise); } return await fetchPromise; }catch(error){ if(options.use_cache){ ongoingRequests.delete(options.cache_key); } throw error; } }