feat: sitemap remediation, PWA activation, search refinements, Steam Deck UX
Sitemap: - Switch from ISR (revalidate=3600) to force-dynamic for per-request generation - Flatten into single app/sitemap.ts with inlined static entries and DB queries - NULL-safe syncStatus filter: ne(games.syncStatus, 'failed') OR isNull(games.syncStatus) - Structured JSON logging for generated URLs and DB errors - Delete lib/sitemap/* helpers and app/api/revalidate-sitemap route - Add basic vitest coverage for sitemap exports PWA & Offline: - Add @serwist/next service worker (webpack build) with runtime caching - Cache strategies: stale-while-revalidate for game pages, network-first for listings/API, cache-first for Steam CDN images - Offline fallback page (public/offline.html) - Manifest icons: 192px maskable + 512px any - Viewport meta with viewport-fit=cover, user-scalable=no - Apple mobile web app meta tags Search / Filter Refinements: - Multi-genre OR support in listing API (comma-separated genres) - Device-scoped FPS filter (min/max FPS constrained to selected device) - Client-side URL state sync via router.replace for shareable filtered views - Initialize filter state from URL params on mount - Auto-collapse filter panel on saved-filter load - Fix multi-genre saved filter parsing (comma-separated) Steam Deck / Touch / Gamepad UX: - WCAG 2.1 AA touch targets (44x44px) on all filter controls - .gamepad-focus CSS focus ring for controller navigation - useGamepadNavigation hook: D-pad/left-stick roving tabindex, A/B/X/Y actions - Integrate gamepad hook into games page (X=search, Y=toggle filters) Chore: - Bump version to 2026.0.97
This commit is contained in:
@@ -1,54 +0,0 @@
|
||||
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://<your-domain>/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<NextResponse> {
|
||||
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 },
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user