diff options
Diffstat (limited to 'apps/browser-extension/src/utils/badgeCache.ts')
| -rw-r--r-- | apps/browser-extension/src/utils/badgeCache.ts | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/apps/browser-extension/src/utils/badgeCache.ts b/apps/browser-extension/src/utils/badgeCache.ts new file mode 100644 index 00000000..caa4231d --- /dev/null +++ b/apps/browser-extension/src/utils/badgeCache.ts @@ -0,0 +1,82 @@ +// Badge count cache helpers +import { BookmarkTypes } from "@karakeep/shared/types/bookmarks"; + +import { getPluginSettings } from "./settings"; +import { getApiClient, getQueryClient } from "./trpc"; +import { urlsMatchIgnoringAnchorAndTrailingSlash } from "./url"; + +/** + * Fetches the bookmark status for a given URL from the API. + * This function will be used by our cache as the "fetcher". + * @param url The URL to check. + * @returns The bookmark id if found, null if not found. + */ +async function fetchBadgeStatus(url: string): Promise<string | null> { + const api = await getApiClient(); + if (!api) { + // This case should ideally not happen if settings are correct + throw new Error("[badgeCache] API client not configured"); + } + try { + const data = await api.bookmarks.searchBookmarks.query({ + text: "url:" + url, + }); + const bookmarks = data.bookmarks; + const bookmarksLength = bookmarks.length; + if (bookmarksLength === 0) { + return null; + } + + // First check the exact match (including anchor points) + const exactMatch = + bookmarks.find( + (b) => + b.content.type === BookmarkTypes.LINK && + urlsMatchIgnoringAnchorAndTrailingSlash(url, b.content.url), + ) || null; + + return exactMatch ? exactMatch.id : null; + } catch (error) { + console.error(`[badgeCache] Failed to fetch status for ${url}:`, error); + // In case of API error, return a non-cacheable empty status + // Propagate so cache treats this as a miss and doesn’t store + throw error; + } +} + +/** + * Get badge status for a URL using the SWR cache. + * @param url The URL to get the status for. + */ +export async function getBadgeStatus(url: string): Promise<string | null> { + const { useBadgeCache, badgeCacheExpireMs } = await getPluginSettings(); + if (!useBadgeCache) return fetchBadgeStatus(url); + + const queryClient = await getQueryClient(); + if (!queryClient) return fetchBadgeStatus(url); + + return await queryClient.fetchQuery({ + queryKey: ["badgeStatus", url], + queryFn: () => fetchBadgeStatus(url), + // Keep in memory for twice as long as stale time + gcTime: badgeCacheExpireMs * 2, + // Use the user-configured cache expire time + staleTime: badgeCacheExpireMs, + }); +} + +/** + * Clear badge status cache for a specific URL or all URLs. + * @param url The URL to clear. If not provided, clears the entire cache. + */ +export async function clearBadgeStatus(url?: string): Promise<void> { + const queryClient = await getQueryClient(); + if (!queryClient) return; + + if (url) { + await queryClient.invalidateQueries({ queryKey: ["badgeStatus", url] }); + } else { + await queryClient.invalidateQueries({ queryKey: ["badgeStatus"] }); + } + console.log(`[badgeCache] Invalidated cache for: ${url || "all"}`); +} |
