diff --git a/.env.example b/.env.example index a503f93..cb419ac 100644 --- a/.env.example +++ b/.env.example @@ -86,4 +86,14 @@ STEAMGRIDDB_API_KEY="your_steamgriddb_api_key_here" # CONTACT FORM # ----------------------------------------------------------------------------- # Discord webhook URL for contact/report submissions -DISCORD_WEBHOOK_URL="" \ No newline at end of file +DISCORD_WEBHOOK_URL="" + +# ----------------------------------------------------------------------------- +# SITEMAP +# ----------------------------------------------------------------------------- +# Secret token for on-demand sitemap revalidation (generate with: openssl rand -base64 32) +# Leave empty to disable the revalidation endpoint +REVALIDATE_SECRET="" + +# ISR revalidation interval in seconds for sitemap.xml (default: 3600 = 1 hour) +SITEMAP_REVALIDATE_SECONDS="" \ No newline at end of file diff --git a/app/api/revalidate-sitemap/route.ts b/app/api/revalidate-sitemap/route.ts new file mode 100644 index 0000000..0b970c1 --- /dev/null +++ b/app/api/revalidate-sitemap/route.ts @@ -0,0 +1,54 @@ +import { revalidatePath } from "next/cache" +import { NextRequest, NextResponse } from "next/server" + +/** + * On-demand sitemap revalidation webhook. + * + * What this endpoint does: + * Revalidates the `/sitemap.xml` path so Next.js regenerates the sitemap + * at the edge instead of waiting for the next ISR interval. + * + * When to call it: + * - After adding, updating, or removing games + * - After adding, updating, or removing hardware + * - After any bulk import or migration that affects public-facing URLs + * + * How to call it: + * ```bash + * curl -X POST https:///api/revalidate-sitemap \ + * -H "Authorization: Bearer $REVALIDATE_SECRET" + * ``` + * + * @see https://nextjs.org/docs/app/building-your-application/caching#on-demand-revalidation + */ +export async function POST(request: NextRequest): Promise { + const authHeader = request.headers.get("authorization") + const secret = process.env.REVALIDATE_SECRET + + if (!secret) { + return NextResponse.json( + { error: "Revalidation not configured. Set REVALIDATE_SECRET env var." }, + { status: 503 }, + ) + } + + const token = authHeader?.replace("Bearer ", "") + if (token !== secret) { + return NextResponse.json({ error: "Invalid secret" }, { status: 401 }) + } + + try { + revalidatePath("/sitemap.xml") + return NextResponse.json({ + revalidated: true, + path: "/sitemap.xml", + now: Date.now(), + }) + } catch (error) { + console.error("[Revalidate Sitemap] Failed:", error) + return NextResponse.json( + { error: "Revalidation failed" }, + { status: 500 }, + ) + } +}