Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/api/compare/route.empty-fallback.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ describe('GET /api/compare - Empty & Missing Input Fallbacks', () => {
const res = await GET(makeRequest('user1=alice&user2=bob'));
expect(res.status).toBe(200);
expect(res.headers.get('ETag')).toBeTruthy();
expect(res.headers.get('Cache-Control')).toBe('public, s-maxage=3600');
expect(res.headers.get('Cache-Control')).toBe('public, s-maxage=1');
});

it('returns 200 when If-None-Match is an empty string instead of crashing', async () => {
Expand Down
4 changes: 2 additions & 2 deletions app/api/compare/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ describe('GET /api/compare', () => {
const res = await GET(makeRequest('user1=alice&user2=bob'));
expect(res.status).toBe(200);
expect(res.headers.get('ETag')).toBeTruthy();
expect(res.headers.get('Cache-Control')).toBe('public, s-maxage=3600');
expect(res.headers.get('Cache-Control')).toBe('public, s-maxage=1');
});

it('returns 304 Not Modified when If-None-Match matches weak ETag', async () => {
Expand All @@ -199,7 +199,7 @@ describe('GET /api/compare', () => {
expect(res2.status).toBe(304);
expect(res2.body).toBeNull();
expect(res2.headers.get('ETag')).toBe(etag);
expect(res2.headers.get('Cache-Control')).toBe('public, s-maxage=3600');
expect(res2.headers.get('Cache-Control')).toBe('public, s-maxage=1');
});

it('returns 304 Not Modified when If-None-Match matches strong ETag', async () => {
Expand Down
2 changes: 1 addition & 1 deletion app/api/compare/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export async function GET(request: Request) {
const etag = crypto.createHash('sha1').update(jsonPayload).digest('hex');
const weakEtag = `W/"${etag}"`;
const ifNoneMatch = request.headers.get('if-none-match');
const cacheControl = 'public, s-maxage=3600';
const cacheControl = 'public, s-maxage=1';

if (ifNoneMatch) {
const etags = ifNoneMatch.split(',').map((e) => e.trim());
Expand Down
2 changes: 1 addition & 1 deletion app/api/github/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ export async function GET(request: Request) {

const cacheControl = shouldBypassCache
? 'no-cache, no-store, must-revalidate'
: 's-maxage=3600, stale-while-revalidate=86400';
: 's-maxage=1, stale-while-revalidate=59';

const cacheStatus = shouldBypassCache ? 'MISS' : 'HIT';

Expand Down
2 changes: 1 addition & 1 deletion app/api/repo-burnout/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export async function GET(request: Request) {

const cacheControl = shouldBypassCache
? 'no-cache, no-store, must-revalidate'
: 's-maxage=3600, stale-while-revalidate=86400';
: 's-maxage=1, stale-while-revalidate=59';

return NextResponse.json(data, {
status: 200,
Expand Down
4 changes: 2 additions & 2 deletions app/api/spotlight/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export async function GET(request: Request) {
return new NextResponse(null, {
status: 304,
headers: {
'Cache-Control': 'public, max-age=60, s-maxage=3600, stale-while-revalidate=60',
'Cache-Control': 'public, max-age=60, s-maxage=1, stale-while-revalidate=59',
ETag: weakEtag,
},
});
Expand All @@ -113,7 +113,7 @@ export async function GET(request: Request) {
return new NextResponse(svg, {
headers: {
'Content-Type': 'image/svg+xml; charset=utf-8',
'Cache-Control': 'public, max-age=60, s-maxage=3600, stale-while-revalidate=60',
'Cache-Control': 'public, max-age=60, s-maxage=1, stale-while-revalidate=59',
'Content-Security-Policy': SVG_CSP_HEADER,
ETag: weakEtag,
},
Expand Down
4 changes: 2 additions & 2 deletions app/api/stats/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ describe('GET /api/stats', () => {

expect(response.status).toBe(200);
expect(response.headers.get('Cache-Control')).toBe(
'public, s-maxage=3600, stale-while-revalidate=86400'
'public, s-maxage=1, stale-while-revalidate=59'
);
expect(response.headers.get('Pragma')).toBeNull();
expect(response.headers.get('Expires')).toBeNull();
Expand All @@ -168,7 +168,7 @@ describe('GET /api/stats', () => {
});
expect(response.headers.get('X-Refresh-Status')).toBe('Cooldown-Served-Cached');
expect(response.headers.get('Cache-Control')).toBe(
'public, s-maxage=3600, stale-while-revalidate=86400'
'public, s-maxage=1, stale-while-revalidate=59'
);
});

Expand Down
2 changes: 1 addition & 1 deletion app/api/stats/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ export async function GET(request: Request) {
const stats = calculateStreak(calendar, timezone);
const headers = new Headers({
// Cache until next UTC midnight; clients can bust with ?refresh=true
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=86400',
'Cache-Control': 'public, s-maxage=1, stale-while-revalidate=59',
});

if (shouldBypassCache) {
Expand Down
2 changes: 1 addition & 1 deletion app/api/stats/route.validation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ describe('GET /api/stats additional runtime coverage', () => {
expect(response.status).toBe(200);

expect(response.headers.get('Cache-Control')).toBe(
'public, s-maxage=3600, stale-while-revalidate=86400'
'public, s-maxage=1, stale-while-revalidate=59'
);
expect(response.headers.get('Pragma')).toBeNull();
expect(response.headers.get('Expires')).toBeNull();
Expand Down
12 changes: 6 additions & 6 deletions app/api/streak/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -443,15 +443,15 @@ describe('GET /api/streak', () => {
it('caches until UTC midnight by default, using the value from getSecondsUntilUTCMidnight', async () => {
const response = await GET(makeRequest({ user: 'octocat' }));
expect(response.headers.get('Cache-Control')).toBe(
'public, max-age=60, s-maxage=3600, stale-while-revalidate=60'
'public, max-age=60, s-maxage=1, stale-while-revalidate=59'
);
});

it('reflects a different time value when the clock changes', async () => {
vi.mocked(getSecondsUntilUTCMidnight).mockReturnValue(7200);
const response = await GET(makeRequest({ user: 'octocat' }));
expect(response.headers.get('Cache-Control')).toBe(
'public, max-age=60, s-maxage=7200, stale-while-revalidate=60'
'public, max-age=60, s-maxage=1, stale-while-revalidate=59'
);
});

Expand Down Expand Up @@ -1013,7 +1013,7 @@ describe('GET /api/streak', () => {
const response = await GET(makeRequest({ user: 'octocat', tz: 'America/New_York' }));

expect(response.headers.get('Cache-Control')).toBe(
'public, max-age=60, s-maxage=7200, stale-while-revalidate=60'
'public, max-age=60, s-maxage=1, stale-while-revalidate=59'
);
expect(getSecondsUntilMidnightInTimezone).toHaveBeenCalledWith('America/New_York');
expect(getSecondsUntilUTCMidnight).not.toHaveBeenCalled();
Expand Down Expand Up @@ -1571,16 +1571,16 @@ describe('GET /api/streak', () => {
});

describe('stale-while-revalidate cache header', () => {
it('contains stale-while-revalidate=60 for normal request', async () => {
it('contains stale-while-revalidate=59 for normal request', async () => {
const response = await GET(makeRequest({ user: 'octocat' }));

expect(response.headers.get('Cache-Control')).toContain('stale-while-revalidate=60');
expect(response.headers.get('Cache-Control')).toContain('stale-while-revalidate=59');
});

it('does NOT contain stale-while-revalidate when ?refresh=true', async () => {
const response = await GET(makeRequest({ user: 'octocat', refresh: 'true' }));

expect(response.headers.get('Cache-Control')).not.toContain('stale-while-revalidate=60');
expect(response.headers.get('Cache-Control')).not.toContain('stale-while-revalidate=59');
});
});

Expand Down
4 changes: 2 additions & 2 deletions app/api/streak/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
calculateStreak,
calculateMonthlyStats,
aggregateCalendars,
convertLocalToUtc,

Check warning on line 16 in app/api/streak/route.ts

View workflow job for this annotation

GitHub Actions / Format · Lint · Typecheck · Test

'convertLocalToUtc' is defined but never used
chunkDaysIntoWeeks,
normalizeCalendarToTimezone,
isLeapYear,

Check warning on line 19 in app/api/streak/route.ts

View workflow job for this annotation

GitHub Actions / Format · Lint · Typecheck · Test

'isLeapYear' is defined but never used
daysInYear,
} from '@/lib/calculate';
import {
Expand Down Expand Up @@ -55,7 +55,7 @@

import { validationCache as _vc, normalizeCacheKey, cachedValidation } from './validation-cache';
// Re-alias so existing usages in this file continue to work.
const validationCache = _vc;

Check warning on line 58 in app/api/streak/route.ts

View workflow job for this annotation

GitHub Actions / Format · Lint · Typecheck · Test

'validationCache' is assigned a value but never used

const SVG_CSP_HEADER =
"default-src 'none'; style-src 'unsafe-inline' https://fonts.googleapis.com; font-src https://fonts.gstatic.com; connect-src https://fonts.gstatic.com;";
Expand Down Expand Up @@ -546,12 +546,12 @@
getMonthlyReferenceDate(year, timezone)
);

const secondsToMidnight = tzParam

Check warning on line 549 in app/api/streak/route.ts

View workflow job for this annotation

GitHub Actions / Format · Lint · Typecheck · Test

'secondsToMidnight' is assigned a value but never used
? getSecondsUntilMidnightInTimezone(timezone)
: getSecondsUntilUTCMidnight();
const cacheControl = isRefreshRequested
? 'no-cache, no-store, must-revalidate'
: `public, s-maxage=${secondsToMidnight}, stale-while-revalidate=86400`;
: `public, s-maxage=1, stale-while-revalidate=86400`;

const cacheStatusHeader = shouldBypassCache
? `BYPASS, fetched=${new Date().toISOString()}`
Expand Down Expand Up @@ -655,14 +655,14 @@
svg = optimizeSVG(svg);
}

const secondsToMidnight = tzParam

Check warning on line 658 in app/api/streak/route.ts

View workflow job for this annotation

GitHub Actions / Format · Lint · Typecheck · Test

'secondsToMidnight' is assigned a value but never used
? getSecondsUntilMidnightInTimezone(timezone)
: getSecondsUntilUTCMidnight();
const cacheControl = isRefreshRequested
? 'no-cache, no-store, must-revalidate'
: isHistoricalYear
? 'public, max-age=31536000, s-maxage=31536000, immutable'
: `public, max-age=60, s-maxage=${secondsToMidnight}, stale-while-revalidate=60`;
: `public, max-age=60, s-maxage=1, stale-while-revalidate=59`;

const etag = crypto.createHash('sha256').update(svg).digest('hex');
const weakEtag = `W/"${etag}"`;
Expand Down
2 changes: 1 addition & 1 deletion app/api/streak/tests/dateRange.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ describe('GET /api/streak dateRange parameter', () => {
expect(res.status).toBe(200);
expect(res.headers.get('Content-Type')).toBe('image/svg+xml; charset=utf-8');
expect(res.headers.get('Cache-Control')).toBe(
'public, max-age=60, s-maxage=3600, stale-while-revalidate=60'
'public, max-age=60, s-maxage=1, stale-while-revalidate=59'
);
});
});
2 changes: 1 addition & 1 deletion app/api/streak/tests/refresh.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ describe('GET /api/streak - refresh parameter group', () => {

expect(response.status).toBe(200);
expect(response.headers.get('Cache-Control')).toBe(
'public, max-age=60, s-maxage=3600, stale-while-revalidate=60'
'public, max-age=60, s-maxage=1, stale-while-revalidate=59'
);
expect(response.headers.get('X-Cache-Status')).toBe('HIT');
});
Expand Down
2 changes: 1 addition & 1 deletion app/api/streak/tests/views.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ describe('GET /api/streak view parameter integration', () => {
expect(response.status).toBe(200);
expect(response.headers.get('Content-Type')).toBe('image/svg+xml; charset=utf-8');
expect(response.headers.get('Cache-Control')).toBe(
'public, max-age=60, s-maxage=3600, stale-while-revalidate=60'
'public, max-age=60, s-maxage=1, stale-while-revalidate=59'
);
expect(response.headers.get('X-Cache-Status')).toBe('HIT');
});
Expand Down
2 changes: 1 addition & 1 deletion app/api/streak/tests/weekday.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ describe('GET /api/streak?view=weekday', () => {

expect(response.status).toBe(200);
expect(response.headers.get('Cache-Control')).toBe(
'public, max-age=60, s-maxage=3600, stale-while-revalidate=60'
'public, max-age=60, s-maxage=1, stale-while-revalidate=59'
);
expect(response.headers.get('X-Cache-Status')).toBe('HIT');
});
Expand Down
10 changes: 5 additions & 5 deletions utils/cacheControl.empty-fallback.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ import { buildCacheControlHeader } from './cacheControl';
describe('buildCacheControlHeader - Edge Cases & Empty/Missing Inputs Verification', () => {
it('1. falls back to default cache control when options object is completely omitted', () => {
// Calling the function with no arguments should fallback gracefully without throwing
expect(buildCacheControlHeader()).toBe('s-maxage=3600, stale-while-revalidate=86400');
expect(buildCacheControlHeader()).toBe('public, s-maxage=1, stale-while-revalidate=59');
});

it('2. falls back to default cache control when options is an empty object', () => {
expect(buildCacheControlHeader({})).toBe('s-maxage=3600, stale-while-revalidate=86400');
expect(buildCacheControlHeader({})).toBe('public, s-maxage=1, stale-while-revalidate=59');
});

it('3. falls back to default cache control when options object is null', () => {
// Casting to any to test JavaScript-level null input resilience
expect(buildCacheControlHeader(null as any)).toBe(
's-maxage=3600, stale-while-revalidate=86400'
'public, s-maxage=1, stale-while-revalidate=59'
);
});

Expand All @@ -26,15 +26,15 @@ describe('buildCacheControlHeader - Edge Cases & Empty/Missing Inputs Verificati
secondsToMidnight: undefined,
isHistoricalYear: undefined,
})
).toBe('s-maxage=3600, stale-while-revalidate=86400');
).toBe('public, s-maxage=1, stale-while-revalidate=59');

expect(
buildCacheControlHeader({
bypass: null as any,
secondsToMidnight: null as any,
isHistoricalYear: null as any,
})
).toBe('s-maxage=3600, stale-while-revalidate=86400');
).toBe('public, s-maxage=1, stale-while-revalidate=59');
});

it('5. prioritizes bypass=true even if other options are invalid/null/undefined', () => {
Expand Down
4 changes: 2 additions & 2 deletions utils/cacheControl.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ describe('buildCacheControlHeader', () => {

it('returns s-maxage with secondsToMidnight', () => {
expect(buildCacheControlHeader({ secondsToMidnight: 3600 })).toBe(
'public, s-maxage=3600, stale-while-revalidate=86400'
'public, s-maxage=1, stale-while-revalidate=59'
);
});

it('returns default s-maxage when no options given', () => {
expect(buildCacheControlHeader({})).toBe('s-maxage=3600, stale-while-revalidate=86400');
expect(buildCacheControlHeader({})).toBe('public, s-maxage=1, stale-while-revalidate=59');
});
});
7 changes: 3 additions & 4 deletions utils/cacheControl.theme-contrast.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { buildCacheControlHeader } from './cacheControl';
describe('cacheControl - Dark and Light Prefers-Color-Scheme Visual Cohesion', () => {
it('returns the default s-maxage header when no options are provided', () => {
const header = buildCacheControlHeader({});
expect(header).toBe('s-maxage=3600, stale-while-revalidate=86400');
expect(header).toBe('public, s-maxage=1, stale-while-revalidate=59');
});

it('returns a no-store directive when bypass is true, overriding all other options', () => {
Expand All @@ -23,12 +23,11 @@ describe('cacheControl - Dark and Light Prefers-Color-Scheme Visual Cohesion', (

it('includes secondsToMidnight in the s-maxage when provided without bypass or historical', () => {
const header = buildCacheControlHeader({ secondsToMidnight: 7200 });
expect(header).toMatch(/^public, s-maxage=7200,/);
expect(header).toContain('stale-while-revalidate=86400');
expect(header).toBe('public, s-maxage=1, stale-while-revalidate=59');
});

it('handles secondsToMidnight of zero correctly, producing s-maxage=0', () => {
const header = buildCacheControlHeader({ secondsToMidnight: 0 });
expect(header).toBe('public, s-maxage=0, stale-while-revalidate=86400');
expect(header).toBe('public, s-maxage=1, stale-while-revalidate=59');
});
});
4 changes: 2 additions & 2 deletions utils/cacheControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ export function buildCacheControlHeader(options: CacheControlOptions = {}): stri
}

if (secondsToMidnight !== undefined && secondsToMidnight !== null) {
return `public, s-maxage=${secondsToMidnight}, stale-while-revalidate=86400`;
return `public, s-maxage=1, stale-while-revalidate=59`;
}

return 's-maxage=3600, stale-while-revalidate=86400';
return 'public, s-maxage=1, stale-while-revalidate=59';
}
Loading