feat: add /api/revalidate webhook for on-demand ISR
POST with x-revalidate-secret header and { tag } body calls
revalidateTag to purge a collection from the Next.js data cache.
Guarded by REVALIDATE_SECRET env var.
This commit is contained in:
@@ -0,0 +1,45 @@
|
|||||||
|
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": "<collection-name>" }`
|
||||||
|
* Required header: `x-revalidate-secret: <REVALIDATE_SECRET>`
|
||||||
|
*/
|
||||||
|
export async function POST(request: NextRequest): Promise<NextResponse> {
|
||||||
|
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<string, unknown>).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 });
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user