diff --git a/app/devices/[slug]/opengraph-image.tsx b/app/devices/[slug]/opengraph-image.tsx index 4504e62..21f93d8 100644 --- a/app/devices/[slug]/opengraph-image.tsx +++ b/app/devices/[slug]/opengraph-image.tsx @@ -4,6 +4,7 @@ import { hardware, performanceEntries, gameVersions, games } from "@/lib/db/sche import { eq, and, sql } from "drizzle-orm" export const runtime = "nodejs" +export const dynamic = "force-dynamic" export const alt = "Device benchmarks on DeckyVault" export const size = { width: 1200, height: 630 } export const contentType = "image/png" diff --git a/app/devices/[slug]/page.tsx b/app/devices/[slug]/page.tsx index e628334..a58f766 100644 --- a/app/devices/[slug]/page.tsx +++ b/app/devices/[slug]/page.tsx @@ -8,10 +8,16 @@ import type { Metadata } from "next" export const revalidate = 3600 export async function generateStaticParams() { - const devices = await db - .select({ slug: hardware.slug }) - .from(hardware) - return devices.map((d) => ({ slug: d.slug })) + try { + const devices = await db + .select({ slug: hardware.slug }) + .from(hardware) + return devices.map((d) => ({ slug: d.slug })) + } catch { + // DB unreachable during build (e.g. Docker builder without network access). + // Return empty — pages will be generated on first request via ISR. + return [] + } } export async function generateMetadata({ diff --git a/app/devices/page.tsx b/app/devices/page.tsx index e245601..2f162fc 100644 --- a/app/devices/page.tsx +++ b/app/devices/page.tsx @@ -4,6 +4,9 @@ import { eq, sql, desc } from "drizzle-orm" import { DevicesPageClient } from "./page-client" import type { Metadata } from "next" +// This page needs live data — skip static generation at build time +export const dynamic = "force-dynamic" + export const metadata: Metadata = { title: "Devices — DeckyVault", description: diff --git a/app/game/[id]/opengraph-image.tsx b/app/game/[id]/opengraph-image.tsx index 457e444..a4a4be1 100644 --- a/app/game/[id]/opengraph-image.tsx +++ b/app/game/[id]/opengraph-image.tsx @@ -5,6 +5,9 @@ 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" diff --git a/app/game/[id]/page.tsx b/app/game/[id]/page.tsx index 0e8d303..9aef754 100644 --- a/app/game/[id]/page.tsx +++ b/app/game/[id]/page.tsx @@ -15,6 +15,9 @@ import { and, desc, eq, sql } from "drizzle-orm" import { isSyncStale, syncSteamGame } from "@/lib/steam/sync" import { GamePageClient } from "./game-page-client" +// This page needs live data — skip static generation at build time +export const dynamic = "force-dynamic" + async function resolveGame(id: string) { const isNumeric = /^\d+$/.test(id) let game diff --git a/app/game/[id]/submit/page.tsx b/app/game/[id]/submit/page.tsx index 00d036b..2919516 100644 --- a/app/game/[id]/submit/page.tsx +++ b/app/game/[id]/submit/page.tsx @@ -4,6 +4,9 @@ import { games, gameVersions } from "@/lib/db/schema" import { eq, sql } from "drizzle-orm" import { GameEntryWizard } from "@/components/wizard/game-entry-wizard" +// This page needs live data — skip static generation at build time +export const dynamic = "force-dynamic" + export const metadata = { title: "Submit Benchmark", } diff --git a/app/games/page.tsx b/app/games/page.tsx index dc7be58..d7facdd 100644 --- a/app/games/page.tsx +++ b/app/games/page.tsx @@ -10,6 +10,9 @@ import { import { sql, eq, and, desc, inArray } from "drizzle-orm" import { GamesPageClient } from "./games-page-client" +// This page needs live data — skip static generation at build time +export const dynamic = "force-dynamic" + export const metadata: Metadata = { title: "Games — DeckyVault", description: diff --git a/app/profile/[id]/page.tsx b/app/profile/[id]/page.tsx index 4dd39ab..d8f9636 100644 --- a/app/profile/[id]/page.tsx +++ b/app/profile/[id]/page.tsx @@ -4,6 +4,9 @@ import { user, performanceEntries, games, gameVersions, hardware } from "@/lib/d import { eq, sql, and, desc } from "drizzle-orm" import { ProfilePageClient } from "./profile-page-client" +// This page needs live data — skip static generation at build time +export const dynamic = "force-dynamic" + export const metadata = { title: "Profile", } diff --git a/app/sitemap.ts b/app/sitemap.ts index 07b50a7..4b50170 100644 --- a/app/sitemap.ts +++ b/app/sitemap.ts @@ -4,35 +4,45 @@ import { games, hardware } from "@/lib/db/schema" const BASE_URL = "https://deckyvault.xyz" +// Skip static generation — rebuild sitemap at request time with fresh data +export const dynamic = "force-dynamic" + export default async function sitemap(): Promise { - const [allGames, allDevices] = await Promise.all([ - db.select({ id: games.id, updatedAt: games.updatedAt, capsuleImage: games.capsuleImage }).from(games), - db.select({ slug: hardware.slug, createdAt: hardware.createdAt }).from(hardware), - ]) - - const gameEntries: MetadataRoute.Sitemap = allGames.map((game) => ({ - url: `${BASE_URL}/game/${game.id}`, - lastModified: game.updatedAt, - changeFrequency: "weekly" as const, - priority: 0.8, - images: game.capsuleImage ? [game.capsuleImage] : undefined, - })) - - const deviceEntries: MetadataRoute.Sitemap = allDevices.map((device) => ({ - url: `${BASE_URL}/devices/${device.slug}`, - lastModified: device.createdAt, - changeFrequency: "monthly" as const, - priority: 0.6, - })) - - return [ + // Static pages that don't need DB + const staticEntries: MetadataRoute.Sitemap = [ { url: BASE_URL, lastModified: new Date(), changeFrequency: "weekly" as const, priority: 1 }, { url: `${BASE_URL}/games`, lastModified: new Date(), changeFrequency: "weekly" as const, priority: 0.7 }, { url: `${BASE_URL}/devices`, lastModified: new Date(), changeFrequency: "monthly" as const, priority: 0.6 }, { url: `${BASE_URL}/contact`, lastModified: new Date(), changeFrequency: "monthly" as const, priority: 0.3 }, { url: `${BASE_URL}/login`, lastModified: new Date(), changeFrequency: "monthly" as const, priority: 0.3 }, { url: `${BASE_URL}/signup`, lastModified: new Date(), changeFrequency: "monthly" as const, priority: 0.3 }, - ...gameEntries, - ...deviceEntries, ] + + try { + const [allGames, allDevices] = await Promise.all([ + db.select({ id: games.id, updatedAt: games.updatedAt, capsuleImage: games.capsuleImage }).from(games), + db.select({ slug: hardware.slug, createdAt: hardware.createdAt }).from(hardware), + ]) + + const gameEntries: MetadataRoute.Sitemap = allGames.map((game) => ({ + url: `${BASE_URL}/game/${game.id}`, + lastModified: game.updatedAt, + changeFrequency: "weekly" as const, + priority: 0.8, + images: game.capsuleImage ? [game.capsuleImage] : undefined, + })) + + const deviceEntries: MetadataRoute.Sitemap = allDevices.map((device) => ({ + url: `${BASE_URL}/devices/${device.slug}`, + lastModified: device.createdAt, + changeFrequency: "monthly" as const, + priority: 0.6, + })) + + return [...staticEntries, ...gameEntries, ...deviceEntries] + } catch { + // DB unreachable during build — return static sitemap only. + // Dynamic entries will be available at request time. + return staticEntries + } } \ No newline at end of file