138 lines
4 KiB
TypeScript
138 lines
4 KiB
TypeScript
import { QueryClient } from '@tanstack/react-query';
|
|
import { persistQueryClient } from '@tanstack/query-persist-client-core';
|
|
import { get, set, del } from 'idb-keyval';
|
|
import LZString from 'lz-string';
|
|
|
|
const CACHE_KEY = 'khollise-cache'; // Key for IndexedDB storage
|
|
|
|
// Check if we're in a browser environment with IndexedDB support
|
|
const isIndexedDBAvailable = () => {
|
|
return typeof window !== 'undefined' &&
|
|
typeof window.indexedDB !== 'undefined' &&
|
|
window.indexedDB !== null;
|
|
};
|
|
|
|
// Custom IndexedDB persister with LZ-string compression
|
|
const createIDBPersister = () => {
|
|
// Return a no-op persister if IndexedDB is not available
|
|
if (!isIndexedDBAvailable()) {
|
|
console.warn('IndexedDB not available - cache persistence disabled');
|
|
return {
|
|
persistClient: async () => { },
|
|
restoreClient: async () => undefined,
|
|
removeClient: async () => { },
|
|
};
|
|
}
|
|
|
|
return {
|
|
persistClient: async (client: any) => {
|
|
try {
|
|
// Double-check IndexedDB availability before operation
|
|
if (!isIndexedDBAvailable()) {
|
|
console.warn('IndexedDB not available during persist operation');
|
|
return;
|
|
}
|
|
|
|
// Serialize the client data
|
|
const serializedClient = JSON.stringify(client);
|
|
|
|
// Compress the serialized data
|
|
const compressedData = LZString.compress(serializedClient);
|
|
|
|
// Store compressed data in IndexedDB
|
|
await set(CACHE_KEY, compressedData);
|
|
} catch (error) {
|
|
console.error('Failed to persist client cache:', error);
|
|
}
|
|
},
|
|
|
|
restoreClient: async () => {
|
|
try {
|
|
// Double-check IndexedDB availability before operation
|
|
if (!isIndexedDBAvailable()) {
|
|
console.warn('IndexedDB not available during restore operation');
|
|
return undefined;
|
|
}
|
|
|
|
// Get compressed data from IndexedDB
|
|
const compressedData = await get(CACHE_KEY);
|
|
|
|
if (!compressedData) {
|
|
console.log('No cached data found in IndexedDB');
|
|
return undefined;
|
|
}
|
|
|
|
// Decompress the data
|
|
const decompressedData = LZString.decompress(compressedData);
|
|
|
|
if (!decompressedData) {
|
|
console.warn('Failed to decompress cached data');
|
|
return undefined;
|
|
}
|
|
|
|
// Parse and return the client data
|
|
const client = JSON.parse(decompressedData);
|
|
console.log('Cache restored from IndexedDB');
|
|
return client;
|
|
|
|
} catch (error) {
|
|
console.error('Failed to restore client cache:', error);
|
|
// Clear corrupted cache if IndexedDB is available
|
|
if (isIndexedDBAvailable()) {
|
|
try {
|
|
await del(CACHE_KEY);
|
|
} catch (delError) {
|
|
console.error('Failed to clear corrupted cache:', delError);
|
|
}
|
|
}
|
|
return undefined;
|
|
}
|
|
},
|
|
|
|
removeClient: async () => {
|
|
try {
|
|
// Double-check IndexedDB availability before operation
|
|
if (!isIndexedDBAvailable()) {
|
|
console.warn('IndexedDB not available during remove operation');
|
|
return;
|
|
}
|
|
|
|
await del(CACHE_KEY);
|
|
console.log('Cache cleared from IndexedDB');
|
|
} catch (error) {
|
|
console.error('Failed to remove client cache:', error);
|
|
}
|
|
},
|
|
};
|
|
};
|
|
|
|
// Create QueryClient with persistence
|
|
const createQueryClient = () => {
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
gcTime: 1000 * 60 * 60 * 24, // 24 hours (formerly cacheTime)
|
|
refetchOnWindowFocus: false,
|
|
retry: 2,
|
|
},
|
|
},
|
|
});
|
|
|
|
// Only set up persistence if IndexedDB is available
|
|
if (isIndexedDBAvailable()) {
|
|
persistQueryClient({
|
|
queryClient,
|
|
persister: createIDBPersister(),
|
|
maxAge: 1000 * 60 * 60 * 24, // 24 hours
|
|
buster: 'v1', // Change this to invalidate cache
|
|
})
|
|
} else {
|
|
console.warn('Cache persistence disabled - IndexedDB not available');
|
|
}
|
|
|
|
return queryClient;
|
|
};
|
|
|
|
const queryClient = createQueryClient();
|
|
export default queryClient;
|