From 3eed62b7d42b8b90f8dad1917831013626065ac2 Mon Sep 17 00:00:00 2001 From: Cody Olsen Date: Mon, 8 Apr 2024 15:30:55 +0200 Subject: [PATCH] fix: migrate from `next-sanity/webhook` to `@sanity/webhook` --- package-lock.json | 1 + package.json | 1 + pages/api/revalidate.ts | 61 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index bfdb8973b..eb0309c19 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "@sanity/preview-url-secret": "1.6.7", "@sanity/vision": "3.36.4", "@sanity/visual-editing": "1.8.7", + "@sanity/webhook": "4.0.2-bc", "@vercel/og": "0.6.2", "classnames": "2.5.1", "date-fns": "3.6.0", diff --git a/package.json b/package.json index bff06ac97..563b207c7 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@sanity/preview-url-secret": "1.6.7", "@sanity/vision": "3.36.4", "@sanity/visual-editing": "1.8.7", + "@sanity/webhook": "4.0.2-bc", "@vercel/og": "0.6.2", "classnames": "2.5.1", "date-fns": "3.6.0", diff --git a/pages/api/revalidate.ts b/pages/api/revalidate.ts index 97cedf2ec..e2a469318 100644 --- a/pages/api/revalidate.ts +++ b/pages/api/revalidate.ts @@ -22,17 +22,27 @@ * 16. Redeploy with `npx vercel --prod` to apply the new environment variable */ +import { isValidSignature, SIGNATURE_HEADER_NAME } from '@sanity/webhook' import { apiVersion, dataset, projectId } from 'lib/sanity.api' import type { NextApiRequest, NextApiResponse } from 'next' +import type { PageConfig } from 'next/types' import { createClient, groq, type SanityClient, type SanityDocument, } from 'next-sanity' -import { parseBody, type ParsedBody } from 'next-sanity/webhook' - -export { config } from 'next-sanity/webhook' +import type { ParsedBody } from 'next-sanity/webhook' + +export const config = { + api: { + /** + * Next.js will by default parse the body, which can lead to invalid signatures. + */ + bodyParser: false, + }, + runtime: 'nodejs', +} satisfies PageConfig export default async function revalidate( req: NextApiRequest, @@ -67,6 +77,49 @@ export default async function revalidate( } } +async function parseBody( + req: NextApiRequest, + secret?: string, + waitForContentLakeEventualConsistency: boolean = true, +): Promise> { + let signature = req.headers[SIGNATURE_HEADER_NAME] + if (Array.isArray(signature)) { + signature = signature[0] + } + if (!signature) { + console.error('Missing signature header') + return { body: null, isValidSignature: null } + } + + if (req.readableEnded) { + throw new Error( + `Request already ended and the POST body can't be read. Have you setup \`export {config} from 'next-sanity/webhook' in your webhook API handler?\``, + ) + } + + const body = await readBody(req) + const validSignature = secret + ? await isValidSignature(body, signature, secret.trim()) + : null + + if (validSignature !== false && waitForContentLakeEventualConsistency) { + await new Promise((resolve) => setTimeout(resolve, 1000)) + } + + return { + body: body.trim() ? JSON.parse(body) : null, + isValidSignature: validSignature, + } +} + +async function readBody(readable: NextApiRequest): Promise { + const chunks = [] + for await (const chunk of readable) { + chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk) + } + return Buffer.concat(chunks).toString('utf8') +} + type StaleRoute = '/' | `/posts/${string}` async function queryStaleRoutes( @@ -81,7 +134,7 @@ async function queryStaleRoutes( if (body._type === 'post') { const exists = await client.fetch(groq`*[_id == $id][0]`, { id: body._id }) if (!exists) { - let staleRoutes: StaleRoute[] = ['/'] + const staleRoutes: StaleRoute[] = ['/'] if ((body.slug as any)?.current) { staleRoutes.push(`/posts/${(body.slug as any).current}`) }