diff --git a/app/api/debug/profile-cache/route.ts b/app/api/debug/profile-cache/route.ts new file mode 100644 index 00000000..084d30e6 --- /dev/null +++ b/app/api/debug/profile-cache/route.ts @@ -0,0 +1,51 @@ +import { NextRequest } from "next/server"; +import { + debugFetchProfiles, + debugReadCache, + type DebugCacheEntry, + type Profile, +} from "src/identity/profileCache"; + +export const runtime = "nodejs"; +export const dynamic = "force-dynamic"; + +// GET /api/debug/profile-cache?dids=did:plc:foo,did:plc:bar +// Reports what's currently in Redis for each DID and what the upstream +// Bluesky getProfiles call returns right now. Does not write to the cache. +export async function GET(req: NextRequest) { + const param = req.nextUrl.searchParams.get("dids"); + if (!param) { + return Response.json( + { error: "`dids` query param required (comma-separated)" }, + { status: 400 }, + ); + } + + const dids = Array.from( + new Set( + param + .split(",") + .map((s) => s.trim()) + .filter(Boolean), + ), + ); + if (dids.length === 0) { + return Response.json({ error: "no DIDs provided" }, { status: 400 }); + } + + const [cacheEntries, fetched] = await Promise.all([ + debugReadCache(dids), + debugFetchProfiles(dids), + ]); + + const result = dids.map((did) => { + const cache: DebugCacheEntry = cacheEntries.get(did) ?? { status: "miss" }; + const live: Profile | null = fetched.get(did) ?? null; + return { did, cache, live }; + }); + + return Response.json( + { dids, result }, + { headers: { "Cache-Control": "no-store" } }, + ); +} diff --git a/app/debug/profile-cache/page.tsx b/app/debug/profile-cache/page.tsx new file mode 100644 index 00000000..c3911837 --- /dev/null +++ b/app/debug/profile-cache/page.tsx @@ -0,0 +1,199 @@ +import { + debugFetchProfiles, + debugReadCache, + type DebugCacheEntry, + type Profile, +} from "src/identity/profileCache"; + +export const dynamic = "force-dynamic"; +export const runtime = "nodejs"; + +type SearchParams = Promise<{ dids?: string }>; + +export default async function ProfileCacheDebugPage({ + searchParams, +}: { + searchParams: SearchParams; +}) { + const { dids: didsParam } = await searchParams; + const dids = parseDids(didsParam); + + let rows: { + did: string; + cache: DebugCacheEntry; + live: Profile | null; + }[] = []; + + if (dids.length > 0) { + const [cacheEntries, fetched] = await Promise.all([ + debugReadCache(dids), + debugFetchProfiles(dids), + ]); + rows = dids.map((did) => ({ + did, + cache: cacheEntries.get(did) ?? { status: "miss" }, + live: fetched.get(did) ?? null, + })); + } + + return ( +
+

Profile Cache Debug

+

+ Shows what's in the Redis cache and what bsky's + getProfiles returns right now. The cache is not updated. +

+ +
+ +