Skip to content

Commit af66ff7

Browse files
conico974Nicolas Dorseuil
and
Nicolas Dorseuil
authored
Add a force-revalidate api route (#3263)
Co-authored-by: Nicolas Dorseuil <[email protected]>
1 parent 6f8ecd6 commit af66ff7

File tree

3 files changed

+55
-0
lines changed

3 files changed

+55
-0
lines changed

.changeset/gorgeous-cycles-cheat.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"gitbook-v2": patch
3+
---
4+
5+
add a force-revalidate api route to force bust the cache in case of errors

packages/gitbook-v2/next-env.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference types="next" />
22
/// <reference types="next/image-types/global" />
3+
/// <reference types="next/navigation-types/compat/navigation" />
34

45
// NOTE: This file should not be edited
56
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import crypto from 'node:crypto';
2+
import type { NextApiRequest, NextApiResponse } from 'next';
3+
4+
interface JsonBody {
5+
// The paths need to be the rewritten one, `res.revalidate` call don't go through the middleware
6+
paths: string[];
7+
}
8+
9+
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
10+
// Only allow POST requests
11+
if (req.method !== 'POST') {
12+
return res.status(405).json({ error: 'Method not allowed' });
13+
}
14+
const signatureHeader = req.headers['x-gitbook-signature'] as string | undefined;
15+
if (!signatureHeader) {
16+
return res.status(400).json({ error: 'Missing signature header' });
17+
}
18+
// We cannot use env from `@/v2/lib/env` here as it make it crash because of the import "server-only" in the file.
19+
if (process.env.GITBOOK_SECRET) {
20+
try {
21+
const computedSignature = crypto
22+
.createHmac('sha256', process.env.GITBOOK_SECRET)
23+
.update(JSON.stringify(req.body))
24+
.digest('hex');
25+
26+
if (computedSignature === signatureHeader) {
27+
const results = await Promise.allSettled(
28+
(req.body as JsonBody).paths.map((path) => {
29+
// biome-ignore lint/suspicious/noConsole: we want to log here
30+
console.log(`Revalidating path: ${path}`);
31+
return res.revalidate(path);
32+
})
33+
);
34+
return res.status(200).json({
35+
success: results.every((result) => result.status === 'fulfilled'),
36+
errors: results
37+
.filter((result) => result.status === 'rejected')
38+
.map((result) => (result as PromiseRejectedResult).reason),
39+
});
40+
}
41+
return res.status(401).json({ error: 'Invalid signature' });
42+
} catch (error) {
43+
console.error('Error during revalidation:', error);
44+
return res.status(400).json({ error: 'Invalid request or unable to parse JSON' });
45+
}
46+
}
47+
// If no secret is set, we do not allow revalidation
48+
return res.status(403).json({ error: 'Revalidation is disabled' });
49+
}

0 commit comments

Comments
 (0)