import { api } from "src/boot/axios"; const createDbConnection = (dbName = "apiCache", version = 1) => { let db = null; const ready = new Promise((resolve, reject) => { const request = indexedDB.open(dbName, version); request.onerror = () => reject(request.error); request.onsuccess = () => { db = request.result; resolve(db); }; request.onupgradeneeded = (event) => { const db = event.target.result; if (!db.objectStoreNames.contains("apiCache")) { db.createObjectStore("apiCache", { keyPath: "key" }); } }; }); return { getDb: () => ready, }; }; const { getDb } = createDbConnection(); const getFromCache = async (key) => { const db = await getDb(); return new Promise((resolve) => { const transaction = db.transaction(["apiCache"], "readonly"); const store = transaction.objectStore("apiCache"); const request = store.get(key); request.onsuccess = () => { const entry = request.result; if (entry?.timestamp + entry?.ttl > Date.now()) { resolve(entry.data); } else { resolve(null); } }; }); }; const setInCache = async (key, data, ttl) => { const db = await getDb(); const entry = { key, data, timestamp: Date.now(), ttl: ttl * 1000, }; return new Promise((resolve) => { const transaction = db.transaction(["apiCache"], "readwrite"); const store = transaction.objectStore("apiCache"); store.put(entry); transaction.oncomplete = () => resolve(); }); }; const clearCache = async (cacheKey) => { const db = await getDb(); const transaction = db.transaction(["apiCache"], "readwrite"); const store = transaction.objectStore("apiCache"); return new Promise((resolve) => { if (!cacheKey) { store.clear(); transaction.oncomplete = () => resolve(); return; } const request = store.getAllKeys(); request.onsuccess = () => { const deletePromises = request.result .filter((key) => key.includes(cacheKey)) .map( (key) => new Promise((resolve) => { const deleteRequest = store.delete(key); deleteRequest.onsuccess = () => resolve(); }), ); Promise.all(deletePromises).then(() => resolve()); }; }); }; export const createCachedApi = (namespace, ttl = 3600) => { const getCacheKey = (path) => `${namespace}:${path}`; const getResourcePaths = (path) => { const segments = path.split("/").filter(Boolean); const paths = []; for (let i = 0; i <= segments.length; i++) { const currentPath = "/" + segments.slice(0, i).join("/"); paths.push(currentPath); } return paths; }; const invalidateAll = async (path) => { const paths = getResourcePaths(path); await Promise.all(paths.map((path) => clearCache(getCacheKey(path)))); }; const get = async (path, options = {}) => { const key = getCacheKey(path); const cached = await getFromCache(key); if (cached) return cached; const { data } = await api.get(path); await setInCache(key, { data }, options.ttl ?? ttl); return { data }; }; const post = async (path, payload) => { const { data } = await api.post(path, payload); await invalidateAll(path); return { data }; }; const put = async (path, payload) => { const { data } = await api.put(path, payload); await invalidateAll(path); return { data }; }; const del = async (path) => { const { data } = await api.delete(path); await invalidateAll(path); return { data }; }; return { get, post, put, del, invalidateAll }; };