import { revalidateTag } from 'next/cache'; import { type NextRequest, NextResponse } from 'next/server'; /** * POST /api/revalidate * * Webhook endpoint for on-demand ISR. PocketBase (or any external * caller) sends this request after mutating CMS content so the * relevant tag is purged from the Next.js data cache. * * Expected body: `{ "tag": "" }` * Required header: `x-revalidate-secret: ` */ export async function POST(request: NextRequest): Promise { const secret = request.headers.get('x-revalidate-secret'); if (secret !== process.env.REVALIDATE_SECRET) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } let body: unknown; try { body = await request.json(); } catch { return NextResponse.json({ error: 'Invalid JSON body' }, { status: 400 }); } if ( typeof body !== 'object' || body === null || !('tag' in body) || typeof (body as Record).tag !== 'string' ) { return NextResponse.json({ error: 'Missing or invalid "tag" field' }, { status: 400 }); } const tag = (body as { tag: string }).tag; /* Second arg is required by the Next.js 15 type signature; * "max" means the purge propagates indefinitely — correct for * an on-demand webhook that has no TTL of its own. */ revalidateTag(tag, 'max'); return NextResponse.json({ revalidated: true, tag }, { status: 200 }); }