diff --git a/app/api/stats/route.empty-fallback.test.ts b/app/api/stats/route.empty-fallback.test.ts index e04351b2b..7797b8d70 100644 --- a/app/api/stats/route.empty-fallback.test.ts +++ b/app/api/stats/route.empty-fallback.test.ts @@ -4,6 +4,8 @@ import type { ContributionCalendar } from '../../../types'; vi.mock('../../../lib/github', () => ({ fetchGitHubContributions: vi.fn(), + contributionsCache: { has: vi.fn().mockResolvedValue(false) }, + cacheKey: vi.fn().mockReturnValue('key'), })); import { fetchGitHubContributions } from '../../../lib/github'; diff --git a/app/api/stats/route.mouse-interactivity.test.ts b/app/api/stats/route.mouse-interactivity.test.ts index 790038cd5..4de5099c4 100644 --- a/app/api/stats/route.mouse-interactivity.test.ts +++ b/app/api/stats/route.mouse-interactivity.test.ts @@ -8,6 +8,8 @@ import type { ContributionCalendar, ExtendedContributionData } from '@/types'; vi.mock('@/lib/github', () => ({ fetchGitHubContributions: vi.fn(), + contributionsCache: { has: vi.fn().mockResolvedValue(false) }, + cacheKey: vi.fn().mockReturnValue('key'), })); const mockCalendar: ContributionCalendar = { diff --git a/app/api/stats/route.test.ts b/app/api/stats/route.test.ts index afafd7f0f..ad3062328 100644 --- a/app/api/stats/route.test.ts +++ b/app/api/stats/route.test.ts @@ -3,6 +3,8 @@ import { GET } from './route'; vi.mock('../../../lib/github', () => ({ fetchGitHubContributions: vi.fn(), + contributionsCache: { has: vi.fn().mockResolvedValue(false) }, + cacheKey: vi.fn().mockReturnValue('key'), })); import { fetchGitHubContributions } from '../../../lib/github'; diff --git a/app/api/stats/route.ts b/app/api/stats/route.ts index 9a6a7ba95..8e0c39ba9 100644 --- a/app/api/stats/route.ts +++ b/app/api/stats/route.ts @@ -1,6 +1,6 @@ // app/api/stats/route.ts import { NextResponse } from 'next/server'; -import { fetchGitHubContributions } from '@/lib/github'; +import { fetchGitHubContributions, contributionsCache, cacheKey } from '@/lib/github'; import { calculateStreak } from '@/lib/calculate'; import { statsParamsSchema } from '@/lib/validations'; import { getClientIp } from '@/utils/getClientIp'; @@ -122,6 +122,9 @@ export async function GET(request: Request) { } try { + const key = cacheKey('contributions', user); + const wasCachedBefore = await contributionsCache.has(key); + // Authenticated -> user's OAuth token (their quota); anonymous -> undefined (global PAT). const userToken = await getUserGitHubToken(); const userData = await fetchGitHubContributions(user, { @@ -144,7 +147,7 @@ export async function GET(request: Request) { headers.set('Pragma', 'no-cache'); headers.set('Expires', '0'); } - headers.set('X-Cache-Status', shouldBypassCache ? 'MISS' : 'HIT'); + headers.set('X-Cache-Status', shouldBypassCache ? 'MISS' : wasCachedBefore ? 'HIT' : 'MISS'); headers.set( 'X-Refresh-Status', shouldBypassCache ? 'Fresh' : isRefreshRequested ? 'Cooldown-Served-Cached' : 'Cached' diff --git a/app/api/stats/route.validation.test.ts b/app/api/stats/route.validation.test.ts index b15d2fc68..9b3ca047e 100644 --- a/app/api/stats/route.validation.test.ts +++ b/app/api/stats/route.validation.test.ts @@ -3,6 +3,12 @@ import { GET } from './route'; vi.mock('@/lib/github', () => ({ fetchGitHubContributions: vi.fn(), + contributionsCache: { has: vi.fn().mockResolvedValue(true) }, + cacheKey: vi.fn().mockReturnValue('key'), +})); + +vi.mock('@/lib/githubtoken', () => ({ + getUserGitHubToken: vi.fn().mockResolvedValue(undefined), })); import { fetchGitHubContributions } from '@/lib/github';