UNPKG

@bob-obringer/nextjs-sanity-io-webhooks

Version:
79 lines (78 loc) 3.11 kB
import { isValidSignature, SIGNATURE_HEADER_NAME } from "@sanity/webhook"; import { HttpErrorBadRequest, HttpErrorForbidden, unstable_getErrorResponse, } from "@bob-obringer/http-errors"; import {} from "@sanity/client"; import { revalidatePath, revalidateTag } from "next/cache"; export function createSanityWebhook({ handlers, secret, }) { return { async POST(req) { let doc; try { doc = await verifyBody(req, secret); } catch (e) { return unstable_getErrorResponse(e); } const sanityOperation = req.headers.get("sanity-operation"); try { for (const { operations, handler, documentType, revalidatePath: _revalidatePath, revalidateTag: _revalidateTag, } of handlers) { if (!isTargetDocumentType(doc, documentType)) continue; const ops = Array.isArray(operations) ? operations : [operations]; if (!ops.includes(sanityOperation)) continue; console.log(`Sanity Webhook: ${sanityOperation} ${doc._type} (${doc._id})`); if (_revalidatePath) { const paths = Array.isArray(_revalidatePath) ? _revalidatePath : [_revalidatePath]; for (const path of paths) revalidatePath(path, "page"); } if (_revalidateTag) { const tags = Array.isArray(_revalidateTag) ? _revalidateTag : [_revalidateTag]; for (const tag of tags) revalidateTag(tag); } if (handler) await handler(doc, sanityOperation); } return new Response("OK", { status: 200 }); } catch (e) { return unstable_getErrorResponse(e); } }, }; } function isTargetDocumentType(doc, documentType) { return doc._type === documentType; } async function verifyBody(req, secret) { if (!req.body) throw new HttpErrorBadRequest("Missing Body"); const signature = req.headers.get(SIGNATURE_HEADER_NAME); if (!signature) throw new HttpErrorForbidden("Missing Signature"); const body = await readBody(req.body); const isValidRequest = await isValidSignature(body, signature, secret); if (!isValidRequest) throw new HttpErrorForbidden("Invalid Signature"); return JSON.parse(body); } async function readBody(readable) { const reader = readable.getReader(); const chunks = []; try { let result = await reader.read(); while (!result.done) { chunks.push(result.value); result = await reader.read(); } } finally { reader.releaseLock(); } return Buffer.concat(chunks).toString("utf8"); }