upstash / qstash-js

Message queue for serverless
https://docs.upstash.com/qstash
MIT License
135 stars 12 forks source link

Add a working example of nextjs edge functions on Vercel #22

Closed spyl94 closed 10 months ago

spyl94 commented 1 year ago

It would be great to have an example of qstash verifySignature inside a Vercel Edge Fuctions.

The README say it's supported but I'm getting Error: The edge runtime does not support Node.js 'crypto' module. error. (https://nextjs.org/docs/messages/node-module-in-edge-runtime)

import { verifySignature } from '@upstash/qstash/nextjs';

export const config = {
  runtime: 'experimental-edge',
  api: {
    bodyParser: false,
  },
};

const handler = async () => {
  console.log('If this is printed, the signature has already been verified');
};

// @ts-expect-error edge is not supported yet by TS types
export default verifySignature(handler);
chronark commented 1 year ago

Hey @spyl94. The Receiver Should work in edge functions.

verifySignature is a nextjs specific syntactic sugar for regular serverless function. Even if it didn't use nodejs specifics, it would not be compatible with the signature of an edge function handler.

I'm curious why do you want to run this at the edge? I doubt latency is your motivation here.

spyl94 commented 1 year ago

Thanks, I will try to implement my own verifySignature for edge functions.

My main motivation is that edge functions are a lot cheaper to run than serverless functions (https://vercel.com/docs/concepts/limits/overview#functions-comparison), and powerful enough to consume a single message !

spyl94 commented 1 year ago

I tried to use :

import { Receiver } from '@upstash/qstash/nodejs';

const receiver = new Receiver({
    currentSigningKey,
    nextSigningKey,
    subtleCrypto: crypto.subtle,
});

But I still got the The edge runtime does not support Node.js 'crypto' module. error.

So instead I had to rewrite without the SDK : https://gist.github.com/spyl94/f49f4bb34aa1c3fec724de7c40f82f78

chronark commented 1 year ago

Hmm. I would've assumed that something like this should work: https://github.com/upstash/sdk-qstash-ts/tree/main/examples%2Fcloudflare-workers

Since vercel edge is built on CF workers

spyl94 commented 1 year ago

Yes importing from @upstash/qstash/cloudflare works great !

chadedrupt commented 1 year ago

This is causing issues for me in a plain Node.js backed serverless functions. Suspecting this is what's causing it https://github.com/upstash/sdk-qstash-ts/blob/66b1c18fc19e0a93ae5dd70a4f653a9a3b9e3651/pkg/receiver.ts#L2

pencilcheck commented 1 year ago

might be related as crypto isn't supported in node 14. it looks like qstash is assuming node 16+ which is not possbile due to the library dependencies

chronark commented 1 year ago

@chadedrupt what node version are you on? as @pencilcheck said, this is probably due to node 14

angelhodar commented 1 year ago

Just in case anyone has problems, if you want to process the request json after validation, make sure you clone it before, otherwise you will get an error saying Body is unusable. This is an example of edge validator using @upstash/qstash/cloudlfare:

export const validate = (handler: any) => {
  const qstashReceiver = new Receiver({
    currentSigningKey: process.env.QSTASH_CURRENT_SIGNING_KEY!,
    nextSigningKey: process.env.QSTASH_NEXT_SIGNING_KEY!,
  });

  return async (request: Request, ...params: any) => {
    const clonedRequest = request.clone()

    const isValid = await qstashReceiver.verify({
      signature: clonedRequest.headers.get("upstash-signature")!,
      body: await clonedRequest.text(),
    });

    if (!isValid) {
      return new Response("Unauthorized", {
        status: 401,
        statusText: "Unauthorized",
      });
    }

    return await handler(request, ...params);
  };
};

Edit: If you try to use requests.clone() and then use the request.json(), it will break in Vercel Edge runtime. You can see the issue here

chronark commented 10 months ago

https://github.com/upstash/sdk-qstash-ts/tree/main/examples/nextjs this example now has