Description
The Open Graph image generator at app/api/og/route.tsx fetches /api/streak?user=...&refresh=true and then calls res.json() on the response (line 24). However, the /api/streak endpoint (app/api/streak/route.ts:130) returns an image/svg+xml response, not JSON. The res.json() call always throws a parse error, which is silently swallowed by the empty catch {} block on line 34. The fallback values (totalCommits = 0, longestStreak = 0, currentStreak = 0) are always used, meaning every OG preview image shows 0 / 0 / 0 regardless of the user's actual stats.
This means any time a user shares their CommitPulse profile link on social media, Discord, Slack, or any platform that renders OG previews, the generated image displays completely empty/zeroed stats — defeating the core purpose of the OG image.
Affected Files
app/api/og/route.tsx (lines 19–36 — fetch + JSON parse of SVG response)
app/api/streak/route.ts (line 130 — returns Content-Type: image/svg+xml)
Expected Behaviour
The OG image should display the user's real contribution stats (total commits, longest streak, current streak) by correctly obtaining the data from the GitHub API.
Actual Behaviour
The OG image always shows 0 for all three stats because the SVG response body cannot be parsed as JSON. The empty catch {} block silently swallows the parse error, and the zero-initialized variables are used to render the image. Every shared profile link generates a meaningless OG preview.
Proposed Fix
Replace the self-referencing HTTP fetch to the SVG-producing API route with direct imports of the data-fetching functions. Both fetchGitHubContributions and calculateStreak work in the edge runtime, so they can be called directly:
// app/api/og/route.tsx — complete replacement of the data-fetching logic
import { ImageResponse } from 'next/og';
import { NextRequest } from 'next/server';
import { ogParamsSchema } from '../../../lib/validations';
import { fetchGitHubContributions } from '../../../lib/github';
import { calculateStreak } from '../../../lib/calculate';
export const runtime = 'edge';
export async function GET(req: NextRequest) {
const { searchParams } = new URL(req.url);
const { user } = ogParamsSchema.parse(
Object.fromEntries(searchParams.entries())
);
let totalCommits = 0;
let longestStreak = 0;
let currentStreak = 0;
try {
// Call the GitHub data layer directly instead of fetching the
// SVG-producing /api/streak route (which returns image/svg+xml,
// not JSON).
const calendar = await fetchGitHubContributions(user, {
bypassCache: true,
});
const stats = calculateStreak(calendar);
totalCommits = stats.totalContributions;
longestStreak = stats.longestStreak;
currentStreak = stats.currentStreak;
} catch {
// fallback — show zeros if the user doesn't exist or the API is down
}
return new ImageResponse(
// ... rest of the JSX stays exactly the same ...
Key changes:
- Removed the
fetch(\${baseUrl}/api/streak?user=...`)` call that returned SVG
- Imported
fetchGitHubContributions from lib/github and calculateStreak from lib/calculate
- Called the data functions directly, which return structured data instead of SVG markup
- The OG image now correctly displays real contribution statistics
An alternative fix if direct imports aren't desired (e.g., to keep the OG route decoupled) would be to add a separate /api/streak/data endpoint that returns JSON, and have the OG route fetch that instead. However, direct imports are simpler, faster (no HTTP overhead), and avoid the coupling issue entirely.
Description
The Open Graph image generator at
app/api/og/route.tsxfetches/api/streak?user=...&refresh=trueand then callsres.json()on the response (line 24). However, the/api/streakendpoint (app/api/streak/route.ts:130) returns animage/svg+xmlresponse, not JSON. Theres.json()call always throws a parse error, which is silently swallowed by the emptycatch {}block on line 34. The fallback values (totalCommits = 0,longestStreak = 0,currentStreak = 0) are always used, meaning every OG preview image shows 0 / 0 / 0 regardless of the user's actual stats.This means any time a user shares their CommitPulse profile link on social media, Discord, Slack, or any platform that renders OG previews, the generated image displays completely empty/zeroed stats — defeating the core purpose of the OG image.
Affected Files
app/api/og/route.tsx(lines 19–36 — fetch + JSON parse of SVG response)app/api/streak/route.ts(line 130 — returnsContent-Type: image/svg+xml)Expected Behaviour
The OG image should display the user's real contribution stats (total commits, longest streak, current streak) by correctly obtaining the data from the GitHub API.
Actual Behaviour
The OG image always shows
0for all three stats because the SVG response body cannot be parsed as JSON. The emptycatch {}block silently swallows the parse error, and the zero-initialized variables are used to render the image. Every shared profile link generates a meaningless OG preview.Proposed Fix
Replace the self-referencing HTTP fetch to the SVG-producing API route with direct imports of the data-fetching functions. Both
fetchGitHubContributionsandcalculateStreakwork in the edge runtime, so they can be called directly:Key changes:
fetch(\${baseUrl}/api/streak?user=...`)` call that returned SVGfetchGitHubContributionsfromlib/githubandcalculateStreakfromlib/calculateAn alternative fix if direct imports aren't desired (e.g., to keep the OG route decoupled) would be to add a separate
/api/streak/dataendpoint that returns JSON, and have the OG route fetch that instead. However, direct imports are simpler, faster (no HTTP overhead), and avoid the coupling issue entirely.