@bob-obringer/nextjs-sanity-io-webhooks
Version:
Declaritive Sanity.io webhook route generator
79 lines (78 loc) • 3.11 kB
JavaScript
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");
}