Const
Check if a specific manga title is in cache
Force a sync of the caches
Reset all caches (both in-memory and localStorage)
Clear cache entry for a specific manga title
The manga title to clear from cache
boolean True if an entry was cleared, false if no entry was found
Clear cache entries for multiple manga titles at once
Array of manga titles to clear from cache
number Number of cache entries cleared
export const cacheDebugger = {
/**
* Get a summary of the current cache status
*/
getCacheStatus(): {
inMemoryCache: number;
localStorage: {
mangaCache: number;
searchCache: number;
};
} {
// Check in-memory cache
const inMemoryCount = Object.keys(mangaCache).length;
// Check localStorage
let storedMangaCount = 0;
let storedSearchCount = 0;
if (globalThis.window !== undefined) {
try {
const mangaCacheData = localStorage.getItem("anilist_manga_cache");
if (mangaCacheData) {
const parsed = JSON.parse(mangaCacheData);
storedMangaCount = Object.keys(parsed).length;
}
const searchCacheData = localStorage.getItem("anilist_search_cache");
if (searchCacheData) {
const parsed = JSON.parse(searchCacheData);
storedSearchCount = Object.keys(parsed).length;
}
} catch (e) {
console.error("Error checking localStorage cache:", e);
}
}
return {
inMemoryCache: inMemoryCount,
localStorage: {
mangaCache: storedMangaCount,
searchCache: storedSearchCount,
},
};
},
/**
* Check if a specific manga title is in cache
*/
checkMangaInCache(title: string): {
found: boolean;
cacheKey: string;
entry?: {
mangaCount: number;
timestamp: number;
age: string;
};
} {
const cacheKey = generateCacheKey(title);
const entry = mangaCache[cacheKey];
if (!entry) {
return { found: false, cacheKey };
}
// Calculate age
const ageMs = Date.now() - entry.timestamp;
const ageMinutes = Math.floor(ageMs / 60000);
let age: string;
if (ageMinutes < 60) {
age = `${ageMinutes} minute(s)`;
} else if (ageMinutes < 1440) {
age = `${Math.floor(ageMinutes / 60)} hour(s)`;
} else {
age = `${Math.floor(ageMinutes / 1440)} day(s)`;
}
return {
found: true,
cacheKey,
entry: {
mangaCount: entry.manga.length,
timestamp: entry.timestamp,
age,
},
};
},
/**
* Force a sync of the caches
*/
forceSyncCaches(): void {
syncWithClientCache();
console.log("Cache sync forced, current status:");
console.log(this.getCacheStatus());
},
/**
* Reset all caches (both in-memory and localStorage)
*/
resetAllCaches(): void {
// Clear in-memory cache
clearMangaCache();
// Clear localStorage caches
if (globalThis.window !== undefined) {
try {
localStorage.removeItem("anilist_manga_cache");
localStorage.removeItem("anilist_search_cache");
console.log("All AniList caches have been cleared");
} catch (e) {
console.error("Error clearing localStorage caches:", e);
}
}
},
/**
* Clear cache entry for a specific manga title
* @param title The manga title to clear from cache
* @returns boolean True if an entry was cleared, false if no entry was found
*/
clearCacheEntryForTitle(title: string): boolean {
const mainKey = generateCacheKey(title);
let cleared = false;
// Remove direct cache entry if present
if (mangaCache[mainKey]) {
delete mangaCache[mainKey];
cleared = true;
}
const titleLower = title.toLowerCase().trim();
const isExactTitleMatch = (m?: AniListManga): boolean => {
if (!m?.title) return false;
const romaji = m.title.romaji?.toLowerCase().trim() ?? "";
const english = m.title.english?.toLowerCase().trim() ?? "";
return romaji === titleLower || english === titleLower;
};
// Collect keys to remove by checking if any entry's manga list contains an exact match
const keysToRemove = Object.keys(mangaCache).filter((key) => {
if (key === mainKey) return false; // already handled
const entry = mangaCache[key];
if (!entry || !Array.isArray(entry.manga) || entry.manga.length === 0)
return false;
return entry.manga.some(isExactTitleMatch);
});
// Remove collected keys
if (keysToRemove.length > 0) {
for (const k of keysToRemove) {
delete mangaCache[k];
}
cleared = true;
}
if (cleared) {
saveCache();
}
return cleared;
},
/**
* Clear cache entries for multiple manga titles at once
* @param titles Array of manga titles to clear from cache
* @returns number Number of cache entries cleared
*/
clearCacheForTitles(titles: string[]): number {
if (!titles || titles.length === 0) return 0;
console.log(`Clearing cache for ${titles.length} manga titles...`);
let entriesCleared = 0;
let notFoundCount = 0;
// Process all titles in a batch
for (const title of titles) {
if (this.clearCacheEntryForTitle(title)) {
entriesCleared++;
} else {
notFoundCount++;
}
}
console.log(
`Cleared ${entriesCleared} cache entries (${notFoundCount} titles had no existing cache entries)`,
);
return entriesCleared;
},
clearAllCaches() {
// Clear in-memory cache
for (const key of Object.keys(mangaCache)) {
delete mangaCache[key];
}
// Clear localStorage caches
try {
localStorage.removeItem("anilist_manga_cache");
localStorage.removeItem("anilist_search_cache");
console.log("All AniList caches cleared successfully");
} catch (e) {
console.error("Error clearing localStorage caches:", e);
}
return this.getCacheStatus();
},
printCacheKeysFor(title: string) {
const key = generateCacheKey(title);
console.log(`Cache key for "${title}": ${key}`);
// Check if we have a cache entry for this title
if (mangaCache[key]) {
console.log(
`Found in-memory cache entry for "${title}" with ${mangaCache[key].manga.length} results`,
);
} else {
console.log(`No in-memory cache entry found for "${title}"`);
}
return key;
},
dumpCache() {
return {
...mangaCache,
};
},
};
Debug and troubleshoot the cache status. Exposes functions to check and diagnose cache issues.