Skip to content

Commit

Permalink
Implement route to invalidate data cache (#2916)
Browse files Browse the repository at this point in the history
  • Loading branch information
SamyPesse authored Mar 4, 2025
1 parent 13514bf commit 76c7974
Showing 4 changed files with 84 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/lemon-pugs-smell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'gitbook-v2': minor
---

Add route to revalidate cached data
33 changes: 33 additions & 0 deletions packages/gitbook-v2/src/app/~gitbook/revalidate/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { type NextRequest, NextResponse } from 'next/server';

import { withVerifySignature } from '@v2/lib/routes';
import { revalidateTag } from 'next/cache';

interface JsonBody {
tags: string[];
}

/**
* Revalidate cached data based on tags.
* The body should be a JSON with { tags: string[] }
*/
export async function POST(req: NextRequest) {
return withVerifySignature<JsonBody>(req, async (body) => {
if (!body.tags || !Array.isArray(body.tags)) {
return NextResponse.json(
{
error: 'tags must be an array',
},
{ status: 400 }
);
}

body.tags.forEach((tag) => {
revalidateTag(tag);
});

return NextResponse.json({
success: true,
});
});
}
5 changes: 5 additions & 0 deletions packages/gitbook-v2/src/lib/env.ts
Original file line number Diff line number Diff line change
@@ -58,3 +58,8 @@ export const GITBOOK_INTEGRATIONS_HOST =
export const GITBOOK_IMAGE_RESIZE_URL = process.env.GITBOOK_IMAGE_RESIZE_URL ?? null;
export const GITBOOK_IMAGE_RESIZE_SIGNING_KEY =
process.env.GITBOOK_IMAGE_RESIZE_SIGNING_KEY ?? null;

/**
* Secret used to validate requests from the GitBook app.
*/
export const GITBOOK_SECRET = process.env.GITBOOK_SECRET ?? null;
41 changes: 41 additions & 0 deletions packages/gitbook-v2/src/lib/routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import crypto from 'node:crypto';
import { NextResponse } from 'next/server';
import { GITBOOK_SECRET } from './env';

/**
* Verify the signature of the request and call the function with the body.
*/
export async function withVerifySignature<T>(
request: Request,
fn: (body: T) => Promise<NextResponse>
) {
try {
const rawBody = await request.text();
const body = JSON.parse(rawBody) as T;

if (GITBOOK_SECRET) {
// Retrieve the signature header from the request
const incomingSignature = request.headers.get('x-gitbook-signature');
if (!incomingSignature) {
return NextResponse.json({ error: 'Missing signature header' }, { status: 400 });
}

const computedSignature = crypto
.createHmac('sha256', GITBOOK_SECRET)
.update(rawBody)
.digest('hex');

// Compare incoming signature to computed signature
if (incomingSignature !== computedSignature) {
return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });
}
}

return await fn(body);
} catch (_error) {
return NextResponse.json(
{ error: 'Invalid request or unable to parse JSON' },
{ status: 400 }
);
}
}

0 comments on commit 76c7974

Please sign in to comment.