import { ImageResponse } from "next/og" import { db } from "@/lib/db/index" import { games, gameVersions, performanceEntries } from "@/lib/db/schema" import { eq, and, sql } from "drizzle-orm" import { readFile } from "node:fs/promises" import { join } from "node:path" // This needs live data — skip static generation at build time export const dynamic = "force-dynamic" export const alt = "DeckyVault - Game Benchmarks" export const size = { width: 1200, height: 630 } export const contentType = "image/png" export default async function Image({ params }: { params: Promise<{ id: string }> }) { const { id } = await params const isNumeric = /^\d+$/.test(id) let game if (isNumeric) { const rows = await db.select().from(games).where(eq(games.steamAppId, Number(id))).limit(1) game = rows[0] } else { const rows = await db.select().from(games).where(eq(games.id, id)).limit(1) game = rows[0] } if (!game) { return new ImageResponse( (
Game Not Found
DeckyVault
), { ...size } ) } // Get best FPS stat let avgFps: number | null = null try { const [bestStat] = await db .select({ avgFps: sql`round(avg(${performanceEntries.fpsAvg})::numeric, 1)` }) .from(performanceEntries) .innerJoin(gameVersions, eq(performanceEntries.versionId, gameVersions.id)) .where(and(eq(gameVersions.gameId, game.id), eq(performanceEntries.isRemoved, false))) .limit(1) avgFps = bestStat?.avgFps ?? null } catch { // No FPS data available — that's fine } const logoData = await readFile(join(process.cwd(), "app/icon.png"), "base64") const logoSrc = `data:image/png;base64,${logoData}` return new ImageResponse( (
DeckyVault
{game.title}
{game.developer && by {game.developer}} {avgFps !== null && ~{avgFps} avg FPS}
{game.genres && game.genres.length > 0 && (
{game.genres.slice(0, 4).map((genre: string) => ( {genre} ))}
)}
), { ...size } ) }