UNPKG

@upstash/qstash

Version:

Official Typescript client for QStash

178 lines (176 loc) 5.87 kB
import { Receiver, serve } from "./chunk-RQPZUJXG.mjs"; // platforms/nextjs.ts var BAD_REQUEST = 400; function verifySignature(handler, config) { const currentSigningKey = config?.currentSigningKey ?? process.env.QSTASH_CURRENT_SIGNING_KEY; if (!currentSigningKey) { throw new Error( "currentSigningKey is required, either in the config or as env variable QSTASH_CURRENT_SIGNING_KEY" ); } const nextSigningKey = config?.nextSigningKey ?? process.env.QSTASH_NEXT_SIGNING_KEY; if (!nextSigningKey) { throw new Error( "nextSigningKey is required, either in the config or as env variable QSTASH_NEXT_SIGNING_KEY" ); } const receiver = new Receiver({ currentSigningKey, nextSigningKey }); return async (request, response) => { const signature = request.headers["upstash-signature"]; if (!signature) { response.status(BAD_REQUEST); response.send("`Upstash-Signature` header is missing"); response.end(); return; } if (typeof signature !== "string") { throw new TypeError("`Upstash-Signature` header is not a string"); } const chunks = []; for await (const chunk of request) { chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk); } const body = Buffer.concat(chunks).toString("utf8"); const isValid = await receiver.verify({ signature, body, clockTolerance: config?.clockTolerance }); if (!isValid) { response.status(BAD_REQUEST); response.send("Invalid signature"); response.end(); return; } try { request.body = request.headers["content-type"] === "application/json" ? JSON.parse(body) : body; } catch { request.body = body; } return handler(request, response); }; } function verifySignatureEdge(handler, config) { const currentSigningKey = config?.currentSigningKey ?? process.env.QSTASH_CURRENT_SIGNING_KEY; if (!currentSigningKey) { throw new Error( "currentSigningKey is required, either in the config or as env variable QSTASH_CURRENT_SIGNING_KEY" ); } const nextSigningKey = config?.nextSigningKey ?? process.env.QSTASH_NEXT_SIGNING_KEY; if (!nextSigningKey) { throw new Error( "nextSigningKey is required, either in the config or as env variable QSTASH_NEXT_SIGNING_KEY" ); } const receiver = new Receiver({ currentSigningKey, nextSigningKey }); return async (request, nfe) => { const requestClone = request.clone(); const signature = request.headers.get("upstash-signature"); if (!signature) { return new Response(new TextEncoder().encode("`Upstash-Signature` header is missing"), { status: 403 }); } if (typeof signature !== "string") { throw new TypeError("`Upstash-Signature` header is not a string"); } const body = await requestClone.text(); const isValid = await receiver.verify({ signature, body, clockTolerance: config?.clockTolerance }); if (!isValid) { return new Response(new TextEncoder().encode("invalid signature"), { status: 403 }); } return handler(request, nfe); }; } function verifySignatureAppRouter(handler, config) { const currentSigningKey = config?.currentSigningKey ?? process.env.QSTASH_CURRENT_SIGNING_KEY; if (!currentSigningKey) { throw new Error( "currentSigningKey is required, either in the config or as env variable QSTASH_CURRENT_SIGNING_KEY" ); } const nextSigningKey = config?.nextSigningKey ?? process.env.QSTASH_NEXT_SIGNING_KEY; if (!nextSigningKey) { throw new Error( "nextSigningKey is required, either in the config or as env variable QSTASH_NEXT_SIGNING_KEY" ); } const receiver = new Receiver({ currentSigningKey, nextSigningKey }); return async (request, params) => { const requestClone = request.clone(); const signature = request.headers.get("upstash-signature"); if (!signature) { return new Response(new TextEncoder().encode("`Upstash-Signature` header is missing"), { status: 403 }); } if (typeof signature !== "string") { throw new TypeError("`Upstash-Signature` header is not a string"); } const body = await requestClone.text(); const isValid = await receiver.verify({ signature, body, clockTolerance: config?.clockTolerance }); if (!isValid) { return new Response(new TextEncoder().encode("invalid signature"), { status: 403 }); } return handler(request, params); }; } var serve2 = (routeFunction, options) => { const handler = serve(routeFunction, { onStepFinish: (workflowRunId) => new Response(JSON.stringify({ workflowRunId }), { status: 200 }), ...options }); return async (request) => { return await handler(request); }; }; var servePagesRouter = (routeFunction, options) => { const handler = serve(routeFunction, options); return async (req, res) => { if (req.method?.toUpperCase() !== "POST") { res.status(405).json("Only POST requests are allowed in worklfows"); return; } else if (!req.url) { res.status(400).json("url not found in the request"); return; } const protocol = req.headers["x-forwarded-proto"]; const baseUrl = options?.baseUrl ?? `${protocol}://${req.headers.host}`; const request = new Request(options?.url ?? `${baseUrl}${req.url}`, { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition body: JSON.stringify(req.body) ?? "", headers: new Headers(req.headersDistinct), method: "POST" }); const response = await handler(request); res.status(response.status).json(await response.json()); }; }; export { serve2 as serve, servePagesRouter, verifySignature, verifySignatureAppRouter, verifySignatureEdge };